| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=correlated-propagation -S %s | FileCheck %s |
| |
| target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" |
| target triple = "x86_64-apple-macosx10.10.0" |
| |
| declare void @check1(i1) #1 |
| declare void @check2(i1) #1 |
| declare void @llvm.assume(i1) |
| |
| ; Make sure we propagate the value of %tmp35 to the true/false cases |
| |
| define void @test1(i64 %tmp35) { |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: bb: |
| ; CHECK-NEXT: [[TMP36:%.*]] = icmp sgt i64 [[TMP35:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[TMP36]], label [[BB_TRUE:%.*]], label [[BB_FALSE:%.*]] |
| ; CHECK: bb_true: |
| ; CHECK-NEXT: tail call void @check1(i1 false) #[[ATTR2:[0-9]+]] |
| ; CHECK-NEXT: unreachable |
| ; CHECK: bb_false: |
| ; CHECK-NEXT: tail call void @check2(i1 true) #[[ATTR2]] |
| ; CHECK-NEXT: unreachable |
| ; |
| bb: |
| %tmp36 = icmp sgt i64 %tmp35, 0 |
| br i1 %tmp36, label %bb_true, label %bb_false |
| |
| bb_true: |
| %tmp47 = icmp slt i64 %tmp35, 0 |
| tail call void @check1(i1 %tmp47) #4 |
| unreachable |
| |
| bb_false: |
| %tmp48 = icmp sle i64 %tmp35, 0 |
| tail call void @check2(i1 %tmp48) #4 |
| unreachable |
| } |
| |
| ; This is the same as test1 but with a diamond to ensure we |
| ; get %tmp36 from both true and false BBs. |
| |
| define void @test2(i64 %tmp35, i1 %inner_cmp) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: bb: |
| ; CHECK-NEXT: [[TMP36:%.*]] = icmp sgt i64 [[TMP35:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[TMP36]], label [[BB_TRUE:%.*]], label [[BB_FALSE:%.*]] |
| ; CHECK: bb_true: |
| ; CHECK-NEXT: br i1 [[INNER_CMP:%.*]], label [[INNER_TRUE:%.*]], label [[INNER_FALSE:%.*]] |
| ; CHECK: inner_true: |
| ; CHECK-NEXT: br label [[MERGE:%.*]] |
| ; CHECK: inner_false: |
| ; CHECK-NEXT: br label [[MERGE]] |
| ; CHECK: merge: |
| ; CHECK-NEXT: tail call void @check1(i1 false) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: bb_false: |
| ; CHECK-NEXT: tail call void @check2(i1 true) #[[ATTR2]] |
| ; CHECK-NEXT: unreachable |
| ; |
| bb: |
| %tmp36 = icmp sgt i64 %tmp35, 0 |
| br i1 %tmp36, label %bb_true, label %bb_false |
| |
| bb_true: |
| br i1 %inner_cmp, label %inner_true, label %inner_false |
| |
| inner_true: |
| br label %merge |
| |
| inner_false: |
| br label %merge |
| |
| merge: |
| %tmp47 = icmp slt i64 %tmp35, 0 |
| tail call void @check1(i1 %tmp47) #0 |
| unreachable |
| |
| bb_false: |
| %tmp48 = icmp sle i64 %tmp35, 0 |
| tail call void @check2(i1 %tmp48) #4 |
| unreachable |
| } |
| |
| ; Make sure binary operator transfer functions are run when RHS is non-constant |
| |
| define i1 @test3(i32 %x, i32 %y) #0 { |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]] |
| ; CHECK: cont1: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] |
| ; CHECK: cont2: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: br label [[OUT]] |
| ; CHECK: out: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| entry: |
| %cmp1 = icmp ult i32 %x, 10 |
| br i1 %cmp1, label %cont1, label %out |
| |
| cont1: |
| %cmp2 = icmp ult i32 %y, 10 |
| br i1 %cmp2, label %cont2, label %out |
| |
| cont2: |
| %add = add i32 %x, %y |
| %cmp3 = icmp ult i32 %add, 25 |
| br label %out |
| |
| out: |
| %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ] |
| ret i1 %ret |
| } |
| |
| ; Same as previous but make sure nobody gets over-zealous |
| |
| define i1 @test4(i32 %x, i32 %y) #0 { |
| ; CHECK-LABEL: @test4( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]] |
| ; CHECK: cont1: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] |
| ; CHECK: cont2: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[ADD]], 15 |
| ; CHECK-NEXT: br label [[OUT]] |
| ; CHECK: out: |
| ; CHECK-NEXT: [[RET:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[CONT1]] ], [ [[CMP3]], [[CONT2]] ] |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| entry: |
| %cmp1 = icmp ult i32 %x, 10 |
| br i1 %cmp1, label %cont1, label %out |
| |
| cont1: |
| %cmp2 = icmp ult i32 %y, 10 |
| br i1 %cmp2, label %cont2, label %out |
| |
| cont2: |
| %add = add i32 %x, %y |
| %cmp3 = icmp ult i32 %add, 15 |
| br label %out |
| |
| out: |
| %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ] |
| ret i1 %ret |
| } |
| |
| ; Make sure binary operator transfer functions are run when RHS is non-constant |
| |
| define i1 @test5(i32 %x, i32 %y) #0 { |
| ; CHECK-LABEL: @test5( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 5 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]] |
| ; CHECK: cont1: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 5 |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] |
| ; CHECK: cont2: |
| ; CHECK-NEXT: [[SHIFTED:%.*]] = shl nuw nsw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: br label [[OUT]] |
| ; CHECK: out: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| entry: |
| %cmp1 = icmp ult i32 %x, 5 |
| br i1 %cmp1, label %cont1, label %out |
| |
| cont1: |
| %cmp2 = icmp ult i32 %y, 5 |
| br i1 %cmp2, label %cont2, label %out |
| |
| cont2: |
| %shifted = shl i32 %x, %y |
| %cmp3 = icmp ult i32 %shifted, 65536 |
| br label %out |
| |
| out: |
| %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ] |
| ret i1 %ret |
| } |
| |
| ; Same as previous but make sure nobody gets over-zealous |
| |
| define i1 @test6(i32 %x, i32 %y) #0 { |
| ; CHECK-LABEL: @test6( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 5 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]] |
| ; CHECK: cont1: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 15 |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] |
| ; CHECK: cont2: |
| ; CHECK-NEXT: [[SHIFTED:%.*]] = shl nuw nsw i32 [[X]], [[Y]] |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[SHIFTED]], 65536 |
| ; CHECK-NEXT: br label [[OUT]] |
| ; CHECK: out: |
| ; CHECK-NEXT: [[RET:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ true, [[CONT1]] ], [ [[CMP3]], [[CONT2]] ] |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| entry: |
| %cmp1 = icmp ult i32 %x, 5 |
| br i1 %cmp1, label %cont1, label %out |
| |
| cont1: |
| %cmp2 = icmp ult i32 %y, 15 |
| br i1 %cmp2, label %cont2, label %out |
| |
| cont2: |
| %shifted = shl i32 %x, %y |
| %cmp3 = icmp ult i32 %shifted, 65536 |
| br label %out |
| |
| out: |
| %ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont2 ] |
| ret i1 %ret |
| } |
| |
| define i1 @test7(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test7( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp sge i32 [[ADD]], 0 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp0 = icmp sge i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %add = add i32 %a, %b |
| %res = icmp sge i32 %add, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test8(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test8( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| begin: |
| %cmp0 = icmp sge i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %add = add nsw i32 %a, %b |
| %res = icmp sge i32 %add, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test10(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test10( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[A:%.*]], -256 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], [[B:%.*]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp uge i32 [[ADD]], -256 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp = icmp uge i32 %a, 4294967040 |
| br i1 %cmp, label %bb, label %exit |
| |
| bb: |
| %add = add i32 %a, %b |
| %res = icmp uge i32 %add, 4294967040 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test11(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test11( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[A:%.*]], -256 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], [[B:%.*]] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| begin: |
| %cmp = icmp uge i32 %a, 4294967040 |
| br i1 %cmp, label %bb, label %exit |
| |
| bb: |
| %add = add nuw i32 %a, %b |
| %res = icmp uge i32 %add, 4294967040 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test12(i32 %x) { |
| ; CHECK-LABEL: @test12( |
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[X:%.*]] to i64 |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[ZEXT]], 7 |
| ; CHECK-NEXT: [[SHR:%.*]] = lshr i64 [[MUL]], 32 |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[SHR]] to i32 |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %zext = zext i32 %x to i64 |
| %mul = mul nuw i64 %zext, 7 |
| %shr = lshr i64 %mul, 32 |
| %trunc = trunc i64 %shr to i32 |
| %cmp = icmp ult i32 %trunc, 7 |
| ret i1 %cmp |
| } |
| |
| define i1 @test13(i8 %x, ptr %p) { |
| ; CHECK-LABEL: @test13( |
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X:%.*]] to i64 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT]], 128 |
| ; CHECK-NEXT: store i64 [[ADD]], ptr [[P:%.*]], align 8 |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %zext = zext i8 %x to i64 |
| %add = add nuw nsw i64 %zext, 128 |
| %cmp = icmp ult i64 %add, 384 |
| ; Without this extra use, InstSimplify could handle this |
| store i64 %add, ptr %p |
| ret i1 %cmp |
| } |
| |
| define i1 @test14(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test14( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp sge i32 [[SUB]], 0 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp0 = icmp sge i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub i32 %a, %b |
| %res = icmp sge i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test15(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test15( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp sge i32 [[SUB]], 0 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp0 = icmp sge i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub nsw i32 %a, %b |
| %res = icmp sge i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test16(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test16( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sge i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| begin: |
| %cmp0 = icmp sge i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub nuw i32 %a, %b |
| %res = icmp sge i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test17(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test17( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp sle i32 [[SUB]], 0 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp0 = icmp sle i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub i32 %a, %b |
| %res = icmp sle i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test18(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test18( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nuw i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES:%.*]] = icmp sle i32 [[SUB]], 0 |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[BB]] ] |
| ; CHECK-NEXT: ret i1 [[IV]] |
| ; |
| begin: |
| %cmp0 = icmp sle i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub nuw i32 %a, %b |
| %res = icmp sle i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test19(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test19( |
| ; CHECK-NEXT: begin: |
| ; CHECK-NEXT: [[CMP0:%.*]] = icmp sle i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp sge i32 [[B:%.*]], 0 |
| ; CHECK-NEXT: [[BR:%.*]] = and i1 [[CMP0]], [[CMP1]] |
| ; CHECK-NEXT: br i1 [[BR]], label [[BB:%.*]], label [[EXIT:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| begin: |
| %cmp0 = icmp sle i32 %a, 0 |
| %cmp1 = icmp sge i32 %b, 0 |
| %br = and i1 %cmp0, %cmp1 |
| br i1 %br, label %bb, label %exit |
| |
| bb: |
| %sub = sub nsw i32 %a, %b |
| %res = icmp sle i32 %sub, 0 |
| br label %exit |
| |
| exit: |
| %iv = phi i1 [ true, %begin ], [ %res, %bb ] |
| ret i1 %iv |
| } |
| |
| define i1 @test_br_cmp_with_offset(i64 %idx) { |
| ; CHECK-LABEL: @test_br_cmp_with_offset( |
| ; CHECK-NEXT: [[IDX_OFF1:%.*]] = add i64 [[IDX:%.*]], -5 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IDX_OFF1]], 3 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[IDX_OFF2:%.*]] = add nsw i64 [[IDX]], -1 |
| ; CHECK-NEXT: ret i1 true |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret i1 undef |
| ; |
| %idx.off1 = add i64 %idx, -5 |
| %cmp1 = icmp ult i64 %idx.off1, 3 |
| br i1 %cmp1, label %if.true, label %if.false |
| |
| if.true: |
| %idx.off2 = add i64 %idx, -1 |
| %cmp2 = icmp ult i64 %idx.off2, 10 |
| ret i1 %cmp2 |
| |
| if.false: |
| ret i1 undef |
| } |
| |
| define i1 @test_assume_cmp_with_offset(i64 %idx) { |
| ; CHECK-LABEL: @test_assume_cmp_with_offset( |
| ; CHECK-NEXT: [[IDX_OFF1:%.*]] = add i64 [[IDX:%.*]], -5 |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IDX_OFF1]], 3 |
| ; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP1]]) |
| ; CHECK-NEXT: [[IDX_OFF2:%.*]] = add nsw i64 [[IDX]], -1 |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %idx.off1 = add i64 %idx, -5 |
| %cmp1 = icmp ult i64 %idx.off1, 3 |
| tail call void @llvm.assume(i1 %cmp1) |
| %idx.off2 = add i64 %idx, -1 |
| %cmp2 = icmp ult i64 %idx.off2, 10 |
| ret i1 %cmp2 |
| } |
| |
| define void @test_cmp_phi(i8 %a) { |
| ; CHECK-LABEL: @test_cmp_phi( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C0:%.*]] = icmp ult i8 [[A:%.*]], 2 |
| ; CHECK-NEXT: br i1 [[C0]], label [[LOOP:%.*]], label [[EXIT:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[P:%.*]] = phi i8 [ [[A]], [[ENTRY:%.*]] ], [ [[B:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[C1:%.*]] = icmp ne i8 [[P]], 0 |
| ; CHECK-NEXT: [[C4:%.*]] = call i1 @get_bool() |
| ; CHECK-NEXT: [[B]] = zext i1 [[C4]] to i8 |
| ; CHECK-NEXT: br i1 [[C1]], label [[LOOP]], label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %c0 = icmp ult i8 %a, 2 |
| br i1 %c0, label %loop, label %exit |
| |
| loop: |
| %p = phi i8 [ %a, %entry ], [ %b, %loop ] |
| %c1 = icmp ne i8 %p, 0 |
| %c2 = icmp ne i8 %p, 2 |
| %c3 = and i1 %c1, %c2 |
| %c4 = call i1 @get_bool() |
| %b = zext i1 %c4 to i8 |
| br i1 %c3, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| declare i1 @get_bool() |
| |
| define void @test_icmp_or_ult(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_or_ult( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[OR]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp uge i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp uge i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %or = or i32 %a, %b |
| %cmp = icmp ult i32 %or, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ult i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ult i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp uge i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp uge i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_or_ule(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_or_ule( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[OR]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ugt i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp ugt i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %or = or i32 %a, %b |
| %cmp = icmp ule i32 %or, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ule i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ule i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp ugt i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ugt i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_or_ugt(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_or_ugt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[OR]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %or = or i32 %a, %b |
| %cmp = icmp ugt i32 %or, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ugt i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ugt i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp ule i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ule i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_or_uge(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_or_uge( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[OR]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp uge i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %or = or i32 %a, %b |
| %cmp = icmp uge i32 %or, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp uge i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp ult i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ult i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_or_slt(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_or_slt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[OR:%.*]] = or i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[OR]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp slt i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp sge i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp sge i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %or = or i32 %a, %b |
| %cmp = icmp slt i32 %or, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp slt i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp slt i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp sge i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp sge i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_and_ugt(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_and_ugt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[AND]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ule i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp ule i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %and = and i32 %a, %b |
| %cmp = icmp ugt i32 %and, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ugt i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ugt i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp ule i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ule i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_and_uge(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_and_uge( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[AND]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp ult i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %and = and i32 %a, %b |
| %cmp = icmp uge i32 %and, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp uge i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp ult i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ult i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_and_ult(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_and_ult( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[AND]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %and = and i32 %a, %b |
| %cmp = icmp ult i32 %and, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ult i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ult i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp uge i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp uge i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_and_sgt(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @test_icmp_and_sgt( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[AND]], 42 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp sle i32 [[A]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp sle i32 [[B]], 42 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %and = and i32 %a, %b |
| %cmp = icmp sgt i32 %and, 42 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp sgt i32 %a, 42 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp sgt i32 %b, 42 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| %cmp4 = icmp sle i32 %a, 42 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp sle i32 %b, 42 |
| call void @check1(i1 %cmp5) |
| ret void |
| } |
| |
| define void @test_icmp_mask_eq_two_values(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_eq_two_values( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], -2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 10 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 false) |
| ; CHECK-NEXT: call void @check1(i1 false) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, -2 |
| %cmp = icmp eq i32 %and, 10 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 10 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ule i32 %a, 11 |
| call void @check1(i1 %cmp3) |
| %cmp4 = icmp ult i32 %a, 10 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ugt i32 %a, 11 |
| call void @check1(i1 %cmp5) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_eq_bit_set(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_eq_bit_set( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 32 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 32 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp uge i32 [[A]], 33 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, 32 |
| %cmp = icmp eq i32 %and, 32 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 32 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp uge i32 %a, 33 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_eq_bit_unset(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_eq_bit_unset( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 32 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i32 [[A]], -34 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, 32 |
| %cmp = icmp eq i32 %and, 0 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ule i32 %a, -33 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ule i32 %a, -34 |
| call void @check1(i1 %cmp3) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_eq_wrong_predicate(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_eq_wrong_predicate( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], -2 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 10 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i32 [[A]], 10 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i32 [[A]], 11 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 10 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp ugt i32 [[A]], 11 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, -2 |
| %cmp = icmp ne i32 %and, 10 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 10 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ule i32 %a, 11 |
| call void @check1(i1 %cmp3) |
| %cmp4 = icmp ult i32 %a, 10 |
| call void @check1(i1 %cmp4) |
| %cmp5 = icmp ugt i32 %a, 11 |
| call void @check1(i1 %cmp5) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_ne(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_ne( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 6 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[A]], 2 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], -1 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, 6 |
| %cmp = icmp ne i32 %and, 0 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 2 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ugt i32 %a, 2 |
| call void @check1(i1 %cmp3) |
| %cmp4 = icmp ult i32 %a, -1 |
| call void @check1(i1 %cmp4) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_ne_nonzero_cmp(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_ne_nonzero_cmp( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 6 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 6 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i32 [[A]], 2 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[A]], 2 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP3]]) |
| ; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], -1 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP4]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, 6 |
| %cmp = icmp ne i32 %and, 6 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp uge i32 %a, 2 |
| call void @check1(i1 %cmp2) |
| %cmp3 = icmp ugt i32 %a, 2 |
| call void @check1(i1 %cmp3) |
| %cmp4 = icmp ult i32 %a, -1 |
| call void @check1(i1 %cmp4) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @test_icmp_mask_ne_zero_mask(i32 %a) { |
| ; CHECK-LABEL: @test_icmp_mask_ne_zero_mask( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A:%.*]], 0 |
| ; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] |
| ; CHECK: if.true: |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[A]], 0 |
| ; CHECK-NEXT: call void @check1(i1 [[CMP2]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: if.false: |
| ; CHECK-NEXT: ret void |
| ; |
| %and = and i32 %a, 0 |
| %cmp = icmp ne i32 %and, 0 |
| br i1 %cmp, label %if.true, label %if.false |
| |
| if.true: |
| %cmp2 = icmp ne i32 %a, 0 |
| call void @check1(i1 %cmp2) |
| ret void |
| |
| if.false: |
| ret void |
| } |
| |
| define void @non_const_range(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @non_const_range( |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], 11 |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 21 |
| ; CHECK-NEXT: [[AND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false |
| ; CHECK-NEXT: br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: [[A_100:%.*]] = add nuw nsw i32 [[A]], 100 |
| ; CHECK-NEXT: call void @check1(i1 true) |
| ; CHECK-NEXT: call void @check1(i1 false) |
| ; CHECK-NEXT: [[A_10:%.*]] = add nuw nsw i32 [[A]], 10 |
| ; CHECK-NEXT: [[CMP5:%.*]] = icmp ne i32 [[A_10]], [[B]] |
| ; CHECK-NEXT: call void @check1(i1 [[CMP5]]) |
| ; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[A_10]], [[B]] |
| ; CHECK-NEXT: call void @check1(i1 [[CMP6]]) |
| ; CHECK-NEXT: ret void |
| ; CHECK: else: |
| ; CHECK-NEXT: ret void |
| ; |
| %cmp1 = icmp ult i32 %a, 11 |
| %cmp2 = icmp ult i32 %b, 21 |
| %and = select i1 %cmp1, i1 %cmp2, i1 false |
| br i1 %and, label %if, label %else |
| |
| if: |
| %a.100 = add nuw nsw i32 %a, 100 |
| %cmp3 = icmp ne i32 %a.100, %b |
| call void @check1(i1 %cmp3) |
| %cmp4 = icmp eq i32 %a.100, %b |
| call void @check1(i1 %cmp4) |
| |
| %a.10 = add nuw nsw i32 %a, 10 |
| %cmp5 = icmp ne i32 %a.10, %b |
| call void @check1(i1 %cmp5) |
| %cmp6 = icmp eq i32 %a.10, %b |
| call void @check1(i1 %cmp6) |
| ret void |
| |
| else: |
| ret void |
| } |
| |
| define i1 @non_const_range_minmax(i8 %a, i8 %b) { |
| ; CHECK-LABEL: @non_const_range_minmax( |
| ; CHECK-NEXT: [[A2:%.*]] = call i8 @llvm.umin.i8(i8 [[A:%.*]], i8 10) |
| ; CHECK-NEXT: [[B2:%.*]] = call i8 @llvm.umax.i8(i8 [[B:%.*]], i8 11) |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %a2 = call i8 @llvm.umin.i8(i8 %a, i8 10) |
| %b2 = call i8 @llvm.umax.i8(i8 %b, i8 11) |
| %cmp1 = icmp ult i8 %a2, %b2 |
| ret i1 %cmp1 |
| } |
| |
| ; FIXME: Also support vectors. |
| define <2 x i1> @non_const_range_minmax_vec(<2 x i8> %a, <2 x i8> %b) { |
| ; CHECK-LABEL: @non_const_range_minmax_vec( |
| ; CHECK-NEXT: [[A2:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 10, i8 10>) |
| ; CHECK-NEXT: [[B2:%.*]] = call <2 x i8> @llvm.umax.v2i8(<2 x i8> [[B:%.*]], <2 x i8> <i8 11, i8 11>) |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i8> [[A2]], [[B2]] |
| ; CHECK-NEXT: ret <2 x i1> [[CMP1]] |
| ; |
| %a2 = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %a, <2 x i8> <i8 10, i8 10>) |
| %b2 = call <2 x i8> @llvm.umax.v2i8(<2 x i8> %b, <2 x i8> <i8 11, i8 11>) |
| %cmp1 = icmp ult <2 x i8> %a2, %b2 |
| ret <2 x i1> %cmp1 |
| } |
| |
| declare i8 @llvm.umin.i8(i8, i8) |
| declare i8 @llvm.umax.i8(i8, i8) |
| declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>) |
| declare <2 x i8> @llvm.umax.v2i8(<2 x i8>, <2 x i8>) |
| |
| attributes #4 = { noreturn } |