Skip to content

[RISCV] Explicitly check for supported opcodes in optimizeCondBranch. NFC #145622

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

Merged
merged 3 commits into from
Jun 26, 2025

Conversation

topperc
Copy link
Collaborator

@topperc topperc commented Jun 25, 2025

We don't support any of the immediate branches in this function yet so explicitly exclude them rather than relying on isReg to return false.

Remove use of AnalyzeBranch. It doesn't help us much. Part of the code was already getting the operands directly and it just complicated creating a new branch.

I also inlined the modifyBranch function so we could use addReg on BuildMI.

Ultimately I want to try to fix that the RISCVCC enum has turned into a proxy for opcode by having an entry for each vendor's branch instructions. So I probably won't commit this until I figure out if this helps move in that direction or if other changes are needed.

We don't support any of the immediate branches in this function yet
so explicitly exclude them rather than relying on isReg to return
false.

Remove use of AnalyzeBranch. It doesn't help us much. Part of the
code was already getting the operands directly and it just complicated
creating a new branch.

I also inlined the modifyBranch function so we could use addReg on
BuildMI.

Ultimately I want to try to fix that the RISCVCC enum has turned into
a proxy for opcode by having an entry for each vendor's branch
instructions. So I probably won't commit this until I figure out if
this helps move in that direction or if other changes are needed.
@topperc topperc requested review from preames and mshockwave June 25, 2025 01:04
@topperc topperc changed the title [RISCV] Explicitly check for supported opcodes in optimizeCondBranch. [RISCV] Explicitly check for supported opcodes in optimizeCondBranch. NFC Jun 25, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 25, 2025

@llvm/pr-subscribers-backend-risc-v

Author: Craig Topper (topperc)

Changes

We don't support any of the immediate branches in this function yet so explicitly exclude them rather than relying on isReg to return false.

Remove use of AnalyzeBranch. It doesn't help us much. Part of the code was already getting the operands directly and it just complicated creating a new branch.

I also inlined the modifyBranch function so we could use addReg on BuildMI.

Ultimately I want to try to fix that the RISCVCC enum has turned into a proxy for opcode by having an entry for each vendor's branch instructions. So I probably won't commit this until I figure out if this helps move in that direction or if other changes are needed.


Full diff: https://github.com/llvm/llvm-project/pull/145622.diff

1 Files Affected:

  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+45-34)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 5711f0077b12d..9defcd5c85053 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1379,40 +1379,50 @@ bool RISCVInstrInfo::isFromLoadImm(const MachineRegisterInfo &MRI,
 }
 
 bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
+  bool IsSigned = false;
+  bool IsEquality = false;
+  switch (MI.getOpcode()) {
+  default:
+    return false;
+  case RISCV::BEQ:
+  case RISCV::BNE:
+    IsEquality = true;
+    break;
+  case RISCV::BGE:
+  case RISCV::BLT:
+    IsSigned = true;
+    break;
+  case RISCV::BGEU:
+  case RISCV::BLTU:
+    break;
+  }
+
   MachineBasicBlock *MBB = MI.getParent();
   MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
 
-  MachineBasicBlock *TBB, *FBB;
-  SmallVector<MachineOperand, 3> Cond;
-  if (analyzeBranch(*MBB, TBB, FBB, Cond, /*AllowModify=*/false))
-    return false;
+  const MachineOperand &LHS = MI.getOperand(0);
+  const MachineOperand &RHS = MI.getOperand(1);
+  MachineBasicBlock *TBB = MI.getOperand(2).getMBB();
 
-  RISCVCC::CondCode CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm());
+  RISCVCC::CondCode CC = getCondFromBranchOpc(MI.getOpcode());
   assert(CC != RISCVCC::COND_INVALID);
 
-  auto modifyBranch = [&]() {
-    // Build the new branch and remove the old one.
-    BuildMI(*MBB, MI, MI.getDebugLoc(),
-            getBrCond(static_cast<RISCVCC::CondCode>(Cond[0].getImm())))
-        .add(Cond[1])
-        .add(Cond[2])
-        .addMBB(TBB);
-    MI.eraseFromParent();
-  };
-
   // Canonicalize conditional branches which can be constant folded into
   // beqz or bnez.  We can't modify the CFG here.
   int64_t C0, C1;
