llvm-project/llvm/lib/Target/RISCV/RISCVLateBranchOpt.cpp
Craig Topper c8243251cb
[RISCV] Remove separate immediate condition codes from RISCVCC. NFC (#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
2025-06-25 23:09:24 -07:00

112 lines
3.3 KiB
C++

//===-- RISCVLateBranchOpt.cpp - Late Stage Branch Optimization -----------===//
//
// 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 file provides RISC-V specific target optimizations, currently it's
/// limited to convert conditional branches into unconditional branches when
/// the condition can be statically evaluated.
///
//===----------------------------------------------------------------------===//
#include "RISCVInstrInfo.h"
#include "RISCVSubtarget.h"
using namespace llvm;
#define RISCV_LATE_BRANCH_OPT_NAME "RISC-V Late Branch Optimisation Pass"
namespace {
struct RISCVLateBranchOpt : public MachineFunctionPass {
static char ID;
RISCVLateBranchOpt() : MachineFunctionPass(ID) {}
StringRef getPassName() const override { return RISCV_LATE_BRANCH_OPT_NAME; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction &Fn) override;
private:
bool runOnBasicBlock(MachineBasicBlock &MBB) const;
const RISCVInstrInfo *RII = nullptr;
};
} // namespace
char RISCVLateBranchOpt::ID = 0;
INITIALIZE_PASS(RISCVLateBranchOpt, "riscv-late-branch-opt",
RISCV_LATE_BRANCH_OPT_NAME, false, false)
bool RISCVLateBranchOpt::runOnBasicBlock(MachineBasicBlock &MBB) const {
MachineBasicBlock *TBB, *FBB;
SmallVector<MachineOperand, 4> Cond;
if (RII->analyzeBranch(MBB, TBB, FBB, Cond, /*AllowModify=*/false))
return false;
if (!TBB || Cond.size() != 3)
return false;
RISCVCC::CondCode CC = RISCVInstrInfo::getCondFromBranchOpc(Cond[0].getImm());
assert(CC != RISCVCC::COND_INVALID);
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
// Try and convert a conditional branch that can be evaluated statically
// into an unconditional branch.
int64_t C0, C1;
if (!RISCVInstrInfo::isFromLoadImm(MRI, Cond[1], C0) ||
!RISCVInstrInfo::isFromLoadImm(MRI, Cond[2], C1))
return false;
MachineBasicBlock *Folded =
RISCVInstrInfo::evaluateCondBranch(CC, C0, C1) ? TBB : FBB;
// At this point, its legal to optimize.
RII->removeBranch(MBB);
// Only need to insert a branch if we're not falling through.
if (Folded) {
DebugLoc DL = MBB.findBranchDebugLoc();
RII->insertBranch(MBB, Folded, nullptr, {}, DL);
}
// Update the successors. Remove them all and add back the correct one.
while (!MBB.succ_empty())
MBB.removeSuccessor(MBB.succ_end() - 1);
// If it's a fallthrough, we need to figure out where MBB is going.
if (!Folded) {
MachineFunction::iterator Fallthrough = ++MBB.getIterator();
if (Fallthrough != MBB.getParent()->end())
MBB.addSuccessor(&*Fallthrough);
} else
MBB.addSuccessor(Folded);
return true;
}
bool RISCVLateBranchOpt::runOnMachineFunction(MachineFunction &Fn) {
if (skipFunction(Fn.getFunction()))
return false;
auto &ST = Fn.getSubtarget<RISCVSubtarget>();
RII = ST.getInstrInfo();
bool Changed = false;
for (MachineBasicBlock &MBB : Fn)
Changed |= runOnBasicBlock(MBB);
return Changed;
}
FunctionPass *llvm::createRISCVLateBranchOptPass() {
return new RISCVLateBranchOpt();
}