[llvm] [RISCV] Enable early if-conversion (PR #92959)

Mikhail Gudim via llvm-commits llvm-commits at lists.llvm.org
Tue May 21 13:17:05 PDT 2024


https://github.com/mgudim created https://github.com/llvm/llvm-project/pull/92959

Implements the necessary target methods (insertSelect, canInsertSelect) and adds early if-conversion to the RISCV pipeline. Doing if-conversion increases the number of executed instructions, so it only makes sense if there is enough ILP.

>From ba0bf89c2a1636b258d551c2dc96594879b8ddb7 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Tue, 21 May 2024 15:26:47 -0400
Subject: [PATCH] [RISCV] Enable early if-conversion.

Implements the necessary target methods (insertSelect, canInsertSelect)
and adds early if-conversion to the RISCV pipeline. Doing if-conversion
increases the number of executed instructions, so it only makes sense if
there is enough ILP.
---
 llvm/lib/CodeGen/EarlyIfConversion.cpp       |   2 +-
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp     | 109 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVInstrInfo.h       |  14 +++
 llvm/lib/Target/RISCV/RISCVSubtarget.cpp     |  14 +++
 llvm/lib/Target/RISCV/RISCVSubtarget.h       |   2 +
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp |   8 ++
 6 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/EarlyIfConversion.cpp b/llvm/lib/CodeGen/EarlyIfConversion.cpp
index 2a7bee1618deb..2f8729fcbb945 100644
--- a/llvm/lib/CodeGen/EarlyIfConversion.cpp
+++ b/llvm/lib/CodeGen/EarlyIfConversion.cpp
@@ -879,7 +879,7 @@ bool EarlyIfConverter::shouldConvertIf() {
   // from a loop-invariant address predictable; we were unable to prove that it
   // doesn't alias any of the memory-writes in the loop, but it is likely to
   // read to same value multiple times.
-  if (CurrentLoop && any_of(IfConv.Cond, [&](MachineOperand &MO) {
+  if (CurrentLoop && all_of(IfConv.Cond, [&](MachineOperand &MO) {
         if (!MO.isReg() || !MO.isUse())
           return false;
         Register Reg = MO.getReg();
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 444b9076005c2..0cd7b3f40523b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1446,6 +1446,115 @@ RISCVInstrInfo::optimizeSelect(MachineInstr &MI,
   return NewMI;
 }
 
+int RISCVInstrInfo::getICmpCost(unsigned CC, const TargetSchedModel &SchedModel) const {
+  switch (CC) {
+    default:
+      llvm_unreachable("Unknown condition code!");
+    case RISCVCC::COND_LT:
+      return SchedModel.computeInstrLatency(RISCV::SLT);
+    case RISCVCC::COND_LTU:
+      return SchedModel.computeInstrLatency(RISCV::SLTU);
+    case RISCVCC::COND_EQ:
+      return SchedModel.computeInstrLatency(RISCV::XOR) + SchedModel.computeInstrLatency(RISCV::SLTIU);
+    case RISCVCC::COND_NE:
+      return SchedModel.computeInstrLatency(RISCV::XOR) + SchedModel.computeInstrLatency(RISCV::SLTU);
+    case RISCVCC::COND_GE:
+      return SchedModel.computeInstrLatency(RISCV::XORI) + SchedModel.computeInstrLatency(RISCV::SLT);
+    case RISCVCC::COND_GEU:
+      return SchedModel.computeInstrLatency(RISCV::XORI) + SchedModel.computeInstrLatency(RISCV::SLTU);
+  }
+}
+
+void RISCVInstrInfo::insertICmp(MachineBasicBlock &MBB,
+                                MachineBasicBlock::iterator MI,
+                                const DebugLoc &DL, Register DstReg,
+                                ArrayRef<MachineOperand> Cond) const {
+  MachineRegisterInfo &MRI = MI->getParent()->getParent()->getRegInfo();
+  unsigned CC = Cond[0].getImm();
+  Register LHSReg = Cond[1].getReg();
+  Register RHSReg = Cond[2].getReg();
+
+  switch (CC) {
+    default:
+      llvm_unreachable("Unknown condition code!");
+    case RISCVCC::COND_LT:
+    case RISCVCC::COND_LTU: {
+      BuildMI(MBB, MI, DL, get(CC == RISCVCC::COND_LT ? RISCV::SLT : RISCV::SLTU),
+              DstReg)
+          .addReg(LHSReg)
+          .addReg(RHSReg);
+      return;
+    }
+    case RISCVCC::COND_EQ:
+    case RISCVCC::COND_NE: {
+      Register XorReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+      BuildMI(MBB, MI, DL, get(RISCV::XOR), XorReg).addReg(LHSReg).addReg(RHSReg);
+      if (CC == RISCVCC::COND_EQ) {
+        BuildMI(MBB, MI, DL, get(RISCV::SLTIU), DstReg).addReg(XorReg).addImm(1);
+        return;
+      } else {
+        BuildMI(MBB, MI, DL, get(RISCV::SLTU), DstReg)
+            .addReg(RISCV::X0)
+            .addReg(XorReg);
+        return;
+      }
+    }
+    case RISCVCC::COND_GE:
+    case RISCVCC::COND_GEU: {
+      Register NotCCReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+      BuildMI(MBB, MI, DL, get(CC == RISCVCC::COND_GE ? RISCV::SLT : RISCV::SLTU),
+              NotCCReg)
+          .addReg(LHSReg)
+          .addReg(RHSReg);
+      BuildMI(MBB, MI, DL, get(RISCV::XORI), DstReg).addReg(NotCCReg).addImm(1);
+      return;
+    }
+  }
+}
+
+void RISCVInstrInfo::insertSelect(MachineBasicBlock &MBB,
+                                  MachineBasicBlock::iterator MI,
+                                  const DebugLoc &DL, Register DstReg,
+                                  ArrayRef<MachineOperand> Cond,
+                                  Register TrueReg, Register FalseReg) const {
+  MachineFunction &MF = *MI->getParent()->getParent();
+  const RISCVSubtarget &ST = MF.getSubtarget<RISCVSubtarget>();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+
+  Register CCReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+  insertICmp(MBB, MI, DL, CCReg, Cond);
+  unsigned CondZeroEqzOpc =
+      ST.hasVendorXVentanaCondOps() ? RISCV::VT_MASKC : RISCV::CZERO_EQZ;
+  unsigned CondZeroNezOpc =
+      ST.hasVendorXVentanaCondOps() ? RISCV::VT_MASKCN : RISCV::CZERO_NEZ;
+  Register TrueValOrZeroReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+  Register FalseValOrZeroReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+  BuildMI(MBB, MI, DL, get(CondZeroEqzOpc), TrueValOrZeroReg)
+      .addReg(TrueReg)
+      .addReg(CCReg);
+  BuildMI(MBB, MI, DL, get(CondZeroNezOpc), FalseValOrZeroReg)
+      .addReg(FalseReg)
+      .addReg(CCReg);
+  BuildMI(MBB, MI, DL, get(RISCV::OR), DstReg)
+      .addReg(TrueValOrZeroReg)
+      .addReg(FalseValOrZeroReg);
+  return;
+}
+
+bool RISCVInstrInfo::canInsertSelect(const MachineBasicBlock &MBB,
+                                     ArrayRef<MachineOperand> Cond, Register DstReg,
+                                     Register TrueReg, Register FalseReg, int &CondCycles,
+                                     int &TrueCycles, int &FalseCycles) const {
+  TargetSchedModel SchedModel;
+  SchedModel.init(&STI);
+
+  CondCycles = getICmpCost(Cond[0].getImm(), SchedModel);
+  TrueCycles = SchedModel.computeInstrLatency(RISCV::OR) + SchedModel.computeInstrLatency(STI.hasVendorXVentanaCondOps() ? RISCV::VT_MASKC : RISCV::CZERO_EQZ);
+  FalseCycles = SchedModel.computeInstrLatency(RISCV::OR) + SchedModel.computeInstrLatency(STI.hasVendorXVentanaCondOps() ? RISCV::VT_MASKCN : RISCV::CZERO_NEZ);
+
+  return true;
+}
+
 unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.isMetaInstruction())
     return 0;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index e069717aaef23..92c01f5e8d098 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -149,6 +149,20 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
                                SmallPtrSetImpl<MachineInstr *> &SeenMIs,
                                bool) const override;
 
+  int getICmpCost(unsigned CC, const TargetSchedModel &SchedModel) const;
+  void insertICmp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+                  const DebugLoc &DL, Register DstReg,
+                  ArrayRef<MachineOperand> Cond) const;
+
+  bool canInsertSelect(const MachineBasicBlock &, ArrayRef<MachineOperand> Cond,
+                       Register, Register, Register, int &, int &,
+                       int &) const override;
+
+  void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+                    const DebugLoc &DL, Register DstReg,
+                    ArrayRef<MachineOperand> Cond, Register TrueReg,
+                    Register FalseReg) const override;
+
   bool isAsCheapAsAMove(const MachineInstr &MI) const override;
 
   std::optional<DestSourcePair>
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index d3236bb07d56d..acb2c7954cd6e 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -65,6 +65,11 @@ static cl::opt<unsigned> RISCVMinimumJumpTableEntries(
     "riscv-min-jump-table-entries", cl::Hidden,
     cl::desc("Set minimum number of entries to use a jump table on RISCV"));
 
+static cl::opt<bool> RISCVDisableEarlyIfcvt(
+    "riscv-disable-early-ifcvt", cl::Hidden,
+    cl::desc("Disable early if-conversion"),
+    cl::init(true), cl::Hidden);
+
 void RISCVSubtarget::anchor() {}
 
 RISCVSubtarget &
@@ -203,3 +208,12 @@ unsigned RISCVSubtarget::getMinimumJumpTableEntries() const {
              ? RISCVMinimumJumpTableEntries
              : TuneInfo->MinimumJumpTableEntries;
 }
+
+bool RISCVSubtarget::enableEarlyIfConversion() const {
+  TargetSchedModel SchedModel;
+  SchedModel.init(this);
+  return 
+    !RISCVDisableEarlyIfcvt &&
+    (hasStdExtZicond() || hasVendorXVentanaCondOps()) &&
+    SchedModel.hasInstrSchedModelOrItineraries();
+}
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index c880c9e921e0e..fe8143942e938 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -303,6 +303,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
   unsigned getMinimumJumpTableEntries() const;
 
   bool supportsInitUndef() const override { return hasVInstructions(); }
+
+  bool enableEarlyIfConversion() const override;
 };
 } // End llvm namespace
 
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 5aab138dae408..a205738eeebd9 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -349,6 +349,7 @@ class RISCVPassConfig : public TargetPassConfig {
   bool addPreISel() override;
   void addCodeGenPrepare() override;
   bool addInstSelector() override;
+  bool addILPOpts() override;
   bool addIRTranslator() override;
   void addPreLegalizeMachineIR() override;
   bool addLegalizeMachineIR() override;
@@ -450,6 +451,13 @@ bool RISCVPassConfig::addInstSelector() {
   return false;
 }
 
+bool RISCVPassConfig::addILPOpts() {
+  if (getOptLevel() != CodeGenOptLevel::None) {
+    addPass(&EarlyIfConverterID);
+  }
+  return true;
+}
+
 bool RISCVPassConfig::addIRTranslator() {
   addPass(new IRTranslator(getOptLevel()));
   return false;



More information about the llvm-commits mailing list