llvm.org GIT mirror llvm / da72052
[mips] Fix compact branch hazard detection In certain cases it is possible that transient instructions such as %reg = IMPLICIT_DEF as a single instruction in a basic block to reach the MipsHazardSchedule pass. This patch teaches MipsHazardSchedule to properly look through such cases. Reviewers: vkalintiris, zoran.jovanovic Differential Revision: https://reviews.llvm.org/D27209 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289529 91177308-0d34-0410-b5e6-96231b3b80d8 Simon Dardis 2 years ago
2 changed file(s) with 201 addition(s) and 23 deletion(s). Raw diff Collapse all Expand all
9090 return new MipsHazardSchedule();
9191 }
9292
93 // Find the next real instruction from the current position.
93 // Find the next real instruction from the current position in current basic
94 // block.
95 static Iter getNextMachineInstrInBB(Iter Position) {
96 Iter I = Position, E = Position->getParent()->end();
97 I = std::find_if_not(I, E,
98 [](const Iter &Insn) { return Insn->isTransient(); });
99
100 return I;
101 }
102
103 // Find the next real instruction from the current position, looking through
104 // basic block boundaries.
94105 static Iter getNextMachineInstr(Iter Position) {
95 Iter I = Position, E = Position->getParent()->end();
96 I = std::find_if_not(I, E, [](const Iter &Insn) { return Insn->isTransient(); });
97 assert(I != E);
98 return I;
106 if (std::next(Position) == Position->getParent()->end()) {
107 const MachineBasicBlock * MBB = (&*Position)->getParent();
108 for (auto *Succ : MBB->successors()) {
109 if (MBB->isLayoutSuccessor(Succ)) {
110 Iter I = Succ->begin();
111 Iter Next = getNextMachineInstrInBB(I);
112 if (Next == Succ->end()) {
113 return getNextMachineInstr(I);
114 } else {
115 return I;
116 }
117 }
118 }
119 llvm_unreachable("Should have identified the end of the function earlier!");
120 }
121
122 return getNextMachineInstrInBB(Position);
99123 }
100124
101125 bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
103127 const MipsSubtarget *STI =
104128 &static_cast(MF.getSubtarget());
105129
106 // Forbidden slot hazards are only defined for MIPSR6.
130 // Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
107131 if (!STI->hasMips32r6() || STI->inMicroMipsMode())
108132 return false;
109133
117141 if (!TII->HasForbiddenSlot(*I))
118142 continue;
119143
120 bool InsertNop = false;
121 // Next instruction in the basic block.
122 if (std::next(I) != FI->end() &&
123 !TII->SafeInForbiddenSlot(*getNextMachineInstr(std::next(I)))) {
124 InsertNop = true;
125 } else {
126 // Next instruction in the physical successor basic block.
127 for (auto *Succ : FI->successors()) {
128 if (FI->isLayoutSuccessor(Succ) &&
129 getNextMachineInstr(Succ->begin()) != Succ->end() &&
130 !TII->SafeInForbiddenSlot(*getNextMachineInstr(Succ->begin()))) {
131 InsertNop = true;
132 break;
133 }
144 Iter Inst;
145 bool LastInstInFunction =
146 std::next(I) == FI->end() && std::next(FI) == MF.end();
147 if (!LastInstInFunction) {
148 if (std::next(I) != FI->end()) {
149 // Start looking from the next instruction in the basic block.
150 Inst = getNextMachineInstr(std::next(I));
151 } else {
152 // Next instruction in the physical successor basic block.
153 Inst = getNextMachineInstr(I);
134154 }
135155 }
136156
137 if (InsertNop) {
157 if (LastInstInFunction || !TII->SafeInForbiddenSlot(*Inst)) {
138158 Changed = true;
139 MIBundleBuilder(&*I).append(
140 BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
159 MIBundleBuilder(&*I)
160 .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
141161 NumInsertedNops++;
142162 }
143163 }
0 # RUN: llc -march=mips64 -mcpu=mips64r6 -start-after=block-placement -o - %s | FileCheck %s
1
2 # Check that MipsHazardSchedule sees through basic blocks with transient instructions.
3 # The mir code in this file isn't representative of the llvm-ir.
4
5 --- |
6 ; ModuleID = 'test.ll'
7 source_filename = "test.c"
8 target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"
9 target triple = "mips64-img-linux-gnu"
10
11 ; Function Attrs: nounwind
12 define i32 @f(i32 signext %a) {
13 entry:
14 %retval = alloca i32, align 4
15 %a.addr = alloca i32, align 4
16 store i32 %a, i32* %a.addr, align 4
17 %0 = load i32, i32* %a.addr, align 4
18 %cmp = icmp sgt i32 %0, 5
19 br i1 %cmp, label %if.then, label %if.else
20
21 if.then: ; preds = %entry
22 %1 = load i32, i32* %a.addr, align 4
23 %2 = load i32, i32* %a.addr, align 4
24 %add = add nsw i32 %1, %2
25 store i32 %add, i32* %retval, align 4
26 br label %return
27
28 if.else: ; preds = %entry
29 %3 = load i32, i32* %a.addr, align 4
30 %call = call i32 @g(i32 signext %3)
31 store i32 %call, i32* %retval, align 4
32 br label %return
33
34 return: ; preds = %if.else, %if.then
35 %4 = load i32, i32* %retval, align 4
36 ret i32 %4
37 }
38
39 declare i32 @g(i32 signext)
40
41 ; Function Attrs: nounwind
42 declare void @llvm.stackprotector(i8*, i8**)
43
44 !llvm.ident = !{!0}
45
46 !0 = !{!"clang version 4.0.0 "}
47
48 ...
49 ---
50 # CHECK-LABEL: f:
51 # CHECK: bgtzc
52 # CHECK-NEXT: nop
53 # CHECK: bltzc
54 # CHECK-NEXT: nop
55 # CHECK: blezc
56 name: f
57 alignment: 3
58 exposesReturnsTwice: false
59 legalized: false
60 regBankSelected: false
61 selected: false
62 tracksRegLiveness: true
63 liveins:
64 - { reg: '%a0_64' }
65 - { reg: '%t9_64' }
66 calleeSavedRegisters: [ '%fp', '%gp', '%ra', '%d12', '%d13', '%d14', '%d15',
67 '%f24', '%f25', '%f26', '%f27', '%f28', '%f29',
68 '%f30', '%f31', '%fp_64', '%f_hi24', '%f_hi25',
69 '%f_hi26', '%f_hi27', '%f_hi28', '%f_hi29', '%f_hi30',
70 '%f_hi31', '%gp_64', '%ra_64', '%s0', '%s1', '%s2',
71 '%s3', '%s4', '%s5', '%s6', '%s7', '%d24_64', '%d25_64',
72 '%d26_64', '%d27_64', '%d28_64', '%d29_64', '%d30_64',
73 '%d31_64', '%s0_64', '%s1_64', '%s2_64', '%s3_64',
74 '%s4_64', '%s5_64', '%s6_64', '%s7_64' ]
75 frameInfo:
76 isFrameAddressTaken: false
77 isReturnAddressTaken: false
78 hasStackMap: false
79 hasPatchPoint: false
80 stackSize: 32
81 offsetAdjustment: 0
82 maxAlignment: 8
83 adjustsStack: true
84 hasCalls: true
85 maxCallFrameSize: 0
86 hasOpaqueSPAdjustment: false
87 hasVAStart: false
88 hasMustTailInVarArgFunc: false
89 stack:
90 - { id: 0, name: retval, offset: -28, size: 4, alignment: 4 }
91 - { id: 1, name: a.addr, offset: -32, size: 4, alignment: 4 }
92 - { id: 2, type: spill-slot, offset: -8, size: 8, alignment: 8, callee-saved-register: '%ra_64' }
93 - { id: 3, type: spill-slot, offset: -16, size: 8, alignment: 8, callee-saved-register: '%fp_64' }
94 - { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '%gp_64' }
95 body: |
96 bb.0.entry:
97 successors: %bb.1.if.then(0x40000000), %bb.5.if.else(0x40000000)
98 liveins: %a0_64, %t9_64, %ra_64, %fp_64, %gp_64
99
100 %sp_64 = DADDiu %sp_64, -32
101 CFI_INSTRUCTION def_cfa_offset 32
102 SD killed %ra_64, %sp_64, 24 :: (store 8 into %stack.2)
103 SD killed %fp_64, %sp_64, 16 :: (store 8 into %stack.3)
104 SD killed %gp_64, %sp_64, 8 :: (store 8 into %stack.4)
105 CFI_INSTRUCTION offset %ra_64, -8
106 CFI_INSTRUCTION offset %fp_64, -16
107 CFI_INSTRUCTION offset %gp_64, -24
108 CFI_INSTRUCTION def_cfa_register %fp_64
109 %at_64 = LUi64 @f
110 %v0_64 = DADDu killed %at_64, %t9_64
111 SW %a0, %sp_64, 0 :: (store 4 into %ir.a.addr)
112 BGTZC %a0, %bb.5.if.else, implicit-def %at
113
114 bb.1.if.then:
115 successors: %bb.6.return(0x40000000), %bb.2.if.then(0x40000000)
116 liveins: %a0
117
118 BLTZC %a0, %bb.6.return, implicit-def %at
119
120 bb.2.if.then:
121 successors: %bb.3.if.else(0x80000000)
122 %t8 = IMPLICIT_DEF
123
124 bb.3.if.else:
125 successors: %bb.6.return(0x40000000), %bb.4.if.else(0x40000000)
126 liveins: %t8
127
128 BLEZC %t8, %bb.6.return, implicit-def %at
129
130 bb.4.if.else:
131 successors: %bb.6.return(0x80000000)
132 liveins: %t8
133
134 %at = LW %sp_64, 0 :: (dereferenceable load 4 from %ir.a.addr)
135 %at = ADDu killed %at, %t8
136 SW killed %at, %sp_64, 4 :: (store 4 into %ir.retval)
137 J %bb.6.return, implicit-def dead %at
138
139 bb.5.if.else:
140 successors: %bb.6.return(0x80000000)
141 liveins: %v0_64
142
143 %gp_64 = DADDiu killed %v0_64, @f
144 %a0_64 = LW64 %sp_64, 0 :: (dereferenceable load 4 from %ir.a.addr)
145 %t9_64 = LD %gp_64, @g :: (load 8 from call-entry @g)
146 JALR64Pseudo %t9_64, csr_n64, implicit-def dead %ra, implicit %a0_64, implicit %gp_64, implicit-def %sp, implicit-def %v0
147 SW killed %v0, %sp_64, 4 :: (store 4 into %ir.retval)
148
149 bb.6.return:
150 %v0 = LW %sp_64, 4 :: (dereferenceable load 4 from %ir.retval)
151 %gp_64 = LD %sp_64, 8 :: (load 8 from %stack.4)
152 %fp_64 = LD %sp_64, 16 :: (load 8 from %stack.3)
153 %ra_64 = LD %sp_64, 24 :: (load 8 from %stack.2)
154 %sp_64 = DADDiu %sp_64, 32
155 PseudoReturn64 %ra_64
156
157 ...