-  if (isFromLoadImm(MRI, Cond[1], C0) && isFromLoadImm(MRI, Cond[2], C1)) {
-    unsigned NewCC =
-        evaluateCondBranch(CC, C0, C1) ? RISCVCC::COND_EQ : RISCVCC::COND_NE;
-    Cond[0] = MachineOperand::CreateImm(NewCC);
-    Cond[1] = Cond[2] = MachineOperand::CreateReg(RISCV::X0, /*isDef=*/false);
-    modifyBranch();
+  if (isFromLoadImm(MRI, LHS, C0) && isFromLoadImm(MRI, RHS, C1)) {
+    unsigned NewOpc = evaluateCondBranch(CC, C0, C1) ? RISCV::BEQ : RISCV::BNE;
+    MachineOperand Zero = MachineOperand::CreateReg(RISCV::X0, /*isDef=*/false);
+    // Build the new branch and remove the old one.
+    BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpc))
+        .add(Zero)
+        .add(Zero)
+        .addMBB(TBB);
+    MI.eraseFromParent();
     return true;
   }
 
-  if (CC == RISCVCC::COND_EQ || CC == RISCVCC::COND_NE)
+  if (IsEquality)
     return false;
 
   // For two constants C0 and C1 from
@@ -1432,8 +1442,6 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
   //
   // To make sure this optimization is really beneficial, we only
   // optimize for cases where Y had only one use (i.e. only used by the branch).
-  MachineOperand &LHS = MI.getOperand(0);
-  MachineOperand &RHS = MI.getOperand(1);
   // Try to find the register for constant Z; return
   // invalid register otherwise.
   auto searchConst = [&](int64_t C1) -> Register {
@@ -1449,23 +1457,25 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
     return Register();
   };
 
+  unsigned NewOpc = RISCVCC::getBrCond(getOppositeBranchCondition(CC));
+
   // Might be case 1.
   // Don't change 0 to 1 since we can use x0.
   // For unsigned cases changing -1U to 0 would be incorrect.
   // The incorrect case for signed would be INT_MAX, but isFromLoadImm can't
   // return that.
   if (isFromLoadImm(MRI, LHS, C0) && C0 != 0 && LHS.getReg().isVirtual() &&
-      MRI.hasOneUse(LHS.getReg()) &&
-      (CC == RISCVCC::COND_GE || CC == RISCVCC::COND_LT || C0 != -1)) {
+      MRI.hasOneUse(LHS.getReg()) && (IsSigned || C0 != -1)) {
     assert(isInt<12>(C0) && "Unexpected immediate");
     if (Register RegZ = searchConst(C0 + 1)) {
-      reverseBranchCondition(Cond);
-      Cond[1] = MachineOperand::CreateReg(RHS.getReg(), /*isDef=*/false);
-      Cond[2] = MachineOperand::CreateReg(RegZ, /*isDef=*/false);
+      BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpc))
+          .add(RHS)
+          .addReg(RegZ)
+          .addMBB(TBB);
       // We might extend the live range of Z, clear its kill flag to
       // account for this.
       MRI.clearKillFlags(RegZ);
-      modifyBranch();
+      MI.eraseFromParent();
       return true;
     }
   }
@@ -1479,13 +1489,14 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
       MRI.hasOneUse(RHS.getReg())) {
     assert(isInt<12>(C0) && "Unexpected immediate");
     if (Register RegZ = searchConst(C0 - 1)) {
-      reverseBranchCondition(Cond);
-      Cond[1] = MachineOperand::CreateReg(RegZ, /*isDef=*/false);
-      Cond[2] = MachineOperand::CreateReg(LHS.getReg(), /*isDef=*/false);
+      BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpc))
+          .addReg(RegZ)
+          .add(LHS)
+          .addMBB(TBB);
       // We might extend the live range of Z, clear its kill flag to
       // account for this.
       MRI.clearKillFlags(RegZ);
