1; RUN: opt -S -jump-threading < %s | FileCheck %s 2 3declare void @foo() 4declare void @bar() 5declare void @baz() 6declare void @quux() 7 8 9; Jump threading of branch with select as condition. 10; Mostly theoretical since instruction combining simplifies all selects of 11; booleans where at least one operand is true/false/undef. 12 13; CHECK-LABEL: @test_br( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: br i1 %cond, label %L1, 16define void @test_br(i1 %cond, i1 %value) nounwind { 17entry: 18 br i1 %cond, label %L0, label %L3 19L0: 20 %expr = select i1 %cond, i1 true, i1 %value 21 br i1 %expr, label %L1, label %L2 22 23L1: 24 call void @foo() 25 ret void 26L2: 27 call void @bar() 28 ret void 29L3: 30 call void @baz() 31 br label %L0 32} 33 34 35; Jump threading of switch with select as condition. 36 37; CHECK-LABEL: @test_switch( 38; CHECK-NEXT: entry: 39; CHECK-NEXT: br i1 %cond, label %L1, 40define void @test_switch(i1 %cond, i8 %value) nounwind { 41entry: 42 br i1 %cond, label %L0, label %L4 43L0: 44 %expr = select i1 %cond, i8 1, i8 %value 45 switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2] 46 47L1: 48 call void @foo() 49 ret void 50L2: 51 call void @bar() 52 ret void 53L3: 54 call void @baz() 55 ret void 56L4: 57 call void @quux() 58 br label %L0 59} 60 61; Make sure the blocks in the indirectbr test aren't trivially removable as 62; successors by taking their addresses. 63@anchor = constant [3 x i8*] [ 64 i8* blockaddress(@test_indirectbr, %L1), 65 i8* blockaddress(@test_indirectbr, %L2), 66 i8* blockaddress(@test_indirectbr, %L3) 67] 68 69 70; Jump threading of indirectbr with select as address. 71 72; CHECK-LABEL: @test_indirectbr( 73; CHECK-NEXT: entry: 74; CHECK-NEXT: br i1 %cond, label %L1, label %L3 75define void @test_indirectbr(i1 %cond, i8* %address) nounwind { 76entry: 77 br i1 %cond, label %L0, label %L3 78L0: 79 %indirect.goto.dest = select i1 %cond, i8* blockaddress(@test_indirectbr, %L1), i8* %address 80 indirectbr i8* %indirect.goto.dest, [label %L1, label %L2, label %L3] 81 82L1: 83 call void @foo() 84 ret void 85L2: 86 call void @bar() 87 ret void 88L3: 89 call void @baz() 90 ret void 91} 92 93 94; A more complicated case: the condition is a select based on a comparison. 95 96; CHECK-LABEL: @test_switch_cmp( 97; CHECK-NEXT: entry: 98; CHECK-NEXT: br i1 %cond, label %L0, label %[[THREADED:[A-Za-z.0-9]+]] 99; CHECK: [[THREADED]]: 100; CHECK-NEXT: call void @quux 101; CHECK-NEXT: br label %L1 102define void @test_switch_cmp(i1 %cond, i32 %val, i8 %value) nounwind { 103entry: 104 br i1 %cond, label %L0, label %L4 105L0: 106 %val.phi = phi i32 [%val, %entry], [-1, %L4] 107 %cmp = icmp slt i32 %val.phi, 0 108 %expr = select i1 %cmp, i8 1, i8 %value 109 switch i8 %expr, label %L3 [i8 1, label %L1 i8 2, label %L2] 110 111L1: 112 call void @foo() 113 ret void 114L2: 115 call void @bar() 116 ret void 117L3: 118 call void @baz() 119 ret void 120L4: 121 call void @quux() 122 br label %L0 123} 124 125; Make sure the edge value of %0 from entry to L2 includes 0 and L3 is 126; reachable. 127; CHECK: test_switch_default 128; CHECK: entry: 129; CHECK: load 130; CHECK: icmp 131; CHECK: [[THREADED:[A-Za-z.0-9]+]]: 132; CHECK: store 133; CHECK: br 134; CHECK: L2: 135; CHECK: icmp 136define void @test_switch_default(i32* nocapture %status) nounwind { 137entry: 138 %0 = load i32, i32* %status, align 4 139 switch i32 %0, label %L2 [ 140 i32 5061, label %L1 141 i32 0, label %L2 142 ] 143 144L1: 145 store i32 10025, i32* %status, align 4 146 br label %L2 147 148L2: 149 %1 = load i32, i32* %status, align 4 150 %cmp57.i = icmp eq i32 %1, 0 151 br i1 %cmp57.i, label %L3, label %L4 152 153L3: 154 store i32 10000, i32* %status, align 4 155 br label %L4 156 157L4: 158 ret void 159} 160 161define void @unfold1(double %x, double %y) nounwind { 162entry: 163 %sub = fsub double %x, %y 164 %cmp = fcmp ogt double %sub, 1.000000e+01 165 br i1 %cmp, label %cond.end4, label %cond.false 166 167cond.false: ; preds = %entry 168 %add = fadd double %x, %y 169 %cmp1 = fcmp ogt double %add, 1.000000e+01 170 %add. = select i1 %cmp1, double %add, double 0.000000e+00 171 br label %cond.end4 172 173cond.end4: ; preds = %entry, %cond.false 174 %cond5 = phi double [ %add., %cond.false ], [ %sub, %entry ] 175 %cmp6 = fcmp oeq double %cond5, 0.000000e+00 176 br i1 %cmp6, label %if.then, label %if.end 177 178if.then: ; preds = %cond.end4 179 call void @foo() 180 br label %if.end 181 182if.end: ; preds = %if.then, %cond.end4 183 ret void 184 185; CHECK-LABEL: @unfold1 186; CHECK: br i1 %cmp, label %cond.end4, label %cond.false 187; CHECK: br i1 %cmp1, label %cond.end4, label %if.then 188; CHECK: br i1 %cmp6, label %if.then, label %if.end 189; CHECK: br label %if.end 190} 191 192 193define void @unfold2(i32 %x, i32 %y) nounwind { 194entry: 195 %sub = sub nsw i32 %x, %y 196 %cmp = icmp sgt i32 %sub, 10 197 br i1 %cmp, label %cond.end4, label %cond.false 198 199cond.false: ; preds = %entry 200 %add = add nsw i32 %x, %y 201 %cmp1 = icmp sgt i32 %add, 10 202 %add. = select i1 %cmp1, i32 0, i32 %add 203 br label %cond.end4 204 205cond.end4: ; preds = %entry, %cond.false 206 %cond5 = phi i32 [ %add., %cond.false ], [ %sub, %entry ] 207 %cmp6 = icmp eq i32 %cond5, 0 208 br i1 %cmp6, label %if.then, label %if.end 209 210if.then: ; preds = %cond.end4 211 call void @foo() 212 br label %if.end 213 214if.end: ; preds = %if.then, %cond.end4 215 ret void 216 217; CHECK-LABEL: @unfold2 218; CHECK: br i1 %cmp, label %if.end, label %cond.false 219; CHECK: br i1 %cmp1, label %if.then, label %cond.end4 220; CHECK: br i1 %cmp6, label %if.then, label %if.end 221; CHECK: br label %if.end 222} 223