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 9declare void @foo() 10declare void @A() 11declare void @B(i32) 12declare void @C() 13 14define void @indbrtest0(i8** %P, i8** %Q) { 15entry: 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** %Q 21 indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2] 22BB0: 23 call void @A() 24 br label %BB1 25BB1: 26 %x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ] 27 call void @B(i32 %x) 28 ret void 29BB2: 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 41define void @indbrtest1(i8** %P, i8** %Q) { 42entry: 43 store i8* blockaddress(@indbrtest1, %BB0), i8** %P 44 call void @foo() 45 %t = load i8** %Q 46 indirectbr i8* %t, [label %BB0, label %BB0] 47BB0: 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 59define void @indbrtest2(i8* %t) { 60entry: 61 indirectbr i8* %t, [label %BB0, label %BB0] 62BB0: 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: @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: 86define void @indbrtest3(i1 %cond, i8* %address) nounwind { 87entry: 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 91L1: 92 call void @A() 93 ret void 94L2: 95 call void @C() 96 ret void 97L3: 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: @indbrtest4 108; CHECK-NEXT: entry: 109; CHECK-NEXT: br label %L1 110define void @indbrtest4(i1 %cond) nounwind { 111entry: 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 115L1: 116 call void @A() 117 ret void 118L2: 119 call void @C() 120 ret void 121L3: 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: @indbrtest5 130; CHECK-NEXT: entry: 131; CHECK-NEXT: unreachable 132; CHECK-NEXT: } 133define void @indbrtest5(i1 %cond, i8* %anchor) nounwind { 134entry: 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 140L1: 141 call void @A() 142 ret void 143L2: 144 call void @C() 145 ret void 146L3: 147 call void @foo() 148 ret void 149L4: 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: @indbrtest6 160; CHECK-NEXT: entry: 161; CHECK-NEXT: unreachable 162; CHECK-NEXT: } 163define void @indbrtest6(i1 %cond, i8* %anchor) nounwind { 164entry: 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 170L1: 171 call void @A() 172 ret void 173L2: 174 call void @C() 175 ret void 176L3: 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 188define void @indbrtest7() { 189escape-string.top: 190 %xval202x = call i32 @xfunc5x() 191 br label %xlab5x 192 193xlab8x: ; preds = %xlab5x 194 %xvaluex = call i32 @xselectorx() 195 %xblkx.x = getelementptr [9 x i8*]* @xblkx.bbs, i32 0, i32 %xvaluex 196 %xblkx.load = load 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 199xblkx.begin: 200 br label %xblkx.end 201 202xblkx.begin3: 203 br label %xblkx.end 204 205xblkx.begin4: 206 br label %xblkx.end 207 208xblkx.begin5: 209 br label %xblkx.end 210 211xblkx.begin6: 212 br label %xblkx.end 213 214xblkx.begin7: 215 br label %xblkx.end 216 217xblkx.begin8: 218 br label %xblkx.end 219 220xblkx.begin9: 221 br label %xblkx.end 222 223xblkx.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 227v2j: 228; CHECK: %xunusedx = call i32 @xactionx() 229 %xunusedx = call i32 @xactionx() 230 br label %xlab4x 231 232xlab17x: 233 br label %xlab4x 234 235xlab4x: 236 %incr19 = add i32 %xval704x.0, 1 237 br label %xlab5x 238 239xlab5x: 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 244xlab9x: 245 ret void 246} 247 248declare i32 @xfunc5x() 249declare i8 @xfunc7x() 250declare i32 @xselectorx() 251declare i32 @xactionx() 252