-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Exegesis][RISCV] Add initial RVV support #128767
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-tools-llvm-exegesis Author: Min-Yih Hsu (mshockwave) ChangesThis patch adds initial vector extension support to RISC-V's exegesis. The strategy here is to enumerate all RVV pseudo opcodes as their MC opcode counterparts are kind of useless under this circumstance. We also enumerate all possible VTYPE operands in each CodeTemplate configuration. Various of MachineFunction Passes are used for post processing the snippets, like inserting VSETVLI instructions. See https://llvm.org/devmtg/2024-10/slides/techtalk/Hsu-RVV-Exegesis.pdf for more technical details. Note that I didn't bring all RVV snippet generator features from #114149 (I did address related review comments from there though), for example the newly added I also made some changes outside the RVV snippet generator -- adding Patch is 55.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128767.diff 22 Files Affected:
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 80ff18d914dca..135aec0c8135c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -432,7 +432,44 @@ enum RoundingMode {
RNE = 1,
RDN = 2,
ROD = 3,
+ Invalid
};
+
+inline static StringRef roundingModeToString(RoundingMode RndMode) {
+ switch (RndMode) {
+ default:
+ llvm_unreachable("Unknown vector fixed-point rounding mode");
+ case RISCVVXRndMode::RNU:
+ return "rnu";
+ case RISCVVXRndMode::RNE:
+ return "rne";
+ case RISCVVXRndMode::RDN:
+ return "rdn";
+ case RISCVVXRndMode::ROD:
+ return "rod";
+ }
+}
+
+inline static RoundingMode stringToRoundingMode(StringRef Str) {
+ return StringSwitch<RoundingMode>(Str)
+ .Case("rnu", RISCVVXRndMode::RNU)
+ .Case("rne", RISCVVXRndMode::RNE)
+ .Case("rdn", RISCVVXRndMode::RDN)
+ .Case("rod", RISCVVXRndMode::ROD)
+ .Default(RISCVVXRndMode::Invalid);
+}
+
+inline static bool isValidRoundingMode(unsigned Mode) {
+ switch (Mode) {
+ default:
+ return false;
+ case RISCVVXRndMode::RNU:
+ case RISCVVXRndMode::RNE:
+ case RISCVVXRndMode::RDN:
+ case RISCVVXRndMode::ROD:
+ return true;
+ }
+}
} // namespace RISCVVXRndMode
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/eligible-inst.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/eligible-inst.test
new file mode 100644
index 0000000000000..189adf2c1b334
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/eligible-inst.test
@@ -0,0 +1,10 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency \
+# RUN: --opcode-name=PseudoVCOMPRESS_VM_M2_E8,PseudoVCPOP_M_B32 | FileCheck %s --allow-empty --check-prefix=LATENCY
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVCOMPRESS_VM_M2_E8,PseudoVCPOP_M_B32 --min-instructions=100 | FileCheck %s --check-prefix=RTHROUGHPUT
+
+# LATENCY-NOT: PseudoVCOMPRESS_VM_M2_E8
+# LATENCY-NOT: PseudoVCPOP_M_B32
+
+# RTHROUGHPUT: PseudoVCOMPRESS_VM_M2_E8
+# RTHROUGHPUT: PseudoVCPOP_M_B32
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/explicit-sew.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/explicit-sew.test
new file mode 100644
index 0000000000000..476cf35818d6f
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/explicit-sew.test
@@ -0,0 +1,7 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVFWREDUSUM_VS_M1_E32 \
+# RUN: --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s
+
+# Make sure none of the config has SEW other than e32
+# CHECK: PseudoVFWREDUSUM_VS_M1_E32
+# CHECK: SEW: e32
+# CHECK-NOT: SEW: e{{(8|16|64)}}
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/filter.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/filter.test
new file mode 100644
index 0000000000000..e3a4336fdf670
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/filter.test
@@ -0,0 +1,6 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=inverse_throughput --opcode-name=PseudoVNCLIPU_WX_M1_MASK \
+# RUN: --riscv-filter-config='vtype = {VXRM: rod, AVL: VLMAX, SEW: e(8|16), Policy: ta/mu}' --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s
+
+# CHECK: config: 'vtype = {VXRM: rod, AVL: VLMAX, SEW: e8, Policy: ta/mu}'
+# CHECK: config: 'vtype = {VXRM: rod, AVL: VLMAX, SEW: e16, Policy: ta/mu}'
+# CHECK-NOT: config: 'vtype = {VXRM: rod, AVL: VLMAX, SEW: e(32|64), Policy: ta/mu}'
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/reduction.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/reduction.test
new file mode 100644
index 0000000000000..a637fa24af16b
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/reduction.test
@@ -0,0 +1,7 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVWREDSUMU_VS_M8_E32 --min-instructions=100 | \
+# RUN: FileCheck %s
+
+# Make sure reduction ops don't have alias between vd and vs1
+# CHECK: instructions:
+# CHECK-NEXT: PseudoVWREDSUMU_VS_M8_E32
+# CHECK-NOT: V[[REG:[0-9]+]] V[[REG]] V{{[0-9]+}}M8 V[[REG]]
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/self-aliasing.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/self-aliasing.test
new file mode 100644
index 0000000000000..c950341716238
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/self-aliasing.test
@@ -0,0 +1,6 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVXOR_VX_M4 --min-instructions=100 | \
+# RUN: FileCheck %s
+
+# Make sure all def / use operands are the same in latency mode.
+# CHECK: instructions:
+# CHECK-NEXT: PseudoVXOR_VX_M4 V[[REG:[0-9]+]]M4 V[[REG]]M4 V[[REG]]M4 X{{.*}}
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/skip-rm.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/skip-rm.test
new file mode 100644
index 0000000000000..a3af37149eeb5
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/skip-rm.test
@@ -0,0 +1,12 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVAADDU_VV_M1 \
+# RUN: --riscv-enumerate-rounding-modes=false --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s --check-prefix=VXRM
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVFADD_VFPR16_M1_E16 \
+# RUN: --riscv-enumerate-rounding-modes=false --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s --check-prefix=FRM
+
+# VXRM: PseudoVAADDU_VV_M1
+# VXRM: VXRM: rnu
+# VXRM-NOT: VXRM: {{(rne|rdn|rod)}}
+
+# FRM: PseudoVFADD_VFPR16_M1_E16
+# FRM: FRM: rne
+# FRM-NOT: FRM: {{(rtz|rdn|rup|rmm|dyn)}}
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew-zvk.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew-zvk.test
new file mode 100644
index 0000000000000..515d3397b57be
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew-zvk.test
@@ -0,0 +1,33 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVAESDF_VS_M1_M1 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=ZVK
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVGHSH_VV_M1 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=ZVK
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSM4K_VI_M1 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=ZVK
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSM3C_VI_M2 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=ZVK
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSHA2MS_VV_M1_E32 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --allow-empty --check-prefix=ZVKNH
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSHA2MS_VV_M2_E64 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --allow-empty --check-prefix=ZVKNH
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p670 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSM3C_VI_M1 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --allow-empty --check-prefix=EMPTY
+
+# Most vector crypto only supports SEW=32, except Zvknhb which also supports SEW=64
+# ZVK-NOT: SEW: e{{(8|16)}}
+# ZVK: SEW: e32
+# ZVK-NOT: SEW: e64
+
+# ZVKNH(A|B) can either have SEW=32 (EGW=128) or SEW=64 (EGW=256)
+
+# ZVKNH-NOT: SEW: e{{(8|16)}}
+# ZVKNH: SEW: e{{(32|64)}}
+
+# EMPTY-NOT: SEW: e{{(8|16|32|64)}}
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew.test
new file mode 100644
index 0000000000000..b678300564529
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/valid-sew.test
@@ -0,0 +1,41 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVMUL_VV_MF4_MASK \
+# RUN: --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s --check-prefix=FRAC-LMUL
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency \
+# RUN: --opcode-name=PseudoVFADD_VFPR16_M1_E16,PseudoVFADD_VV_M2_E16,PseudoVFCLASS_V_MF2 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=FP
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=inverse_throughput \
+# RUN: --opcode-name=PseudoVSEXT_VF8_M2,PseudoVZEXT_VF8_M2 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=VEXT
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-p470 -benchmark-phase=assemble-measured-code --mode=latency \
+# RUN: --opcode-name=PseudoVFREDUSUM_VS_M1_E16 --max-configs-per-opcode=1000 --min-instructions=100 | \
+# RUN: FileCheck %s --check-prefix=VFRED --allow-empty
+
+# Make sure only the supported SEWs are generated for fractional LMUL.
+# FRAC-LMUL: PseudoVMUL_VV_MF4_MASK
+# FRAC-LMUL: SEW: e8
+# FRAC-LMUL: SEW: e16
+# FRAC-LMUL-NOT: SEW: e{{(32|64)}}
+
+# Make sure only SEWs that are equal to the supported FLEN are generated
+# FP: PseudoVFADD_VFPR16_M1_E16
+# FP-NOT: SEW: e8
+# FP: PseudoVFADD_VV_M2_E16
+# FP-NOT: SEW: e8
+# FP: PseudoVFCLASS_V_MF2
+# FP-NOT: SEW: e8
+
+# VS/ZEXT can only operate on SEW that will not lead to invalid EEW on the
+# source operand.
+# VEXT: PseudoVSEXT_VF8_M2
+# VEXT-NOT: SEW: e8
+# VEXT-NOT: SEW: e16
+# VEXT-NOT: SEW: e32
+# VEXT: SEW: e64
+# VEXT: PseudoVZEXT_VF8_M2
+# VEXT-NOT: SEW: e8
+# VEXT-NOT: SEW: e16
+# VEXT-NOT: SEW: e32
+# VEXT: SEW: e64
+
+# P470 doesn't have Zvfh so 16-bit vfredusum shouldn't exist
+# VFRED-NOT: PseudoVFREDUSUM_VS_M1_E16
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/vlmax-only.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/vlmax-only.test
new file mode 100644
index 0000000000000..30897b6e13735
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/vlmax-only.test
@@ -0,0 +1,7 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVFWREDUSUM_VS_M1_E32 \
+# RUN: --riscv-vlmax-for-vl --max-configs-per-opcode=1000 --min-instructions=100 | FileCheck %s
+
+# Only allow VLMAX for AVL when -riscv-vlmax-for-vl is present
+# CHECK: PseudoVFWREDUSUM_VS_M1_E32
+# CHECK: AVL: VLMAX
+# CHECK-NOT: AVL: {{(simm5|<MCOperand: .*>)}}
diff --git a/llvm/test/tools/llvm-exegesis/RISCV/rvv/vtype-rm-setup.test b/llvm/test/tools/llvm-exegesis/RISCV/rvv/vtype-rm-setup.test
new file mode 100644
index 0000000000000..c41b357c13821
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/RISCV/rvv/vtype-rm-setup.test
@@ -0,0 +1,13 @@
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVFWREDUSUM_VS_M1_E32 \
+# RUN: --max-configs-per-opcode=1 --min-instructions=100 --dump-object-to-disk=%t.o > %t.txt
+# RUN: llvm-objdump --triple=riscv64 -d %t.o | FileCheck %s --check-prefix=VFWREDUSUM
+# RUN: llvm-exegesis -mtriple=riscv64 -mcpu=sifive-x280 -benchmark-phase=assemble-measured-code --mode=latency --opcode-name=PseudoVSSRL_VX_MF4 \
+# RUN: --max-configs-per-opcode=1 --min-instructions=100 --dump-object-to-disk=%t.o > %t.txt
+# RUN: llvm-objdump --triple=riscv64 -d %t.o | FileCheck %s --check-prefix=VSSRL
+
+# Make sure the correct VSETVL / VXRM write / FRM write instructions are generated
+# VFWREDUSUM: vsetvli {{.*}}, zero, e32, m1, tu, ma
+# VFWREDUSUM: fsrmi {{.*}}, 0x0
+
+# VSSRL: vsetvli {{.*}}, zero, e8, mf4, tu, ma
+# VSSRL: csrwi vxrm, 0x0
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
index c002f68b427f7..e0e796cee8040 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp
@@ -50,6 +50,8 @@ bool Operand::isTied() const { return TiedToIndex.has_value(); }
bool Operand::isVariable() const { return VariableIndex.has_value(); }
+bool Operand::isEarlyClobber() const { return IsEarlyClobber; }
+
bool Operand::isMemory() const {
return isExplicit() &&
getExplicitOperandInfo().OperandType == MCOI::OPERAND_MEMORY;
@@ -115,6 +117,8 @@ Instruction::create(const MCInstrInfo &InstrInfo,
Operand Operand;
Operand.Index = OpIndex;
Operand.IsDef = (OpIndex < Description->getNumDefs());
+ Operand.IsEarlyClobber =
+ (Description->getOperandConstraint(OpIndex, MCOI::EARLY_CLOBBER) != -1);
// TODO(gchatelet): Handle isLookupPtrRegClass.
if (OpInfo.RegClass >= 0)
Operand.Tracker = &RATC.getRegisterClass(OpInfo.RegClass);
diff --git a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
index c1af10fa460a3..0a62967897c79 100644
--- a/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
+++ b/llvm/tools/llvm-exegesis/lib/MCInstrDescView.h
@@ -72,6 +72,7 @@ struct Operand {
bool isVariable() const;
bool isMemory() const;
bool isImmediate() const;
+ bool isEarlyClobber() const;
unsigned getIndex() const;
unsigned getTiedToIndex() const;
unsigned getVariableIndex() const;
@@ -82,6 +83,7 @@ struct Operand {
// Please use the accessors above and not the following fields.
std::optional<uint8_t> Index;
bool IsDef = false;
+ bool IsEarlyClobber = false;
const RegisterAliasingTracker *Tracker = nullptr; // Set for Register Op.
const MCOperandInfo *Info = nullptr; // Set for Explicit Op.
std::optional<uint8_t> TiedToIndex; // Set for Reg&Explicit Op.
@@ -115,6 +117,8 @@ struct Instruction {
Instruction &operator=(const Instruction &) = delete;
Instruction &operator=(Instruction &&) = delete;
+ unsigned getOpcode() const { return Description.getOpcode(); }
+
// Returns the Operand linked to this Variable.
// In case the Variable is tied, the primary (i.e. Def) Operand is returned.
const Operand &getPrimaryOperand(const Variable &Var) const;
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
index 489ac6d6e34b3..d379874fa1d0e 100644
--- a/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/CMakeLists.txt
@@ -14,6 +14,8 @@ set(LLVM_LINK_COMPONENTS
add_llvm_library(LLVMExegesisRISCV
DISABLE_LLVM_LINK_LLVM_DYLIB
STATIC
+ RISCVExegesisPreprocessing.cpp
+ RISCVExegesisPostprocessing.cpp
Target.cpp
DEPENDS
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPasses.h b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPasses.h
new file mode 100644
index 0000000000000..f206966331756
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPasses.h
@@ -0,0 +1,19 @@
+//===- RISCVExegesisPasses.h - RISC-V specific Exegesis Passes --*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_EXEGESIS_LIB_RISCV_RISCVEXEGESISPASSES_H
+#define LLVM_TOOLS_EXEGESIS_LIB_RISCV_RISCVEXEGESISPASSES_H
+namespace llvm {
+class FunctionPass;
+
+namespace exegesis {
+FunctionPass *createRISCVPreprocessingPass();
+FunctionPass *createRISCVPostprocessingPass();
+} // namespace exegesis
+} // namespace llvm
+#endif
diff --git a/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp
new file mode 100644
index 0000000000000..e25cf04a01d9e
--- /dev/null
+++ b/llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp
@@ -0,0 +1,130 @@
+//===- RISCVExegesisPostprocessing.cpp - Post processing MI for exegesis---===//
+//
+// 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
+// Currently there is only one post-processing we need to do for exegesis:
+// Assign a physical register to VSETVL's rd if it's not X0 (i.e. VLMAX).
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVExegesisPasses.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "riscv-exegesis-post-processing"
+
+namespace {
+struct RISCVExegesisPostprocessing : public MachineFunctionPass {
+ static char ID;
+
+ RISCVExegesisPostprocessing() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+private:
+ // Extremely simple register allocator that picks a register that hasn't
+ // been defined or used in this function.
+ Register allocateGPRRegister(const MachineFunction &MF,
+ const MachineRegisterInfo &MRI);
+
+ bool processVSETVL(MachineInstr &MI, MachineRegisterInfo &MRI);
+ bool processWriteFRM(MachineInstr &MI, MachineRegisterInfo &MRI);
+};
+} // anonymous namespace
+
+char RISCVExegesisPostprocessing::ID = 0;
+
+bool RISCVExegesisPostprocessing::runOnMachineFunction(MachineFunction &MF) {
+ bool Changed = false;
+ for (auto &MBB : MF)
+ for (auto &MI : MBB) {
+ unsigned Opcode = MI.getOpcode();
+ switch (Opcode) {
+ case RISCV::VSETVLI:
+ case RISCV::VSETVL:
+ case RISCV::PseudoVSETVLI:
+ case RISCV::PseudoVSETVLIX0:
+ Changed |= processVSETVL(MI, MF.getRegInfo());
+ break;
+ case RISCV::SwapFRMImm:
+ case RISCV::WriteFRM:
+ Changed |= processWriteFRM(MI, MF.getRegInfo());
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (Changed)
+ MF.getRegInfo().clearVirtRegs();
+
+ LLVM_DEBUG(MF.print(dbgs() << "===After RISCVExegesisPostprocessing===\n");
+ dbgs() << "\n");
+
+ return Changed;
+}
+
+Register RISCVExegesisPostprocessing::allocateGPRRegister(
+ const MachineFunction &MF, const MachineRegisterInfo &MRI) {
+ const auto &TRI = *MRI.getTargetRegisterInfo();
+
+ const TargetRegisterClass *GPRClass =
+ TRI.getRegClass(RISCV::GPRJALRRegClassID);
+ BitVector Candidates = TRI.getAllocatableSet(MF, GPRClass);
+
+ for (unsigned SetIdx : Candidates.set_bits()) {
+ if (MRI.reg_empty(Register(SetIdx)))
+ return Register(SetIdx);
+ }
+
+ // All bets are off, assign a fixed one.
+ return RISCV::X5;
+}
+
+bool RISCVExegesisPostprocessing::processVSETVL(MachineInstr &MI,
+ MachineRegisterInfo &MRI) {
+ bool Changed = false;
+ // Replace both AVL and VL (i.e. the result) operands with physical
+ // registers.
+ for (unsigned Idx = 0U; Idx < 2;...
[truncated]
|
@@ -53,6 +53,8 @@ computeAliasingInstructions(const LLVMState &State, const Instruction *Instr, | |||
if (OtherOpcode == Instr->Description.getOpcode()) | |||
continue; | |||
const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode); | |||
if (ET.getIgnoredOpcodeReasonOrNull(State, OtherInstr.getOpcode())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason this filter was removed when RISCV's exegesis was first introduced. But it really should be here.
You can test this locally with the following command:git-clang-format --diff 3968ebd00da80a08de84f83a101ebb23710f6631 2147220a8199644656b7ebf3bfc3deca0d16870c --extensions h,cpp -- llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPasses.h llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPreprocessing.cpp llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h llvm/tools/llvm-exegesis/lib/MCInstrDescView.cpp llvm/tools/llvm-exegesis/lib/MCInstrDescView.h llvm/tools/llvm-exegesis/lib/RISCV/Target.cpp llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp llvm/tools/llvm-exegesis/lib/Target.cpp llvm/tools/llvm-exegesis/lib/Target.h llvm/tools/llvm-exegesis/llvm-exegesis.cpp View the diff from clang-format here.diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 135aec0c81..275ee0c286 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -427,13 +427,7 @@ inline static bool isValidRoundingMode(unsigned Mode) {
} // namespace RISCVFPRndMode
namespace RISCVVXRndMode {
-enum RoundingMode {
- RNU = 0,
- RNE = 1,
- RDN = 2,
- ROD = 3,
- Invalid
-};
+enum RoundingMode { RNU = 0, RNE = 1, RDN = 2, ROD = 3, Invalid };
inline static StringRef roundingModeToString(RoundingMode RndMode) {
switch (RndMode) {
|
// - Zfinx registers | ||
// Generate 'NOP' so that exegesis treats such registers as initialized | ||
// (it tries to initialize them with '0' anyway). | ||
return {nop()}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem of using NOPs here is that if these registers are considered initialized, Exegesis would start to track liveness on the MachineFunction. But we don't have proper code to actually initialize these registers, so MachineVerifier would complain about using uninitialized registers.
It's a lot easier to just leave these registers uninitialized for now.
llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp
Outdated
Show resolved
Hide resolved
llvm/tools/llvm-exegesis/lib/RISCV/RISCVExegesisPostprocessing.cpp
Outdated
Show resolved
Hide resolved
void addTargetSpecificPasses(PassManagerBase &PM) const override { | ||
// Turn AVL operand of physical registers into virtual registers. | ||
PM.add(exegesis::createRISCVPreprocessingPass()); | ||
PM.add(createRISCVInsertVSETVLIPass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this require InsertVSETVLI to continue working on MIR without live intervals set up? @lukel97 do we plan to make VSETVLI insertion require live intervals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/76/builds/7363 Here is the relevant piece of the build log for the reference
|
This is fixed by 8c5cd77 |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/145/builds/5368 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/187/builds/4579 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/42/builds/3471 Here is the relevant piece of the build log for the reference
|
Fixed by b697bf3 |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/127/builds/2556 Here is the relevant piece of the build log for the reference
|
Fixed by b2cc28c |
Mitigated by 23c41bf |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/146/builds/2380 Here is the relevant piece of the build log for the reference
|
It's unusual to include a FooSubtarget.h header outside of lib/Target (the subtarget header includes a bunch of llvm-tblgen'd files, so this serializes the build, etc). Is there a way to prevent this inclusion? |
See here for the additional tblgen deps: #128767 (comment)
See here for the additional tblgen deps: llvm/llvm-project#128767 (comment)
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/14/builds/2709 Here is the relevant piece of the build log for the reference
|
Good point. I've just created a PR for this: #129568 |
See here for the additional tblgen deps: llvm#128767 (comment)
This patch adds initial vector extension support to RISC-V's exegesis. The strategy here is to enumerate all RVV pseudo opcodes as their MC opcode counterparts are kind of useless under this circumstance. We also enumerate all possible VTYPE operands in each CodeTemplate configuration. Various of MachineFunction Passes are used for post processing the snippets, like inserting VSETVLI instructions.
See https://llvm.org/devmtg/2024-10/slides/techtalk/Hsu-RVV-Exegesis.pdf for more technical details.
Note that I didn't bring all RVV snippet generator features from #114149 (I did address related review comments from there though), for example the newly added
ExegesisTarget::assignInitialRegisterValue
callback. Because they're slightly orthogonal and I'm planning to add them in separate patches.I also made some changes outside the RVV snippet generator -- adding
exegesis::Operand::isEarlyClobber
and printer for VXRM rounding modes in RISCVBaseInfo.h. I didn't split them into a separate patch because they're relatively hard to test in standalone patches. Plus, RVV snippet generator is the only user.