-      modifyBranch();
+      MI.eraseFromParent();
       return true;
     }
   }

@lenary
Copy link
Member

lenary commented Jun 25, 2025

Ultimately I want to try to fix that the RISCVCC enum has turned into a proxy for opcode by having an entry for each vendor's branch instructions.

Do you have a view on where you're trying to go? Just having the conditions, or also having e.g. both equal and equal to immediate?

@topperc
Copy link
Collaborator Author

topperc commented Jun 25, 2025

Ultimately I want to try to fix that the RISCVCC enum has turned into a proxy for opcode by having an entry for each vendor's branch instructions.

Do you have a view on where you're trying to go? Just having the conditions, or also having e.g. both equal and equal to immediate?

I'm considering making analyzeBranch return the raw opcode instead of the condition code enum. And make the reverseBranchCondition work on raw opcodes.

I would reduce the condition code enum back down to 6 values.

This would leave select instructions as the primary user of the condition code enum. My thought is we could use the select opcode + condition code enum to expand the select into branches.

It might still be useful to translate an opcode into the 6 condition codes like we currently need to do for evaluateCondBranch. So I may leave getCondFromBranchOpc but reduce it to only return the 6 possible values.

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@topperc topperc merged commit cca44e0 into llvm:main Jun 26, 2025
4 of 6 checks passed
@topperc topperc deleted the pr/condbranch branch June 26, 2025 04:28
topperc added a commit that referenced this pull request Jun 26, 2025
…145762)

This wasn't scalable and made the RISCVCC enum effectively just
a different way of spelling the branch opcodes.
    
This patch reduces RISCVCC back down to 6 enum values. The primary user
is select pseudoinstructions which now share the same encoding across
all
vendor extensions. The select opcode and condition code are used to
determine the branch opcode when expanding the pseudo.
    
The Cond SmallVector returned by analyzeBranch now returns the opcode
instead of the RISCVCC. reverseBranchCondition now works directly on
opcodes. getOppositeBranchCondition is also retained.

Stacked on #145622
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
… NFC (llvm#145622)

We don't support any of the immediate branches in this function yet so
explicitly exclude them rather than relying on isReg to return false.

Remove use of AnalyzeBranch. It doesn't help us much. Part of the code
was already getting the operands directly and it just complicated
creating a new branch.

I also inlined the modifyBranch function so we could use addReg on
BuildMI.
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
…lvm#145762)

This wasn't scalable and made the RISCVCC enum effectively just
a different way of spelling the branch opcodes.
    
This patch reduces RISCVCC back down to 6 enum values. The primary user
is select pseudoinstructions which now share the same encoding across
all
vendor extensions. The select opcode and condition code are used to
determine the branch opcode when expanding the pseudo.
    
The Cond SmallVector returned by analyzeBranch now returns the opcode
instead of the RISCVCC. reverseBranchCondition now works directly on
opcodes. getOppositeBranchCondition is also retained.

Stacked on llvm#145622
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
… NFC (llvm#145622)

We don't support any of the immediate branches in this function yet so
explicitly exclude them rather than relying on isReg to return false.

Remove use of AnalyzeBranch. It doesn't help us much. Part of the code
was already getting the operands directly and it just complicated
creating a new branch.

I also inlined the modifyBranch function so we could use addReg on
BuildMI.
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
…lvm#145762)

This wasn't scalable and made the RISCVCC enum effectively just
a different way of spelling the branch opcodes.
    
This patch reduces RISCVCC back down to 6 enum values. The primary user
is select pseudoinstructions which now share the same encoding across
all
vendor extensions. The select opcode and condition code are used to
determine the branch opcode when expanding the pseudo.
    
The Cond SmallVector returned by analyzeBranch now returns the opcode
instead of the RISCVCC. reverseBranchCondition now works directly on
opcodes. getOppositeBranchCondition is also retained.

Stacked on llvm#145622
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants