Skip to content

[RISCV] Add late optimization pass for riscv #133256

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 28 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4a64565
[RISCV] Canonicalize foldable branch conditions in optimizeCondBranch
preames Mar 25, 2025
40439cd
clang-format
preames Mar 25, 2025
25c88ba
[RISCV] Add late optimization pass for riscv
mikhailramalho Mar 26, 2025
8aac8e9
Fix pipeline tests
mikhailramalho Mar 26, 2025
3d28d5f
Updated description
mikhailramalho Mar 27, 2025
36d9adc
Removed messy code
mikhailramalho Mar 27, 2025
08ddd9e
Updated tests
mikhailramalho Mar 27, 2025
df34ba6
Make evaluateCondBranch, isLoadImm, and isFromLoadImm static member f…
mikhailramalho Mar 27, 2025
81dffc3
Merge remote-tracking branch 'origin/main' into riscv-late-opt1
mikhailramalho Mar 27, 2025
e53bb1b
Cleanup includes
mikhailramalho Mar 27, 2025
b9303d3
Moved declaration of Folded
mikhailramalho Mar 27, 2025
51d4ef3
Added documentation to new static functions
mikhailramalho Mar 27, 2025
e353109
Make isLoadImm private
mikhailramalho Mar 27, 2025
fbec07f
No need to update TBB and FBB
mikhailramalho Mar 27, 2025
bbda8ff
Don't run the new pass on -O0
mikhailramalho Mar 27, 2025
24e7a91
Merge remote-tracking branch 'origin/main' into riscv-late-opt1
mikhailramalho Mar 27, 2025
eedbddd
Updated test
mikhailramalho Mar 27, 2025
f710dbe
No need to clear cond
mikhailramalho Mar 27, 2025
cad5541
clang-format
mikhailramalho Mar 27, 2025
acecac2
Moved isLoadImm out of RISCVInstrInfo
mikhailramalho Mar 27, 2025
d9020ff
Removed wrong comment
mikhailramalho Mar 27, 2025
66be46c
Sort list of files
mikhailramalho Mar 27, 2025
81f8b1e
Rename trySimplifyCondBr and return early when possible
mikhailramalho Mar 27, 2025
ef5b386
Renamed pass
mikhailramalho Mar 27, 2025
953a78d
clang-format
mikhailramalho Mar 27, 2025
2505795
Update header
mikhailramalho Mar 27, 2025
0230f5d
Merge remote-tracking branch 'origin/main' into riscv-late-opt1
mikhailramalho Mar 27, 2025
46aec7c
Rename file
mikhailramalho Mar 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_llvm_target(RISCVCodeGen
RISCVConstantPoolValue.cpp
RISCVDeadRegisterDefinitions.cpp
RISCVMakeCompressible.cpp
RISCVLateOpt.cpp
RISCVExpandAtomicPseudoInsts.cpp
RISCVExpandPseudoInsts.cpp
RISCVFoldMemOffset.cpp
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ void initializeRISCVLandingPadSetupPass(PassRegistry &);
FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
CodeGenOptLevel OptLevel);

FunctionPass *createRISCVLateOptPass();
void initializeRISCVLateOptPass(PassRegistry &);

FunctionPass *createRISCVMakeCompressibleOptPass();
void initializeRISCVMakeCompressibleOptPass(PassRegistry &);

Expand Down
53 changes: 28 additions & 25 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ static RISCVCC::CondCode getCondFromBranchOpc(unsigned Opc) {
}
}

