[llvm] [Exegesis][RISCV] Add RISCV support for llvm-exegesis (PR #89047)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 28 06:14:56 PDT 2024
https://github.com/AnastasiyaChernikova updated https://github.com/llvm/llvm-project/pull/89047
>From 3d4fba71357d3c10570a076dc93d58f6020159fc Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Thu, 4 Apr 2024 14:52:53 +0300
Subject: [PATCH 01/10] [Exegesis][RISCV] Add RISCV support for llvm-exegesis
Llvm-exegesis RISCV port is a result of team effort. Below everyone involved listed.
Co-authored-by: Konstantin Vladimirov <konstantin.vladimirov at syntacore.com>
Co-authored-by: Dmitrii Petrov <dmitrii.petrov at syntacore.com>
Co-authored-by: Dmitry Bushev <dmitry.bushev at syntacore.com>
Co-authored-by: Mark Goncharov <mark.goncharov at syntacore.com>
Co-authored-by: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
---
.../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 3 +
llvm/lib/Target/RISCV/RISCVInstrInfo.td | 4 +-
llvm/lib/Target/RISCV/RISCVInstrInfoF.td | 4 +
.../RISCV/latency-by-extension-A.s | 59 +++
.../RISCV/latency-by-extension-C.s | 65 +++
.../llvm-exegesis/RISCV/latency-by-load.s | 60 +++
.../RISCV/latency-by-opcode-name-FADD_D.s | 11 +
.../llvm-exegesis/lib/AArch64/Target.cpp | 4 +
llvm/tools/llvm-exegesis/lib/Assembler.cpp | 10 +-
llvm/tools/llvm-exegesis/lib/BenchmarkCode.h | 5 +
llvm/tools/llvm-exegesis/lib/CMakeLists.txt | 3 +
llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp | 8 +
llvm/tools/llvm-exegesis/lib/CodeTemplate.h | 6 +
llvm/tools/llvm-exegesis/lib/LlvmState.cpp | 6 +
.../llvm-exegesis/lib/MCInstrDescView.cpp | 33 +-
.../tools/llvm-exegesis/lib/MCInstrDescView.h | 13 +-
llvm/tools/llvm-exegesis/lib/Mips/Target.cpp | 6 +-
llvm/tools/llvm-exegesis/lib/PerfHelper.h | 2 +-
.../llvm-exegesis/lib/PowerPC/Target.cpp | 7 +
.../llvm-exegesis/lib/RISCV/CMakeLists.txt | 22 +
.../llvm-exegesis/lib/RISCV/RISCVCounters.cpp | 66 +++
.../llvm-exegesis/lib/RISCV/RISCVCounters.h | 31 ++
llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp | 414 ++++++++++++++++++
.../lib/SerialSnippetGenerator.cpp | 62 ++-
llvm/tools/llvm-exegesis/lib/SnippetFile.cpp | 15 +-
.../llvm-exegesis/lib/SnippetGenerator.cpp | 13 +-
llvm/tools/llvm-exegesis/lib/Target.cpp | 4 +
llvm/tools/llvm-exegesis/lib/Target.h | 19 +
llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 6 +
llvm/tools/llvm-exegesis/llvm-exegesis.cpp | 68 ++-
30 files changed, 984 insertions(+), 45 deletions(-)
create mode 100644 llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
create mode 100644 llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
create mode 100644 llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
create mode 100644 llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
create mode 100644 llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
create mode 100644 llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
create mode 100644 llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.h
create mode 100644 llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 08f056f78979a..552f5962b22a5 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -299,6 +299,9 @@ enum OperandType : unsigned {
OPERAND_RVKRNUM_2_14,
OPERAND_SPIMM,
OPERAND_LAST_RISCV_IMM = OPERAND_SPIMM,
+ // Operand is a 3-bit rounding mode, '111' indicates FRM register.
+ // Represents 'frm' argument passing to floating-point operations.
+ OPERAND_FRMARG,
// Operand is either a register or uimm5, this is used by V extension pseudo
// instructions to represent a value that be passed as AVL to either vsetvli
// or vsetivli.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 9d574edb4e6d1..c0a77db8601c7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -511,7 +511,7 @@ class BranchCC_rri<bits<3> funct3, string opcodestr>
let isTerminator = 1;
}
-let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
+let hasSideEffects = 0, mayLoad = 1, mayStore = 0, UseNamedOperandTable = 1 in {
class Load_ri<bits<3> funct3, string opcodestr>
: RVInstI<funct3, OPC_LOAD, (outs GPR:$rd), (ins GPRMem:$rs1, simm12:$imm12),
opcodestr, "$rd, ${imm12}(${rs1})">;
@@ -526,7 +526,7 @@ class HLoad_r<bits<7> funct7, bits<5> funct5, string opcodestr>
// Operands for stores are in the order srcreg, base, offset rather than
// reflecting the order these fields are specified in the instruction
// encoding.
-let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in {
+let hasSideEffects = 0, mayLoad = 0, mayStore = 1, UseNamedOperandTable = 1 in {
class Store_rri<bits<3> funct3, string opcodestr>
: RVInstS<funct3, OPC_STORE, (outs),
(ins GPR:$rs2, GPRMem:$rs1, simm12:$imm12),
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
index 7d89608de1223..846f90e83df80 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
@@ -130,6 +130,8 @@ def frmarg : Operand<XLenVT> {
let ParserMatchClass = FRMArg;
let PrintMethod = "printFRMArg";
let DecoderMethod = "decodeFRMArg";
+ let OperandType = "OPERAND_FRMARG";
+ let OperandNamespace = "RISCVOp";
}
// Variants of the rounding mode operand that default to 'rne'. This is used
@@ -150,6 +152,8 @@ def frmarglegacy : Operand<XLenVT> {
let ParserMatchClass = FRMArgLegacy;
let PrintMethod = "printFRMArgLegacy";
let DecoderMethod = "decodeFRMArg";
+ let OperandType = "OPERAND_FRMARG";
+ let OperandNamespace = "RISCVOp";
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
new file mode 100644
index 0000000000000..8cd11ffc3c1f6
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
@@ -0,0 +1,59 @@
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOAND_D -mattr="+a" | FileCheck --check-prefix=TEST1 %s
+
+TEST1: ---
+TEST1-NEXT: mode: latency
+TEST1-NEXT: key:
+TEST1-NEXT: instructions:
+TEST1-NEXT: - 'AMOAND_D [[RE01:X[0-9]+]] X10 [[RE01:X[0-9]+]]'
+TEST1-NEXT: config: ''
+TEST1-NEXT: register_initial_values:
+TEST1-NEXT: - '[[RE01:X[0-9]+]]=0x0'
+TEST1-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOADD_W -mattr="+a" | FileCheck --check-prefix=TEST2 %s
+
+TEST2: ---
+TEST2-NEXT: mode: latency
+TEST2-NEXT: key:
+TEST2-NEXT: instructions:
+TEST2-NEXT: - 'AMOADD_W [[RE02:X[0-9]+]] X10 [[RE02:X[0-9]+]]'
+TEST2-NEXT: config: ''
+TEST2-NEXT: register_initial_values:
+TEST2-NEXT: - '[[RE02:X[0-9]+]]=0x0'
+TEST2-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOMAXU_D -mattr="+a" | FileCheck --check-prefix=TEST3 %s
+
+TEST3: ---
+TEST3-NEXT: mode: latency
+TEST3-NEXT: key:
+TEST3-NEXT: instructions:
+TEST3-NEXT: - 'AMOMAXU_D [[RE03:X[0-9]+]] X10 [[RE03:X[0-9]+]]'
+TEST3-NEXT: config: ''
+TEST3-NEXT: register_initial_values:
+TEST3-NEXT: - '[[RE03:X[0-9]+]]=0x0'
+TEST3-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOMIN_W -mattr="+a" | FileCheck --check-prefix=TEST4 %s
+
+TEST4: ---
+TEST4-NEXT: mode: latency
+TEST4-NEXT: key:
+TEST4-NEXT: instructions:
+TEST4-NEXT: - 'AMOMIN_W [[RE04:X[0-9]+]] X10 [[RE04:X[0-9]+]]'
+TEST4-NEXT: config: ''
+TEST4-NEXT: register_initial_values:
+TEST4-NEXT: - '[[RE04:X[0-9]+]]=0x0'
+TEST4-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOXOR_D -mattr="+a" | FileCheck --check-prefix=TEST5 %s
+
+TEST5: ---
+TEST5-NEXT: mode: latency
+TEST5-NEXT: key:
+TEST5-NEXT: instructions:
+TEST5-NEXT: - 'AMOXOR_D [[RE05:X[0-9]+]] X10 [[RE05:X[0-9]+]]'
+TEST5-NEXT: config: ''
+TEST5-NEXT: register_initial_values:
+TEST5-NEXT: - '[[RE05:X[0-9]+]]=0x0'
+TEST5-LAST: ...
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
new file mode 100644
index 0000000000000..e22ddc2d76955
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
@@ -0,0 +1,65 @@
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ADDI -mattr=+c | FileCheck --check-prefix=TEST1 %s
+
+TEST1: ---
+TEST1-NEXT: mode: latency
+TEST1-NEXT: key:
+TEST1-NEXT: instructions:
+TEST1-NEXT: - 'C_ADDI [[REG01:X[0-9]+]] [[RE02:X[0-9]+]] [[IMM0:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ADDIW -mattr=+c | FileCheck --check-prefix=TEST2 %s
+
+TEST2: ---
+TEST2-NEXT: mode: latency
+TEST2-NEXT: key:
+TEST2-NEXT: instructions:
+TEST2-NEXT: - 'C_ADDIW [[REG11:X[0-9]+]] [[RE12:X[0-9]+]] [[IMM1:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ANDI -mattr=+c | FileCheck --check-prefix=TEST3 %s
+
+TEST3: ---
+TEST3-NEXT: mode: latency
+TEST3-NEXT: key:
+TEST3-NEXT: instructions:
+TEST3-NEXT: - 'C_ANDI [[REG31:X[0-9]+]] [[REG32:X[0-9]+]] [[IMM3:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SLLI -mattr=+c | FileCheck --check-prefix=TEST4 %s
+
+TEST4: ---
+TEST4-NEXT: mode: latency
+TEST4-NEXT: key:
+TEST4-NEXT: instructions:
+TEST4-NEXT: - 'C_SLLI [[REG81:X[0-9]+]] [[REG82:X[0-9]+]] [[IMM8:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SRAI -mattr=+c | FileCheck --check-prefix=TEST5 %s
+
+TEST5: ---
+TEST5-NEXT: mode: latency
+TEST5-NEXT: key:
+TEST5-NEXT: instructions:
+TEST5-NEXT: - 'C_SRAI [[REG91:X[0-9]+]] [[REG92:X[0-9]+]] [[IMM9:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SRLI -mattr=+c | FileCheck --check-prefix=TEST6 %s
+
+TEST6: ---
+TEST6-NEXT: mode: latency
+TEST6-NEXT: key:
+TEST6-NEXT: instructions:
+TEST6-NEXT: - 'C_SRLI [[REG101:X[0-9]+]] [[REG102:X[0-9]+]] [[IMM10:i_0x[0-9]+]]'
+TEST6-LAST: ...
+
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_LD -mattr=+c | FileCheck --check-prefix=TEST7 %s
+
+TEST7: ---
+TEST7-NEXT: mode: latency
+TEST7-NEXT: key:
+TEST7-NEXT: instructions:
+TEST7-NEXT: - 'C_LD [[REG61:X[0-9]+]] [[REG62:X[0-9]+]] [[IMM6:i_0x[0-9]+]]'
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_LW -mattr=+c | FileCheck --check-prefix=TEST8 %s
+
+TEST8: ---
+TEST8-NEXT: mode: latency
+TEST8-NEXT: key:
+TEST8-NEXT: instructions:
+TEST8-NEXT: - 'C_LW [[REG71:X[0-9]+]] [[REG72:X[0-9]+]] [[IMM7:i_0x[0-9]+]]'
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 0000000000000..b685d8759c27c
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
@@ -0,0 +1,60 @@
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LD | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LW | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LH | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LWU | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LBU | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LB | 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 -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LR_W_RL -mattr="+a" | 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/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
new file mode 100644
index 0000000000000..fd58bfb7c1a84
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
@@ -0,0 +1,11 @@
+# RUN: llvm-exegesis -mtriple=riscv64-unknown-linux-gnu -mode=latency --benchmark-phase=assemble-measured-code -mattr=+d -opcode-name=FADD_D | FileCheck %s
+
+CHECK: ---
+CHECK-NEXT: mode: latency
+CHECK-NEXT: key:
+CHECK-NEXT: instructions:
+CHECK-NEXT: - 'FADD_D [[REG1:F[0-9]+_D]] [[REG2:F[0-9]+_D]] [[REG3:F[0-9]+_D]] i_0x7'
+CHECK-NEXT: config: ''
+CHECK-NEXT: register_initial_values:
+CHECK-DAG: - '[[REG1]]=0x0'
+CHECK-LAST: ...
diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
index 51846862f0a73..6a3eba2459556 100644
--- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
@@ -45,6 +45,10 @@ class ExegesisAArch64Target : public ExegesisTarget {
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
private:
+ unsigned findRegisterByName(const StringRef RegName) const override {
+ return AArch64::NoRegister;
+ }
+
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override {
if (AArch64::GPR32RegClass.contains(Reg))
diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
index 92ab3a96d91e6..2908ea80d0e47 100644
--- a/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -168,7 +168,15 @@ void BasicBlockFiller::addInstruction(const MCInst &Inst, const DebugLoc &DL) {
} else if (Op.isImm()) {
Builder.addImm(Op.getImm());
} else if (!Op.isValid()) {
- llvm_unreachable("Operand is not set");
+ std::string Message;
+ llvm::raw_string_ostream MessageOut(Message);
+ MessageOut << "Operand is not set: Instr: ";
+ Inst.dump_pretty(MessageOut, MCII->getName(Inst.getOpcode()));
+ MessageOut << "; OpIndex: " << OpIndex;
+ const MCOperandInfo &OperandInfo = MCID.operands()[OpIndex];
+ MessageOut << "; OpInfo.OperandType: "
+ << static_cast<uint32_t>(OperandInfo.OperandType);
+ report_fatal_error(Twine(Message));
} else {
llvm_unreachable("Not yet implemented");
}
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
index 1db8472e99f7c..4d5fc241fde0d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
@@ -17,6 +17,11 @@
namespace llvm {
namespace exegesis {
+struct ScratchMemoryStore {
+ unsigned Reg;
+ unsigned Offset;
+};
+
// A collection of instructions that are to be assembled, executed and measured.
struct BenchmarkCode {
BenchmarkKey Key;
diff --git a/llvm/tools/llvm-exegesis/lib/CMakeLists.txt b/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
index 414b49e5e021c..d95c37ff5426b 100644
--- a/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
+++ b/llvm/tools/llvm-exegesis/lib/CMakeLists.txt
@@ -12,6 +12,9 @@ endif()
if (LLVM_TARGETS_TO_BUILD MATCHES "Mips")
list(APPEND LLVM_EXEGESIS_TARGETS "Mips")
endif()
+if(LLVM_TARGETS_TO_BUILD MATCHES "RISCV")
+ list(APPEND LLVM_EXEGESIS_TARGETS "RISCV")
+endif()
set(LLVM_EXEGESIS_TARGETS ${LLVM_EXEGESIS_TARGETS} PARENT_SCOPE)
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
index fd156ee01e7ce..9b5bfe3196dcd 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
@@ -57,6 +57,14 @@ const MCOperand &InstructionTemplate::getValueFor(const Operand &Op) const {
return getValueFor(Instr->Variables[Op.getVariableIndex()]);
}
+MCOperand &InstructionTemplate::getValueFor(unsigned OpIdx) {
+ return getValueFor(Instr->Variables[OpIdx]);
+}
+
+const MCOperand &InstructionTemplate::getValueFor(unsigned OpIdx) const {
+ return getValueFor(Instr->Variables[OpIdx]);
+}
+
bool InstructionTemplate::hasImmediateVariables() const {
return any_of(Instr->Variables, [this](const Variable &Var) {
return Instr->getPrimaryOperand(Var).isImmediate();
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
index 7aca224302a1f..85fcb4e908f01 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
@@ -35,6 +35,8 @@ struct InstructionTemplate {
const MCOperand &getValueFor(const Variable &Var) const;
MCOperand &getValueFor(const Operand &Op);
const MCOperand &getValueFor(const Operand &Op) const;
+ MCOperand &getValueFor(unsigned OpIdx);
+ const MCOperand &getValueFor(unsigned OpIdx) const;
bool hasImmediateVariables() const;
const Instruction &getInstr() const { return *Instr; }
ArrayRef<MCOperand> getVariableValues() const { return VariableValues; }
@@ -133,6 +135,10 @@ struct CodeTemplate {
// the pointer to this memory is passed in to the function.
unsigned ScratchSpacePointerInReg = 0;
+ // Require to pre-store value of a given register (fisrt)
+ // to scratch memory with given offset (second)
+ SmallVector<std::pair<unsigned, unsigned>, 2> PreinitScratchMemory;
+
#if defined(__GNUC__) && (defined(__clang__) || LLVM_GNUC_PREREQ(8, 0, 0))
// FIXME: GCC7 bug workaround. Drop #if after GCC7 no longer supported.
private:
diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
index 17d09a1ec0cf3..d387251a687e6 100644
--- a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
+++ b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
@@ -45,6 +45,12 @@ Expected<LLVMState> LLVMState::Create(std::string TripleName,
if (CpuName == "native")
CpuName = std::string(sys::getHostCPUName());
+ if (CpuName.empty()) {
+ std::unique_ptr<MCSubtargetInfo> Empty_STI(
+ TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+ CpuName = Empty_STI->getAllProcessorDescriptions().begin()->Key;
+ }
+
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, CpuName, ""));
assert(STI && "Unable to create subtarget info!");
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
index 9c926d1fc6112..7705d9af4057e 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -89,17 +89,17 @@ const BitVector *BitVectorCache::getUnique(BitVector &&BV) const {
return Entry.get();
}
-Instruction::Instruction(const MCInstrDesc *Description, StringRef Name,
- SmallVector<Operand, 8> Operands,
- SmallVector<Variable, 4> Variables,
- const BitVector *ImplDefRegs,
- const BitVector *ImplUseRegs,
- const BitVector *AllDefRegs,
- const BitVector *AllUseRegs)
+Instruction::Instruction(
+ const MCInstrDesc *Description, StringRef Name,
+ SmallVector<Operand, 8> Operands, SmallVector<Variable, 4> Variables,
+ const BitVector *ImplDefRegs, const BitVector *ImplUseRegs,
+ const BitVector *AllDefRegs, const BitVector *AllUseRegs,
+ const BitVector *MemoryRegs, const BitVector *NotMemoryRegs)
: Description(*Description), Name(Name), Operands(std::move(Operands)),
Variables(std::move(Variables)), ImplDefRegs(*ImplDefRegs),
ImplUseRegs(*ImplUseRegs), AllDefRegs(*AllDefRegs),
- AllUseRegs(*AllUseRegs) {}
+ AllUseRegs(*AllUseRegs), MemoryRegs(*MemoryRegs),
+ NotMemoryRegs(*NotMemoryRegs) {}
std::unique_ptr<Instruction>
Instruction::create(const MCInstrInfo &InstrInfo,
@@ -166,6 +166,9 @@ Instruction::create(const MCInstrInfo &InstrInfo,
BitVector ImplUseRegs = RATC.emptyRegisters();
BitVector AllDefRegs = RATC.emptyRegisters();
BitVector AllUseRegs = RATC.emptyRegisters();
+ BitVector MemoryRegs = RATC.emptyRegisters();
+ BitVector NotMemoryRegs = RATC.emptyRegisters();
+
for (const auto &Op : Operands) {
if (Op.isReg()) {
const auto &AliasingBits = Op.getRegisterAliasing().aliasedBits();
@@ -177,6 +180,10 @@ Instruction::create(const MCInstrInfo &InstrInfo,
ImplDefRegs |= AliasingBits;
if (Op.isUse() && Op.isImplicit())
ImplUseRegs |= AliasingBits;
+ if (Op.isUse() && Op.isMemory())
+ MemoryRegs |= AliasingBits;
+ if (Op.isUse() && !Op.isMemory())
+ NotMemoryRegs |= AliasingBits;
}
}
// Can't use make_unique because constructor is private.
@@ -185,7 +192,9 @@ Instruction::create(const MCInstrInfo &InstrInfo,
std::move(Variables), BVC.getUnique(std::move(ImplDefRegs)),
BVC.getUnique(std::move(ImplUseRegs)),
BVC.getUnique(std::move(AllDefRegs)),
- BVC.getUnique(std::move(AllUseRegs))));
+ BVC.getUnique(std::move(AllUseRegs)),
+ BVC.getUnique(std::move(MemoryRegs)),
+ BVC.getUnique(std::move(NotMemoryRegs))));
}
const Operand &Instruction::getPrimaryOperand(const Variable &Var) const {
@@ -240,6 +249,12 @@ bool Instruction::hasAliasingRegisters(
ForbiddenRegisters);
}
+bool Instruction::hasAliasingNotMemoryRegisters(
+ const BitVector &ForbiddenRegisters) const {
+ return anyCommonExcludingForbidden(AllDefRegs, NotMemoryRegs,
+ ForbiddenRegisters);
+}
+
bool Instruction::hasOneUseOrOneDef() const {
return AllDefRegs.count() || AllUseRegs.count();
}
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index f8ebc07d01f35..edc1a341b27ce 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -133,6 +133,12 @@ struct Instruction {
// aliasing Use and Def registers.
bool hasAliasingRegisters(const BitVector &ForbiddenRegisters) const;
+ // Whether this instruction is self aliasing through some registers.
+ // Repeating this instruction may execute sequentially by picking aliasing
+ // Def and Not Memory Use registers. It may also execute in parallel by
+ // picking non aliasing Def and Not Memory Use registers.
+ bool hasAliasingNotMemoryRegisters(const BitVector &ForbiddenRegisters) const;
+
// Whether this instruction's registers alias with OtherInstr's registers.
bool hasAliasingRegistersThrough(const Instruction &OtherInstr,
const BitVector &ForbiddenRegisters) const;
@@ -160,12 +166,17 @@ struct Instruction {
const BitVector &ImplUseRegs; // The set of aliased implicit use registers.
const BitVector &AllDefRegs; // The set of all aliased def registers.
const BitVector &AllUseRegs; // The set of all aliased use registers.
+ const BitVector &MemoryRegs; // The set of all aliased memory use registers.
+ const BitVector
+ &NotMemoryRegs; // The set of all aliased not memory use registers.
+
private:
Instruction(const MCInstrDesc *Description, StringRef Name,
SmallVector<Operand, 8> Operands,
SmallVector<Variable, 4> Variables, const BitVector *ImplDefRegs,
const BitVector *ImplUseRegs, const BitVector *AllDefRegs,
- const BitVector *AllUseRegs);
+ const BitVector *AllUseRegs, const BitVector *MemoryRegs,
+ const BitVector *NotMemoryRegs);
};
// Instructions are expensive to instantiate. This class provides a cache of
diff --git a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
index 731e037c240df..917c055e29d8f 100644
--- a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
@@ -62,7 +62,7 @@ class ExegesisMipsTarget : public ExegesisTarget {
unsigned getMaxMemoryAccessSize() const override { return 64; }
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
unsigned Offset) const override;
-
+ unsigned findRegisterByName(const StringRef RegName) const override;
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
bool matchesArch(Triple::ArchType Arch) const override {
@@ -148,6 +148,10 @@ void ExegesisMipsTarget::fillMemoryOperands(InstructionTemplate &IT,
setMemOp(IT, 2, MCOperand::createImm(Offset)); // Disp
}
+unsigned ExegesisMipsTarget::findRegisterByName(const StringRef RegName) const {
+ return Mips::NoRegister;
+}
+
std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
index 4a825b293b716..1e0fca7380863 100644
--- a/llvm/tools/llvm-exegesis/lib/PerfHelper.h
+++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
@@ -119,7 +119,7 @@ class CounterGroup {
virtual void start();
/// Stops the measurement of the event.
- void stop();
+ virtual void stop();
/// Returns the current value of the counter or error if it cannot be read.
/// FunctionBytes: The benchmark function being executed.
diff --git a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
index 5c944c90384e3..0031fb89118dd 100644
--- a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
@@ -33,6 +33,8 @@ class ExegesisPowerPCTarget : public ExegesisTarget {
: ExegesisTarget(PPCCpuPfmCounters, PPC_MC::isOpcodeAvailable) {}
private:
+ unsigned findRegisterByName(const StringRef RegName) const override;
+
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
bool matchesArch(Triple::ArchType Arch) const override {
@@ -92,6 +94,11 @@ void ExegesisPowerPCTarget::fillMemoryOperands(InstructionTemplate &IT,
setMemOp(IT, MemOpIdx + 2, MCOperand::createReg(Reg)); // BaseReg
}
+unsigned
+ExegesisPowerPCTarget::findRegisterByName(const StringRef RegName) const {
+ return PPC::NoRegister;
+}
+
std::vector<MCInst> ExegesisPowerPCTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
new file mode 100644
index 0000000000000..ea0ced1786a0c
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
@@ -0,0 +1,22 @@
+include_directories(
+ ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV
+ ${LLVM_BINARY_DIR}/lib/Target/RISCV
+)
+
+set(LLVM_LINK_COMPONENTS
+ RISCV
+ Exegesis
+ Core
+ Support
+ )
+
+add_llvm_library(LLVMExegesisRISCV
+ DISABLE_LLVM_LINK_LLVM_DYLIB
+ STATIC
+ Target.cpp
+ RISCVCounters.cpp
+
+ DEPENDS
+ intrinsics_gen
+ RISCVCommonTableGen
+ )
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
new file mode 100644
index 0000000000000..1d421b3c31c36
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
@@ -0,0 +1,66 @@
+//===-- RISCVCounters.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVCounters.h"
+
+namespace llvm {
+namespace exegesis {
+
+// This implementation of RISCV target for Exegesis doesn't use libpfm
+// and provides manual implementation of performance counters.
+
+inline uint64_t getRISCVCpuCyclesCount() {
+#ifdef __riscv
+ uint64_t Counter;
+ asm("csrr %0, cycle" : "=r"(Counter)::"memory");
+ return Counter;
+#else
+ return 0;
+#endif
+}
+
+class RISCVCpuCyclesCounter : public pfm::CounterGroup {
+ uint64_t StartValue;
+ uint64_t EndValue;
+ uint64_t MeasurementCycles;
+
+public:
+ explicit RISCVCpuCyclesCounter(pfm::PerfEvent &&Event);
+
+ void start() override { StartValue = getRISCVCpuCyclesCount(); }
+
+ void stop() override { EndValue = getRISCVCpuCyclesCount(); }
+
+ Expected<llvm::SmallVector<int64_t, 4>>
+ readOrError(StringRef FunctionBytes) const override;
+};
+
+RISCVCpuCyclesCounter::RISCVCpuCyclesCounter(pfm::PerfEvent &&Event)
+ : CounterGroup(std::move(Event), {}) {
+ StartValue = getRISCVCpuCyclesCount();
+ EndValue = getRISCVCpuCyclesCount();
+ MeasurementCycles = EndValue - StartValue;
+ if (MeasurementCycles == 0) {
+ report_fatal_error("MeasurementCycles == 0, "
+ "performance counters are not configured.");
+ }
+ StartValue = EndValue = 0;
+}
+
+Expected<SmallVector<int64_t, 4>>
+RISCVCpuCyclesCounter::readOrError(StringRef FunctionBytes) const {
+ uint64_t Counter = EndValue - StartValue - MeasurementCycles;
+ return SmallVector<int64_t, 4>({static_cast<int64_t>(Counter)});
+}
+std::unique_ptr<pfm::CounterGroup>
+createRISCVCpuCyclesCounter(pfm::PerfEvent &&Event) {
+ return std::make_unique<RISCVCpuCyclesCounter>(std::move(Event));
+}
+
+} // namespace exegesis
+} // namespace llvm
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.h b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.h
new file mode 100644
index 0000000000000..203f6af76aaaf
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.h
@@ -0,0 +1,31 @@
+//===-- RISCVCounters.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// RISC-V perf counters.
+///
+/// More info at: https://lwn.net/Articles/680985
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_LIB_RISCV_RISCVCOUNTERS_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_LIB_RISCV_RISCVCOUNTERS_H
+
+#include "../PerfHelper.h"
+#include "../Target.h"
+#include <memory>
+
+namespace llvm {
+namespace exegesis {
+
+std::unique_ptr<pfm::CounterGroup>
+createRISCVCpuCyclesCounter(pfm::PerfEvent &&Event);
+
+} // namespace exegesis
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_LIB_RISCV_RISCVCOUNTERS_H
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
new file mode 100644
index 0000000000000..c6d392b3b6d7a
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -0,0 +1,414 @@
+//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../Target.h"
+
+#include "RISCVCounters.h"
+
+#include "MCTargetDesc/RISCVBaseInfo.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "MCTargetDesc/RISCVMatInt.h"
+#include "RISCVInstrInfo.h"
+
+// include computeAvailableFeatures and computeRequiredFeatures.
+#define GET_COMPUTE_FEATURES
+#define GET_AVAILABLE_OPCODE_CHECKER
+#include "RISCVGenInstrInfo.inc"
+#undef GET_COMPUTE_FEATURES
+#undef GET_AVAILABLE_OPCODE_CHECKER
+
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+
+#include <vector>
+
+namespace llvm {
+namespace exegesis {
+
+namespace {
+
+// TODO move perf counter data to td files (although it looks like an overkill
+// of sorts)
+
+static const char *RISCVPfmCounterNames[] = {
+ "CPU_CYCLES", // 0
+};
+
+static const PfmCountersInfo RISCVDefaultPfmCounters = {
+ RISCVPfmCounterNames[0], // Cycle counter
+ nullptr, // No uops counter.
+ nullptr, // No issue counters.
+ 0};
+
+static const CpuAndPfmCounters RISCVCpuPfmCounters[] = {
+ {"", &RISCVDefaultPfmCounters},
+};
+
+class ExegesisRISCVTarget : public ExegesisTarget {
+public:
+ ExegesisRISCVTarget();
+
+ Expected<std::unique_ptr<pfm::CounterGroup>>
+ createCounter(StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters,
+ const pid_t ProcessID) const override;
+
+ bool checkOpcodeSupported(int Opcode,
+ const MCSubtargetInfo &SI) const override;
+
+ unsigned findRegisterByName(const StringRef RegName) const override;
+
+ bool matchesArch(Triple::ArchType Arch) const override;
+
+ std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
+ const APInt &Value) const override;
+
+ unsigned getDefaultLoopCounterRegister(const Triple &) const override;
+
+ void decrementLoopCounterAndJump(MachineBasicBlock &MBB,
+ MachineBasicBlock &TargetMBB,
+ const MCInstrInfo &MII,
+ unsigned LoopRegister) const override;
+
+ unsigned getScratchMemoryRegister(const Triple &TT) const override;
+
+ void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
+ unsigned Offset) const override;
+
+ virtual std::vector<MCInst>
+ storeRegValueToScratch(const MCSubtargetInfo &STI, unsigned Reg,
+ unsigned Offset) const override;
+ ArrayRef<unsigned> getUnavailableRegisters() const override;
+
+ Error randomizeTargetMCOperand(const Instruction &Instr, const Variable &Var,
+ MCOperand &AssignedValue,
+ const BitVector &ForbiddenRegs) const override;
+
+ void processInstructionReservedRegs(InstructionTemplate &IT) const override;
+
+ std::vector<InstructionTemplate>
+ generateInstructionVariants(const Instruction &Instr,
+ unsigned MaxConfigsPerOpcode) const override;
+};
+
+ExegesisRISCVTarget::ExegesisRISCVTarget()
+ : ExegesisTarget(RISCVCpuPfmCounters, RISCV_MC::isOpcodeAvailable) {}
+
+Expected<std::unique_ptr<pfm::CounterGroup>> ExegesisRISCVTarget::createCounter(
+ StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters, const pid_t ProcessID) const {
+ if (CounterName == RISCVPfmCounterNames[0]) {
+ return createRISCVCpuCyclesCounter(pfm::PerfEvent(CounterName));
+ }
+ return make_error<Failure>(Twine("Unsupported performance counter '")
+ .concat(CounterName)
+ .concat("'"));
+}
+
+bool ExegesisRISCVTarget::checkOpcodeSupported(
+ int Opcode, const MCSubtargetInfo &SI) const {
+ auto Features = SI.getFeatureBits();
+ FeatureBitset AvailableFeatures =
+ RISCV_MC::computeAvailableFeatures(Features);
+ FeatureBitset RequiredFeatures = RISCV_MC::computeRequiredFeatures(Opcode);
+ FeatureBitset MissingFeatures =
+ (AvailableFeatures & RequiredFeatures) ^ RequiredFeatures;
+ return MissingFeatures.none();
+}
+
+#define GET_REGISTER_MATCHER
+#include "RISCVGenAsmMatcher.inc"
+
+unsigned
+ExegesisRISCVTarget::findRegisterByName(const StringRef RegName) const {
+ unsigned Reg;
+ if ((Reg = MatchRegisterName(RegName)))
+ return Reg;
+ if ((Reg = MatchRegisterAltName(RegName)))
+ return Reg;
+ return RISCV::NoRegister;
+}
+
+bool ExegesisRISCVTarget::matchesArch(Triple::ArchType Arch) const {
+ return Arch == Triple::riscv32 || Arch == Triple::riscv64;
+}
+
+// Stores constant value to a general-purpose (integer) register.
+static std::vector<MCInst> loadIntReg(const MCSubtargetInfo &STI, unsigned Reg,
+ const APInt &Value) {
+ RISCVMatInt::InstSeq InstSeq =
+ RISCVMatInt::generateInstSeq(Value.getSExtValue(), STI);
+ // First instruction has form 'Op DestReg, X0, Imm'
+ MCRegister SrcReg = RISCV::X0;
+ MCRegister DestReg = Reg;
+ std::vector<MCInst> MatIntInstrs;
+ MatIntInstrs.reserve(InstSeq.size());
+ for (const RISCVMatInt::Inst &Inst : InstSeq) {
+ switch (Inst.getOpndKind()) {
+ case RISCVMatInt::Imm:
+ MatIntInstrs.push_back(
+ MCInstBuilder(RISCV::LUI).addReg(DestReg).addImm(Inst.getImm()));
+ break;
+ case RISCVMatInt::RegX0:
+ MatIntInstrs.push_back(MCInstBuilder(RISCV::ADD_UW)
+ .addReg(DestReg)
+ .addReg(SrcReg)
+ .addReg(RISCV::X0));
+ break;
+ case RISCVMatInt::RegReg:
+ MatIntInstrs.push_back(MCInstBuilder(Inst.getOpcode())
+ .addReg(DestReg)
+ .addReg(SrcReg)
+ .addReg(SrcReg));
+ break;
+ case RISCVMatInt::RegImm:
+ MatIntInstrs.push_back(MCInstBuilder(Inst.getOpcode())
+ .addReg(DestReg)
+ .addReg(SrcReg)
+ .addImm(Inst.getImm()));
+ break;
+ default:
+ llvm_unreachable("Unexpected kind!");
+ }
+ // Further instructions have form 'Op DestReg, DestReg, Imm'
+ SrcReg = DestReg;
+ }
+ return MatIntInstrs;
+}
+
+const unsigned ScratchIntReg = RISCV::X30; // t5
+
+// Stores constant bits to a floating-point register.
+static std::vector<MCInst> loadFPRegBits(const MCSubtargetInfo &STI,
+ unsigned Reg, const APInt &Bits,
+ unsigned FmvOpcode) {
+ std::vector<MCInst> Instrs = loadIntReg(STI, ScratchIntReg, Bits);
+ Instrs.push_back(MCInstBuilder(FmvOpcode).addReg(Reg).addReg(ScratchIntReg));
+ return Instrs;
+}
+
+// main idea is:
+// we support APInt only if (represented as double) it have zero fractional
+// part: 1.0, 2.0, 3.0, etc... then we can do the trick: write int to tmp reg t5
+// and then do FCVT this is only reliable thing in 32-bit mode, otherwise we
+// need to use __floatsidf
+static std::vector<MCInst> loadFP64RegBits32(const MCSubtargetInfo &STI,
+ unsigned Reg, const APInt &Bits) {
+ double D = Bits.bitsToDouble();
+ double IPart;
+ double FPart = std::modf(D, &IPart);
+
+ if (std::abs(FPart) > std::numeric_limits<double>::epsilon()) {
+ errs() << "loadFP64RegBits32 is not implemented for doubles like " << D
+ << ", please remove fractional part\n";
+ return {};
+ }
+
+ std::vector<MCInst> Instrs = loadIntReg(STI, ScratchIntReg, Bits);
+ Instrs.push_back(
+ MCInstBuilder(RISCV::FCVT_D_W).addReg(Reg).addReg(ScratchIntReg));
+ return Instrs;
+}
+
+static MCInst nop() {
+ // ADDI X0, X0, 0
+ return MCInstBuilder(RISCV::ADDI)
+ .addReg(RISCV::X0)
+ .addReg(RISCV::X0)
+ .addImm(0);
+}
+
+static bool isVectorRegList(unsigned Reg) {
+ return RISCV::VRM2RegClass.contains(Reg) ||
+ RISCV::VRM4RegClass.contains(Reg) ||
+ RISCV::VRM8RegClass.contains(Reg) ||
+ RISCV::VRN2M1RegClass.contains(Reg) ||
+ RISCV::VRN2M2RegClass.contains(Reg) ||
+ RISCV::VRN2M4RegClass.contains(Reg) ||
+ RISCV::VRN3M1RegClass.contains(Reg) ||
+ RISCV::VRN3M2RegClass.contains(Reg) ||
+ RISCV::VRN4M1RegClass.contains(Reg) ||
+ RISCV::VRN4M2RegClass.contains(Reg) ||
+ RISCV::VRN5M1RegClass.contains(Reg) ||
+ RISCV::VRN6M1RegClass.contains(Reg) ||
+ RISCV::VRN7M1RegClass.contains(Reg) ||
+ RISCV::VRN8M1RegClass.contains(Reg);
+}
+
+std::vector<MCInst> ExegesisRISCVTarget::setRegTo(const MCSubtargetInfo &STI,
+ unsigned Reg,
+ const APInt &Value) const {
+ if (RISCV::GPRRegClass.contains(Reg))
+ return loadIntReg(STI, Reg, Value);
+ if (RISCV::FPR16RegClass.contains(Reg))
+ return loadFPRegBits(STI, Reg, Value, RISCV::FMV_H_X);
+ if (RISCV::FPR32RegClass.contains(Reg))
+ return loadFPRegBits(STI, Reg, Value, RISCV::FMV_W_X);
+ if (RISCV::FPR64RegClass.contains(Reg)) {
+ if (STI.hasFeature(RISCV::Feature64Bit))
+ return loadFPRegBits(STI, Reg, Value, RISCV::FMV_D_X);
+ else
+ return loadFP64RegBits32(STI, Reg, Value);
+ }
+ if (Reg == RISCV::FRM || Reg == RISCV::VL || Reg == RISCV::VLENB ||
+ Reg == RISCV::VTYPE || RISCV::GPRPairRegClass.contains(Reg) ||
+ RISCV::VRRegClass.contains(Reg) || isVectorRegList(Reg)) {
+ // Don't initialize:
+ // - FRM
+ // - VL, VLENB, VTYPE
+ // - vector registers (and vector register lists)
+ // - Zfinx registers
+ // Generate 'NOP' so that exegesis treats such registers as initialized
+ // (it tries to initialize them with '0' anyway).
+ return {nop()};
+ }
+ errs() << "setRegTo is not implemented for Reg " << Reg
+ << ", results will be unreliable\n";
+ return {};
+}
+
+const unsigned DefaultLoopCounterReg = RISCV::X31; // t6
+const unsigned ScratchMemoryReg = RISCV::X10; // a0
+
+unsigned
+ExegesisRISCVTarget::getDefaultLoopCounterRegister(const Triple &) const {
+ return DefaultLoopCounterReg;
+}
+
+void ExegesisRISCVTarget::decrementLoopCounterAndJump(
+ MachineBasicBlock &MBB, MachineBasicBlock &TargetMBB,
+ const MCInstrInfo &MII, unsigned LoopRegister) const {
+ BuildMI(&MBB, DebugLoc(), MII.get(RISCV::ADDI))
+ .addDef(LoopRegister)
+ .addUse(LoopRegister)
+ .addImm(-1);
+ BuildMI(&MBB, DebugLoc(), MII.get(RISCV::BNE))
+ .addUse(LoopRegister)
+ .addUse(RISCV::X0)
+ .addMBB(&TargetMBB);
+}
+
+unsigned ExegesisRISCVTarget::getScratchMemoryRegister(const Triple &TT) const {
+ return ScratchMemoryReg; // a0
+}
+
+void ExegesisRISCVTarget::fillMemoryOperands(InstructionTemplate &IT,
+ unsigned Reg,
+ unsigned Offset) const {
+ // TODO: for now we ignore Offset because have no way
+ // to detect it in instruction.
+ auto &I = IT.getInstr();
+
+ auto MemOpIt =
+ find_if(I.Operands, [](Operand const &Op) { return Op.isMemory(); });
+ assert(MemOpIt != I.Operands.end() &&
+ "Instruction must have memory operands");
+
+ auto &MemOp = *MemOpIt;
+
+ assert(MemOp.isReg() && "Memory operand expected to be register");
+
+ IT.getValueFor(MemOp) = MCOperand::createReg(Reg);
+}
+
+std::vector<MCInst> ExegesisRISCVTarget::storeRegValueToScratch(
+ const MCSubtargetInfo &STI, unsigned Reg, unsigned Offset) const {
+ std::vector<MCInst> Ret;
+
+ if (RISCV::GPRRegClass.contains(Reg)) {
+ Ret.push_back(MCInstBuilder(RISCV::SW)
+ .addReg(Reg)
+ .addReg(ScratchMemoryReg)
+ .addImm(Offset));
+ return Ret;
+ }
+
+ errs() << "Failed to store value of " << Reg << " register to scratch memory";
+ return {nop()};
+}
+
+const unsigned UnavailableRegisters[4] = {RISCV::X0, DefaultLoopCounterReg,
+ ScratchIntReg, ScratchMemoryReg};
+
+ArrayRef<unsigned> ExegesisRISCVTarget::getUnavailableRegisters() const {
+ return ArrayRef(UnavailableRegisters);
+}
+
+Error ExegesisRISCVTarget::randomizeTargetMCOperand(
+ const Instruction &Instr, const Variable &Var, MCOperand &AssignedValue,
+ const BitVector &ForbiddenRegs) const {
+ uint8_t OperandType =
+ Instr.getPrimaryOperand(Var).getExplicitOperandInfo().OperandType;
+
+ switch (OperandType) {
+ case RISCVOp::OPERAND_FRMARG:
+ AssignedValue = MCOperand::createImm(RISCVFPRndMode::DYN);
+ break;
+ case RISCVOp::OPERAND_SIMM10_LSB0000_NONZERO:
+ AssignedValue = MCOperand::createImm(0b1 << 4);
+ break;
+ case RISCVOp::OPERAND_SIMM6_NONZERO:
+ case RISCVOp::OPERAND_UIMMLOG2XLEN_NONZERO:
+ AssignedValue = MCOperand::createImm(1);
+ break;
+ default:
+ if (OperandType >= RISCVOp::OPERAND_FIRST_RISCV_IMM &&
+ OperandType <= RISCVOp::OPERAND_LAST_RISCV_IMM)
+ AssignedValue = MCOperand::createImm(0);
+ }
+ return Error::success();
+}
+
+// Process instructions that used ReservedRegisters.
+// We must not create instructions that used rd=x0. But for some of them in C
+// extension we use registers in which we are really not going to write to.
+// Registers were reserved in RISCVRegisterInfo.cpp using markSuperRegs function
+// and should not be redeclared. Thus we must set appropriate register
+// explicitly for each instruction according to RVC spec.
+void ExegesisRISCVTarget::processInstructionReservedRegs(
+ InstructionTemplate &IT) const {
+ MCOperand &AssignedValue = IT.getValueFor(0);
+
+ switch (IT.getOpcode()) {
+ case RISCV::C_ADDI16SP:
+ AssignedValue = MCOperand::createReg(RISCV::X2);
+ break;
+ case RISCV::C_ADDI_NOP:
+ case RISCV::C_ADD_HINT:
+ case RISCV::C_SLLI_HINT:
+ AssignedValue = MCOperand::createReg(RISCV::X0);
+ break;
+ default:
+ break;
+ }
+}
+
+std::vector<InstructionTemplate>
+ExegesisRISCVTarget::generateInstructionVariants(
+ const Instruction &Instr, unsigned int MaxConfigsPerOpcode) const {
+ InstructionTemplate IT{&Instr};
+ for (const Operand &Op : Instr.Operands) {
+ if (Op.isMemory()) {
+ IT.getValueFor(Op) = MCOperand::createReg(ScratchMemoryReg);
+ }
+ }
+ return {IT};
+}
+
+} // anonymous namespace
+
+static ExegesisTarget *getTheRISCVExegesisTarget() {
+ static ExegesisRISCVTarget Target;
+ return &Target;
+}
+
+void InitializeRISCVExegesisTarget() {
+ ExegesisTarget::registerTarget(getTheRISCVExegesisTarget());
+}
+
+} // namespace exegesis
+} // namespace llvm
diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
index 7100b51bbb729..4971c5b609725 100644
--- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -52,13 +52,16 @@ computeAliasingInstructions(const LLVMState &State, const Instruction *Instr,
continue;
if (OtherOpcode == Instr->Description.getOpcode())
continue;
+ if (!State.getExegesisTarget().checkOpcodeSupported(
+ OtherOpcode, State.getSubtargetInfo()))
+ continue;
const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode);
const MCInstrDesc &OtherInstrDesc = OtherInstr.Description;
// Ignore instructions that we cannot run.
if (OtherInstrDesc.isPseudo() || OtherInstrDesc.usesCustomInsertionHook() ||
OtherInstrDesc.isBranch() || OtherInstrDesc.isIndirectBranch() ||
OtherInstrDesc.isCall() || OtherInstrDesc.isReturn()) {
- continue;
+ continue;
}
if (OtherInstr.hasMemoryOperands())
continue;
@@ -81,12 +84,10 @@ static ExecutionMode getExecutionModes(const Instruction &Instr,
EM |= ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS;
if (Instr.hasMemoryOperands())
EM |= ExecutionMode::SERIAL_VIA_MEMORY_INSTR;
- else {
- if (Instr.hasAliasingRegisters(ForbiddenRegisters))
- EM |= ExecutionMode::SERIAL_VIA_EXPLICIT_REGS;
- if (Instr.hasOneUseOrOneDef())
- EM |= ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR;
- }
+ if (Instr.hasAliasingNotMemoryRegisters(ForbiddenRegisters))
+ EM |= ExecutionMode::SERIAL_VIA_EXPLICIT_REGS;
+ if (Instr.hasOneUseOrOneDef())
+ EM |= ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR;
return EM;
}
@@ -104,6 +105,7 @@ static void appendCodeTemplates(const LLVMState &State,
case ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS: {
// Picking whatever value for the tied variable will make the instruction
// serial.
+ State.getExegesisTarget().processInstructionReservedRegs(Variant);
CodeTemplate CT;
CT.Execution = ExecutionModeBit;
CT.Info = std::string(ExecutionClassDescription);
@@ -113,7 +115,51 @@ 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;
+
+ auto &DefOp = *DefOpIt;
+ auto &ET = State.getExegesisTarget();
+ auto ScratchMemoryRegister = ET.getScratchMemoryRegister(
+ State.getTargetMachine().getTargetTriple());
+ auto &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;
+ if (CT.ScratchSpacePointerInReg == 0)
+ CT.ScratchSpacePointerInReg = ScratchMemoryRegister;
+
+ CT.Info = std::string(ExecutionClassDescription);
+ CT.Instructions.push_back(std::move(Variant));
+ CT.PreinitScratchMemory.emplace_back(ScratchMemoryRegister,
+ /* Offset */ 0);
+ CodeTemplates.push_back(std::move(CT));
+ }
+
+ // TODO: implement more cases
return;
}
case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index 431d99c72b808..89254fb1eee30 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -36,10 +36,11 @@ namespace {
class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
public:
explicit BenchmarkCodeStreamer(
- MCContext *Context, const DenseMap<StringRef, unsigned> &RegNameToRegNo,
+ const ExegesisTarget &Target, MCContext *Context,
+ const DenseMap<StringRef, unsigned> &RegNameToRegNo,
BenchmarkCode *Result)
- : MCStreamer(*Context), RegNameToRegNo(RegNameToRegNo), Result(Result) {}
-
+ : MCStreamer(*Context), Target(Target), RegNameToRegNo(RegNameToRegNo),
+ Result(Result) {}
// Implementation of the MCStreamer interface. We only care about
// instructions.
void emitInstruction(const MCInst &Instruction,
@@ -207,6 +208,8 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
Align ByteAlignment, SMLoc Loc) override {}
unsigned findRegisterByName(const StringRef RegName) const {
+ if (unsigned Reg = Target.findRegisterByName(RegName))
+ return Reg;
auto Iter = RegNameToRegNo.find(RegName);
if (Iter != RegNameToRegNo.end())
return Iter->second;
@@ -214,7 +217,7 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
<< "' is not a valid register name for the target\n";
return 0;
}
-
+ const ExegesisTarget &Target;
const DenseMap<StringRef, unsigned> &RegNameToRegNo;
BenchmarkCode *const Result;
unsigned InvalidComments = 0;
@@ -248,8 +251,8 @@ Expected<std::vector<BenchmarkCode>> readSnippets(const LLVMState &State,
TM.getTarget().createMCObjectFileInfo(Context, /*PIC=*/false));
Context.setObjectFileInfo(ObjectFileInfo.get());
Context.initInlineSourceManager();
- BenchmarkCodeStreamer Streamer(&Context, State.getRegNameToRegNoMapping(),
- &Result);
+ BenchmarkCodeStreamer Streamer(State.getExegesisTarget(), &Context,
+ State.getRegNameToRegNoMapping(), &Result);
std::string Error;
raw_string_ostream ErrorStream(Error);
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
index 7dcff60a8fd11..8eaf83044e0dd 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -73,6 +73,9 @@ Error SnippetGenerator::generateConfigurations(
for (CodeTemplate &CT : Templates) {
// TODO: Generate as many BenchmarkCode as needed.
{
+ CT.ScratchSpacePointerInReg =
+ State.getExegesisTarget().getScratchMemoryRegister(
+ State.getTargetMachine().getTargetTriple());
BenchmarkCode BC;
BC.Info = CT.Info;
BC.Key.Instructions.reserve(CT.Instructions.size());
@@ -108,6 +111,12 @@ std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues(
// Loop invariant: DefinedRegs[i] is true iif it has been set at least once
// before the current instruction.
BitVector DefinedRegs = State.getRATC().emptyRegisters();
+ // If target always expects a scratch memory register as live input,
+ // mark it as defined.
+ const ExegesisTarget &Target = State.getExegesisTarget();
+ unsigned ScratchMemoryReg = Target.getScratchMemoryRegister(
+ State.getTargetMachine().getTargetTriple());
+ DefinedRegs.set(ScratchMemoryReg);
std::vector<RegisterValue> RIV;
for (const InstructionTemplate &IT : Instructions) {
// Returns the register that this Operand sets or uses, or 0 if this is not
@@ -200,7 +209,9 @@ static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
if (ROV.Op->isExplicit()) {
auto &AssignedValue = IB.getValueFor(*ROV.Op);
if (AssignedValue.isValid()) {
- assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
+ // TODO don't re-assign register operands which are already "locked"
+ // by Target in corresponding InstructionTemplate
+ // assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
return;
}
AssignedValue = MCOperand::createReg(ROV.Reg);
diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp
index 29e58692f0e92..533f709147eb6 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Target.cpp
@@ -212,6 +212,10 @@ class ExegesisDefaultTarget : public ExegesisTarget {
ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {}
private:
+ unsigned findRegisterByName(const StringRef RegName) const override {
+ llvm_unreachable("Not yet implemented");
+ }
+
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override {
llvm_unreachable("Not yet implemented");
diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h
index 522c75d15703d..96088f88a89a9 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/llvm/tools/llvm-exegesis/lib/Target.h
@@ -86,6 +86,14 @@ class ExegesisTarget {
ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID = 0) const;
+ virtual bool checkOpcodeSupported(int Opcode,
+ const MCSubtargetInfo &SI) const {
+ return true;
+ }
+
+ // Find register by name, NoRegister if not found.
+ virtual unsigned findRegisterByName(const StringRef RegName) const = 0;
+
// Targets can use this to add target-specific passes in assembleToStream();
virtual void addTargetSpecificPasses(PassManagerBase &PM) const {}
@@ -201,6 +209,14 @@ class ExegesisTarget {
"fillMemoryOperands() requires getScratchMemoryRegister() > 0");
}
+ // Generates code to store register into scratch memory with offset.
+ virtual std::vector<MCInst> storeRegValueToScratch(const MCSubtargetInfo &STI,
+ unsigned Reg,
+ unsigned Offset) const {
+ llvm_unreachable(
+ "storeRegValueToScratch() requires getScratchMemoryRegister() > 0");
+ }
+
// Returns a counter usable as a loop counter.
virtual unsigned getDefaultLoopCounterRegister(const Triple &) const {
return 0;
@@ -238,6 +254,9 @@ class ExegesisTarget {
"targets with target-specific operands should implement this");
}
+ // Process instructions that used reserved registers.
+ virtual void processInstructionReservedRegs(InstructionTemplate &IT) const {}
+
// Returns true if this instruction is supported as a back-to-back
// instructions.
// FIXME: Eventually we should discover this dynamically.
diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index dbb2bf409316e..51ef3e872b967 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -736,6 +736,8 @@ class ExegesisX86Target : public ExegesisTarget {
const MCInstrInfo &MII,
unsigned LoopRegister) const override;
+ unsigned findRegisterByName(const StringRef RegName) const override;
+
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
@@ -1009,6 +1011,10 @@ static std::vector<MCInst> loadImmediateSegmentRegister(unsigned Reg,
#endif // defined(__x86_64__) && defined(__linux__)
}
+unsigned ExegesisX86Target::findRegisterByName(const StringRef RegName) const {
+ return X86::NoRegister;
+}
+
std::vector<MCInst> ExegesisX86Target::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index 06e1c7f3c1bbe..d286de9005424 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -57,7 +57,9 @@ static cl::opt<int> OpcodeIndex(
static cl::opt<std::string>
OpcodeNames("opcode-name",
- cl::desc("comma-separated list of opcodes to measure, by name"),
+ cl::desc("comma-separated list of opcodes to measure, "
+ "each item is either opcode name ('OP') "
+ "or opcode range ('OP1..OP2', ends are inclusive)"),
cl::cat(BenchmarkOptions), cl::init(""));
static cl::opt<std::string> SnippetsFile("snippets-file",
@@ -235,7 +237,7 @@ static cl::opt<std::string>
static cl::opt<std::string>
MCPU("mcpu",
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
- cl::value_desc("cpu-name"), cl::cat(Options), cl::init("native"));
+ cl::value_desc("cpu-name"), cl::cat(Options), cl::init(""));
static cl::opt<std::string>
DumpObjectToDisk("dump-object-to-disk",
@@ -269,6 +271,10 @@ static cl::list<ValidationEvent> ValidationCounters(
"counter to validate benchmarking assumptions"),
cl::CommaSeparated, cl::cat(BenchmarkOptions), ValidationEventOptions());
+static cl::opt<std::string> MAttr(
+ "mattr", cl::desc("comma-separated list of target architecture features"),
+ cl::value_desc("+feature1,-feature2,..."), cl::cat(Options), cl::init(""));
+
static ExitOnError ExitOnErr("llvm-exegesis error: ");
// Helper function that logs the error(s) and exits.
@@ -291,6 +297,22 @@ T ExitOnFileError(const Twine &FileName, Expected<T> &&E) {
return std::move(*E);
}
+static const char *getIgnoredOpcodeReasonOrNull(const LLVMState &State,
+ unsigned Opcode) {
+ const MCInstrDesc &InstrDesc = State.getIC().getInstr(Opcode).Description;
+ if (InstrDesc.isPseudo() || InstrDesc.usesCustomInsertionHook())
+ return "Unsupported opcode: isPseudo/usesCustomInserter";
+ if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
+ return "Unsupported opcode: isBranch/isIndirectBranch";
+ if (InstrDesc.isCall() || InstrDesc.isReturn())
+ return "Unsupported opcode: isCall/isReturn";
+ return nullptr;
+}
+
+static bool isIgnoredOpcode(const LLVMState &State, unsigned Opcode) {
+ return getIgnoredOpcodeReasonOrNull(State, Opcode) != nullptr;
+}
+
// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
// and returns the opcode indices or {} if snippets should be read from
// `SnippetsFile`.
@@ -335,10 +357,32 @@ static std::vector<unsigned> getOpcodesOrDie(const LLVMState &State) {
std::vector<unsigned> Result;
Result.reserve(Pieces.size());
for (const StringRef &OpcodeName : Pieces) {
- if (unsigned Opcode = ResolveName(OpcodeName))
+ if (unsigned Opcode = ResolveName(OpcodeName)) {
Result.push_back(Opcode);
- else
+ continue;
+ }
+ // Not a known opcode name; should be an opcode name range.
+ size_t DotDotPos = OpcodeName.find("..");
+ if (DotDotPos == StringRef::npos) {
ExitWithError(Twine("unknown opcode ").concat(OpcodeName));
+ }
+ StringRef BeginOpcodeName = OpcodeName.substr(0, DotDotPos);
+ unsigned BeginOpcode =
+ BeginOpcodeName.empty() ? 1 : ResolveName(BeginOpcodeName);
+ if (BeginOpcode == 0) {
+ ExitWithError(Twine("unknown opcode ").concat(BeginOpcodeName));
+ }
+ StringRef EndOpcodeName = OpcodeName.substr(DotDotPos + 2);
+ unsigned EndOpcode = EndOpcodeName.empty()
+ ? State.getInstrInfo().getNumOpcodes() - 1
+ : ResolveName(EndOpcodeName);
+ if (EndOpcode == 0) {
+ ExitWithError(Twine("unknown opcode ").concat(EndOpcodeName));
+ }
+ for (unsigned I = BeginOpcode; I <= EndOpcode; ++I) {
+ if (!isIgnoredOpcode(State, I))
+ Result.push_back(I);
+ }
}
return Result;
}
@@ -347,17 +391,11 @@ static std::vector<unsigned> getOpcodesOrDie(const LLVMState &State) {
static Expected<std::vector<BenchmarkCode>>
generateSnippets(const LLVMState &State, unsigned Opcode,
const BitVector &ForbiddenRegs) {
- const Instruction &Instr = State.getIC().getInstr(Opcode);
- const MCInstrDesc &InstrDesc = Instr.Description;
// Ignore instructions that we cannot run.
- if (InstrDesc.isPseudo() || InstrDesc.usesCustomInsertionHook())
- return make_error<Failure>(
- "Unsupported opcode: isPseudo/usesCustomInserter");
- if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
- return make_error<Failure>("Unsupported opcode: isBranch/isIndirectBranch");
- if (InstrDesc.isCall() || InstrDesc.isReturn())
- return make_error<Failure>("Unsupported opcode: isCall/isReturn");
+ if (const char *Reason = getIgnoredOpcodeReasonOrNull(State, Opcode))
+ return make_error<Failure>(Reason);
+ const Instruction &Instr = State.getIC().getInstr(Opcode);
const std::vector<InstructionTemplate> InstructionVariants =
State.getExegesisTarget().generateInstructionVariants(
Instr, MaxConfigsPerOpcode);
@@ -474,8 +512,8 @@ void benchmarkMain() {
InitializeAllAsmParsers();
InitializeAllExegesisTargets();
- const LLVMState State =
- ExitOnErr(LLVMState::Create(TripleName, MCPU, "", UseDummyPerfCounters));
+ const LLVMState State = ExitOnErr(
+ LLVMState::Create(TripleName, MCPU, MAttr, UseDummyPerfCounters));
// Preliminary check to ensure features needed for requested
// benchmark mode are present on target CPU and/or OS.
>From 10d4f37bb8b7a33fd7ea02dbbed13cc01d10aad6 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Thu, 16 May 2024 20:11:54 +0300
Subject: [PATCH 02/10] Addressing review comments
---
llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp | 4 ++++
llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp | 6 ------
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
index c6d392b3b6d7a..0909c4d3250f7 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -375,9 +375,13 @@ void ExegesisRISCVTarget::processInstructionReservedRegs(
switch (IT.getOpcode()) {
case RISCV::C_ADDI16SP:
+ case RISCV::C_ADDI4SPN:
AssignedValue = MCOperand::createReg(RISCV::X2);
break;
case RISCV::C_ADDI_NOP:
+ case RISCV::C_LI_HINT:
+ case RISCV::C_LUI_HINT:
+ case RISCV::C_MV_HINT:
case RISCV::C_ADD_HINT:
case RISCV::C_SLLI_HINT:
AssignedValue = MCOperand::createReg(RISCV::X0);
diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
index 4971c5b609725..9739b48b2b97e 100644
--- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -57,12 +57,6 @@ computeAliasingInstructions(const LLVMState &State, const Instruction *Instr,
continue;
const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode);
const MCInstrDesc &OtherInstrDesc = OtherInstr.Description;
- // Ignore instructions that we cannot run.
- if (OtherInstrDesc.isPseudo() || OtherInstrDesc.usesCustomInsertionHook() ||
- OtherInstrDesc.isBranch() || OtherInstrDesc.isIndirectBranch() ||
- OtherInstrDesc.isCall() || OtherInstrDesc.isReturn()) {
- continue;
- }
if (OtherInstr.hasMemoryOperands())
continue;
if (!ET.allowAsBackToBack(OtherInstr))
>From 45dbe40b5da8af385bb29e98417d104b19ef638a Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Tue, 21 May 2024 16:29:05 +0300
Subject: [PATCH 03/10] Addressing review comments
---
.../RISCV/latency-by-extension-A.s | 118 +++++++++---------
.../RISCV/latency-by-extension-C.s | 98 +++++++--------
.../llvm-exegesis/RISCV/latency-by-load.s | 88 ++++++-------
.../RISCV/latency-by-opcode-name-FADD_D.s | 2 +-
llvm/tools/llvm-exegesis/lib/Assembler.cpp | 10 +-
llvm/tools/llvm-exegesis/lib/LlvmState.cpp | 6 -
.../tools/llvm-exegesis/lib/MCInstrDescView.h | 4 +-
llvm/tools/llvm-exegesis/llvm-exegesis.cpp | 2 +-
8 files changed, 157 insertions(+), 171 deletions(-)
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
index 8cd11ffc3c1f6..a0b5932e83467 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
@@ -1,59 +1,59 @@
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOAND_D -mattr="+a" | FileCheck --check-prefix=TEST1 %s
-
-TEST1: ---
-TEST1-NEXT: mode: latency
-TEST1-NEXT: key:
-TEST1-NEXT: instructions:
-TEST1-NEXT: - 'AMOAND_D [[RE01:X[0-9]+]] X10 [[RE01:X[0-9]+]]'
-TEST1-NEXT: config: ''
-TEST1-NEXT: register_initial_values:
-TEST1-NEXT: - '[[RE01:X[0-9]+]]=0x0'
-TEST1-LAST: ...
-
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOADD_W -mattr="+a" | FileCheck --check-prefix=TEST2 %s
-
-TEST2: ---
-TEST2-NEXT: mode: latency
-TEST2-NEXT: key:
-TEST2-NEXT: instructions:
-TEST2-NEXT: - 'AMOADD_W [[RE02:X[0-9]+]] X10 [[RE02:X[0-9]+]]'
-TEST2-NEXT: config: ''
-TEST2-NEXT: register_initial_values:
-TEST2-NEXT: - '[[RE02:X[0-9]+]]=0x0'
-TEST2-LAST: ...
-
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOMAXU_D -mattr="+a" | FileCheck --check-prefix=TEST3 %s
-
-TEST3: ---
-TEST3-NEXT: mode: latency
-TEST3-NEXT: key:
-TEST3-NEXT: instructions:
-TEST3-NEXT: - 'AMOMAXU_D [[RE03:X[0-9]+]] X10 [[RE03:X[0-9]+]]'
-TEST3-NEXT: config: ''
-TEST3-NEXT: register_initial_values:
-TEST3-NEXT: - '[[RE03:X[0-9]+]]=0x0'
-TEST3-LAST: ...
-
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOMIN_W -mattr="+a" | FileCheck --check-prefix=TEST4 %s
-
-TEST4: ---
-TEST4-NEXT: mode: latency
-TEST4-NEXT: key:
-TEST4-NEXT: instructions:
-TEST4-NEXT: - 'AMOMIN_W [[RE04:X[0-9]+]] X10 [[RE04:X[0-9]+]]'
-TEST4-NEXT: config: ''
-TEST4-NEXT: register_initial_values:
-TEST4-NEXT: - '[[RE04:X[0-9]+]]=0x0'
-TEST4-LAST: ...
-
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=AMOXOR_D -mattr="+a" | FileCheck --check-prefix=TEST5 %s
-
-TEST5: ---
-TEST5-NEXT: mode: latency
-TEST5-NEXT: key:
-TEST5-NEXT: instructions:
-TEST5-NEXT: - 'AMOXOR_D [[RE05:X[0-9]+]] X10 [[RE05:X[0-9]+]]'
-TEST5-NEXT: config: ''
-TEST5-NEXT: register_initial_values:
-TEST5-NEXT: - '[[RE05:X[0-9]+]]=0x0'
-TEST5-LAST: ...
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOAND_D -mattr="+a" | FileCheck --check-prefix=AMOAND_D %s
+
+AMOAND_D: ---
+AMOAND_D-NEXT: mode: latency
+AMOAND_D-NEXT: key:
+AMOAND_D-NEXT: instructions:
+AMOAND_D-NEXT: - 'AMOAND_D [[RE01:X[0-9]+]] X10 [[RE01:X[0-9]+]]'
+AMOAND_D-NEXT: config: ''
+AMOAND_D-NEXT: register_initial_values:
+AMOAND_D-NEXT: - '[[RE01:X[0-9]+]]=0x0'
+AMOAND_D-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOADD_W -mattr="+a" | FileCheck --check-prefix=AMOADD_W %s
+
+AMOADD_W: ---
+AMOADD_W-NEXT: mode: latency
+AMOADD_W-NEXT: key:
+AMOADD_W-NEXT: instructions:
+AMOADD_W-NEXT: - 'AMOADD_W [[RE02:X[0-9]+]] X10 [[RE02:X[0-9]+]]'
+AMOADD_W-NEXT: config: ''
+AMOADD_W-NEXT: register_initial_values:
+AMOADD_W-NEXT: - '[[RE02:X[0-9]+]]=0x0'
+AMOADD_W-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOMAXU_D -mattr="+a" | FileCheck --check-prefix=AMOMAXU_D %s
+
+AMOMAXU_D: ---
+AMOMAXU_D-NEXT: mode: latency
+AMOMAXU_D-NEXT: key:
+AMOMAXU_D-NEXT: instructions:
+AMOMAXU_D-NEXT: - 'AMOMAXU_D [[RE03:X[0-9]+]] X10 [[RE03:X[0-9]+]]'
+AMOMAXU_D-NEXT: config: ''
+AMOMAXU_D-NEXT: register_initial_values:
+AMOMAXU_D-NEXT: - '[[RE03:X[0-9]+]]=0x0'
+AMOMAXU_D-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOMIN_W -mattr="+a" | FileCheck --check-prefix=AMOMIN_W %s
+
+AMOMIN_W: ---
+AMOMIN_W-NEXT: mode: latency
+AMOMIN_W-NEXT: key:
+AMOMIN_W-NEXT: instructions:
+AMOMIN_W-NEXT: - 'AMOMIN_W [[RE04:X[0-9]+]] X10 [[RE04:X[0-9]+]]'
+AMOMIN_W-NEXT: config: ''
+AMOMIN_W-NEXT: register_initial_values:
+AMOMIN_W-NEXT: - '[[RE04:X[0-9]+]]=0x0'
+AMOMIN_W-LAST: ...
+
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOXOR_D -mattr="+a" | FileCheck --check-prefix=AMOXOR_D %s
+
+AMOXOR_D: ---
+AMOXOR_D-NEXT: mode: latency
+AMOXOR_D-NEXT: key:
+AMOXOR_D-NEXT: instructions:
+AMOXOR_D-NEXT: - 'AMOXOR_D [[RE05:X[0-9]+]] X10 [[RE05:X[0-9]+]]'
+AMOXOR_D-NEXT: config: ''
+AMOXOR_D-NEXT: register_initial_values:
+AMOXOR_D-NEXT: - '[[RE05:X[0-9]+]]=0x0'
+AMOXOR_D-LAST: ...
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
index e22ddc2d76955..108e1cb411d61 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
@@ -1,65 +1,65 @@
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ADDI -mattr=+c | FileCheck --check-prefix=TEST1 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_ADDI -mattr=+c | FileCheck --check-prefix=C_ADDI %s
-TEST1: ---
-TEST1-NEXT: mode: latency
-TEST1-NEXT: key:
-TEST1-NEXT: instructions:
-TEST1-NEXT: - 'C_ADDI [[REG01:X[0-9]+]] [[RE02:X[0-9]+]] [[IMM0:i_0x[0-9]+]]'
+C_ADDI: ---
+C_ADDI-NEXT: mode: latency
+C_ADDI-NEXT: key:
+C_ADDI-NEXT: instructions:
+C_ADDI-NEXT: - 'C_ADDI [[REG01:X[0-9]+]] [[RE02:X[0-9]+]] [[IMM0:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ADDIW -mattr=+c | FileCheck --check-prefix=TEST2 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_ADDIW -mattr=+c | FileCheck --check-prefix=C_ADDIW %s
-TEST2: ---
-TEST2-NEXT: mode: latency
-TEST2-NEXT: key:
-TEST2-NEXT: instructions:
-TEST2-NEXT: - 'C_ADDIW [[REG11:X[0-9]+]] [[RE12:X[0-9]+]] [[IMM1:i_0x[0-9]+]]'
+C_ADDIW: ---
+C_ADDIW-NEXT: mode: latency
+C_ADDIW-NEXT: key:
+C_ADDIW-NEXT: instructions:
+C_ADDIW-NEXT: - 'C_ADDIW [[REG11:X[0-9]+]] [[RE12:X[0-9]+]] [[IMM1:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_ANDI -mattr=+c | FileCheck --check-prefix=TEST3 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_ANDI -mattr=+c | FileCheck --check-prefix=C_ANDI %s
-TEST3: ---
-TEST3-NEXT: mode: latency
-TEST3-NEXT: key:
-TEST3-NEXT: instructions:
-TEST3-NEXT: - 'C_ANDI [[REG31:X[0-9]+]] [[REG32:X[0-9]+]] [[IMM3:i_0x[0-9]+]]'
+C_ANDI: ---
+C_ANDI-NEXT: mode: latency
+C_ANDI-NEXT: key:
+C_ANDI-NEXT: instructions:
+C_ANDI-NEXT: - 'C_ANDI [[REG31:X[0-9]+]] [[REG32:X[0-9]+]] [[IMM3:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SLLI -mattr=+c | FileCheck --check-prefix=TEST4 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_SLLI -mattr=+c | FileCheck --check-prefix=C_SLLI %s
-TEST4: ---
-TEST4-NEXT: mode: latency
-TEST4-NEXT: key:
-TEST4-NEXT: instructions:
-TEST4-NEXT: - 'C_SLLI [[REG81:X[0-9]+]] [[REG82:X[0-9]+]] [[IMM8:i_0x[0-9]+]]'
+C_SLLI: ---
+C_SLLI-NEXT: mode: latency
+C_SLLI-NEXT: key:
+C_SLLI-NEXT: instructions:
+C_SLLI-NEXT: - 'C_SLLI [[REG81:X[0-9]+]] [[REG82:X[0-9]+]] [[IMM8:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SRAI -mattr=+c | FileCheck --check-prefix=TEST5 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_SRAI -mattr=+c | FileCheck --check-prefix=C_SRAI %s
-TEST5: ---
-TEST5-NEXT: mode: latency
-TEST5-NEXT: key:
-TEST5-NEXT: instructions:
-TEST5-NEXT: - 'C_SRAI [[REG91:X[0-9]+]] [[REG92:X[0-9]+]] [[IMM9:i_0x[0-9]+]]'
+C_SRAI: ---
+C_SRAI-NEXT: mode: latency
+C_SRAI-NEXT: key:
+C_SRAI-NEXT: instructions:
+C_SRAI-NEXT: - 'C_SRAI [[REG91:X[0-9]+]] [[REG92:X[0-9]+]] [[IMM9:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_SRLI -mattr=+c | FileCheck --check-prefix=TEST6 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_SRLI -mattr=+c | FileCheck --check-prefix=C_SRLI %s
-TEST6: ---
-TEST6-NEXT: mode: latency
-TEST6-NEXT: key:
-TEST6-NEXT: instructions:
-TEST6-NEXT: - 'C_SRLI [[REG101:X[0-9]+]] [[REG102:X[0-9]+]] [[IMM10:i_0x[0-9]+]]'
-TEST6-LAST: ...
+C_SRLI: ---
+C_SRLI-NEXT: mode: latency
+C_SRLI-NEXT: key:
+C_SRLI-NEXT: instructions:
+C_SRLI-NEXT: - 'C_SRLI [[REG101:X[0-9]+]] [[REG102:X[0-9]+]] [[IMM10:i_0x[0-9]+]]'
+C_SRLI-LAST: ...
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_LD -mattr=+c | FileCheck --check-prefix=TEST7 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_LD -mattr=+c | FileCheck --check-prefix=C_LD %s
-TEST7: ---
-TEST7-NEXT: mode: latency
-TEST7-NEXT: key:
-TEST7-NEXT: instructions:
-TEST7-NEXT: - 'C_LD [[REG61:X[0-9]+]] [[REG62:X[0-9]+]] [[IMM6:i_0x[0-9]+]]'
+C_LD: ---
+C_LD-NEXT: mode: latency
+C_LD-NEXT: key:
+C_LD-NEXT: instructions:
+C_LD-NEXT: - 'C_LD [[REG61:X[0-9]+]] [[REG62:X[0-9]+]] [[IMM6:i_0x[0-9]+]]'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=C_LW -mattr=+c | FileCheck --check-prefix=TEST8 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_LW -mattr=+c | FileCheck --check-prefix=C_LW %s
-TEST8: ---
-TEST8-NEXT: mode: latency
-TEST8-NEXT: key:
-TEST8-NEXT: instructions:
-TEST8-NEXT: - 'C_LW [[REG71:X[0-9]+]] [[REG72:X[0-9]+]] [[IMM7:i_0x[0-9]+]]'
+C_LW: ---
+C_LW-NEXT: mode: latency
+C_LW-NEXT: key:
+C_LW-NEXT: instructions:
+C_LW-NEXT: - 'C_LW [[REG71:X[0-9]+]] [[REG72:X[0-9]+]] [[IMM7:i_0x[0-9]+]]'
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
index b685d8759c27c..ba985e231e5ce 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-load.s
@@ -1,60 +1,60 @@
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LD | FileCheck --check-prefix=TEST1 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LD | FileCheck --check-prefix=LD %s
-TEST1: ---
-TEST1-NEXT: mode: latency
-TEST1-NEXT: key:
-TEST1-NEXT: instructions:
-TEST1-NEXT: - 'LD X10 X10 i_0x0'
+LD: ---
+LD-NEXT: mode: latency
+LD-NEXT: key:
+LD-NEXT: instructions:
+LD-NEXT: - 'LD X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LW | FileCheck --check-prefix=TEST2 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LW | FileCheck --check-prefix=LW %s
-TEST2: ---
-TEST2-NEXT: mode: latency
-TEST2-NEXT: key:
-TEST2-NEXT: instructions:
-TEST2-NEXT: - 'LW X10 X10 i_0x0'
+LW: ---
+LW-NEXT: mode: latency
+LW-NEXT: key:
+LW-NEXT: instructions:
+LW-NEXT: - 'LW X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LH | FileCheck --check-prefix=TEST3 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LH | FileCheck --check-prefix=LH %s
-TEST3: ---
-TEST3-NEXT: mode: latency
-TEST3-NEXT: key:
-TEST3-NEXT: instructions:
-TEST3-NEXT: - 'LH X10 X10 i_0x0'
+LH: ---
+LH-NEXT: mode: latency
+LH-NEXT: key:
+LH-NEXT: instructions:
+LH-NEXT: - 'LH X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LWU | FileCheck --check-prefix=TEST4 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LWU | FileCheck --check-prefix=LWU %s
-TEST4: ---
-TEST4-NEXT: mode: latency
-TEST4-NEXT: key:
-TEST4-NEXT: instructions:
-TEST4-NEXT: - 'LWU X10 X10 i_0x0'
+LWU: ---
+LWU-NEXT: mode: latency
+LWU-NEXT: key:
+LWU-NEXT: instructions:
+LWU-NEXT: - 'LWU X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LBU | FileCheck --check-prefix=TEST5 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LBU | FileCheck --check-prefix=LBU %s
-TEST5: ---
-TEST5-NEXT: mode: latency
-TEST5-NEXT: key:
-TEST5-NEXT: instructions:
-TEST5-NEXT: - 'LBU X10 X10 i_0x0'
+LBU: ---
+LBU-NEXT: mode: latency
+LBU-NEXT: key:
+LBU-NEXT: instructions:
+LBU-NEXT: - 'LBU X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LUI 2>&1 | FileCheck --check-prefix=TEST6 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LUI 2>&1 | FileCheck --check-prefix=LUI %s
-TEST6: LUI: No strategy found to make the execution serial
+LUI: LUI: No strategy found to make the execution serial
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LB | FileCheck --check-prefix=TEST7 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LB | FileCheck --check-prefix=LB %s
-TEST7: ---
-TEST7-NEXT: mode: latency
-TEST7-NEXT: key:
-TEST7-NEXT: instructions:
-TEST7-NEXT: - 'LB X10 X10 i_0x0'
+LB: ---
+LB-NEXT: mode: latency
+LB-NEXT: key:
+LB-NEXT: instructions:
+LB-NEXT: - 'LB X10 X10 i_0x0'
-# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --benchmark-phase=assemble-measured-code -opcode-name=LR_W_RL -mattr="+a" | FileCheck --check-prefix=TEST8 %s
+# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=LR_W_RL -mattr="+a" | FileCheck --check-prefix=LR_W_RL %s
-TEST8: ---
-TEST8-NEXT: mode: latency
-TEST8-NEXT: key:
-TEST8-NEXT: instructions:
-TEST8-NEXT: - 'LR_W_RL X10 X10'
+LR_W_RL: ---
+LR_W_RL-NEXT: mode: latency
+LR_W_RL-NEXT: key:
+LR_W_RL-NEXT: instructions:
+LR_W_RL-NEXT: - 'LR_W_RL X10 X10'
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
index fd58bfb7c1a84..0a4cca1ffc1c1 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
@@ -1,4 +1,4 @@
-# RUN: llvm-exegesis -mtriple=riscv64-unknown-linux-gnu -mode=latency --benchmark-phase=assemble-measured-code -mattr=+d -opcode-name=FADD_D | FileCheck %s
+# RUN: llvm-exegesis -mtriple=riscv64-unknown-linux-gnu --mcpu=generic -mode=latency --benchmark-phase=assemble-measured-code -mattr=+d -opcode-name=FADD_D | FileCheck %s
CHECK: ---
CHECK-NEXT: mode: latency
diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
index 2908ea80d0e47..92ab3a96d91e6 100644
--- a/llvm/tools/llvm-exegesis/lib/Assembler.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Assembler.cpp
@@ -168,15 +168,7 @@ void BasicBlockFiller::addInstruction(const MCInst &Inst, const DebugLoc &DL) {
} else if (Op.isImm()) {
Builder.addImm(Op.getImm());
} else if (!Op.isValid()) {
- std::string Message;
- llvm::raw_string_ostream MessageOut(Message);
- MessageOut << "Operand is not set: Instr: ";
- Inst.dump_pretty(MessageOut, MCII->getName(Inst.getOpcode()));
- MessageOut << "; OpIndex: " << OpIndex;
- const MCOperandInfo &OperandInfo = MCID.operands()[OpIndex];
- MessageOut << "; OpInfo.OperandType: "
- << static_cast<uint32_t>(OperandInfo.OperandType);
- report_fatal_error(Twine(Message));
+ llvm_unreachable("Operand is not set");
} else {
llvm_unreachable("Not yet implemented");
}
diff --git a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
index d387251a687e6..17d09a1ec0cf3 100644
--- a/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
+++ b/llvm/tools/llvm-exegesis/lib/LlvmState.cpp
@@ -45,12 +45,6 @@ Expected<LLVMState> LLVMState::Create(std::string TripleName,
if (CpuName == "native")
CpuName = std::string(sys::getHostCPUName());
- if (CpuName.empty()) {
- std::unique_ptr<MCSubtargetInfo> Empty_STI(
- TheTarget->createMCSubtargetInfo(TripleName, "", ""));
- CpuName = Empty_STI->getAllProcessorDescriptions().begin()->Key;
- }
-
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, CpuName, ""));
assert(STI && "Unable to create subtarget info!");
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index edc1a341b27ce..da84ce793eb02 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -167,8 +167,8 @@ struct Instruction {
const BitVector &AllDefRegs; // The set of all aliased def registers.
const BitVector &AllUseRegs; // The set of all aliased use registers.
const BitVector &MemoryRegs; // The set of all aliased memory use registers.
- const BitVector
- &NotMemoryRegs; // The set of all aliased not memory use registers.
+ // The set of all aliased not memory use registers.
+ const BitVector &NotMemoryRegs;
private:
Instruction(const MCInstrDesc *Description, StringRef Name,
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index d286de9005424..f496a881fc030 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -237,7 +237,7 @@ static cl::opt<std::string>
static cl::opt<std::string>
MCPU("mcpu",
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
- cl::value_desc("cpu-name"), cl::cat(Options), cl::init(""));
+ cl::value_desc("cpu-name"), cl::cat(Options), cl::init("native"));
static cl::opt<std::string>
DumpObjectToDisk("dump-object-to-disk",
>From 8088b2b498af99872fd4e23d191638ab27dd4ce4 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Tue, 21 May 2024 19:16:19 +0300
Subject: [PATCH 04/10] Addressing review comments
---
.../llvm-exegesis/lib/AArch64/Target.cpp | 4 ----
llvm/tools/llvm-exegesis/lib/BenchmarkCode.h | 5 -----
llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp | 5 +++--
llvm/tools/llvm-exegesis/lib/CodeTemplate.h | 4 ++--
.../llvm-exegesis/lib/MCInstrDescView.cpp | 21 ++++++++-----------
.../tools/llvm-exegesis/lib/MCInstrDescView.h | 4 +---
llvm/tools/llvm-exegesis/lib/Mips/Target.cpp | 5 -----
.../llvm-exegesis/lib/PowerPC/Target.cpp | 7 -------
llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp | 2 +-
.../lib/SerialSnippetGenerator.cpp | 2 +-
llvm/tools/llvm-exegesis/lib/Target.cpp | 4 ----
llvm/tools/llvm-exegesis/lib/Target.h | 4 +++-
llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 6 ------
13 files changed, 20 insertions(+), 53 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
index 6a3eba2459556..51846862f0a73 100644
--- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp
@@ -45,10 +45,6 @@ class ExegesisAArch64Target : public ExegesisTarget {
: ExegesisTarget(AArch64CpuPfmCounters, AArch64_MC::isOpcodeAvailable) {}
private:
- unsigned findRegisterByName(const StringRef RegName) const override {
- return AArch64::NoRegister;
- }
-
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override {
if (AArch64::GPR32RegClass.contains(Reg))
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
index 4d5fc241fde0d..1db8472e99f7c 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h
@@ -17,11 +17,6 @@
namespace llvm {
namespace exegesis {
-struct ScratchMemoryStore {
- unsigned Reg;
- unsigned Offset;
-};
-
// A collection of instructions that are to be assembled, executed and measured.
struct BenchmarkCode {
BenchmarkKey Key;
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
index 9b5bfe3196dcd..74a78b0f1c56f 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.cpp
@@ -57,11 +57,12 @@ const MCOperand &InstructionTemplate::getValueFor(const Operand &Op) const {
return getValueFor(Instr->Variables[Op.getVariableIndex()]);
}
-MCOperand &InstructionTemplate::getValueFor(unsigned OpIdx) {
+MCOperand &InstructionTemplate::getValueForOperandIdx(unsigned OpIdx) {
return getValueFor(Instr->Variables[OpIdx]);
}
-const MCOperand &InstructionTemplate::getValueFor(unsigned OpIdx) const {
+const MCOperand &
+InstructionTemplate::getValueForOperandIdx(unsigned OpIdx) const {
return getValueFor(Instr->Variables[OpIdx]);
}
diff --git a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
index 85fcb4e908f01..662fd90306a45 100644
--- a/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
+++ b/llvm/tools/llvm-exegesis/lib/CodeTemplate.h
@@ -35,8 +35,8 @@ struct InstructionTemplate {
const MCOperand &getValueFor(const Variable &Var) const;
MCOperand &getValueFor(const Operand &Op);
const MCOperand &getValueFor(const Operand &Op) const;
- MCOperand &getValueFor(unsigned OpIdx);
- const MCOperand &getValueFor(unsigned OpIdx) const;
+ MCOperand &getValueForOperandIdx(unsigned OpIdx);
+ const MCOperand &getValueForOperandIdx(unsigned OpIdx) const;
bool hasImmediateVariables() const;
const Instruction &getInstr() const { return *Instr; }
ArrayRef<MCOperand> getVariableValues() const { return VariableValues; }
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
index 7705d9af4057e..f9b3666d36f78 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -89,17 +89,18 @@ const BitVector *BitVectorCache::getUnique(BitVector &&BV) const {
return Entry.get();
}
-Instruction::Instruction(
- const MCInstrDesc *Description, StringRef Name,
- SmallVector<Operand, 8> Operands, SmallVector<Variable, 4> Variables,
- const BitVector *ImplDefRegs, const BitVector *ImplUseRegs,
- const BitVector *AllDefRegs, const BitVector *AllUseRegs,
- const BitVector *MemoryRegs, const BitVector *NotMemoryRegs)
+Instruction::Instruction(const MCInstrDesc *Description, StringRef Name,
+ SmallVector<Operand, 8> Operands,
+ SmallVector<Variable, 4> Variables,
+ const BitVector *ImplDefRegs,
+ const BitVector *ImplUseRegs,
+ const BitVector *AllDefRegs,
+ const BitVector *AllUseRegs,
+ const BitVector *NotMemoryRegs)
: Description(*Description), Name(Name), Operands(std::move(Operands)),
Variables(std::move(Variables)), ImplDefRegs(*ImplDefRegs),
ImplUseRegs(*ImplUseRegs), AllDefRegs(*AllDefRegs),
- AllUseRegs(*AllUseRegs), MemoryRegs(*MemoryRegs),
- NotMemoryRegs(*NotMemoryRegs) {}
+ AllUseRegs(*AllUseRegs), NotMemoryRegs(*NotMemoryRegs) {}
std::unique_ptr<Instruction>
Instruction::create(const MCInstrInfo &InstrInfo,
@@ -166,7 +167,6 @@ Instruction::create(const MCInstrInfo &InstrInfo,
BitVector ImplUseRegs = RATC.emptyRegisters();
BitVector AllDefRegs = RATC.emptyRegisters();
BitVector AllUseRegs = RATC.emptyRegisters();
- BitVector MemoryRegs = RATC.emptyRegisters();
BitVector NotMemoryRegs = RATC.emptyRegisters();
for (const auto &Op : Operands) {
@@ -180,8 +180,6 @@ Instruction::create(const MCInstrInfo &InstrInfo,
ImplDefRegs |= AliasingBits;
if (Op.isUse() && Op.isImplicit())
ImplUseRegs |= AliasingBits;
- if (Op.isUse() && Op.isMemory())
- MemoryRegs |= AliasingBits;
if (Op.isUse() && !Op.isMemory())
NotMemoryRegs |= AliasingBits;
}
@@ -193,7 +191,6 @@ Instruction::create(const MCInstrInfo &InstrInfo,
BVC.getUnique(std::move(ImplUseRegs)),
BVC.getUnique(std::move(AllDefRegs)),
BVC.getUnique(std::move(AllUseRegs)),
- BVC.getUnique(std::move(MemoryRegs)),
BVC.getUnique(std::move(NotMemoryRegs))));
}
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index da84ce793eb02..c6f47a438ad49 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -166,7 +166,6 @@ struct Instruction {
const BitVector &ImplUseRegs; // The set of aliased implicit use registers.
const BitVector &AllDefRegs; // The set of all aliased def registers.
const BitVector &AllUseRegs; // The set of all aliased use registers.
- const BitVector &MemoryRegs; // The set of all aliased memory use registers.
// The set of all aliased not memory use registers.
const BitVector &NotMemoryRegs;
@@ -175,8 +174,7 @@ struct Instruction {
SmallVector<Operand, 8> Operands,
SmallVector<Variable, 4> Variables, const BitVector *ImplDefRegs,
const BitVector *ImplUseRegs, const BitVector *AllDefRegs,
- const BitVector *AllUseRegs, const BitVector *MemoryRegs,
- const BitVector *NotMemoryRegs);
+ const BitVector *AllUseRegs, const BitVector *NotMemoryRegs);
};
// Instructions are expensive to instantiate. This class provides a cache of
diff --git a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
index 917c055e29d8f..6231c971fadb9 100644
--- a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
@@ -62,7 +62,6 @@ class ExegesisMipsTarget : public ExegesisTarget {
unsigned getMaxMemoryAccessSize() const override { return 64; }
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
unsigned Offset) const override;
- unsigned findRegisterByName(const StringRef RegName) const override;
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
bool matchesArch(Triple::ArchType Arch) const override {
@@ -148,10 +147,6 @@ void ExegesisMipsTarget::fillMemoryOperands(InstructionTemplate &IT,
setMemOp(IT, 2, MCOperand::createImm(Offset)); // Disp
}
-unsigned ExegesisMipsTarget::findRegisterByName(const StringRef RegName) const {
- return Mips::NoRegister;
-}
-
std::vector<MCInst> ExegesisMipsTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
diff --git a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
index 0031fb89118dd..5c944c90384e3 100644
--- a/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/PowerPC/Target.cpp
@@ -33,8 +33,6 @@ class ExegesisPowerPCTarget : public ExegesisTarget {
: ExegesisTarget(PPCCpuPfmCounters, PPC_MC::isOpcodeAvailable) {}
private:
- unsigned findRegisterByName(const StringRef RegName) const override;
-
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
bool matchesArch(Triple::ArchType Arch) const override {
@@ -94,11 +92,6 @@ void ExegesisPowerPCTarget::fillMemoryOperands(InstructionTemplate &IT,
setMemOp(IT, MemOpIdx + 2, MCOperand::createReg(Reg)); // BaseReg
}
-unsigned
-ExegesisPowerPCTarget::findRegisterByName(const StringRef RegName) const {
- return PPC::NoRegister;
-}
-
std::vector<MCInst> ExegesisPowerPCTarget::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
index 0909c4d3250f7..2583365a3945b 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -371,7 +371,7 @@ Error ExegesisRISCVTarget::randomizeTargetMCOperand(
// explicitly for each instruction according to RVC spec.
void ExegesisRISCVTarget::processInstructionReservedRegs(
InstructionTemplate &IT) const {
- MCOperand &AssignedValue = IT.getValueFor(0);
+ MCOperand &AssignedValue = IT.getValueForOperandIdx(0);
switch (IT.getOpcode()) {
case RISCV::C_ADDI16SP:
diff --git a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
index 9739b48b2b97e..1f1e3983d3014 100644
--- a/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp
@@ -125,7 +125,7 @@ static void appendCodeTemplates(const LLVMState &State,
if (DefOpIt == I.Operands.end())
return;
- auto &DefOp = *DefOpIt;
+ const Operand &DefOp = *DefOpIt;
auto &ET = State.getExegesisTarget();
auto ScratchMemoryRegister = ET.getScratchMemoryRegister(
State.getTargetMachine().getTargetTriple());
diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp
index 533f709147eb6..29e58692f0e92 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Target.cpp
@@ -212,10 +212,6 @@ class ExegesisDefaultTarget : public ExegesisTarget {
ExegesisDefaultTarget() : ExegesisTarget({}, opcodeIsNotAvailable) {}
private:
- unsigned findRegisterByName(const StringRef RegName) const override {
- llvm_unreachable("Not yet implemented");
- }
-
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override {
llvm_unreachable("Not yet implemented");
diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h
index 96088f88a89a9..0e63c6879e712 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/llvm/tools/llvm-exegesis/lib/Target.h
@@ -92,7 +92,9 @@ class ExegesisTarget {
}
// Find register by name, NoRegister if not found.
- virtual unsigned findRegisterByName(const StringRef RegName) const = 0;
+ virtual unsigned findRegisterByName(const StringRef RegName) const {
+ return MCRegister::NoRegister;
+ }
// Targets can use this to add target-specific passes in assembleToStream();
virtual void addTargetSpecificPasses(PassManagerBase &PM) const {}
diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index 51ef3e872b967..dbb2bf409316e 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -736,8 +736,6 @@ class ExegesisX86Target : public ExegesisTarget {
const MCInstrInfo &MII,
unsigned LoopRegister) const override;
- unsigned findRegisterByName(const StringRef RegName) const override;
-
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
@@ -1011,10 +1009,6 @@ static std::vector<MCInst> loadImmediateSegmentRegister(unsigned Reg,
#endif // defined(__x86_64__) && defined(__linux__)
}
-unsigned ExegesisX86Target::findRegisterByName(const StringRef RegName) const {
- return X86::NoRegister;
-}
-
std::vector<MCInst> ExegesisX86Target::setRegTo(const MCSubtargetInfo &STI,
unsigned Reg,
const APInt &Value) const {
>From 660829389207813048610dcd23d595609a2932f5 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Thu, 23 May 2024 20:59:19 +0300
Subject: [PATCH 05/10] Fixed tests
---
.../tools/llvm-exegesis/RISCV/latency-by-extension-A.s | 10 +++++-----
.../tools/llvm-exegesis/RISCV/latency-by-extension-C.s | 2 +-
.../RISCV/latency-by-opcode-name-FADD_D.s | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
index a0b5932e83467..bdc02d4af2155 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-A.s
@@ -8,7 +8,7 @@ AMOAND_D-NEXT: - 'AMOAND_D [[RE01:X[0-9]+]] X10 [[RE01:X[0-9]+]]'
AMOAND_D-NEXT: config: ''
AMOAND_D-NEXT: register_initial_values:
AMOAND_D-NEXT: - '[[RE01:X[0-9]+]]=0x0'
-AMOAND_D-LAST: ...
+AMOAND_D-DAG: ...
# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOADD_W -mattr="+a" | FileCheck --check-prefix=AMOADD_W %s
@@ -20,7 +20,7 @@ AMOADD_W-NEXT: - 'AMOADD_W [[RE02:X[0-9]+]] X10 [[RE02:X[0-9]+]]'
AMOADD_W-NEXT: config: ''
AMOADD_W-NEXT: register_initial_values:
AMOADD_W-NEXT: - '[[RE02:X[0-9]+]]=0x0'
-AMOADD_W-LAST: ...
+AMOADD_W-DAG: ...
# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOMAXU_D -mattr="+a" | FileCheck --check-prefix=AMOMAXU_D %s
@@ -32,7 +32,7 @@ AMOMAXU_D-NEXT: - 'AMOMAXU_D [[RE03:X[0-9]+]] X10 [[RE03:X[0-9]+]]'
AMOMAXU_D-NEXT: config: ''
AMOMAXU_D-NEXT: register_initial_values:
AMOMAXU_D-NEXT: - '[[RE03:X[0-9]+]]=0x0'
-AMOMAXU_D-LAST: ...
+AMOMAXU_D-DAG: ...
# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOMIN_W -mattr="+a" | FileCheck --check-prefix=AMOMIN_W %s
@@ -44,7 +44,7 @@ AMOMIN_W-NEXT: - 'AMOMIN_W [[RE04:X[0-9]+]] X10 [[RE04:X[0-9]+]]'
AMOMIN_W-NEXT: config: ''
AMOMIN_W-NEXT: register_initial_values:
AMOMIN_W-NEXT: - '[[RE04:X[0-9]+]]=0x0'
-AMOMIN_W-LAST: ...
+AMOMIN_W-DAG: ...
# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=AMOXOR_D -mattr="+a" | FileCheck --check-prefix=AMOXOR_D %s
@@ -56,4 +56,4 @@ AMOXOR_D-NEXT: - 'AMOXOR_D [[RE05:X[0-9]+]] X10 [[RE05:X[0-9]+]]'
AMOXOR_D-NEXT: config: ''
AMOXOR_D-NEXT: register_initial_values:
AMOXOR_D-NEXT: - '[[RE05:X[0-9]+]]=0x0'
-AMOXOR_D-LAST: ...
+AMOXOR_D-DAG: ...
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
index 108e1cb411d61..00bd79729539f 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-extension-C.s
@@ -45,7 +45,7 @@ C_SRLI-NEXT: mode: latency
C_SRLI-NEXT: key:
C_SRLI-NEXT: instructions:
C_SRLI-NEXT: - 'C_SRLI [[REG101:X[0-9]+]] [[REG102:X[0-9]+]] [[IMM10:i_0x[0-9]+]]'
-C_SRLI-LAST: ...
+C_SRLI-DAG: ...
# RUN: llvm-exegesis -mode=latency -mtriple=riscv64-unknown-linux-gnu --mcpu=generic --benchmark-phase=assemble-measured-code -opcode-name=C_LD -mattr=+c | FileCheck --check-prefix=C_LD %s
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
index 0a4cca1ffc1c1..2dea89cca4d7e 100644
--- a/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
+++ b/llvm/test/tools/llvm-exegesis/RISCV/latency-by-opcode-name-FADD_D.s
@@ -8,4 +8,4 @@ CHECK-NEXT: - 'FADD_D [[REG1:F[0-9]+_D]] [[REG2:F[0-9]+_D]] [[REG3:F[0-9]+_D
CHECK-NEXT: config: ''
CHECK-NEXT: register_initial_values:
CHECK-DAG: - '[[REG1]]=0x0'
-CHECK-LAST: ...
+CHECK-DAG: ...
>From fe13a8eefc3bde109a7d2c378fbb8a40999ef808 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Fri, 24 May 2024 18:35:05 +0300
Subject: [PATCH 06/10] Addressing review comments
---
llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp | 7 +++++++
llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp | 6 +++---
llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp | 1 -
llvm/tools/llvm-exegesis/lib/Target.h | 2 +-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
index 1d421b3c31c36..a9d207fa3d157 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
@@ -5,6 +5,10 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+//
+// This file defines RISC-V perf counters.
+//
+//===----------------------------------------------------------------------===//
#include "RISCVCounters.h"
@@ -45,6 +49,9 @@ RISCVCpuCyclesCounter::RISCVCpuCyclesCounter(pfm::PerfEvent &&Event)
StartValue = getRISCVCpuCyclesCount();
EndValue = getRISCVCpuCyclesCount();
MeasurementCycles = EndValue - StartValue;
+ // If values of two calls CpuCyclesCounters don`t differ
+ // it means that counters don`t configured properly, report error.
+ // MeasurementCycles the smallest interval between two counter calls.
if (MeasurementCycles == 0) {
report_fatal_error("MeasurementCycles == 0, "
"performance counters are not configured.");
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
index 2583365a3945b..77365c5ccadf1 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -60,7 +60,7 @@ class ExegesisRISCVTarget : public ExegesisTarget {
bool checkOpcodeSupported(int Opcode,
const MCSubtargetInfo &SI) const override;
- unsigned findRegisterByName(const StringRef RegName) const override;
+ MCRegister findRegisterByName(const StringRef RegName) const override;
bool matchesArch(Triple::ArchType Arch) const override;
@@ -123,9 +123,9 @@ bool ExegesisRISCVTarget::checkOpcodeSupported(
#define GET_REGISTER_MATCHER
#include "RISCVGenAsmMatcher.inc"
-unsigned
+MCRegister
ExegesisRISCVTarget::findRegisterByName(const StringRef RegName) const {
- unsigned Reg;
+ MCRegister Reg;
if ((Reg = MatchRegisterName(RegName)))
return Reg;
if ((Reg = MatchRegisterAltName(RegName)))
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
index 8eaf83044e0dd..48357d443f713 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp
@@ -211,7 +211,6 @@ static void setRegisterOperandValue(const RegisterOperandAssignment &ROV,
if (AssignedValue.isValid()) {
// TODO don't re-assign register operands which are already "locked"
// by Target in corresponding InstructionTemplate
- // assert(AssignedValue.isReg() && AssignedValue.getReg() == ROV.Reg);
return;
}
AssignedValue = MCOperand::createReg(ROV.Reg);
diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h
index 0e63c6879e712..b48d027fb83fb 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/llvm/tools/llvm-exegesis/lib/Target.h
@@ -92,7 +92,7 @@ class ExegesisTarget {
}
// Find register by name, NoRegister if not found.
- virtual unsigned findRegisterByName(const StringRef RegName) const {
+ virtual MCRegister findRegisterByName(const StringRef RegName) const {
return MCRegister::NoRegister;
}
>From fec059e994a4e2af8ebe9ba29ba92a4c11bfa358 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Fri, 31 May 2024 19:03:43 +0300
Subject: [PATCH 07/10] Addressing review comments
---
llvm/lib/Target/RISCV/CMakeLists.txt | 1 +
llvm/lib/Target/RISCV/RISCV.td | 6 ++
llvm/lib/Target/RISCV/RISCVPfmCounters.td | 18 ++++
llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp | 18 +---
llvm/tools/llvm-exegesis/lib/SnippetFile.cpp | 1 +
llvm/tools/llvm-exegesis/llvm-exegesis.cpp | 92 ++++++++++++-------
.../llvm-project-overlay/llvm/BUILD.bazel | 1 +
7 files changed, 89 insertions(+), 48 deletions(-)
create mode 100644 llvm/lib/Target/RISCV/RISCVPfmCounters.td
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 8715403f3839a..cbb276a0dc04d 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -15,6 +15,7 @@ tablegen(LLVM RISCVGenRegisterBank.inc -gen-register-bank)
tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM RISCVGenSearchableTables.inc -gen-searchable-tables)
tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget)
+tablegen(LLVM RISCVGenExegesis.inc -gen-exegesis)
set(LLVM_TARGET_DEFINITIONS RISCVGISel.td)
tablegen(LLVM RISCVGenGlobalISel.inc -gen-global-isel)
diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
index 09f496574d64a..fe8d0a757d58b 100644
--- a/llvm/lib/Target/RISCV/RISCV.td
+++ b/llvm/lib/Target/RISCV/RISCV.td
@@ -82,3 +82,9 @@ def RISCV : Target {
let AssemblyWriters = [RISCVAsmWriter];
let AllowRegisterRenaming = 1;
}
+
+//===----------------------------------------------------------------------===//
+// Pfm Counters
+//===----------------------------------------------------------------------===//
+
+include "RISCVPfmCounters.td"
diff --git a/llvm/lib/Target/RISCV/RISCVPfmCounters.td b/llvm/lib/Target/RISCV/RISCVPfmCounters.td
new file mode 100644
index 0000000000000..33650dc5b0017
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVPfmCounters.td
@@ -0,0 +1,18 @@
+//===-- RISCVPfmCounters.td - RISC-V Hardware Counters -----*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This describes the available hardware counters for RISC-V.
+//
+//===----------------------------------------------------------------------===//
+
+def CpuCyclesPfmCounter : PfmCounter<"CPU_CYCLES">;
+
+def DefaultPfmCounters : ProcPfmCounters {
+ let CycleCounter = CpuCyclesPfmCounter;
+}
+def : PfmCountersDefaultBinding<DefaultPfmCounters>;
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
index 77365c5ccadf1..84634db285ba6 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp
@@ -31,22 +31,7 @@ namespace exegesis {
namespace {
-// TODO move perf counter data to td files (although it looks like an overkill
-// of sorts)
-
-static const char *RISCVPfmCounterNames[] = {
- "CPU_CYCLES", // 0
-};
-
-static const PfmCountersInfo RISCVDefaultPfmCounters = {
- RISCVPfmCounterNames[0], // Cycle counter
- nullptr, // No uops counter.
- nullptr, // No issue counters.
- 0};
-
-static const CpuAndPfmCounters RISCVCpuPfmCounters[] = {
- {"", &RISCVDefaultPfmCounters},
-};
+#include "RISCVGenExegesis.inc"
class ExegesisRISCVTarget : public ExegesisTarget {
public:
@@ -102,6 +87,7 @@ Expected<std::unique_ptr<pfm::CounterGroup>> ExegesisRISCVTarget::createCounter(
StringRef CounterName, const LLVMState &State,
ArrayRef<const char *> ValidationCounters, const pid_t ProcessID) const {
if (CounterName == RISCVPfmCounterNames[0]) {
+ // TODO add support for Linux perf counters
return createRISCVCpuCyclesCounter(pfm::PerfEvent(CounterName));
}
return make_error<Failure>(Twine("Unsupported performance counter '")
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index 89254fb1eee30..412c06cc5acbd 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -208,6 +208,7 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
Align ByteAlignment, SMLoc Loc) override {}
unsigned findRegisterByName(const StringRef RegName) const {
+ // TODO make use of RegNameToRegNo map
if (unsigned Reg = Target.findRegisterByName(RegName))
return Reg;
auto Iter = RegNameToRegNo.find(RegName);
diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index f496a881fc030..b8ef7e2a5c60c 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -50,17 +50,27 @@
namespace llvm {
namespace exegesis {
+struct OpcodeNameParser
+ : public cl::parser<std::vector<std::pair<StringRef, StringRef>>> {
+ OpcodeNameParser(cl::Option &O)
+ : cl::parser<std::vector<std::pair<StringRef, StringRef>>>(O) {}
+ bool parse(cl::Option &O, StringRef ArgName, const StringRef ArgValue,
+ std::vector<std::pair<StringRef, StringRef>> &Val);
+};
+
static cl::opt<int> OpcodeIndex(
"opcode-index",
cl::desc("opcode to measure, by index, or -1 to measure all opcodes"),
cl::cat(BenchmarkOptions), cl::init(0));
-static cl::opt<std::string>
+static cl::opt<std::vector<std::pair<StringRef, StringRef>>, false,
+ OpcodeNameParser>
OpcodeNames("opcode-name",
cl::desc("comma-separated list of opcodes to measure, "
"each item is either opcode name ('OP') "
"or opcode range ('OP1..OP2', ends are inclusive)"),
- cl::cat(BenchmarkOptions), cl::init(""));
+ cl::cat(BenchmarkOptions),
+ cl::init(std::vector<std::pair<StringRef, StringRef>>()));
static cl::opt<std::string> SnippetsFile("snippets-file",
cl::desc("code snippets to measure"),
@@ -313,6 +323,27 @@ static bool isIgnoredOpcode(const LLVMState &State, unsigned Opcode) {
return getIgnoredOpcodeReasonOrNull(State, Opcode) != nullptr;
}
+bool OpcodeNameParser::parse(
+ cl::Option &O, StringRef ArgName, const StringRef OpcodeNames,
+ std::vector<std::pair<StringRef, StringRef>> &Val) {
+ SmallVector<StringRef, 2> Pieces;
+ StringRef(OpcodeNames)
+ .split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
+ for (const StringRef &OpcodeName : Pieces) {
+ size_t DotDotPos = OpcodeName.find("..");
+ if (DotDotPos == StringRef::npos) {
+ Val.push_back(std::make_pair(OpcodeName, OpcodeName));
+ continue;
+ }
+ StringRef BeginOpcodeName = OpcodeName.substr(0, DotDotPos);
+ StringRef EndOpcodeName = OpcodeName.substr(DotDotPos + 2);
+ Val.push_back(std::make_pair(BeginOpcodeName, EndOpcodeName));
+ }
+ if (Val.empty())
+ return O.error("No matching opcode names");
+ return false;
+}
+
// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
// and returns the opcode indices or {} if snippets should be read from
// `SnippetsFile`.
@@ -351,37 +382,34 @@ static std::vector<unsigned> getOpcodesOrDie(const LLVMState &State) {
return I->getSecond();
return 0u;
};
- SmallVector<StringRef, 2> Pieces;
- StringRef(OpcodeNames.getValue())
- .split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
+
std::vector<unsigned> Result;
- Result.reserve(Pieces.size());
- for (const StringRef &OpcodeName : Pieces) {
- if (unsigned Opcode = ResolveName(OpcodeName)) {
- Result.push_back(Opcode);
- continue;
- }
- // Not a known opcode name; should be an opcode name range.
- size_t DotDotPos = OpcodeName.find("..");
- if (DotDotPos == StringRef::npos) {
- ExitWithError(Twine("unknown opcode ").concat(OpcodeName));
- }
- StringRef BeginOpcodeName = OpcodeName.substr(0, DotDotPos);
- unsigned BeginOpcode =
- BeginOpcodeName.empty() ? 1 : ResolveName(BeginOpcodeName);
- if (BeginOpcode == 0) {
- ExitWithError(Twine("unknown opcode ").concat(BeginOpcodeName));
- }
- StringRef EndOpcodeName = OpcodeName.substr(DotDotPos + 2);
- unsigned EndOpcode = EndOpcodeName.empty()
- ? State.getInstrInfo().getNumOpcodes() - 1
- : ResolveName(EndOpcodeName);
- if (EndOpcode == 0) {
- ExitWithError(Twine("unknown opcode ").concat(EndOpcodeName));
- }
- for (unsigned I = BeginOpcode; I <= EndOpcode; ++I) {
- if (!isIgnoredOpcode(State, I))
- Result.push_back(I);
+ for (const std::pair<StringRef, StringRef> &OpcodeName : OpcodeNames) {
+ if (OpcodeName.first == OpcodeName.second) {
+ if (unsigned Opcode = ResolveName(OpcodeName.first)) {
+ Result.push_back(Opcode);
+ continue;
+ } else {
+ ExitWithError(Twine("unknown opcode ").concat(OpcodeName.first));
+ }
+ } else {
+ StringRef BeginOpcodeName = OpcodeName.first;
+ unsigned BeginOpcode =
+ BeginOpcodeName.empty() ? 1 : ResolveName(BeginOpcodeName);
+ if (BeginOpcode == 0) {
+ ExitWithError(Twine("unknown opcode ").concat(BeginOpcodeName));
+ }
+ StringRef EndOpcodeName = OpcodeName.second;
+ unsigned EndOpcode = EndOpcodeName.empty()
+ ? State.getInstrInfo().getNumOpcodes() - 1
+ : ResolveName(EndOpcodeName);
+ if (EndOpcode == 0) {
+ ExitWithError(Twine("unknown opcode ").concat(EndOpcodeName));
+ }
+ for (unsigned I = BeginOpcode; I <= EndOpcode; ++I) {
+ if (!isIgnoredOpcode(State, I))
+ Result.push_back(I);
+ }
}
}
return Result;
diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index c469da74fc561..752f215d6a781 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -2178,6 +2178,7 @@ llvm_target_lib_list = [lib for lib in [
("-gen-register-info", "lib/Target/RISCV/RISCVGenRegisterInfo.inc"),
("-gen-subtarget", "lib/Target/RISCV/RISCVGenSubtargetInfo.inc"),
("-gen-searchable-tables", "lib/Target/RISCV/RISCVGenSearchableTables.inc"),
+ ("-gen-exegesis", "lib/Target/RISCV/RISCVGenExegesis.inc"),
],
"tbl_deps": [
":riscv_isel_target_gen",
>From e097a550b7537817e34aec8d9c216a1eadc72085 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Thu, 13 Jun 2024 17:32:29 +0300
Subject: [PATCH 08/10] Addressing review comments
---
llvm/tools/llvm-exegesis/lib/Mips/Target.cpp | 1 +
.../llvm-exegesis/lib/RISCV/RISCVCounters.cpp | 20 ++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
index 6231c971fadb9..731e037c240df 100644
--- a/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Mips/Target.cpp
@@ -62,6 +62,7 @@ class ExegesisMipsTarget : public ExegesisTarget {
unsigned getMaxMemoryAccessSize() const override { return 64; }
void fillMemoryOperands(InstructionTemplate &IT, unsigned Reg,
unsigned Offset) const override;
+
std::vector<MCInst> setRegTo(const MCSubtargetInfo &STI, unsigned Reg,
const APInt &Value) const override;
bool matchesArch(Triple::ArchType Arch) const override {
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
index a9d207fa3d157..02a459ad56f6c 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
@@ -20,9 +20,23 @@ namespace exegesis {
inline uint64_t getRISCVCpuCyclesCount() {
#ifdef __riscv
- uint64_t Counter;
- asm("csrr %0, cycle" : "=r"(Counter)::"memory");
- return Counter;
+#if __riscv_xlen == 32
+ uint32_t cycles_lo, cycles_hi0, cycles_hi1;
+ asm volatile("rdtimeh %0\n"
+ "rdtime %1\n"
+ "rdtimeh %2\n"
+ "sub %0, %0, %2\n"
+ "seqz %0, %0\n"
+ "sub %0, zero, %0\n"
+ "and %1, %1, %0\n"
+ : "=r"(cycles_hi0), "=r"(cycles_lo), "=r"(cycles_hi1));
+ return static_cast<uint64_t>((static_cast<uint64_t>(cycles_hi1) << 32) |
+ cycles_lo);
+#else
+ uint64_t cycles;
+ asm volatile("rdtime %0" : "=r"(cycles));
+ return static_cast<uint64_t>(cycles);
+#endif
#else
return 0;
#endif
>From 742152889a82633a75a854dcf880920546440cc9 Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Tue, 18 Jun 2024 19:23:55 +0300
Subject: [PATCH 09/10] Addressing review comments
---
llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
index 02a459ad56f6c..9d094f9494f4c 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
@@ -22,9 +22,9 @@ inline uint64_t getRISCVCpuCyclesCount() {
#ifdef __riscv
#if __riscv_xlen == 32
uint32_t cycles_lo, cycles_hi0, cycles_hi1;
- asm volatile("rdtimeh %0\n"
- "rdtime %1\n"
- "rdtimeh %2\n"
+ asm volatile("rdcycleh %0\n"
+ "rdcycle %1\n"
+ "rdcycleh %2\n"
"sub %0, %0, %2\n"
"seqz %0, %0\n"
"sub %0, zero, %0\n"
@@ -34,7 +34,7 @@ inline uint64_t getRISCVCpuCyclesCount() {
cycles_lo);
#else
uint64_t cycles;
- asm volatile("rdtime %0" : "=r"(cycles));
+ asm volatile("rdcycle %0" : "=r"(cycles));
return static_cast<uint64_t>(cycles);
#endif
#else
>From 25991375f8dbc80d2ec2dbca4849ce18a9868f9b Mon Sep 17 00:00:00 2001
From: Anastasiya Chernikova <anastasiya.chernikova at syntacore.com>
Date: Fri, 28 Jun 2024 16:12:20 +0300
Subject: [PATCH 10/10] Addressing review comments
---
llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt | 1 +
llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
index ea0ced1786a0c..78eec178a456a 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
@@ -4,6 +4,7 @@ include_directories(
)
set(LLVM_LINK_COMPONENTS
+ CodeGen
RISCV
Exegesis
Core
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
index 9d094f9494f4c..48e619c762eb4 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVCounters.cpp
@@ -11,6 +11,8 @@
//===----------------------------------------------------------------------===//
#include "RISCVCounters.h"
+#include <linux/sysctl.h>
+#include <sys/types.h>
namespace llvm {
namespace exegesis {
@@ -19,7 +21,13 @@ namespace exegesis {
// and provides manual implementation of performance counters.
inline uint64_t getRISCVCpuCyclesCount() {
-#ifdef __riscv
+#if defined(__riscv) && defined(__linux__)
+ uint32_t Cycle;
+ size_t Length = sizeof(Cycle);
+ if (!sysctlbyname("kernel.perf_user_access", &Cycle, &Length, NULL, 0) ||
+ Cycle != 1)
+ report_fatal_error(
+ "Please write 'sudo echo 1 > /proc/sys/kernel/perf_user_access'");
#if __riscv_xlen == 32
uint32_t cycles_lo, cycles_hi0, cycles_hi1;
asm volatile("rdcycleh %0\n"
More information about the llvm-commits
mailing list