| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s |
| |
| declare void @llvm.assume(i1) |
| |
| declare void @may_unwind() |
| |
| declare void @use(i1) |
| |
| define i1 @assume_dominates(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_dominates( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] |
| ; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_4]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| br i1 %c, label %then, label %else |
| |
| then: |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| ret i1 %res.2 |
| |
| else: |
| %t.3 = icmp ule i8 %add.1, %b |
| %t.4 = icmp ule i8 %a, %b |
| %res.3 = xor i1 %t.3, %t.4 |
| %add.2.1 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2.1, %b |
| %res.4 = xor i1 %res.3, %c.2 |
| ret i1 %res.4 |
| } |
| |
| define i1 @assume_dominates_with_may_unwind_call_before_assume(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_dominates_with_may_unwind_call_before_assume( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] |
| ; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_4]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @may_unwind() |
| call void @llvm.assume(i1 %cmp.1) |
| br i1 %c, label %then, label %else |
| |
| then: |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| ret i1 %res.2 |
| |
| else: |
| %t.3 = icmp ule i8 %add.1, %b |
| %t.4 = icmp ule i8 %a, %b |
| %res.3 = xor i1 %t.3, %t.4 |
| %add.2.1 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2.1, %b |
| %res.4 = xor i1 %res.3, %c.2 |
| ret i1 %res.4 |
| } |
| |
| define i1 @assume_dominates_with_may_unwind_call_after_assume(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_dominates_with_may_unwind_call_after_assume( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[RES_3:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] |
| ; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_4]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| call void @may_unwind() |
| br i1 %c, label %then, label %else |
| |
| then: |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| ret i1 %res.2 |
| |
| else: |
| %t.3 = icmp ule i8 %add.1, %b |
| %t.4 = icmp ule i8 %a, %b |
| %res.3 = xor i1 %t.3, %t.4 |
| %add.2.1 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2.1, %b |
| %res.4 = xor i1 %res.3, %c.2 |
| ret i1 %res.4 |
| } |
| |
| ; Test case from PR54217. |
| define i1 @assume_does_not_dominates_successor_with_may_unwind_call_before_assume(i16 %a, i1 %i.0) { |
| ; CHECK-LABEL: @assume_does_not_dominates_successor_with_may_unwind_call_before_assume( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[I_0:%.*]], label [[EXIT:%.*]], label [[IF_THEN:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i16 [[A:%.*]], 0 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[C_1]]) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp eq i16 [[A]], 0 |
| ; CHECK-NEXT: ret i1 [[C_2]] |
| ; |
| entry: |
| br i1 %i.0, label %exit, label %if.then |
| |
| if.then: |
| call void @may_unwind() |
| %c.1 = icmp eq i16 %a, 0 |
| call void @llvm.assume(i1 %c.1) |
| br label %exit |
| |
| exit: |
| %c.2 = icmp eq i16 %a, 0 |
| ret i1 %c.2 |
| } |
| |
| define i1 @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch(i16 %a) { |
| ; CHECK-LABEL: @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i16 [[A:%.*]], 0 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[C_1]]) |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| entry: |
| call void @may_unwind() |
| %c.1 = icmp eq i16 %a, 0 |
| call void @llvm.assume(i1 %c.1) |
| br label %exit |
| |
| exit: |
| %c.2 = icmp eq i16 %a, 0 |
| ret i1 %c.2 |
| } |
| |
| define i1 @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch_2(i16 %a, i1 %c) { |
| ; CHECK-LABEL: @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch_2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i16 [[A:%.*]], 0 |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[C_1]]) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp eq i16 [[A]], 0 |
| ; CHECK-NEXT: ret i1 [[C_2]] |
| ; |
| entry: |
| br i1 %c, label %then, label %exit |
| |
| then: |
| call void @may_unwind() |
| %c.1 = icmp eq i16 %a, 0 |
| call void @llvm.assume(i1 %c.1) |
| br label %exit |
| |
| exit: |
| %c.2 = icmp eq i16 %a, 0 |
| ret i1 %c.2 |
| } |
| |
| define i1 @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch_cycle(i16 %a, i1 %c) { |
| ; CHECK-LABEL: @assume_dominates_successor_with_may_unwind_call_before_assume_uncond_branch_cycle( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i16 [[A:%.*]], 0 |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[C_1]]) |
| ; CHECK-NEXT: br label [[THEN]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp eq i16 [[A]], 0 |
| ; CHECK-NEXT: ret i1 [[C_2]] |
| ; |
| entry: |
| br i1 %c, label %then, label %exit |
| |
| then: |
| call void @may_unwind() |
| %c.1 = icmp eq i16 %a, 0 |
| call void @use(i1 %c.1) |
| call void @llvm.assume(i1 %c.1) |
| br label %then |
| |
| exit: |
| %c.2 = icmp eq i16 %a, 0 |
| ret i1 %c.2 |
| } |
| |
| define i1 @assume_single_bb(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_single_bb( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| ret i1 %res.2 |
| } |
| |
| define i1 @assume_same_bb(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]] |
| ; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] |
| ; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_4]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| br i1 %c, label %then, label %else |
| |
| then: |
| call void @llvm.assume(i1 %cmp.1) |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| ret i1 %res.2 |
| |
| else: |
| %t.3 = icmp ule i8 %add.1, %b |
| %t.4 = icmp ule i8 %a, %b |
| %res.3 = xor i1 %t.3, %t.4 |
| %add.2.1 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2.1, %b |
| %res.4 = xor i1 %res.3, %c.2 |
| ret i1 %res.4 |
| } |
| |
| define i1 @assume_same_bb2(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb2( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| br label %exit |
| |
| exit: |
| ret i1 %res.2 |
| } |
| |
| |
| ; TODO: Keep track of position of assume and may unwinding calls, simplify |
| ; conditions if possible. |
| define i1 @assume_same_bb_after_may_exiting_call(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb_after_may_exiting_call( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @may_unwind() |
| call void @llvm.assume(i1 %cmp.1) |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| br label %exit |
| |
| exit: |
| ret i1 %res.2 |
| } |
| |
| ; TODO: Keep track of position of assume and may unwinding calls, simplify |
| ; conditions if possible. |
| define i1 @assume_same_bb_before_may_exiting_call(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb_before_may_exiting_call( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| call void @may_unwind() |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| br label %exit |
| |
| exit: |
| ret i1 %res.2 |
| } |
| |
| define i1 @assume_same_bb_after_condition(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb_after_condition( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B:%.*]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %t.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %t.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.1 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @llvm.assume(i1 %cmp.1) |
| br label %exit |
| |
| exit: |
| ret i1 %res.2 |
| } |
| |
| ; The function may exit before the assume if @may_unwind unwinds. Conditions |
| ; before the call cannot be simplified. |
| define i1 @assume_same_bb_after_condition_may_unwind_between(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_same_bb_after_condition_may_unwind_between( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[A]], [[B]] |
| ; CHECK-NEXT: call void @use(i1 [[C_2]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[C_1]], [[C_2]] |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_3:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: call void @use(i1 [[C_3]]) |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_3]] |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %c.1 = icmp ule i8 %add.1, %b |
| call void @use(i1 %c.1) |
| %c.2 = icmp ule i8 %a, %b |
| call void @use(i1 %c.2) |
| %res.1 = xor i1 %c.1, %c.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.3 = icmp ule i8 %add.2, %b |
| call void @use(i1 %c.3) |
| %res.2 = xor i1 %res.1, %c.3 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| call void @may_unwind() |
| call void @llvm.assume(i1 %cmp.1) |
| br label %exit |
| |
| exit: |
| ret i1 %res.2 |
| } |
| |
| ; The information of from the assume can be used to simplify %t.2. |
| define i1 @assume_single_bb_conditions_after_assume(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_single_bb_conditions_after_assume( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| %c.1 = icmp ule i8 %add.1, %b |
| call void @use(i1 %c.1) |
| |
| call void @may_unwind() |
| call void @llvm.assume(i1 %cmp.1) |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %c.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.2 |
| ret i1 %res.2 |
| } |
| |
| ; The information of from the assume can be used to simplify %t.2. |
| ; TODO |
| define i1 @assume_single_bb_assume_at_end_after_may_unwind(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @assume_single_bb_assume_at_end_after_may_unwind( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[C_1]], [[T_2]] |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_2]] |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| %c.1 = icmp ule i8 %add.1, %b |
| call void @use(i1 %c.1) |
| |
| call void @may_unwind() |
| %t.2 = icmp ule i8 %a, %b |
| %res.1 = xor i1 %c.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.2 |
| call void @llvm.assume(i1 %cmp.1) |
| ret i1 %res.2 |
| } |
| |
| ; The definition of %t.2 is before the @llvm.assume call, but all uses are |
| ; after the call. %t.2 can be simplified. |
| ; TODO |
| define i1 @all_uses_after_assume(i8 %a, i8 %b, i1 %c) { |
| ; CHECK-LABEL: @all_uses_after_assume( |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: call void @may_unwind() |
| ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) |
| ; CHECK-NEXT: [[RES_1:%.*]] = xor i1 true, true |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2]], [[B]] |
| ; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_2]] |
| ; CHECK-NEXT: ret i1 [[RES_2]] |
| ; |
| %add.1 = add nsw nuw i8 %a, 1 |
| %cmp.1 = icmp ule i8 %add.1, %b |
| %c.1 = icmp ule i8 %add.1, %b |
| %t.2 = icmp ule i8 %a, %b |
| call void @use(i1 %c.1) |
| |
| call void @may_unwind() |
| call void @llvm.assume(i1 %cmp.1) |
| %res.1 = xor i1 %c.1, %t.2 |
| %add.2 = add nsw nuw i8 %a, 2 |
| %c.2 = icmp ule i8 %add.2, %b |
| %res.2 = xor i1 %res.1, %c.2 |
| ret i1 %res.2 |
| } |
| |
| define i1 @test_order_assume_and_conds_in_different_bb(i16 %a, ptr %dst) { |
| ; CHECK-LABEL: @test_order_assume_and_conds_in_different_bb( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp ult i16 [[A:%.*]], 10 |
| ; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: ret i1 false |
| ; CHECK: else: |
| ; CHECK-NEXT: store volatile float 0.000000e+00, ptr [[DST:%.*]], align 4 |
| ; CHECK-NEXT: [[C_2:%.*]] = icmp eq i16 [[A]], 20 |
| ; CHECK-NEXT: tail call void @llvm.assume(i1 [[C_2]]) |
| ; CHECK-NEXT: ret i1 true |
| ; |
| entry: |
| %c.1 = icmp ult i16 %a, 10 |
| br i1 %c.1, label %then, label %else |
| |
| then: |
| ret i1 0 |
| |
| else: |
| store volatile float 0.000000e+00, ptr %dst |
| %c.2 = icmp eq i16 %a, 20 |
| tail call void @llvm.assume(i1 %c.2) |
| ret i1 %c.2 |
| } |