mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 02:56:08 +00:00
[Exegesis] Implemented strategy for load operation (#113458)
This fix helps to map operand memory to destination registers. If instruction is load, we can self-alias it in case when instruction overrides whole address register. For that we use provided scratch memory.
This commit is contained in:
parent
d0eeeab557
commit
0fcbf148df
60
llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
Normal file
60
llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LD 2>&1 | FileCheck --check-prefix=TEST1 %s
|
||||||
|
|
||||||
|
TEST1: ---
|
||||||
|
TEST1-NEXT: mode: latency
|
||||||
|
TEST1-NEXT: key:
|
||||||
|
TEST1-NEXT: instructions:
|
||||||
|
TEST1-NEXT: - 'LD X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LW 2>&1 | FileCheck --check-prefix=TEST2 %s
|
||||||
|
|
||||||
|
TEST2: ---
|
||||||
|
TEST2-NEXT: mode: latency
|
||||||
|
TEST2-NEXT: key:
|
||||||
|
TEST2-NEXT: instructions:
|
||||||
|
TEST2-NEXT: - 'LW X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LH 2>&1 | FileCheck --check-prefix=TEST3 %s
|
||||||
|
|
||||||
|
TEST3: ---
|
||||||
|
TEST3-NEXT: mode: latency
|
||||||
|
TEST3-NEXT: key:
|
||||||
|
TEST3-NEXT: instructions:
|
||||||
|
TEST3-NEXT: - 'LH X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LWU 2>&1 | FileCheck --check-prefix=TEST4 %s
|
||||||
|
|
||||||
|
TEST4: ---
|
||||||
|
TEST4-NEXT: mode: latency
|
||||||
|
TEST4-NEXT: key:
|
||||||
|
TEST4-NEXT: instructions:
|
||||||
|
TEST4-NEXT: - 'LWU X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LBU 2>&1 | FileCheck --check-prefix=TEST5 %s
|
||||||
|
|
||||||
|
TEST5: ---
|
||||||
|
TEST5-NEXT: mode: latency
|
||||||
|
TEST5-NEXT: key:
|
||||||
|
TEST5-NEXT: instructions:
|
||||||
|
TEST5-NEXT: - 'LBU X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LUI 2>&1 | FileCheck --check-prefix=TEST6 %s
|
||||||
|
|
||||||
|
TEST6: LUI: No strategy found to make the execution serial
|
||||||
|
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -opcode-name=LB 2>&1 | FileCheck --check-prefix=TEST7 %s
|
||||||
|
|
||||||
|
TEST7: ---
|
||||||
|
TEST7-NEXT: mode: latency
|
||||||
|
TEST7-NEXT: key:
|
||||||
|
TEST7-NEXT: instructions:
|
||||||
|
TEST7-NEXT: - 'LB X10 X10 i_0x0'
|
||||||
|
|
||||||
|
# RUN: llvm-exegesis -mode=latency --benchmark-phase=assemble-measured-code -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -mattr=+a -opcode-name=LR_W_RL 2>&1 | FileCheck --check-prefix=TEST8 %s
|
||||||
|
|
||||||
|
TEST8: ---
|
||||||
|
TEST8-NEXT: mode: latency
|
||||||
|
TEST8-NEXT: key:
|
||||||
|
TEST8-NEXT: instructions:
|
||||||
|
TEST8-NEXT: - 'LR_W_RL X10 X10'
|
@ -106,7 +106,48 @@ static void appendCodeTemplates(const LLVMState &State,
|
|||||||
}
|
}
|
||||||
case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: {
|
case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: {
|
||||||
// Select back-to-back memory instruction.
|
// Select back-to-back memory instruction.
|
||||||
// TODO: Implement me.
|
|
||||||
|
auto &I = Variant.getInstr();
|
||||||
|
if (I.Description.mayLoad()) {
|
||||||
|
// If instruction is load, we can self-alias it in case when instruction
|
||||||
|
// overrides whole address register. For that we use provided scratch
|
||||||
|
// memory.
|
||||||
|
|
||||||
|
// TODO: now it is not checked if load writes the whole register.
|
||||||
|
|
||||||
|
auto DefOpIt = find_if(I.Operands, [](Operand const &Op) {
|
||||||
|
return Op.isDef() && Op.isReg();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (DefOpIt == I.Operands.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Operand &DefOp = *DefOpIt;
|
||||||
|
const ExegesisTarget &ET = State.getExegesisTarget();
|
||||||
|
unsigned ScratchMemoryRegister = ET.getScratchMemoryRegister(
|
||||||
|
State.getTargetMachine().getTargetTriple());
|
||||||
|
const llvm::MCRegisterClass &RegClass =
|
||||||
|
State.getTargetMachine().getMCRegisterInfo()->getRegClass(
|
||||||
|
DefOp.getExplicitOperandInfo().RegClass);
|
||||||
|
|
||||||
|
// Register classes of def operand and memory operand must be the same
|
||||||
|
// to perform aliasing.
|
||||||
|
if (!RegClass.contains(ScratchMemoryRegister))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ET.fillMemoryOperands(Variant, ScratchMemoryRegister, 0);
|
||||||
|
Variant.getValueFor(DefOp) = MCOperand::createReg(ScratchMemoryRegister);
|
||||||
|
|
||||||
|
CodeTemplate CT;
|
||||||
|
CT.Execution = ExecutionModeBit;
|
||||||
|
CT.ScratchSpacePointerInReg = ScratchMemoryRegister;
|
||||||
|
|
||||||
|
CT.Info = std::string(ExecutionClassDescription);
|
||||||
|
CT.Instructions.push_back(std::move(Variant));
|
||||||
|
CodeTemplates.push_back(std::move(CT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement more cases
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
|
case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user