| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s |
| |
| |
| define i1 @infer_nuw(i8 range(i8 0, 2) %A, i8 range(i8 0, 2) %B) { |
| ; CHECK-LABEL: define i1 @infer_nuw( |
| ; CHECK-SAME: i8 range(i8 0, 2) [[A:%.*]], i8 range(i8 0, 2) [[B:%.*]]) { |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[B]], [[A]] |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1 |
| ; CHECK-NEXT: ret i1 [[TRUNC]] |
| ; |
| %xor = xor i8 %B, %A |
| %trunc = trunc i8 %xor to i1 |
| ret i1 %trunc |
| } |
| |
| |
| define i4 @infer_nsw(i8 %A) { |
| ; CHECK-LABEL: define range(i4 -4, 4) i4 @infer_nsw( |
| ; CHECK-SAME: i8 [[A:%.*]]) { |
| ; CHECK-NEXT: [[ASHR:%.*]] = ashr i8 [[A]], 5 |
| ; CHECK-NEXT: [[B:%.*]] = trunc nsw i8 [[ASHR]] to i4 |
| ; CHECK-NEXT: ret i4 [[B]] |
| ; |
| %ashr = ashr i8 %A, 5 |
| %result = trunc i8 %ashr to i4 |
| ret i4 %result |
| } |
| |
| |
| define i8 @infer_nuw_nsw(i16 range(i16 -5, -3) %A, i16 range(i16 -5, -3) %B) { |
| ; CHECK-LABEL: define range(i8 0, 8) i8 @infer_nuw_nsw( |
| ; CHECK-SAME: i16 range(i16 -5, -3) [[A:%.*]], i16 range(i16 -5, -3) [[B:%.*]]) { |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i16 [[B]], [[A]] |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw nsw i16 [[XOR]] to i8 |
| ; CHECK-NEXT: ret i8 [[TRUNC]] |
| ; |
| %xor = xor i16 %B, %A |
| %trunc = trunc i16 %xor to i8 |
| ret i8 %trunc |
| } |
| |
| |
| define i8 @infer_nsw_from_assume(i16 %x) { |
| ; CHECK-LABEL: define i8 @infer_nsw_from_assume( |
| ; CHECK-SAME: i16 [[X:%.*]]) { |
| ; CHECK-NEXT: [[ADD:%.*]] = add i16 [[X]], 128 |
| ; CHECK-NEXT: [[OR_COND_I:%.*]] = icmp ult i16 [[ADD]], 256 |
| ; CHECK-NEXT: tail call void @llvm.assume(i1 [[OR_COND_I]]) |
| ; CHECK-NEXT: [[CONV1:%.*]] = trunc nsw i16 [[X]] to i8 |
| ; CHECK-NEXT: ret i8 [[CONV1]] |
| ; |
| %add = add i16 %x, 128 |
| %or.cond.i = icmp ult i16 %add, 256 |
| tail call void @llvm.assume(i1 %or.cond.i) |
| %conv1 = trunc i16 %x to i8 |
| ret i8 %conv1 |
| } |
| |
| |
| define i1 @rust_issue_122734(i8 range(i8 0, 3) %A, i8 range(i8 0, 3) %B) { |
| ; CHECK-LABEL: define i1 @rust_issue_122734( |
| ; CHECK-SAME: i8 range(i8 0, 3) [[A:%.*]], i8 range(i8 0, 3) [[B:%.*]]) { |
| ; CHECK-NEXT: [[START:.*]]: |
| ; CHECK-NEXT: [[LHS:%.*]] = icmp eq i8 [[A]], 2 |
| ; CHECK-NEXT: [[RHS:%.*]] = icmp eq i8 [[B]], 2 |
| ; CHECK-NEXT: [[OR:%.*]] = or i1 [[LHS]], [[RHS]] |
| ; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[RHS]] |
| ; CHECK-NEXT: br i1 [[OR]], label %[[IFTRUE:.*]], label %[[IFFALSE:.*]] |
| ; CHECK: [[IFTRUE]]: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[XOR2:%.*]], %[[IFFALSE]] ], [ [[AND]], %[[START]] ] |
| ; CHECK-NEXT: ret i1 [[PHI]] |
| ; CHECK: [[IFFALSE]]: |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A]], [[B]] |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1 |
| ; CHECK-NEXT: [[XOR2]] = xor i1 [[TRUNC]], true |
| ; CHECK-NEXT: br label %[[IFTRUE]] |
| ; |
| start: |
| %lhs = icmp eq i8 %A, 2 |
| %rhs = icmp eq i8 %B, 2 |
| %or = or i1 %lhs, %rhs |
| %and = and i1 %lhs, %rhs |
| br i1 %or, label %iftrue, label %iffalse |
| |
| iftrue: |
| %phi = phi i1 [ %xor2, %iffalse], [ %and, %start ] |
| ret i1 %phi |
| |
| iffalse: |
| %xor = xor i8 %A, %B |
| %trunc = trunc i8 %xor to i1 |
| %xor2 = xor i1 %trunc, true |
| br label %iftrue |
| } |
| |
| |
| define i1 @overdefined_range_negative(i8 %A, i8 %B) { |
| ; CHECK-LABEL: define i1 @overdefined_range_negative( |
| ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) { |
| ; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A]], [[B]] |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[XOR]] to i1 |
| ; CHECK-NEXT: ret i1 [[TRUNC]] |
| ; |
| %xor = xor i8 %A, %B |
| %trunc = trunc i8 %xor to i1 |
| ret i1 %trunc |
| } |
| |
| define i1 @trunc_nuw_infere_false_for_icmp_ne_1(i8 %x) { |
| ; CHECK-LABEL: define i1 @trunc_nuw_infere_false_for_icmp_ne_1( |
| ; CHECK-SAME: i8 [[X:%.*]]) { |
| ; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i8 [[X]], 1 |
| ; CHECK-NEXT: br i1 [[ICMP]], label %[[IFTRUE:.*]], label %[[IFFALSE:.*]] |
| ; CHECK: [[IFTRUE]]: |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X]] to i1 |
| ; CHECK-NEXT: ret i1 false |
| ; CHECK: [[IFFALSE]]: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %icmp = icmp ne i8 %x, 1 |
| br i1 %icmp, label %iftrue, label %iffalse |
| iftrue: |
| %trunc = trunc nuw i8 %x to i1 |
| ret i1 %trunc |
| iffalse: |
| ret i1 true |
| } |
| |
| define i1 @neg_trunc_do_not_infere_false_for_icmp_ne_1(i8 %x) { |
| ; CHECK-LABEL: define i1 @neg_trunc_do_not_infere_false_for_icmp_ne_1( |
| ; CHECK-SAME: i8 [[X:%.*]]) { |
| ; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i8 [[X]], 1 |
| ; CHECK-NEXT: br i1 [[ICMP]], label %[[IFTRUE:.*]], label %[[IFFALSE:.*]] |
| ; CHECK: [[IFTRUE]]: |
| ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X]] to i1 |
| ; CHECK-NEXT: ret i1 [[TRUNC]] |
| ; CHECK: [[IFFALSE]]: |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %icmp = icmp ne i8 %x, 1 |
| br i1 %icmp, label %iftrue, label %iffalse |
| iftrue: |
| %trunc = trunc i8 %x to i1 |
| ret i1 %trunc |
| iffalse: |
| ret i1 true |
| } |