static bool evaluateCondBranch(unsigned CC, int64_t C0, int64_t C1) {
bool RISCVInstrInfo::evaluateCondBranch(unsigned CC, int64_t C0, int64_t C1) {
switch (CC) {
default:
llvm_unreachable("Unexpected CC");
Expand Down Expand Up @@ -1301,6 +1301,30 @@ bool RISCVInstrInfo::reverseBranchCondition(
return false;
}

bool RISCVInstrInfo::isLoadImm(const MachineInstr *MI, int64_t &Imm) {
// For now, Only checks for LI (i.e. ADDI x0, imm)
if (MI->getOpcode() == RISCV::ADDI && MI->getOperand(1).isReg() &&
MI->getOperand(1).getReg() == RISCV::X0) {
Imm = MI->getOperand(2).getImm();
return true;
}
return false;
}

bool RISCVInstrInfo::isFromLoadImm(const MachineRegisterInfo &MRI,
const MachineOperand &Op, int64_t &Imm) {
// Either a load from immediate instruction or X0.
if (!Op.isReg())
return false;

Register Reg = Op.getReg();
if (Reg == RISCV::X0) {
Imm = 0;
return true;
}
return Reg.isVirtual() && isLoadImm(MRI.getVRegDef(Reg), Imm);
}

bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
MachineBasicBlock *MBB = MI.getParent();
MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
Expand All @@ -1323,31 +1347,10 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
MI.eraseFromParent();
};

// Right now we only care about LI (i.e. ADDI x0, imm)
auto isLoadImm = [](const MachineInstr *MI, int64_t &Imm) -> bool {
if (MI->getOpcode() == RISCV::ADDI && MI->getOperand(1).isReg() &&
MI->getOperand(1).getReg() == RISCV::X0) {
Imm = MI->getOperand(2).getImm();
return true;
}
return false;
};
// Either a load from immediate instruction or X0.
auto isFromLoadImm = [&](const MachineOperand &Op, int64_t &Imm) -> bool {
if (!Op.isReg())
return false;
Register Reg = Op.getReg();
if (Reg == RISCV::X0) {
Imm = 0;
return true;
}
return Reg.isVirtual() && isLoadImm(MRI.getVRegDef(Reg), Imm);
};

// 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(Cond[1], C0) && isFromLoadImm(Cond[2], 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);
Expand Down Expand Up @@ -1393,7 +1396,7 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
return Register();
};

if (isFromLoadImm(LHS, C0) && MRI.hasOneUse(LHS.getReg())) {
if (isFromLoadImm(MRI, LHS, C0) && MRI.hasOneUse(LHS.getReg())) {
// Might be case 1.
// Signed integer overflow is UB. (UINT64_MAX is bigger so we don't need
// to worry about unsigned overflow here)
Expand All @@ -1408,7 +1411,7 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
modifyBranch();
return true;
}
} else if (isFromLoadImm(RHS, C0) && MRI.hasOneUse(RHS.getReg())) {
} else if (isFromLoadImm(MRI, RHS, C0) && MRI.hasOneUse(RHS.getReg())) {
// Might be case 2.
// For unsigned cases, we don't want C1 to wrap back to UINT64_MAX
// when C0 is zero.
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
static bool isLdStSafeToPair(const MachineInstr &LdSt,
const TargetRegisterInfo *TRI);

static bool evaluateCondBranch(unsigned CC, int64_t C0, int64_t C1);

static bool isLoadImm(const MachineInstr *MI, int64_t &Imm);

static bool isFromLoadImm(const MachineRegisterInfo &MRI,
const MachineOperand &Op, int64_t &Imm);

protected:
const RISCVSubtarget &STI;

Expand Down
121 changes: 121 additions & 0 deletions llvm/lib/Target/RISCV/RISCVLateOpt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//===-- RISCVLateOpt.cpp - Late stage 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 DEBUG_TYPE "riscv-late-opt"
#define RISCV_LATE_OPT_NAME "RISC-V Late Stage Optimizations"

namespace {

struct RISCVLateOpt : public MachineFunctionPass {
static char ID;

RISCVLateOpt() : MachineFunctionPass(ID) {}

StringRef getPassName() const override { return RISCV_LATE_OPT_NAME; }

void getAnalysisUsage(AnalysisUsage &AU) const override {
MachineFunctionPass::getAnalysisUsage(AU);
}

bool runOnMachineFunction(MachineFunction &Fn) override;

private:
bool trySimplifyCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
SmallVectorImpl<MachineOperand> &Cond) const;

const RISCVInstrInfo *RII = nullptr;
};
} // namespace

char RISCVLateOpt::ID = 0;
INITIALIZE_PASS(RISCVLateOpt, "riscv-late-opt", RISCV_LATE_OPT_NAME, false,
false)

bool RISCVLateOpt::trySimplifyCondBr(
MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
SmallVectorImpl<MachineOperand> &Cond) const {

if (!TBB || Cond.size() != 3)
return false;

RISCVCC::CondCode CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm());
assert(CC != RISCVCC::COND_INVALID);

// Try and convert a conditional branch that can be evaluated statically
// into an unconditional branch.
MachineBasicBlock *Folded = nullptr;
int64_t C0, C1;

MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
if (RISCVInstrInfo::isFromLoadImm(MRI, Cond[1], C0) &&
RISCVInstrInfo::isFromLoadImm(MRI, Cond[2], C1)) {
Folded = RISCVInstrInfo::evaluateCondBranch(CC, C0, C1) ? TBB : FBB;

// At this point, its legal to optimize.
RII->removeBranch(MBB);
Cond.clear();

// 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);

TBB = Folded;
FBB = nullptr;
return true;
}

return false;
}

