Skip to content

Commit 4f39531

Browse files
committed
[RISCV] Add RemoveBackToBackBranches Pass
According to the MIPS specification, there shouldn't be two conditional branches in the same 8-byte aligned region of code.
1 parent d35403f commit 4f39531

File tree

11 files changed

+292
-6
lines changed

11 files changed

+292
-6
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4941,6 +4941,7 @@ def mload_store_pairs : Flag<["-"], "mload-store-pairs">, Group<m_riscv_Features
49414941
def mno_load_store_pairs : Flag<["-"], "mno-load-store-pairs">, Group<m_riscv_Features_Group>;
49424942
def mccmov : Flag<["-"], "mccmov">, Group<m_riscv_Features_Group>;
49434943
def mno_ccmov : Flag<["-"], "mno-ccmov">, Group<m_riscv_Features_Group>;
4944+
def mremove_back_to_back_branches : Flag<["-"], "mremove_back_to_back_branches">, Group<m_riscv_Features_Group>;
49444945
let Flags = [TargetSpecific] in {
49454946
def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>,
49464947
HelpText<"Enable use of experimental RISC-V extensions.">;

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,6 +2178,10 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args,
21782178
CmdArgs.push_back("-riscv-ccmov=0");
21792179
}
21802180
}
2181+
if (Args.getLastArg(options::OPT_mremove_back_to_back_branches)) {
2182+
CmdArgs.push_back("-mllvm");
2183+
CmdArgs.push_back("-riscv-remove-back-to-back-branches=1");
2184+
}
21812185
// Handle -mrvv-vector-bits=<bits>
21822186
if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {
21832187
StringRef Val = A->getValue();

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ add_llvm_target(RISCVCodeGen
5555
RISCVMoveMerger.cpp
5656
RISCVPushPopOptimizer.cpp
5757
RISCVRegisterInfo.cpp
58+
RISCVRemoveBackToBackBranches.cpp
5859
RISCVSubtarget.cpp
5960
RISCVTargetMachine.cpp
6061
RISCVTargetObjectFile.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ createRISCVInstructionSelector(const RISCVTargetMachine &,
9696
const RISCVRegisterBankInfo &);
9797
void initializeRISCVDAGToDAGISelLegacyPass(PassRegistry &);
9898

99+
FunctionPass *createRISCVRemoveBackToBackBranches();
100+
void initializeRISCVRemoveBackToBackBranchesPass(PassRegistry &);
101+
99102
FunctionPass *createRISCVPostLegalizerCombiner();
100103
void initializeRISCVPostLegalizerCombinerPass(PassRegistry &);
101104

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===----------------------- RISCVRemoveBackToBackBranches.cpp ------------===//
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+
#include "RISCV.h"
10+
#include "RISCVInstrInfo.h"
11+
#include "RISCVSubtarget.h"
12+
#include "llvm/ADT/Statistic.h"
13+
#include "llvm/ADT/StringRef.h"
14+
#include "llvm/CodeGen/MachineBasicBlock.h"
15+
#include "llvm/CodeGen/MachineFunction.h"
16+
#include "llvm/CodeGen/MachineFunctionPass.h"
17+
#include "llvm/CodeGen/MachineInstr.h"
18+
#include "llvm/CodeGen/TargetSubtargetInfo.h"
19+
#include "llvm/Target/TargetMachine.h"
20+
21+
using namespace llvm;
22+
23+
#define DEBUG_TYPE "riscv-remove-back-to-back-branches"
24+
25+
STATISTIC(NumInsertedAligments, "Number of aligments set");
26+
27+
namespace {
28+
29+
// According to the MIPS specification, there shouldn't be two conditional
30+
// branches in the same 8-byte aligned region of code.
31+
constexpr unsigned NumberOfBytesOfCodeRegion = 8;
32+
33+
class RISCVRemoveBackToBackBranches : public MachineFunctionPass {
34+
public:
35+
static char ID;
36+
37+
RISCVRemoveBackToBackBranches() : MachineFunctionPass(ID) {
38+
initializeRISCVRemoveBackToBackBranchesPass(
39+
*PassRegistry::getPassRegistry());
40+
}
41+
42+
StringRef getPassName() const override {
43+
return "RISCV Remove Back To Back Branches Pass";
44+
}
45+
46+
bool runOnMachineFunction(MachineFunction &F) override;
47+
48+
MachineFunctionProperties getRequiredProperties() const override {
49+
return MachineFunctionProperties().set(
50+
MachineFunctionProperties::Property::NoVRegs);
51+
}
52+
53+
private:
54+
const RISCVSubtarget *STI;
55+
const RISCVInstrInfo *TII;
56+
};
57+
58+
} // end of anonymous namespace
59+
60+
char RISCVRemoveBackToBackBranches::ID = 0;
61+
62+
INITIALIZE_PASS(RISCVRemoveBackToBackBranches, DEBUG_TYPE,
63+
"Fix hazards by removing back to back branches", false, false)
64+
65+
/// Returns a pass that clears pipeline hazards.
66+
FunctionPass *llvm::createRISCVRemoveBackToBackBranches() {
67+
return new RISCVRemoveBackToBackBranches();
68+
}
69+
70+
static bool CheckCompressedISA(MachineBasicBlock *MBB,
71+
const RISCVInstrInfo *TII) {
72+
unsigned SizeInBytes = 0;
73+
for (auto &I : *MBB) {
74+
// Skip some 0-sized meta instrucitons, such as debug ones.
75+
if (!TII->getInstSizeInBytes(I))
76+
continue;
77+
78+
SizeInBytes += TII->getInstSizeInBytes(I);
79+
80+
// This means that there is something other than the conditional branch
81+
// here.
82+
if (!I.isConditionalBranch())
83+
continue;
84+
85+
// If it is a conditional branch, make sure it is the last one
86+
// in this MBB and the cumulative size in bytes of other instructions in the
87+
// block is <= 6 (since there potentially could be space for the two
88+
// branches in the same 8-byte aligned code region, when compressed version
89+
// of the instructions (16-bit size) is being used).
90+
if (&I == &*MBB->getLastNonDebugInstr()) {
91+
if (SizeInBytes <= 6)
92+
return true;
93+
return false;
94+
}
95+
}
96+
97+
return false;
98+
}
99+
100+
static bool CheckNonCompressedISA(MachineBasicBlock *MBB,
101+
const RISCVInstrInfo *TII) {
102+
for (auto &I : *MBB) {
103+
// Skip some 0-sized meta instrucitons, such as debug ones.
104+
if (!TII->getInstSizeInBytes(I))
105+
continue;
106+
107+
// This means that there is something other than the conditional branch
108+
// here.
109+
if (!I.isConditionalBranch())
110+
return false;
111+
112+
// If it is a conditional branch, make sure it is the last one
113+
// in this MBB.
114+
if (&I == &*MBB->getLastNonDebugInstr())
115+
return true;
116+
return false;
117+
}
118+
return false;
119+
}
120+
121+
bool RISCVRemoveBackToBackBranches::runOnMachineFunction(MachineFunction &MF) {
122+
STI = &static_cast<const RISCVSubtarget &>(MF.getSubtarget());
123+
TII = static_cast<const RISCVInstrInfo *>(STI->getInstrInfo());
124+
125+
if (!STI->shouldRemoveBackToBackBranches()) {
126+
LLVM_DEBUG(llvm::dbgs()
127+
<< "Ignoring RISCV Remove Back To Back Branches Pass\n");
128+
return false;
129+
}
130+
131+
bool Changed = false;
132+
for (auto &MBB : MF) {
133+
auto BBTerminator = MBB.getFirstTerminator();
134+
// If it is not a conditional branch, we are not interested.
135+
if (BBTerminator == MBB.end() ||
136+
&*BBTerminator != &*MBB.getLastNonDebugInstr() ||
137+
!BBTerminator->isConditionalBranch())
138+
continue;
139+
140+
for (auto &Successor : MBB.successors()) {
141+
// Set up aligment in order to avoid hazards. No 2 conditional branches
142+
// should be in the same 8-byte aligned region of code. Similar to MIPS
143+
// forbidden slots problem. We may want to insert a NOP only, but we
144+
// need to think of Compressed ISA, so it is more safe to just set up
145+
// aligment to the successor block if it meets requirements.
146+
bool ShouldSetAligment = STI->getFeatureBits()[RISCV::FeatureStdExtC]
147+
? CheckCompressedISA(Successor, TII)
148+
: CheckNonCompressedISA(Successor, TII);
149+
if (ShouldSetAligment) {
150+
Successor->setAlignment(Align(NumberOfBytesOfCodeRegion));
151+
Changed = true;
152+
++NumInsertedAligments;
153+
}
154+
}
155+
}
156+
157+
return Changed;
158+
}

llvm/lib/Target/RISCV/RISCVSubtarget.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ static cl::opt<bool> UseCCMovInsn("riscv-ccmov",
7171
cl::desc("RISCV: Use 'ccmov' instruction"),
7272
cl::init(true), cl::Hidden);
7373

74+
static cl::opt<bool> RISCVRemoveBackToBackBranches(
75+
"riscv-remove-back-to-back-branches",
76+
cl::desc("RISCV: Insert nops to clear pipeline hazards."), cl::init(false),
77+
cl::Hidden);
78+
7479
void RISCVSubtarget::anchor() {}
7580

7681
RISCVSubtarget &
@@ -233,3 +238,7 @@ bool RISCVSubtarget::useLoadStorePairs() const {
233238
bool RISCVSubtarget::useCCMovInsn() const {
234239
return UseCCMovInsn && HasMIPSCMov;
235240
}
241+
242+
bool RISCVSubtarget::shouldRemoveBackToBackBranches() const {
243+
return RISCVRemoveBackToBackBranches && hasFeature(RISCV::TuneMIPSP8700);
244+
}

llvm/lib/Target/RISCV/RISCVSubtarget.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
169169
MVT getXLenVT() const {
170170
return is64Bit() ? MVT::i64 : MVT::i32;
171171
}
172-
unsigned getXLen() const {
173-
return is64Bit() ? 64 : 32;
174-
}
172+
unsigned getXLen() const { return is64Bit() ? 64 : 32; }
173+
bool shouldRemoveBackToBackBranches() const;
175174
bool useLoadStorePairs() const;
176175
bool useCCMovInsn() const;
177176
unsigned getFLen() const {

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,13 +579,14 @@ void RISCVPassConfig::addPreEmitPass() {
579579
if (TM->getOptLevel() >= CodeGenOptLevel::Default &&
580580
EnableRISCVCopyPropagation)
581581
addPass(createMachineCopyPropagationPass(true));
582-
addPass(&BranchRelaxationPassID);
583582
addPass(createRISCVMakeCompressibleOptPass());
584583

585584
// LoadStoreOptimizer creates bundles for load-store bonding.
586585
addPass(createUnpackMachineBundles([](const MachineFunction &MF) {
587586
return MF.getSubtarget<RISCVSubtarget>().useLoadStorePairs();
588587
}));
588+
addPass(&BranchRelaxationPassID);
589+
addPass(createRISCVRemoveBackToBackBranches());
589590
}
590591

591592
void RISCVPassConfig::addPreEmitPass2() {
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# RUN: llc -mtriple=riscv64 -mattr=-c -riscv-remove-back-to-back-branches=1 -o - %s | FileCheck %s
2+
3+
# CHECK: %bb.0:
4+
# CHECK: blez
5+
# CHECK: .p2align 3
6+
# CHECK: %bb.1:
7+
# CHECK: blez
8+
9+
--- |
10+
; ModuleID = 'hazaard.c'
11+
source_filename = "hazaard.c"
12+
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
13+
target triple = "riscv64-unknown-linux-gnu"
14+
15+
; Function Attrs: nounwind optsize
16+
define dso_local void @test(i32 noundef signext %a, i32 noundef signext %b) local_unnamed_addr #0 {
17+
entry:
18+
%cmp = icmp sgt i32 %a, 0
19+
br i1 %cmp, label %if.then, label %if.end3
20+
21+
if.then: ; preds = %entry
22+
%cmp1 = icmp slt i32 %b, 1
23+
br i1 %cmp1, label %if.then2, label %if.end3
24+
25+
if.then2: ; preds = %if.then
26+
tail call void asm sideeffect "nop", ""() #1, !srcloc !4
27+
ret void
28+
29+
if.end3: ; preds = %if.then, %entry
30+
ret void
31+
}
32+
33+
attributes #0 = { nounwind optsize "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="mips-p8700" "target-features"="+64bit,+a,+c,+d,+f,+m" }
34+
attributes #1 = { nounwind }
35+
36+
!llvm.module.flags = !{!0, !1, !2}
37+
!llvm.ident = !{!3}
38+
39+
!0 = !{i32 1, !"wchar_size", i32 4}
40+
!1 = !{i32 1, !"target-abi", !"lp64d"}
41+
!2 = !{i32 1, !"SmallDataLimit", i32 8}
42+
!3 = !{!"clang version 14.0.0 (git@github.com:MIPS/llvm.git ae54cf4034587fab977092097c9772c7a275ddc8)"}
43+
!4 = !{i64 88}
44+
45+
...
46+
---
47+
name: test
48+
alignment: 2
49+
exposesReturnsTwice: false
50+
legalized: false
51+
regBankSelected: false
52+
selected: false
53+
failedISel: false
54+
tracksRegLiveness: true
55+
hasWinCFI: false
56+
failsVerification: false
57+
tracksDebugUserValues: true
58+
registers: []
59+
liveins:
60+
- { reg: '$x10', virtual-reg: '' }
61+
- { reg: '$x11', virtual-reg: '' }
62+
frameInfo:
63+
isFrameAddressTaken: false
64+
isReturnAddressTaken: false
65+
hasStackMap: false
66+
hasPatchPoint: false
67+
stackSize: 0
68+
offsetAdjustment: 0
69+
maxAlignment: 1
70+
adjustsStack: false
71+
hasCalls: false
72+
stackProtector: ''
73+
maxCallFrameSize: 0
74+
cvBytesOfCalleeSavedRegisters: 0
75+
hasOpaqueSPAdjustment: false
76+
hasVAStart: false
77+
hasMustTailInVarArgFunc: false
78+
hasTailCall: false
79+
localFrameSize: 0
80+
savePoint: ''
81+
restorePoint: ''
82+
fixedStack: []
83+
stack: []
84+
callSites: []
85+
debugValueSubstitutions: []
86+
constants: []
87+
machineFunctionInfo: {}
88+
body: |
89+
bb.0.entry:
90+
successors: %bb.1(0x50000000), %bb.2(0x30000000)
91+
liveins: $x10, $x11
92+
93+
BGE $x0, killed renamable $x10, %bb.2
94+
95+
bb.1.if.then:
96+
successors: %bb.3(0x30000000), %bb.2(0x50000000)
97+
liveins: $x11
98+
99+
BGE $x0, killed renamable $x11, %bb.3
100+
101+
bb.2.if.end3:
102+
PseudoRET
103+
104+
bb.3.if.then2:
105+
INLINEASM &nop, 1 /* sideeffect attdialect */, !4
106+
PseudoRET
107+
108+
...

llvm/test/CodeGen/RISCV/O0-pipeline.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@
6161
; CHECK-NEXT: Insert fentry calls
6262
; CHECK-NEXT: Insert XRay ops
6363
; CHECK-NEXT: Implement the 'patchable-function' attribute
64-
; CHECK-NEXT: Branch relaxation pass
6564
; CHECK-NEXT: RISC-V Make Compressible
6665
; CHECK-NEXT: Unpack machine instruction bundles
66+
; CHECK-NEXT: Branch relaxation pass
67+
; CHECK-NEXT: RISCV Remove Back To Back Branches Pass
6768
; CHECK-NEXT: Contiguously Lay Out Funclets
6869
; CHECK-NEXT: Remove Loads Into Fake Uses
6970
; CHECK-NEXT: StackMap Liveness Analysis

llvm/test/CodeGen/RISCV/O3-pipeline.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,10 @@
188188
; CHECK-NEXT: Insert XRay ops
189189
; CHECK-NEXT: Implement the 'patchable-function' attribute
190190
; CHECK-NEXT: Machine Copy Propagation Pass
191-
; CHECK-NEXT: Branch relaxation pass
192191
; CHECK-NEXT: RISC-V Make Compressible
193192
; CHECK-NEXT: Unpack machine instruction bundles
193+
; CHECK-NEXT: Branch relaxation pass
194+
; CHECK-NEXT: RISCV Remove Back To Back Branches Pass
194195
; CHECK-NEXT: Contiguously Lay Out Funclets
195196
; CHECK-NEXT: Remove Loads Into Fake Uses
196197
; CHECK-NEXT: StackMap Liveness Analysis

0 commit comments

Comments
 (0)