Skip to content

Commit 25c88ba

Browse files
[RISCV] Add late optimization pass for riscv
This patch is an alternative to PRs llvm#117060, llvm#131684, llvm#131728. The patch adds a late optimization pass that replaces conditional branches that can be statically evaluated with an unconditinal branch. Adding michael as a co-author as most of code that evaluates the condition comes from llvm#131684.
1 parent 40439cd commit 25c88ba

File tree

12 files changed

+271
-83
lines changed

12 files changed

+271
-83
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_llvm_target(RISCVCodeGen
3535
RISCVConstantPoolValue.cpp
3636
RISCVDeadRegisterDefinitions.cpp
3737
RISCVMakeCompressible.cpp
38+
RISCVLateOpt.cpp
3839
RISCVExpandAtomicPseudoInsts.cpp
3940
RISCVExpandPseudoInsts.cpp
4041
RISCVFoldMemOffset.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ void initializeRISCVLandingPadSetupPass(PassRegistry &);
4040
FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
4141
CodeGenOptLevel OptLevel);
4242

43+
FunctionPass *createRISCVLateOptPass();
44+
void initializeRISCVLateOptPass(PassRegistry &);
45+
4346
FunctionPass *createRISCVMakeCompressibleOptPass();
4447
void initializeRISCVMakeCompressibleOptPass(PassRegistry &);
4548

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
//===-- RISCVLateOpt.cpp - Late stage optimization ------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// This file provides RISC-V specific target descriptions.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "MCTargetDesc/RISCVMCTargetDesc.h"
14+
#include "RISCV.h"
15+
#include "RISCVInstrInfo.h"
16+
#include "RISCVSubtarget.h"
17+
#include "llvm/CodeGen/MachineBasicBlock.h"
18+
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
19+
#include "llvm/CodeGen/MachineDominators.h"
20+
#include "llvm/CodeGen/MachineInstrBuilder.h"
21+
#include "llvm/CodeGen/Passes.h"
22+
#include "llvm/CodeGen/RegisterScavenging.h"
23+
#include "llvm/MC/TargetRegistry.h"
24+
#include "llvm/Support/Debug.h"
25+
26+
using namespace llvm;
27+
28+
#define DEBUG_TYPE "riscv-late-opt"
29+
#define RISCV_LATE_OPT_NAME "RISC-V Late Stage Optimizations"
30+
31+
namespace {
32+
33+
struct RISCVLateOpt : public MachineFunctionPass {
34+
static char ID;
35+
36+
RISCVLateOpt() : MachineFunctionPass(ID) {}
37+
38+
StringRef getPassName() const override { return RISCV_LATE_OPT_NAME; }
39+
40+
void getAnalysisUsage(AnalysisUsage &AU) const override {
41+
MachineFunctionPass::getAnalysisUsage(AU);
42+
}
43+
44+
bool runOnMachineFunction(MachineFunction &Fn) override;
45+
46+
private:
47+
bool trySimplifyCondBr(MachineInstr *MI, MachineBasicBlock *TBB,
48+
MachineBasicBlock *FBB,
49+
SmallVectorImpl<MachineOperand> &Cond) const;
50+
51+
const RISCVInstrInfo *RII = nullptr;
52+
};
53+
} // namespace
54+
55+
char RISCVLateOpt::ID = 0;
56+
INITIALIZE_PASS(RISCVLateOpt, "riscv-late-opt", RISCV_LATE_OPT_NAME, false,
57+
false)
58+
59+
bool RISCVLateOpt::trySimplifyCondBr(
60+
MachineInstr *MI, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
61+
SmallVectorImpl<MachineOperand> &Cond) const {
62+
63+
RISCVCC::CondCode CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm());
64+
assert(CC != RISCVCC::COND_INVALID);
65+
66+
// Right now we only care about LI (i.e. ADDI x0, imm)
67+
auto isLoadImm = [](const MachineInstr *MI, int64_t &Imm) -> bool {
68+
if (MI->getOpcode() == RISCV::ADDI && MI->getOperand(1).isReg() &&
69+
MI->getOperand(1).getReg() == RISCV::X0) {
70+
Imm = MI->getOperand(2).getImm();
71+
return true;
72+
}
73+
return false;
74+
};
75+
76+
MachineBasicBlock *MBB = MI->getParent();
77+
MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
78+
// Either a load from immediate instruction or X0.
79+
auto isFromLoadImm = [&](const MachineOperand &Op, int64_t &Imm) -> bool {
80+
if (!Op.isReg())
81+
return false;
82+
Register Reg = Op.getReg();
83+
if (Reg == RISCV::X0) {
84+
Imm = 0;
85+
return true;
86+
}
87+
return Reg.isVirtual() && isLoadImm(MRI.getVRegDef(Reg), Imm);
88+
};
89+
90+
// Try and convert a conditional branch that can be evaluated statically
91+
// into an unconditional branch.
92+
MachineBasicBlock *Folded = nullptr;
93+
int64_t C0, C1;
94+
if (isFromLoadImm(Cond[1], C0) && isFromLoadImm(Cond[2], C1)) {
95+
switch (CC) {
96+
case RISCVCC::COND_INVALID:
97+
llvm_unreachable("Unexpected CC");
98+
case RISCVCC::COND_EQ: {
99+
Folded = (C0 == C1) ? TBB : FBB;
100+
break;
101+
}
102+
case RISCVCC::COND_NE: {
103+
Folded = (C0 != C1) ? TBB : FBB;
104+
break;
105+
}
106+
case RISCVCC::COND_LT: {
107+
Folded = (C0 < C1) ? TBB : FBB;
108+
break;
109+
}
110+
case RISCVCC::COND_GE: {
111+
Folded = (C0 >= C1) ? TBB : FBB;
112+
break;
113+
}
114+
case RISCVCC::COND_LTU: {
115+
Folded = ((uint64_t)C0 < (uint64_t)C1) ? TBB : FBB;
116+
break;
117+
}
118+
case RISCVCC::COND_GEU: {
119+
Folded = ((uint64_t)C0 >= (uint64_t)C1) ? TBB : FBB;
120+
break;
121+
}
122+
}
123+
124+
// Do the conversion
125+
// Build the new unconditional branch
126+
DebugLoc DL = MBB->findBranchDebugLoc();
127+
if (Folded) {
128+
BuildMI(*MBB, MI, DL, RII->get(RISCV::PseudoBR)).addMBB(Folded);
129+
} else {
130+
MachineFunction::iterator Fallthrough = ++MBB->getIterator();
131+
if (Fallthrough == MBB->getParent()->end())
132+
return false;
133+
BuildMI(*MBB, MI, DL, RII->get(RISCV::PseudoBR)).addMBB(&*Fallthrough);
134+
}
135+
136+
// Update successors of MBB->
137+
if (Folded == TBB) {
138+
// If we're taking TBB, then the succ to delete is the fallthrough (if
139+
// it was a succ in the first place), or its the MBB from the
140+
// unconditional branch.
141+
if (!FBB) {
142+
MachineFunction::iterator Fallthrough = ++MBB->getIterator();
143+
if (Fallthrough != MBB->getParent()->end() &&
144+
MBB->isSuccessor(&*Fallthrough))
145+
MBB->removeSuccessor(&*Fallthrough, true);
146+
} else {
147+
MBB->removeSuccessor(FBB, true);
148+
}
149+
} else if (Folded == FBB) {
150+
// If we're taking the fallthrough or unconditional branch, then the
151+
// succ to remove is the one from the conditional branch.
152+
MBB->removeSuccessor(TBB, true);
153+
}
154+
155+
MI->eraseFromParent();
156+
return true;
157+
}
158+
return false;
159+
}
160+
161+
bool RISCVLateOpt::runOnMachineFunction(MachineFunction &Fn) {
162+
if (skipFunction(Fn.getFunction()))
163+
return false;
164+
165+
auto &ST = Fn.getSubtarget<RISCVSubtarget>();
166+
RII = ST.getInstrInfo();
167+
168+
bool Changed = false;
169+
170+
for (MachineBasicBlock &MBB : Fn) {
171+
for (MachineBasicBlock::iterator MII = MBB.begin(), MIE = MBB.end();
172+
MII != MIE;) {
173+
MachineInstr *MI = &*MII;
174+
// We may be erasing MI below, increment MII now.
175+
++MII;
176+
if (!MI->isConditionalBranch())
177+
continue;
178+
179+
MachineBasicBlock *TBB, *FBB;
180+
SmallVector<MachineOperand, 4> Cond;
181+
if (!RII->analyzeBranch(MBB, TBB, FBB, Cond, /*AllowModify=*/false))
182+
Changed |= trySimplifyCondBr(MI, TBB, FBB, Cond);
183+
}
184+
}
185+
186+
return Changed;
187+
}
188+
189+
/// Returns an instance of the Make Compressible Optimization pass.
190+
FunctionPass *llvm::createRISCVLateOptPass() { return new RISCVLateOpt(); }

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
127127
initializeRISCVPostLegalizerCombinerPass(*PR);
128128
initializeKCFIPass(*PR);
129129
initializeRISCVDeadRegisterDefinitionsPass(*PR);
130+
initializeRISCVLateOptPass(*PR);
130131
initializeRISCVMakeCompressibleOptPass(*PR);
131132
initializeRISCVGatherScatterLoweringPass(*PR);
132133
initializeRISCVCodeGenPreparePass(*PR);
@@ -565,6 +566,7 @@ void RISCVPassConfig::addPreEmitPass() {
565566
if (TM->getOptLevel() >= CodeGenOptLevel::Default &&
566567
EnableRISCVCopyPropagation)
567568
addPass(createMachineCopyPropagationPass(true));
569+
addPass(createRISCVLateOptPass());
568570
addPass(&BranchRelaxationPassID);
569571
addPass(createRISCVMakeCompressibleOptPass());
570572
}

