| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=ipsccp -S %s | FileCheck %s |
| |
| @g = global i64 0 |
| declare void @use(i1) |
| |
| define i1 @freeze_undef_i1() { |
| ; CHECK-LABEL: @freeze_undef_i1( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i1 undef |
| ; CHECK-NEXT: ret i1 [[FR]] |
| ; |
| %fr = freeze i1 undef |
| ret i1 %fr |
| } |
| |
| define ptr @freeze_undef_ptr() { |
| ; CHECK-LABEL: @freeze_undef_ptr( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze ptr undef |
| ; CHECK-NEXT: ret ptr [[FR]] |
| ; |
| %fr = freeze ptr undef |
| ret ptr %fr |
| } |
| |
| define float @freeze_undef_float() { |
| ; CHECK-LABEL: @freeze_undef_float( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze float undef |
| ; CHECK-NEXT: ret float [[FR]] |
| ; |
| %fr = freeze float undef |
| ret float %fr |
| } |
| |
| define <2 x i32> @freeze_undef_vector() { |
| ; CHECK-LABEL: @freeze_undef_vector( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze <2 x i32> undef |
| ; CHECK-NEXT: ret <2 x i32> [[FR]] |
| ; |
| %fr = freeze <2 x i32> undef |
| ret <2 x i32> %fr |
| } |
| |
| define i1 @freeze_const_i1() { |
| ; CHECK-LABEL: @freeze_const_i1( |
| ; CHECK-NEXT: ret i1 true |
| ; |
| %fr = freeze i1 1 |
| ret i1 %fr |
| } |
| |
| define ptr @freeze_const_ptr() { |
| ; CHECK-LABEL: @freeze_const_ptr( |
| ; CHECK-NEXT: ret ptr inttoptr (i32 256 to ptr) |
| ; |
| %fr = freeze ptr inttoptr (i32 256 to ptr) |
| ret ptr %fr |
| } |
| |
| define float @freeze_const_float() { |
| ; CHECK-LABEL: @freeze_const_float( |
| ; CHECK-NEXT: ret float 2.500000e-01 |
| ; |
| %fr = freeze float 2.500000e-01 |
| ret float %fr |
| } |
| |
| define <2 x i32> @freeze_const_vector() { |
| ; CHECK-LABEL: @freeze_const_vector( |
| ; CHECK-NEXT: ret <2 x i32> <i32 1, i32 2> |
| ; |
| %fr = freeze <2 x i32> <i32 1, i32 2> |
| ret <2 x i32> %fr |
| } |
| |
| ; make sure we don't constant-propagate values that could potentially be poison |
| define i64 @maybe_poison() { |
| ; CHECK-LABEL: @maybe_poison( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123) |
| ; CHECK-NEXT: ret i64 [[FR]] |
| ; |
| %fr = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123) |
| ret i64 %fr |
| } |
| |
| define {i64, i64} @freeze_struct({i64, i64} %s) { |
| ; CHECK-LABEL: @freeze_struct( |
| ; CHECK-NEXT: [[FR:%.*]] = freeze { i64, i64 } [[S:%.*]] |
| ; CHECK-NEXT: ret { i64, i64 } [[FR]] |
| ; |
| %fr = freeze {i64, i64} %s |
| ret {i64, i64} %fr |
| } |
| |
| define i1 @propagate_range_from_and_through_freeze(i32 %x, i32 %y) { |
| ; CHECK-LABEL: @propagate_range_from_and_through_freeze( |
| ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3 |
| ; CHECK-NEXT: [[AND_FR:%.*]] = freeze i32 [[AND]] |
| ; CHECK-NEXT: [[F_1:%.*]] = icmp eq i32 [[AND_FR]], 100 |
| ; CHECK-NEXT: call void @use(i1 [[F_1]]) |
| ; CHECK-NEXT: [[T_1:%.*]] = icmp ule i32 [[AND_FR]], 3 |
| ; CHECK-NEXT: call void @use(i1 [[T_1]]) |
| ; CHECK-NEXT: [[F_2:%.*]] = icmp ugt i32 [[AND_FR]], 3 |
| ; CHECK-NEXT: call void @use(i1 [[F_2]]) |
| ; CHECK-NEXT: [[C_1:%.*]] = icmp eq i32 [[AND_FR]], [[Y:%.*]] |
| ; CHECK-NEXT: call void @use(i1 [[C_1]]) |
| ; CHECK-NEXT: [[R_1:%.*]] = xor i1 [[T_1]], [[F_1]] |
| ; CHECK-NEXT: [[R_2:%.*]] = xor i1 [[R_1]], [[F_2]] |
| ; CHECK-NEXT: [[R_3:%.*]] = xor i1 [[R_2]], [[C_1]] |
| ; CHECK-NEXT: ret i1 [[R_3]] |
| ; |
| %and = and i32 %x, 3 |
| %and.fr = freeze i32 %and |
| %f.1 = icmp eq i32 %and.fr, 100 |
| call void @use(i1 %f.1) |
| %t.1 = icmp ule i32 %and.fr, 3 |
| call void @use(i1 %t.1) |
| %f.2 = icmp ugt i32 %and.fr, 3 |
| call void @use(i1 %f.2) |
| %c.1 = icmp eq i32 %and.fr, %y |
| call void @use(i1 %c.1) |
| %r.1 = xor i1 %t.1, %f.1 |
| %r.2 = xor i1 %r.1, %f.2 |
| %r.3 = xor i1 %r.2, %c.1 |
| ret i1 %r.3 |
| } |
| |
| define i1 @range_from_phi_with_undef(i1 %c.1, i1 %c.2) { |
| ; CHECK-LABEL: @range_from_phi_with_undef( |
| ; CHECK-NEXT: br i1 [[C_1:%.*]], label [[TRUE_1:%.*]], label [[FALSE:%.*]] |
| ; CHECK: true.1: |
| ; CHECK-NEXT: br i1 [[C_2:%.*]], label [[TRUE_2:%.*]], label [[EXIT:%.*]] |
| ; CHECK: true.2: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: false: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[P:%.*]] = phi i32 [ 10, [[TRUE_1]] ], [ 20, [[TRUE_2]] ], [ undef, [[FALSE]] ] |
| ; CHECK-NEXT: [[P_FR:%.*]] = freeze i32 [[P]] |
| ; CHECK-NEXT: [[T_1:%.*]] = icmp ule i32 [[P_FR]], 20 |
| ; CHECK-NEXT: [[T_2:%.*]] = icmp uge i32 [[P_FR]], 10 |
| ; CHECK-NEXT: [[RES:%.*]] = xor i1 [[T_1]], [[T_2]] |
| ; CHECK-NEXT: ret i1 [[RES]] |
| ; |
| br i1 %c.1, label %true.1, label %false |
| |
| true.1: |
| br i1 %c.2, label %true.2, label %exit |
| |
| true.2: |
| br label %exit |
| |
| false: |
| br label %exit |
| |
| exit: |
| %p = phi i32 [ 10, %true.1 ], [ 20, %true.2], [ undef, %false ] |
| %p.fr = freeze i32 %p |
| %t.1 = icmp ule i32 %p.fr, 20 |
| %t.2 = icmp uge i32 %p.fr, 10 |
| %res = xor i1 %t.1, %t.2 |
| ret i1 %res |
| } |
| |
| define i32 @propagate_info_from_predicate_through_freeze(i32 %x) { |
| ; CHECK-LABEL: @propagate_info_from_predicate_through_freeze( |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 10 |
| ; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]] |
| ; CHECK: then: |
| ; CHECK-NEXT: [[ADD_1:%.*]] = add i32 [[X_FR]], 10 |
| ; CHECK-NEXT: [[ADD_2:%.*]] = add i32 [[X_FR]], 1 |
| ; CHECK-NEXT: ret i32 [[ADD_2]] |
| ; CHECK: else: |
| ; CHECK-NEXT: [[ADD_3:%.*]] = add i32 [[X_FR]], 1 |
| ; CHECK-NEXT: ret i32 [[ADD_3]] |
| ; |
| %cmp = icmp eq i32 %x, 10 |
| %x.fr = freeze i32 %x |
| br i1 %cmp, label %then, label %else |
| |
| then: |
| %add.1 = add i32 %x.fr, %x |
| %add.2 = add i32 %x.fr, 1 |
| ret i32 %add.2 |
| |
| else: |
| %add.3 = add i32 %x.fr, 1 |
| ret i32 %add.3 |
| } |