1 ; RUN: opt -S -simplifycfg < %s | FileCheck %s 2 3 ; SimplifyCFG should eliminate redundant indirectbr edges. 4 5 ; CHECK: indbrtest0 6 ; CHECK: indirectbr i8* %t, [label %BB0, label %BB1, label %BB2] 7 ; CHECK: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ] 8 9 declare void @foo() 10 declare void @A() 11 declare void @B(i32) 12 declare void @C() 13 14 define void @indbrtest0(i8** %P, i8** %Q) { 15 entry: 16 store i8* blockaddress(@indbrtest0, %BB0), i8** %P 17 store i8* blockaddress(@indbrtest0, %BB1), i8** %P 18 store i8* blockaddress(@indbrtest0, %BB2), i8** %P 19 call void @foo() 20 %t = load i8*, i8** %Q 21 indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2] 22 BB0: 23 call void @A() 24 br label %BB1 25 BB1: 26 %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ] 27 call void @B(i32 %x) 28 ret void 29 BB2: 30 call void @C() 31 ret void 32 } 33 34 ; SimplifyCFG should convert the indirectbr into a directbr. It would be even 35 ; better if it removed the branch altogether, but simplifycfdg currently misses 36 ; that because the predecessor is the entry block. 37 38 ; CHECK: indbrtest1 39 ; CHECK: br label %BB0 40 41 define void @indbrtest1(i8** %P, i8** %Q) { 42 entry: 43 store i8* blockaddress(@indbrtest1, %BB0), i8** %P 44 call void @foo() 45 %t = load i8*, i8** %Q 46 indirectbr i8* %t, [label %BB0, label %BB0] 47 BB0: 48 call void @A() 49 ret void 50 } 51 52 ; SimplifyCFG should notice that BB0 does not have its address taken and 53 ; remove it from entry's successor list. 54 55 ; CHECK: indbrtest2 56 ; CHECK: entry: 57 ; CHECK-NEXT: unreachable 58 59 define void @indbrtest2(i8* %t) { 60 entry: 61 indirectbr i8* %t, [label %BB0, label %BB0] 62 BB0: 63 ret void 64 } 65 66 67 ; Make sure the blocks in the next few tests aren't trivially removable as 68 ; successors by taking their addresses. 69 70 @anchor = constant [13 x i8*] [ 71 i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2), i8* blockaddress(@indbrtest3, %L3), 72 i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L2), i8* blockaddress(@indbrtest4, %L3), 73 i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2), i8* blockaddress(@indbrtest5, %L3), i8* blockaddress(@indbrtest5, %L4), 74 i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L2), i8* blockaddress(@indbrtest6, %L3) 75 ] 76 77 ; SimplifyCFG should turn the indirectbr into a conditional branch on the 78 ; condition of the select. 79 80 ; CHECK-LABEL: @indbrtest3( 81 ; CHECK-NEXT: entry: 82 ; CHECK-NEXT: br i1 %cond, label %L1, label %L2 83 ; CHECK-NOT: indirectbr 84 ; CHECK-NOT: br 85 ; CHECK-NOT: L3: 86 define void @indbrtest3(i1 %cond, i8* %address) nounwind { 87 entry: 88 %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest3, %L1), i8* blockaddress(@indbrtest3, %L2) 89 indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3] 90 91 L1: 92 call void @A() 93 ret void 94 L2: 95 call void @C() 96 ret void 97 L3: 98 call void @foo() 99 ret void 100 } 101 102 ; SimplifyCFG should turn the indirectbr into an unconditional branch to the 103 ; only possible destination. 104 ; As in @indbrtest1, it should really remove the branch entirely, but it doesn't 105 ; because it's in the entry block. 106 107 ; CHECK-LABEL: @indbrtest4( 108 ; CHECK-NEXT: entry: 109 ; CHECK-NEXT: br label %L1 110 define void @indbrtest4(i1 %cond) nounwind { 111 entry: 112 %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest4, %L1), i8* blockaddress(@indbrtest4, %L1) 113 indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3] 114 115 L1: 116 call void @A() 117 ret void 118 L2: 119 call void @C() 120 ret void 121 L3: 122 call void @foo() 123 ret void 124 } 125 126 ; SimplifyCFG should turn the indirectbr into an unreachable because neither 127 ; destination is listed as a successor. 128 129 ; CHECK-LABEL: @indbrtest5( 130 ; CHECK-NEXT: entry: 131 ; CHECK-NEXT: unreachable 132 ; CHECK-NEXT: } 133 define void @indbrtest5(i1 %cond, i8* %anchor) nounwind { 134 entry: 135 %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest5, %L1), i8* blockaddress(@indbrtest5, %L2) 136 ; This needs to have more than one successor for this test, otherwise it gets 137 ; replaced with an unconditional branch to the single successor. 138 indirectbr i8* %indirect.goto.dest, [label %L3, label %L4] 139 140 L1: 141 call void @A() 142 ret void 143 L2: 144 call void @C() 145 ret void 146 L3: 147 call void @foo() 148 ret void 149 L4: 150 call void @foo() 151 152 ; This keeps blockaddresses not otherwise listed as successors from being zapped 153 ; before SimplifyCFG even looks at the indirectbr. 154 indirectbr i8* %anchor, [label %L1, label %L2] 155 } 156 157 ; The same as above, except the selected addresses are equal. 158 159 ; CHECK-LABEL: @indbrtest6( 160 ; CHECK-NEXT: entry: 161 ; CHECK-NEXT: unreachable 162 ; CHECK-NEXT: } 163 define void @indbrtest6(i1 %cond, i8* %anchor) nounwind { 164 entry: 165 %indirect.goto.dest = select i1 %cond, i8* blockaddress(@indbrtest6, %L1), i8* blockaddress(@indbrtest6, %L1) 166 ; This needs to have more than one successor for this test, otherwise it gets 167 ; replaced with an unconditional branch to the single successor. 168 indirectbr i8* %indirect.goto.dest, [label %L2, label %L3] 169 170 L1: 171 call void @A() 172 ret void 173 L2: 174 call void @C() 175 ret void 176 L3: 177 call void @foo() 178 179 ; This keeps blockaddresses not otherwise listed as successors from being zapped 180 ; before SimplifyCFG even looks at the indirectbr. 181 indirectbr i8* %anchor, [label %L1, label %L2] 182 } 183 184 ; PR10072 185 186 @xblkx.bbs = internal unnamed_addr constant [9 x i8*] [i8* blockaddress(@indbrtest7, %xblkx.begin), i8* blockaddress(@indbrtest7, %xblkx.begin3), i8* blockaddress(@indbrtest7, %xblkx.begin4), i8* blockaddress(@indbrtest7, %xblkx.begin5), i8* blockaddress(@indbrtest7, %xblkx.begin6), i8* blockaddress(@indbrtest7, %xblkx.begin7), i8* blockaddress(@indbrtest7, %xblkx.begin8), i8* blockaddress(@indbrtest7, %xblkx.begin9), i8* blockaddress(@indbrtest7, %xblkx.end)] 187 188 define void @indbrtest7() { 189 escape-string.top: 190 %xval202x = call i32 @xfunc5x() 191 br label %xlab5x 192 193 xlab8x: ; preds = %xlab5x 194 %xvaluex = call i32 @xselectorx() 195 %xblkx.x = getelementptr [9 x i8*], [9 x i8*]* @xblkx.bbs, i32 0, i32 %xvaluex 196 %xblkx.load = load i8*, i8** %xblkx.x 197 indirectbr i8* %xblkx.load, [label %xblkx.begin, label %xblkx.begin3, label %xblkx.begin4, label %xblkx.begin5, label %xblkx.begin6, label %xblkx.begin7, label %xblkx.begin8, label %xblkx.begin9, label %xblkx.end] 198 199 xblkx.begin: 200 br label %xblkx.end 201 202 xblkx.begin3: 203 br label %xblkx.end 204 205 xblkx.begin4: 206 br label %xblkx.end 207 208 xblkx.begin5: 209 br label %xblkx.end 210 211 xblkx.begin6: 212 br label %xblkx.end 213 214 xblkx.begin7: 215 br label %xblkx.end 216 217 xblkx.begin8: 218 br label %xblkx.end 219 220 xblkx.begin9: 221 br label %xblkx.end 222 223 xblkx.end: 224 %yes.0 = phi i1 [ false, %xblkx.begin ], [ true, %xlab8x ], [ false, %xblkx.begin9 ], [ false, %xblkx.begin8 ], [ false, %xblkx.begin7 ], [ false, %xblkx.begin6 ], [ false, %xblkx.begin5 ], [ true, %xblkx.begin4 ], [ false, %xblkx.begin3 ] 225 br i1 %yes.0, label %v2j, label %xlab17x 226 227 v2j: 228 ; CHECK: %xunusedx = call i32 @xactionx() 229 %xunusedx = call i32 @xactionx() 230 br label %xlab4x 231 232 xlab17x: 233 br label %xlab4x 234 235 xlab4x: 236 %incr19 = add i32 %xval704x.0, 1 237 br label %xlab5x 238 239 xlab5x: 240 %xval704x.0 = phi i32 [ 0, %escape-string.top ], [ %incr19, %xlab4x ] 241 %xval10x = icmp ult i32 %xval704x.0, %xval202x 242 br i1 %xval10x, label %xlab8x, label %xlab9x 243 244 xlab9x: 245 ret void 246 } 247 248 declare i32 @xfunc5x() 249 declare i8 @xfunc7x() 250 declare i32 @xselectorx() 251 declare i32 @xactionx() 252