llvm/test/CodeGen/RISCV/GlobalISel/rv32zbb.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ define i64 @ctpop_i64(i64 %a) nounwind {
357357
define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
358358
; RV32I-LABEL: ctpop_i64_ugt_two:
359359
; RV32I: # %bb.0:
360-
; RV32I-NEXT: beqz zero, .LBB6_2
360+
; RV32I-NEXT: j .LBB6_2
361361
; RV32I-NEXT: # %bb.1:
362362
; RV32I-NEXT: sltiu a0, zero, 0
363363
; RV32I-NEXT: ret
@@ -404,7 +404,7 @@ define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
404404
;
405405
; RV32ZBB-LABEL: ctpop_i64_ugt_two:
406406
; RV32ZBB: # %bb.0:
407-
; RV32ZBB-NEXT: beqz zero, .LBB6_2
407+
; RV32ZBB-NEXT: j .LBB6_2
408408
; RV32ZBB-NEXT: # %bb.1:
409409
; RV32ZBB-NEXT: sltiu a0, zero, 0
410410
; RV32ZBB-NEXT: ret
@@ -422,7 +422,7 @@ define i1 @ctpop_i64_ugt_two(i64 %a) nounwind {
422422
define i1 @ctpop_i64_ugt_one(i64 %a) nounwind {
423423
; RV32I-LABEL: ctpop_i64_ugt_one:
424424
; RV32I: # %bb.0:
425-
; RV32I-NEXT: beqz zero, .LBB7_2
425+
; RV32I-NEXT: j .LBB7_2
426426
; RV32I-NEXT: # %bb.1:
427427
; RV32I-NEXT: snez a0, zero
428428
; RV32I-NEXT: ret
@@ -470,7 +470,7 @@ define i1 @ctpop_i64_ugt_one(i64 %a) nounwind {
470470
;
471471
; RV32ZBB-LABEL: ctpop_i64_ugt_one:
472472
; RV32ZBB: # %bb.0:
473-
; RV32ZBB-NEXT: beqz zero, .LBB7_2
473+
; RV32ZBB-NEXT: j .LBB7_2
474474
; RV32ZBB-NEXT: # %bb.1:
475475
; RV32ZBB-NEXT: snez a0, zero
476476
; RV32ZBB-NEXT: ret

llvm/test/CodeGen/RISCV/bfloat-br-fcmp.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ declare bfloat @dummy(bfloat)
1111
define void @br_fcmp_false(bfloat %a, bfloat %b) nounwind {
1212
; RV32IZFBFMIN-LABEL: br_fcmp_false:
1313
; RV32IZFBFMIN: # %bb.0:
14-
; RV32IZFBFMIN-NEXT: beqz zero, .LBB0_2
14+
; RV32IZFBFMIN-NEXT: j .LBB0_2
1515
; RV32IZFBFMIN-NEXT: # %bb.1: # %if.then
1616
; RV32IZFBFMIN-NEXT: ret
1717
; RV32IZFBFMIN-NEXT: .LBB0_2: # %if.else
@@ -21,7 +21,7 @@ define void @br_fcmp_false(bfloat %a, bfloat %b) nounwind {
2121
;
2222
; RV64IZFBFMIN-LABEL: br_fcmp_false:
2323
; RV64IZFBFMIN: # %bb.0:
24-
; RV64IZFBFMIN-NEXT: beqz zero, .LBB0_2
24+
; RV64IZFBFMIN-NEXT: j .LBB0_2
2525
; RV64IZFBFMIN-NEXT: # %bb.1: # %if.then
2626
; RV64IZFBFMIN-NEXT: ret
2727
; RV64IZFBFMIN-NEXT: .LBB0_2: # %if.else
@@ -581,7 +581,7 @@ if.then:
581581
define void @br_fcmp_true(bfloat %a, bfloat %b) nounwind {
582582
; RV32IZFBFMIN-LABEL: br_fcmp_true:
583583
; RV32IZFBFMIN: # %bb.0:
584-
; RV32IZFBFMIN-NEXT: beqz zero, .LBB16_2
584+
; RV32IZFBFMIN-NEXT: j .LBB16_2
585585
; RV32IZFBFMIN-NEXT: # %bb.1: # %if.else
586586
; RV32IZFBFMIN-NEXT: ret
587587
; RV32IZFBFMIN-NEXT: .LBB16_2: # %if.then
@@ -591,7 +591,7 @@ define void @br_fcmp_true(bfloat %a, bfloat %b) nounwind {
591591
;
592592
; RV64IZFBFMIN-LABEL: br_fcmp_true:
593593
; RV64IZFBFMIN: # %bb.0:
594-
; RV64IZFBFMIN-NEXT: beqz zero, .LBB16_2
594+
; RV64IZFBFMIN-NEXT: j .LBB16_2
595595
; RV64IZFBFMIN-NEXT: # %bb.1: # %if.else
596596
; RV64IZFBFMIN-NEXT: ret
597597
; RV64IZFBFMIN-NEXT: .LBB16_2: # %if.then

llvm/test/CodeGen/RISCV/branch_zero.ll

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
define void @foo(i16 %finder_idx) {
66
; CHECK-LABEL: foo:
77
; CHECK: # %bb.0: # %entry
8-
; CHECK-NEXT: .LBB0_1: # %for.body
9-
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
8+
; CHECK-NEXT: # %bb.1: # %for.body
109
; CHECK-NEXT: slli a0, a0, 48
1110
; CHECK-NEXT: bltz a0, .LBB0_4
1211
; CHECK-NEXT: # %bb.2: # %while.cond.preheader.i
13-
; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
1412
; CHECK-NEXT: li a0, 0
15-
; CHECK-NEXT: bnez zero, .LBB0_1
16-
; CHECK-NEXT: # %bb.3: # %while.body
13+
; CHECK-NEXT: j .LBB0_3
14+
; CHECK-NEXT: .LBB0_3: # %while.body
1715
; CHECK-NEXT: .LBB0_4: # %while.cond1.preheader.i
1816
entry:
1917
br label %for.body
@@ -46,15 +44,13 @@ if.then:
4644
define void @bar(i16 %finder_idx) {
4745
; CHECK-LABEL: bar:
4846
; CHECK: # %bb.0: # %entry
49-
; CHECK-NEXT: .LBB1_1: # %for.body
50-
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
47+
; CHECK-NEXT: # %bb.1: # %for.body
5148
; CHECK-NEXT: slli a0, a0, 48
5249
; CHECK-NEXT: bgez a0, .LBB1_4
5350
; CHECK-NEXT: # %bb.2: # %while.cond.preheader.i
54-
; CHECK-NEXT: # in Loop: Header=BB1_1 Depth=1
5551
; CHECK-NEXT: li a0, 0
56-
; CHECK-NEXT: bnez zero, .LBB1_1
57-
; CHECK-NEXT: # %bb.3: # %while.body
52+
; CHECK-NEXT: j .LBB1_3
53+
; CHECK-NEXT: .LBB1_3: # %while.body
5854
; CHECK-NEXT: .LBB1_4: # %while.cond1.preheader.i
5955
entry:
6056
br label %for.body

0 commit comments

Comments
 (0)