bool RISCVLateOpt::runOnMachineFunction(MachineFunction &Fn) {
if (skipFunction(Fn.getFunction()))
return false;

auto &ST = Fn.getSubtarget<RISCVSubtarget>();
RII = ST.getInstrInfo();

bool Changed = false;

for (MachineBasicBlock &MBB : Fn) {
MachineBasicBlock *TBB, *FBB;
SmallVector<MachineOperand, 4> Cond;
if (!RII->analyzeBranch(MBB, TBB, FBB, Cond, /*AllowModify=*/false))
Changed |= trySimplifyCondBr(MBB, TBB, FBB, Cond);
}

return Changed;
}

/// Returns an instance of the Make Compressible Optimization pass.
FunctionPass *llvm::createRISCVLateOptPass() { return new RISCVLateOpt(); }
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
initializeRISCVPostLegalizerCombinerPass(*PR);
initializeKCFIPass(*PR);
initializeRISCVDeadRegisterDefinitionsPass(*PR);
initializeRISCVLateOptPass(*PR);
initializeRISCVMakeCompressibleOptPass(*PR);
initializeRISCVGatherScatterLoweringPass(*PR);
initializeRISCVCodeGenPreparePass(*PR);
Expand Down Expand Up @@ -565,6 +566,7 @@ void RISCVPassConfig::addPreEmitPass() {
if (TM->getOptLevel() >= CodeGenOptLevel::Default &&
EnableRISCVCopyPropagation)
addPass(createMachineCopyPropagationPass(true));
addPass(createRISCVLateOptPass());
addPass(&BranchRelaxationPassID);
addPass(createRISCVMakeCompressibleOptPass());
}
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/RISCV/GlobalISel/rv32zbb.ll
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ define i64 @ctpop_i64(i64 %a) nounwind {
define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
; RV32I-LABEL: ctpop_i64_ugt_two:
; RV32I: # %bb.0:
; RV32I-NEXT: beqz zero, .LBB6_2
; RV32I-NEXT: j .LBB6_2
; RV32I-NEXT: # %bb.1:
; RV32I-NEXT: sltiu a0, zero, 0
; RV32I-NEXT: ret
Expand Down Expand Up @@ -404,7 +404,7 @@ define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
;
; RV32ZBB-LABEL: ctpop_i64_ugt_two:
; RV32ZBB: # %bb.0:
; RV32ZBB-NEXT: beqz zero, .LBB6_2
; RV32ZBB-NEXT: j .LBB6_2
; RV32ZBB-NEXT: # %bb.1:
; RV32ZBB-NEXT: sltiu a0, zero, 0
; RV32ZBB-NEXT: ret
Expand All @@ -422,7 +422,7 @@ define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
define i1 @ctpop_i64_ugt_one(i64 %a) nounwind {
; RV32I-LABEL: ctpop_i64_ugt_one:
; RV32I: # %bb.0:
; RV32I-NEXT: beqz zero, .LBB7_2
; RV32I-NEXT: j .LBB7_2
; RV32I-NEXT: # %bb.1:
; RV32I-NEXT: snez a0, zero
; RV32I-NEXT: ret
Expand Down Expand Up @@ -470,7 +470,7 @@ define i1 @ctpop_i64_ugt_one(i64 %a) nounwind {
;
; RV32ZBB-LABEL: ctpop_i64_ugt_one:
; RV32ZBB: # %bb.0:
; RV32ZBB-NEXT: beqz zero, .LBB7_2
; RV32ZBB-NEXT: j .LBB7_2
; RV32ZBB-NEXT: # %bb.1:
; RV32ZBB-NEXT: snez a0, zero
; RV32ZBB-NEXT: ret
Expand Down
1 change: 1 addition & 0 deletions llvm/test/CodeGen/RISCV/O0-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
; CHECK-NEXT: Insert fentry calls
; CHECK-NEXT: Insert XRay ops
; CHECK-NEXT: Implement the 'patchable-function' attribute
; CHECK-NEXT: RISC-V Late Stage Optimizations
; CHECK-NEXT: Branch relaxation pass
; CHECK-NEXT: RISC-V Make Compressible
; CHECK-NEXT: Contiguously Lay Out Funclets
Expand Down
1 change: 1 addition & 0 deletions llvm/test/CodeGen/RISCV/O3-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@
; CHECK-NEXT: Insert XRay ops
; CHECK-NEXT: Implement the 'patchable-function' attribute
; CHECK-NEXT: Machine Copy Propagation Pass
; CHECK-NEXT: RISC-V Late Stage Optimizations
; CHECK-NEXT: Branch relaxation pass
; CHECK-NEXT: RISC-V Make Compressible
; CHECK-NEXT: Contiguously Lay Out Funclets
Expand Down
8 changes: 4 additions & 4 deletions llvm/test/CodeGen/RISCV/bfloat-br-fcmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ declare bfloat @dummy(bfloat)
define void @br_fcmp_false(bfloat %a, bfloat %b) nounwind {
; RV32IZFBFMIN-LABEL: br_fcmp_false:
; RV32IZFBFMIN: # %bb.0:
; RV32IZFBFMIN-NEXT: beqz zero, .LBB0_2
; RV32IZFBFMIN-NEXT: j .LBB0_2
; RV32IZFBFMIN-NEXT: # %bb.1: # %if.then
; RV32IZFBFMIN-NEXT: ret
; RV32IZFBFMIN-NEXT: .LBB0_2: # %if.else
Expand All @@ -21,7 +21,7 @@ define void @br_fcmp_false(bfloat %a, bfloat %b) nounwind {
;
; RV64IZFBFMIN-LABEL: br_fcmp_false:
; RV64IZFBFMIN: # %bb.0:
; RV64IZFBFMIN-NEXT: beqz zero, .LBB0_2
; RV64IZFBFMIN-NEXT: j .LBB0_2
; RV64IZFBFMIN-NEXT: # %bb.1: # %if.then
; RV64IZFBFMIN-NEXT: ret
; RV64IZFBFMIN-NEXT: .LBB0_2: # %if.else
Expand Down Expand Up @@ -581,7 +581,7 @@ if.then:
define void @br_fcmp_true(bfloat %a, bfloat %b) nounwind {
; RV32IZFBFMIN-LABEL: br_fcmp_true:
; RV32IZFBFMIN: # %bb.0:
; RV32IZFBFMIN-NEXT: beqz zero, .LBB16_2
; RV32IZFBFMIN-NEXT: j .LBB16_2
; RV32IZFBFMIN-NEXT: # %bb.1: # %if.else
; RV32IZFBFMIN-NEXT: ret
; RV32IZFBFMIN-NEXT: .LBB16_2: # %if.then
Expand All @@ -591,7 +591,7 @@ define void @br_fcmp_true(bfloat %a, bfloat %b) nounwind {
;
; RV64IZFBFMIN-LABEL: br_fcmp_true:
; RV64IZFBFMIN: # %bb.0:
; RV64IZFBFMIN-NEXT: beqz zero, .LBB16_2
; RV64IZFBFMIN-NEXT: j .LBB16_2
; RV64IZFBFMIN-NEXT: # %bb.1: # %if.else
; RV64IZFBFMIN-NEXT: ret
; RV64IZFBFMIN-NEXT: .LBB16_2: # %if.then
Expand Down
10 changes: 2 additions & 8 deletions llvm/test/CodeGen/RISCV/branch_zero.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
define void @foo(i16 %finder_idx) {
; CHECK-LABEL: foo:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: .LBB0_1: # %for.body
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: # %bb.1: # %for.body
; CHECK-NEXT: slli a0, a0, 48
; CHECK-NEXT: bltz a0, .LBB0_4
; CHECK-NEXT: # %bb.2: # %while.cond.preheader.i
; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
; CHECK-NEXT: li a0, 0
; CHECK-NEXT: bnez zero, .LBB0_1
; CHECK-NEXT: # %bb.3: # %while.body
; CHECK-NEXT: .LBB0_4: # %while.cond1.preheader.i
entry:
Expand Down Expand Up @@ -46,14 +43,11 @@ if.then:
define void @bar(i16 %finder_idx) {
; CHECK-LABEL: bar:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: .LBB1_1: # %for.body
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: # %bb.1: # %for.body
; CHECK-NEXT: slli a0, a0, 48
; CHECK-NEXT: bgez a0, .LBB1_4
; CHECK-NEXT: # %bb.2: # %while.cond.preheader.i
; CHECK-NEXT: # in Loop: Header=BB1_1 Depth=1
; CHECK-NEXT: li a0, 0
; CHECK-NEXT: bnez zero, .LBB1_1
; CHECK-NEXT: # %bb.3: # %while.body
; CHECK-NEXT: .LBB1_4: # %while.cond1.preheader.i
entry:
Expand Down
Loading
Loading