diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s new file mode 100644 index 000000000000..63c03516ca5d --- /dev/null +++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s @@ -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' diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp index f233ea4288a7..bdfc93e22273 100644 --- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp +++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp @@ -106,7 +106,48 @@ static void appendCodeTemplates(const LLVMState &State, } case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: { // 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; } case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {