1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes=instcombine -S < %s | FileCheck %s 3 4declare void @use(i32 %x) 5declare i1 @cond() 6 7define void @test_01(i32 %x, i32 %y) { 8; CHECK-LABEL: @test_01( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] 11; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[UNREACHED:%.*]] 12; CHECK: unreached: 13; CHECK-NEXT: [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]]) 14; CHECK-NEXT: call void @use(i32 [[COMPARATOR]]) 15; CHECK-NEXT: unreachable 16; CHECK: exit: 17; CHECK-NEXT: ret void 18; 19entry: 20 %c1 = icmp eq i32 %x, %y 21 %c2 = icmp slt i32 %x, %y 22 %signed = select i1 %c2, i32 -1, i32 1 23 %comparator = select i1 %c1, i32 0, i32 %signed 24 br i1 %c2, label %exit, label %unreached 25 26unreached: 27 call void @use(i32 %comparator) 28 unreachable 29 30exit: 31 ret void 32} 33 34 35define void @test_02(i32 %x, i32 %y) { 36; CHECK-LABEL: @test_02( 37; CHECK-NEXT: entry: 38; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] 39; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]] 40; CHECK: medium: 41; CHECK-NEXT: [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]] 42; CHECK-NEXT: br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]] 43; CHECK: unreached: 44; CHECK-NEXT: [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]]) 45; CHECK-NEXT: call void @use(i32 [[COMPARATOR]]) 46; CHECK-NEXT: unreachable 47; CHECK: exit: 48; CHECK-NEXT: ret void 49; 50entry: 51 %c1 = icmp eq i32 %x, %y 52 %c2 = icmp slt i32 %x, %y 53 %signed = select i1 %c2, i32 -1, i32 1 54 %comparator = select i1 %c1, i32 0, i32 %signed 55 br i1 %c2, label %exit, label %medium 56 57medium: 58 %c3 = icmp sgt i32 %x, %y 59 br i1 %c3, label %exit, label %unreached 60 61unreached: 62 call void @use(i32 %comparator) 63 unreachable 64 65exit: 66 ret void 67} 68 69define i32 @test_03(i32 %x, i32 %y) { 70; CHECK-LABEL: @test_03( 71; CHECK-NEXT: entry: 72; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] 73; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]] 74; CHECK: medium: 75; CHECK-NEXT: [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]] 76; CHECK-NEXT: br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]] 77; CHECK: unreached: 78; CHECK-NEXT: [[COMPARATOR:%.*]] = call i32 @llvm.scmp.i32.i32(i32 [[X]], i32 [[Y]]) 79; CHECK-NEXT: ret i32 [[COMPARATOR]] 80; CHECK: exit: 81; CHECK-NEXT: ret i32 0 82; 83entry: 84 %c1 = icmp eq i32 %x, %y 85 %c2 = icmp slt i32 %x, %y 86 %signed = select i1 %c2, i32 -1, i32 1 87 %comparator = select i1 %c1, i32 0, i32 %signed 88 br i1 %c2, label %exit, label %medium 89 90medium: 91 %c3 = icmp sgt i32 %x, %y 92 br i1 %c3, label %exit, label %unreached 93 94unreached: 95 ret i32 %comparator 96 97exit: 98 ret i32 0 99} 100 101define i32 @test_04(i32 %x, i1 %c) { 102; CHECK-LABEL: @test_04( 103; CHECK-NEXT: bb0: 104; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] 105; CHECK: bb1: 106; CHECK-NEXT: br label [[BB3:%.*]] 107; CHECK: bb2: 108; CHECK-NEXT: br label [[BB3]] 109; CHECK: bb3: 110; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ 1, [[BB2]] ] 111; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1 112; CHECK-NEXT: [[R:%.*]] = add i32 [[P]], [[A]] 113; CHECK-NEXT: ret i32 [[R]] 114; 115bb0: 116 %a = add i32 %x, 1 117 br i1 %c, label %bb1, label %bb2 118bb1: 119 br label %bb3 120bb2: 121 br label %bb3 122bb3: 123 %p = phi i32 [0, %bb1], [1, %bb2] 124 %r = add i32 %p, %a 125 ret i32 %r 126} 127 128; Do not sink into a potentially hotter block. 129define i32 @test_05_neg(i32 %x, i1 %cond) { 130; CHECK-LABEL: @test_05_neg( 131; CHECK-NEXT: bb0: 132; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1 133; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] 134; CHECK: bb1: 135; CHECK-NEXT: br label [[BB3:%.*]] 136; CHECK: bb2: 137; CHECK-NEXT: [[CALL:%.*]] = call i1 @cond() 138; CHECK-NEXT: br i1 [[CALL]], label [[BB2]], label [[BB3]] 139; CHECK: bb3: 140; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ [[A]], [[BB2]] ] 141; CHECK-NEXT: ret i32 [[P]] 142; 143bb0: 144 %a = add i32 %x, 1 145 br i1 %cond, label %bb1, label %bb2 146bb1: 147 br label %bb3 148bb2: 149 %call = call i1 @cond() 150 br i1 %call, label %bb2, label %bb3 151bb3: 152 %p = phi i32 [0, %bb1], [%a, %bb2] 153 ret i32 %p 154} 155 156define i1 @sink_to_unreachable_ret(i16 %X) { 157; CHECK-LABEL: @sink_to_unreachable_ret( 158; CHECK-NEXT: entry: 159; CHECK-NEXT: br label [[LOOP:%.*]] 160; CHECK: loop: 161; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]] 162; CHECK: unreach: 163; CHECK-NEXT: ret i1 poison 164; 165entry: 166 br label %loop 167 168loop: 169 %p = icmp sgt i16 %X, 16 170 br i1 true, label %loop, label %unreach 171 172unreach: 173 ret i1 %p 174} 175 176define void @sink_to_unreachable_condbr(i16 %X) { 177; CHECK-LABEL: @sink_to_unreachable_condbr( 178; CHECK-NEXT: entry: 179; CHECK-NEXT: br label [[LOOP:%.*]] 180; CHECK: loop: 181; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]] 182; CHECK: unreach: 183; CHECK-NEXT: br i1 poison, label [[DUMMY:%.*]], label [[LOOP]] 184; CHECK: dummy: 185; CHECK-NEXT: unreachable 186; 187entry: 188 br label %loop 189 190loop: 191 %p = icmp sgt i16 %X, 16 192 br i1 true, label %loop, label %unreach 193 194unreach: 195 br i1 %p, label %dummy, label %loop 196 197dummy: 198 unreachable 199} 200 201define void @sink_to_unreachable_switch(i16 %X) { 202; CHECK-LABEL: @sink_to_unreachable_switch( 203; CHECK-NEXT: entry: 204; CHECK-NEXT: br label [[LOOP:%.*]] 205; CHECK: loop: 206; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]] 207; CHECK: unreach: 208; CHECK-NEXT: switch i16 poison, label [[UNREACH_RET:%.*]] [ 209; CHECK-NEXT: ] 210; CHECK: unreach.ret: 211; CHECK-NEXT: unreachable 212; 213entry: 214 br label %loop 215 216loop: 217 %quantum = srem i16 %X, 32 218 br i1 true, label %loop, label %unreach 219 220unreach: 221 switch i16 %quantum, label %unreach.ret [] 222 223unreach.ret: 224 unreachable 225} 226 227define void @sink_to_unreachable_indirectbr(ptr %Ptr) { 228; CHECK-LABEL: @sink_to_unreachable_indirectbr( 229; CHECK-NEXT: entry: 230; CHECK-NEXT: br label [[LOOP:%.*]] 231; CHECK: loop: 232; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]] 233; CHECK: unreach: 234; CHECK-NEXT: indirectbr ptr poison, [label %loop] 235; 236entry: 237 br label %loop 238 239loop: 240 %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1 241 br i1 true, label %loop, label %unreach 242 243unreach: 244 indirectbr ptr %gep, [label %loop] 245} 246 247define void @sink_to_unreachable_invoke(ptr %Ptr) personality ptr @__CxxFrameHandler3 { 248; CHECK-LABEL: @sink_to_unreachable_invoke( 249; CHECK-NEXT: entry: 250; CHECK-NEXT: br label [[LOOP:%.*]] 251; CHECK: loop: 252; CHECK-NEXT: br i1 true, label [[LOOP]], label [[UNREACH:%.*]] 253; CHECK: unreach: 254; CHECK-NEXT: invoke void poison(i1 false) 255; CHECK-NEXT: to label [[DUMMY:%.*]] unwind label [[ICATCH_DISPATCH:%.*]] 256; CHECK: unreach2: 257; CHECK-NEXT: invoke void @__CxxFrameHandler3(ptr poison) 258; CHECK-NEXT: to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]] 259; CHECK: unreach3: 260; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none [] 261; CHECK-NEXT: invoke void @__CxxFrameHandler3(ptr poison) [ "funclet"(token [[CLEAN]]) ] 262; CHECK-NEXT: to label [[DUMMY]] unwind label [[ICATCH_DISPATCH]] 263; CHECK: icatch.dispatch: 264; CHECK-NEXT: [[TMP1:%.*]] = catchswitch within none [label %icatch] unwind to caller 265; CHECK: icatch: 266; CHECK-NEXT: [[TMP2:%.*]] = catchpad within [[TMP1]] [ptr null, i32 64, ptr null] 267; CHECK-NEXT: catchret from [[TMP2]] to label [[DUMMY2:%.*]] 268; CHECK: dummy: 269; CHECK-NEXT: ret void 270; CHECK: dummy2: 271; CHECK-NEXT: ret void 272; 273entry: 274 br label %loop 275 276loop: 277 %gep = getelementptr inbounds ptr, ptr %Ptr, i16 1 278 br i1 true, label %loop, label %unreach 279 280unreach: 281 invoke void %gep(i1 false) 282 to label %dummy unwind label %icatch.dispatch 283 284unreach2: 285 invoke void @__CxxFrameHandler3(ptr %gep) 286 to label %dummy unwind label %icatch.dispatch 287 288unreach3: 289 %clean = cleanuppad within none [] 290 invoke void @__CxxFrameHandler3(ptr %gep) [ "funclet"(token %clean) ] 291 to label %dummy unwind label %icatch.dispatch 292 293icatch.dispatch: 294 %tmp1 = catchswitch within none [label %icatch] unwind to caller 295 296icatch: 297 %tmp2 = catchpad within %tmp1 [ptr null, i32 64, ptr null] 298 catchret from %tmp2 to label %dummy2 299 300dummy: 301 ret void 302 303dummy2: 304 ret void 305} 306 307declare void @may_throw() 308declare i32 @__CxxFrameHandler3(...) 309