-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[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
Conversation
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.
@llvm/pr-subscribers-backend-risc-v Author: Craig Topper (topperc) ChangesWe 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:
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;
}
}
|
Do you have a view on where you're trying to go? Just having the conditions, or also having e.g. both |
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. |
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
…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
… 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.
…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
… 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.
…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
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.