| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| define i32 @fold(i32 %x) { |
| ; CHECK-LABEL: @fold( |
| ; CHECK-NEXT: [[Y:%.*]] = freeze i32 [[X:%.*]] |
| ; CHECK-NEXT: ret i32 [[Y]] |
| ; |
| %y = freeze i32 %x |
| %z = freeze i32 %y |
| ret i32 %z |
| } |
| |
| define i32 @make_const() { |
| ; CHECK-LABEL: @make_const( |
| ; CHECK-NEXT: ret i32 10 |
| ; |
| %x = freeze i32 10 |
| ret i32 %x |
| } |
| |
| define i32 @and_freeze_undef(i32 %x) { |
| ; CHECK-LABEL: @and_freeze_undef( |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| %f = freeze i32 undef |
| %res = and i32 %x, %f |
| ret i32 %res |
| } |
| |
| declare void @use_i32(i32) |
| declare void @use_p32(ptr) |
| |
| define i32 @and_freeze_undef_multipleuses(i32 %x) { |
| ; CHECK-LABEL: @and_freeze_undef_multipleuses( |
| ; CHECK-NEXT: call void @use_i32(i32 0) |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| %f = freeze i32 undef |
| %res = and i32 %x, %f |
| call void @use_i32(i32 %f) |
| ret i32 %res |
| } |
| |
| define i32 @or_freeze_undef(i32 %x) { |
| ; CHECK-LABEL: @or_freeze_undef( |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| %f = freeze i32 undef |
| %res = or i32 %x, %f |
| ret i32 %res |
| } |
| |
| define i32 @or_freeze_undef_multipleuses(i32 %x) { |
| ; CHECK-LABEL: @or_freeze_undef_multipleuses( |
| ; CHECK-NEXT: call void @use_i32(i32 0) |
| ; CHECK-NEXT: ret i32 [[X:%.*]] |
| ; |
| %f = freeze i32 undef |
| %res = or i32 %x, %f |
| call void @use_i32(i32 %f) |
| ret i32 %res |
| } |
| |
| declare void @use_i32_i1(i32, i1) |
| |
| define void @or_select_multipleuses(i32 %x, i1 %y) { |
| ; CHECK-LABEL: @or_select_multipleuses( |
| ; CHECK-NEXT: call void @use_i32_i1(i32 32, i1 [[Y:%.*]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %f = freeze i1 undef |
| %a = select i1 %f, i32 %x, i32 32 ; prefers %f to be false |
| %b = or i1 %f, %y ; prefers %f to be true |
| call void @use_i32_i1(i32 %a, i1 %b) |
| ret void |
| } |
| |
| define void @or_select_multipleuses_logical(i32 %x, i1 %y) { |
| ; CHECK-LABEL: @or_select_multipleuses_logical( |
| ; CHECK-NEXT: call void @use_i32_i1(i32 32, i1 [[Y:%.*]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %f = freeze i1 undef |
| %a = select i1 %f, i32 %x, i32 32 ; prefers %f to be false |
| %b = select i1 %f, i1 true, i1 %y ; prefers %f to be true |
| call void @use_i32_i1(i32 %a, i1 %b) |
| ret void |
| } |
| |
| define <3 x i4> @partial_undef_vec() { |
| ; CHECK-LABEL: @partial_undef_vec( |
| ; CHECK-NEXT: ret <3 x i4> <i4 0, i4 1, i4 0> |
| ; |
| %f = freeze <3 x i4> <i4 poison, i4 1, i4 undef> |
| ret <3 x i4> %f |
| } |
| |
| ; Move the freeze forward to prevent poison from spreading. |
| |
| define i32 @early_freeze_test1(i32 %x, i32 %y) { |
| ; CHECK-LABEL: @early_freeze_test1( |
| ; CHECK-NEXT: [[V1:%.*]] = add i32 [[X:%.*]], [[Y:%.*]] |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] |
| ; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1_FR]], 1 |
| ; CHECK-NEXT: [[V3:%.*]] = and i32 [[V2]], 2 |
| ; CHECK-NEXT: ret i32 [[V3]] |
| ; |
| %v1 = add i32 %x, %y |
| %v2 = shl i32 %v1, 1 |
| %v3 = and i32 %v2, 2 |
| %v3.fr = freeze i32 %v3 |
| ret i32 %v3.fr |
| } |
| |
| define i1 @early_freeze_test2(ptr %ptr) { |
| ; CHECK-LABEL: @early_freeze_test2( |
| ; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[PTR:%.*]], align 4 |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] |
| ; CHECK-NEXT: [[V2:%.*]] = and i32 [[V1_FR]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V2]], 0 |
| ; CHECK-NEXT: ret i1 [[COND]] |
| ; |
| %v1 = load i32, ptr %ptr |
| %v2 = and i32 %v1, 1 |
| %cond = icmp eq i32 %v2, 0 |
| %cond.fr = freeze i1 %cond |
| ret i1 %cond.fr |
| } |
| |
| define i32 @early_freeze_test3(i32 %v1) { |
| ; CHECK-LABEL: @early_freeze_test3( |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1:%.*]] |
| ; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1_FR]], 1 |
| ; CHECK-NEXT: [[V4:%.*]] = add i32 [[V2]], 3 |
| ; CHECK-NEXT: ret i32 [[V4]] |
| ; |
| %v2 = shl i32 %v1, 1 |
| %v3 = add nuw i32 %v2, 2 |
| %v4 = or i32 %v3, 1 |
| %v4.fr = freeze i32 %v4 |
| ret i32 %v4.fr |
| } |
| |
| ; If replace all dominated uses of v to freeze(v). |
| |
| define void @freeze_dominated_uses_test1(i32 %v) { |
| ; CHECK-LABEL: @freeze_dominated_uses_test1( |
| ; CHECK-NEXT: [[V_FR:%.*]] = freeze i32 [[V:%.*]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %v.fr = freeze i32 %v |
| call void @use_i32(i32 %v) |
| call void @use_i32(i32 %v.fr) |
| ret void |
| } |
| |
| define void @freeze_dominated_uses_test2(i32 %v) { |
| ; CHECK-LABEL: @freeze_dominated_uses_test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: [[V_FR:%.*]] = freeze i32 [[V:%.*]] |
| ; CHECK-NEXT: call void @use_p32(ptr nonnull [[A]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[V_FR]], 0 |
| ; CHECK-NEXT: br i1 [[COND]], label [[BB0:%.*]], label [[BB1:%.*]] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %a = alloca i32 |
| call void @use_p32(ptr %a) |
| call void @use_i32(i32 %v) |
| %cond = icmp eq i32 %v, 0 |
| br i1 %cond, label %bb0, label %bb1 |
| |
| bb0: |
| %v.fr = freeze i32 %v |
| call void @use_i32(i32 %v.fr) |
| call void @use_i32(i32 %v) |
| br label %end |
| |
| bb1: |
| call void @use_i32(i32 %v) |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; If there is a duplicate freeze, it will be removed. |
| |
| define void @freeze_dominated_uses_test3(i32 %v, i1 %cond) { |
| ; CHECK-LABEL: @freeze_dominated_uses_test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[V_FR1:%.*]] = freeze i32 [[V:%.*]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR1]]) |
| ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB0:%.*]], label [[BB1:%.*]] |
| ; CHECK: bb0: |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR1]]) |
| ; CHECK-NEXT: br label [[END:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: call void @use_i32(i32 [[V_FR1]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %v.fr1 = freeze i32 %v |
| call void @use_i32(i32 %v.fr1) |
| br i1 %cond, label %bb0, label %bb1 |
| |
| bb0: |
| %v.fr2 = freeze i32 %v |
| call void @use_i32(i32 %v.fr2) |
| br label %end |
| |
| bb1: |
| call void @use_i32(i32 %v) |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| declare i32 @__CxxFrameHandler3(...) |
| |
| define void @freeze_dominated_uses_catchswitch(i1 %c, i32 %x) personality ptr @__CxxFrameHandler3 { |
| ; CHECK-LABEL: @freeze_dominated_uses_catchswitch( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: invoke void @use_i32(i32 0) |
| ; CHECK-NEXT: to label [[CLEANUP:%.*]] unwind label [[CATCH_DISPATCH:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: invoke void @use_i32(i32 1) |
| ; CHECK-NEXT: to label [[CLEANUP]] unwind label [[CATCH_DISPATCH]] |
| ; CHECK: catch.dispatch: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[X:%.*]], [[IF_ELSE]] ] |
| ; CHECK-NEXT: [[CS:%.*]] = catchswitch within none [label [[CATCH:%.*]], label %catch2] unwind to caller |
| ; CHECK: catch: |
| ; CHECK-NEXT: [[CP:%.*]] = catchpad within [[CS]] [ptr null, i32 64, ptr null] |
| ; CHECK-NEXT: [[PHI_FREEZE:%.*]] = freeze i32 [[PHI]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[PHI_FREEZE]]) [ "funclet"(token [[CP]]) ] |
| ; CHECK-NEXT: unreachable |
| ; CHECK: catch2: |
| ; CHECK-NEXT: [[CP2:%.*]] = catchpad within [[CS]] [ptr null, i32 64, ptr null] |
| ; CHECK-NEXT: call void @use_i32(i32 [[PHI]]) [ "funclet"(token [[CP2]]) ] |
| ; CHECK-NEXT: unreachable |
| ; CHECK: cleanup: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if.then, label %if.else |
| |
| if.then: |
| invoke void @use_i32(i32 0) |
| to label %cleanup unwind label %catch.dispatch |
| |
| if.else: |
| invoke void @use_i32(i32 1) |
| to label %cleanup unwind label %catch.dispatch |
| |
| catch.dispatch: |
| %phi = phi i32 [ 0, %if.then ], [ %x, %if.else ] |
| %cs = catchswitch within none [label %catch, label %catch2] unwind to caller |
| |
| catch: |
| %cp = catchpad within %cs [ptr null, i32 64, ptr null] |
| %phi.freeze = freeze i32 %phi |
| call void @use_i32(i32 %phi.freeze) [ "funclet"(token %cp) ] |
| unreachable |
| |
| catch2: |
| %cp2 = catchpad within %cs [ptr null, i32 64, ptr null] |
| call void @use_i32(i32 %phi) [ "funclet"(token %cp2) ] |
| unreachable |
| |
| cleanup: |
| ret void |
| } |
| |
| declare i32 @get_i32() |
| |
| define i32 @freeze_use_in_different_branches(i1 %c) { |
| ; CHECK-LABEL: @freeze_use_in_different_branches( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[X:%.*]] = call i32 @get_i32() |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 0) |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: ret i32 0 |
| ; CHECK: else: |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: ret i32 1 |
| ; |
| entry: |
| %x = call i32 @get_i32() |
| call void @use_i32(i32 0) |
| br i1 %c, label %if, label %else |
| |
| if: |
| call void @use_i32(i32 %x) |
| ret i32 0 |
| |
| else: |
| call void @use_i32(i32 %x) |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| ret i32 1 |
| } |
| |
| define i32 @freeze_phi_use(i1 %c) { |
| ; CHECK-LABEL: @freeze_phi_use( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[X:%.*]] = call i32 @get_i32() |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 0) |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[FR]], [[IF]] ], [ 0, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: ret i32 [[PHI]] |
| ; |
| entry: |
| %x = call i32 @get_i32() |
| call void @use_i32(i32 0) |
| br i1 %c, label %if, label %join |
| |
| if: |
| br label %join |
| |
| join: |
| %phi = phi i32 [ %x, %if ], [ 0, %entry ] |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| ret i32 %phi |
| } |
| |
| define i32 @freeze_phi_followed_by_phi(i1 %c, i32 %y, i32 %z) { |
| ; CHECK-LABEL: @freeze_phi_followed_by_phi( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[JOIN]] |
| ; CHECK: join: |
| ; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[Y:%.*]], [[IF]] ], [ [[Z:%.*]], [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[Z]], [[IF]] ], [ [[Y]], [[ENTRY]] ] |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: ret i32 [[PHI]] |
| ; |
| entry: |
| br i1 %c, label %if, label %join |
| |
| if: |
| br label %join |
| |
| join: |
| %x = phi i32 [ %y, %if ], [ %z, %entry ] |
| %phi = phi i32 [ %z, %if ], [ %y, %entry ] |
| call void @use_i32(i32 %x) |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| ret i32 %phi |
| } |
| |
| define i32 @freeze_invoke_use_in_phi(i1 %c) personality ptr undef { |
| ; CHECK-LABEL: @freeze_invoke_use_in_phi( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[X:%.*]] = invoke i32 @get_i32() |
| ; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[INVOKE_UNWIND:%.*]] |
| ; CHECK: invoke.cont: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[INVOKE_CONT]] ] |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[PHI]]) |
| ; CHECK-NEXT: br label [[INVOKE_CONT]] |
| ; CHECK: invoke.unwind: |
| ; CHECK-NEXT: [[TMP0:%.*]] = landingpad i8 |
| ; CHECK-NEXT: cleanup |
| ; CHECK-NEXT: unreachable |
| ; |
| entry: |
| %x = invoke i32 @get_i32() |
| to label %invoke.cont unwind label %invoke.unwind |
| |
| invoke.cont: |
| %phi = phi i32 [ %x, %entry ], [ 0, %invoke.cont ] |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| call void @use_i32(i32 %phi) |
| br label %invoke.cont |
| |
| invoke.unwind: |
| landingpad i8 cleanup |
| unreachable |
| } |
| |
| define i32 @freeze_invoke_use_after_phi(i1 %c) personality ptr undef { |
| ; CHECK-LABEL: @freeze_invoke_use_after_phi( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[X:%.*]] = invoke i32 @get_i32() |
| ; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[INVOKE_UNWIND:%.*]] |
| ; CHECK: invoke.cont: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[INVOKE_CONT]] ] |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[PHI]]) |
| ; CHECK-NEXT: br label [[INVOKE_CONT]] |
| ; CHECK: invoke.unwind: |
| ; CHECK-NEXT: [[TMP0:%.*]] = landingpad i8 |
| ; CHECK-NEXT: cleanup |
| ; CHECK-NEXT: unreachable |
| ; |
| entry: |
| %x = invoke i32 @get_i32() |
| to label %invoke.cont unwind label %invoke.unwind |
| |
| invoke.cont: |
| %phi = phi i32 [ %x, %entry ], [ 0, %invoke.cont ] |
| call void @use_i32(i32 %x) |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| call void @use_i32(i32 %phi) |
| br label %invoke.cont |
| |
| invoke.unwind: |
| landingpad i8 cleanup |
| unreachable |
| } |
| |
| define i32 @freeze_callbr_use_after_phi(i1 %c) { |
| ; CHECK-LABEL: @freeze_callbr_use_after_phi( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[X:%.*]] = callbr i32 asm sideeffect "", "=r"() #[[ATTR1:[0-9]+]] |
| ; CHECK-NEXT: to label [[CALLBR_CONT:%.*]] [] |
| ; CHECK: callbr.cont: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[CALLBR_CONT]] ] |
| ; CHECK-NEXT: call void @use_i32(i32 [[X]]) |
| ; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: call void @use_i32(i32 [[FR]]) |
| ; CHECK-NEXT: call void @use_i32(i32 [[PHI]]) |
| ; CHECK-NEXT: br label [[CALLBR_CONT]] |
| ; |
| entry: |
| %x = callbr i32 asm sideeffect "", "=r"() |
| to label %callbr.cont [] |
| |
| callbr.cont: |
| %phi = phi i32 [ %x, %entry ], [ 0, %callbr.cont ] |
| call void @use_i32(i32 %x) |
| %fr = freeze i32 %x |
| call void @use_i32(i32 %fr) |
| call void @use_i32(i32 %phi) |
| br label %callbr.cont |
| } |
| |
| define i1 @combine_and_after_freezing_uses(i32 %x) { |
| ; CHECK-LABEL: @combine_and_after_freezing_uses( |
| ; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X_FR]], 15 |
| ; CHECK-NEXT: [[AND:%.*]] = icmp eq i32 [[TMP1]], 15 |
| ; CHECK-NEXT: ret i1 [[AND]] |
| ; |
| %and1 = and i32 %x, 4 |
| %cmp1 = icmp ne i32 %and1, 0 |
| %x.fr = freeze i32 %x |
| %and2 = and i32 %x.fr, 11 |
| %cmp2 = icmp eq i32 %and2, 11 |
| %and = and i1 %cmp1, %cmp2 |
| ret i1 %and |
| } |
| |
| declare i1 @mock_use(i64, i64) |
| define i1 @fully_propagate_freeze(i32 %0, i32 noundef %1) { |
| ; CHECK-LABEL: @fully_propagate_freeze( |
| ; CHECK-NEXT: [[DOTFR:%.*]] = freeze i32 [[TMP0:%.*]] |
| ; CHECK-NEXT: [[DR:%.*]] = lshr i32 [[DOTFR]], 2 |
| ; CHECK-NEXT: [[IDX1:%.*]] = zext i32 [[DR]] to i64 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[DR]], 1 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD]], [[TMP1:%.*]] |
| ; CHECK-NEXT: [[IDX2:%.*]] = zext i32 [[DR]] to i64 |
| ; CHECK-NEXT: [[V:%.*]] = call i1 @mock_use(i64 [[IDX1]], i64 [[IDX2]]) |
| ; CHECK-NEXT: [[RET:%.*]] = and i1 [[V]], [[CMP]] |
| ; CHECK-NEXT: ret i1 [[RET]] |
| ; |
| %dr = lshr i32 %0, 2 |
| %idx1 = zext i32 %dr to i64 |
| %add = add i32 %dr, 1 |
| %cmp = icmp slt i32 %add, %1 |
| %cmp.fr = freeze i1 %cmp |
| %idx2 = zext i32 %dr to i64 |
| %v = call i1 @mock_use(i64 %idx1, i64 %idx2) |
| %ret = and i1 %v, %cmp.fr |
| ret i1 %ret |
| } |
| |
| define i32 @propagate_drop_flags_add(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_add( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG_FR]], 2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = add nsw nuw i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_flags_add_foldaway(i32 noundef %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_add_foldaway( |
| ; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG:%.*]], 2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = add nsw nuw i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_flags_sub(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_sub( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG_FR]], -2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = sub nsw nuw i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_flags_mul(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_mul( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = shl i32 [[ARG_FR]], 1 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = mul nsw nuw i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_flags_udiv(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_udiv( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V11:%.*]] = lshr i32 [[ARG_FR]], 1 |
| ; CHECK-NEXT: ret i32 [[V11]] |
| ; |
| %v1 = udiv exact i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_flags_sdiv(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_flags_sdiv( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = ashr i32 [[ARG_FR]], 1 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = sdiv exact i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_shl1(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_shl1( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = shl i32 [[ARG_FR]], 2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = shl nsw nuw i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_shl2(i32 %arg, i32 %unknown) { |
| ; CHECK-LABEL: @propagate_drop_shl2( |
| ; CHECK-NEXT: [[V1:%.*]] = shl nuw nsw i32 [[ARG:%.*]], [[UNKNOWN:%.*]] |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] |
| ; CHECK-NEXT: ret i32 [[V1_FR]] |
| ; |
| %v1 = shl nsw nuw i32 %arg, %unknown |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_ashr1(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_ashr1( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = ashr i32 [[ARG_FR]], 2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = ashr exact i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_ashr2(i32 %arg, i32 %unknown) { |
| ; CHECK-LABEL: @propagate_drop_ashr2( |
| ; CHECK-NEXT: [[V1:%.*]] = ashr exact i32 [[ARG:%.*]], [[UNKNOWN:%.*]] |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] |
| ; CHECK-NEXT: ret i32 [[V1_FR]] |
| ; |
| %v1 = ashr exact i32 %arg, %unknown |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_lshr1(i32 %arg) { |
| ; CHECK-LABEL: @propagate_drop_lshr1( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = lshr i32 [[ARG_FR]], 2 |
| ; CHECK-NEXT: ret i32 [[V1]] |
| ; |
| %v1 = lshr exact i32 %arg, 2 |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define i32 @propagate_drop_lshr2(i32 %arg, i32 %unknown) { |
| ; CHECK-LABEL: @propagate_drop_lshr2( |
| ; CHECK-NEXT: [[V1:%.*]] = lshr exact i32 [[ARG:%.*]], [[UNKNOWN:%.*]] |
| ; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]] |
| ; CHECK-NEXT: ret i32 [[V1_FR]] |
| ; |
| %v1 = lshr exact i32 %arg, %unknown |
| %v1.fr = freeze i32 %v1 |
| ret i32 %v1.fr |
| } |
| |
| define ptr @propagate_drop_gep1(ptr %arg) { |
| ; CHECK-LABEL: @propagate_drop_gep1( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze ptr [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = getelementptr i8, ptr [[ARG_FR]], i64 16 |
| ; CHECK-NEXT: ret ptr [[V1]] |
| ; |
| %v1 = getelementptr inbounds i8, ptr %arg, i64 16 |
| %v1.fr = freeze ptr %v1 |
| ret ptr %v1.fr |
| } |
| |
| define float @propagate_drop_fneg(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fneg( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fneg float [[ARG_FR]] |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = fneg ninf nnan float %arg |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| |
| define float @propagate_drop_fadd(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fadd( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fadd float [[ARG_FR]], 2.000000e+00 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = fadd ninf nnan float %arg, 2.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define float @propagate_drop_fsub(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fsub( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fadd float [[ARG_FR]], -2.000000e+00 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = fsub ninf nnan float %arg, 2.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define float @propagate_drop_fmul(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fmul( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fmul float [[ARG_FR]], 2.000000e+00 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = fmul ninf nnan float %arg, 2.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define float @propagate_drop_fdiv(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fdiv( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fmul float [[ARG_FR]], 5.000000e-01 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = fdiv ninf nnan float %arg, 2.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define float @propagate_drop_frem(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_frem( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = frem float [[ARG_FR]], 2.000000e+00 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = frem ninf nnan float %arg, 2.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define i1 @propagate_drop_fcmp(float %arg) { |
| ; CHECK-LABEL: @propagate_drop_fcmp( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze float [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = fcmp une float [[ARG_FR]], 2.000000e+00 |
| ; CHECK-NEXT: ret i1 [[V1]] |
| ; |
| %v1 = fcmp ninf nnan une float %arg, 2.0 |
| %v1.fr = freeze i1 %v1 |
| ret i1 %v1.fr |
| } |
| |
| define float @propagate_drop_fmath_select(i1 %arg) { |
| ; CHECK-LABEL: @propagate_drop_fmath_select( |
| ; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i1 [[ARG:%.*]] |
| ; CHECK-NEXT: [[V1:%.*]] = select i1 [[ARG_FR]], float 1.000000e+00, float -1.000000e+00 |
| ; CHECK-NEXT: ret float [[V1]] |
| ; |
| %v1 = select ninf nnan i1 %arg, float 1.0, float -1.0 |
| %v1.fr = freeze float %v1 |
| ret float %v1.fr |
| } |
| |
| define void @fold_phi_noop(i32 noundef %init, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_noop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_through(i32 %init, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_through( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_drop_flags(i32 %init, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_drop_flags( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add nsw nuw i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_non_add(i32 %init, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_non_add( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = freeze i32 [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = shl i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = shl i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_gep(ptr %init, ptr %end) { |
| ; CHECK-LABEL: @fold_phi_gep( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = freeze ptr [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = getelementptr i8, ptr [[I]], i64 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[I_NEXT]], [[END:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi ptr [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze ptr %i |
| %i.next = getelementptr i8, ptr %i.fr, i64 1 |
| %cond = icmp eq ptr %i.next, %end |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_multiple_insts(i32 %init, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_multiple_insts( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_SQ:%.*]] = mul i32 [[I]], [[I]] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I_SQ]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.sq = mul nsw nuw i32 %i.fr, %i.fr |
| %i.next = add nsw nuw i32 %i.sq, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_multiple_back_edges(i32 %init, i32 %n, i32 %m) { |
| ; CHECK-LABEL: @fold_phi_multiple_back_edges( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]] |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ], [ [[I_NEXT2:%.*]], [[LOOP_LATCH2:%.*]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[LOOP_LATCH2]] |
| ; CHECK: loop.latch2: |
| ; CHECK-NEXT: [[I_NEXT2]] = add i32 [[I]], 2 |
| ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[I_NEXT]], [[M:%.*]] |
| ; CHECK-NEXT: br i1 [[COND2]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br label %loop |
| |
| loop: ; preds = %loop, %entry |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ], [ %i.next2, %loop.latch2 ] |
| %i.fr = freeze i32 %i |
| %i.next = add nsw nuw i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %loop.latch2 |
| |
| loop.latch2: |
| %i.next2 = add nsw nuw i32 %i.fr, 2 |
| %cond2 = icmp eq i32 %i.next, %m |
| br i1 %cond2, label %loop, label %exit |
| |
| exit: ; preds = %loop |
| ret void |
| } |
| |
| define void @fold_phi_multiple_start_values(i1 %c, i32 %init, i32 %init2, i32 %n) { |
| ; CHECK-LABEL: @fold_phi_multiple_start_values( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[LOOP:%.*]] |
| ; CHECK: if: |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[INIT2:%.*]], [[IF]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_FR:%.*]] = freeze i32 [[I]] |
| ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I_FR]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %if, label %loop |
| |
| if: |
| br label %loop |
| |
| loop: |
| %i = phi i32 [ %init, %entry ], [ %init2, %if ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add nsw nuw i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @fold_phi_invoke_start_value(i32 %n) personality ptr undef { |
| ; CHECK-LABEL: @fold_phi_invoke_start_value( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INIT:%.*]] = invoke i32 @get_i32() |
| ; CHECK-NEXT: to label [[LOOP:%.*]] unwind label [[UNWIND:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_FR:%.*]] = freeze i32 [[I]] |
| ; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I_FR]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: unwind: |
| ; CHECK-NEXT: [[TMP0:%.*]] = landingpad i8 |
| ; CHECK-NEXT: cleanup |
| ; CHECK-NEXT: unreachable |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %init = invoke i32 @get_i32() |
| to label %loop unwind label %unwind |
| |
| loop: |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add nsw nuw i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| unwind: |
| landingpad i8 cleanup |
| unreachable |
| |
| exit: |
| ret void |
| } |
| |
| define void @fold_phi_invoke_noundef_start_value(i32 %n) personality ptr undef { |
| ; CHECK-LABEL: @fold_phi_invoke_noundef_start_value( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[INIT:%.*]] = invoke noundef i32 @get_i32() |
| ; CHECK-NEXT: to label [[LOOP:%.*]] unwind label [[UNWIND:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[INIT]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: [[I_NEXT]] = add i32 [[I]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]] |
| ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] |
| ; CHECK: unwind: |
| ; CHECK-NEXT: [[TMP0:%.*]] = landingpad i8 |
| ; CHECK-NEXT: cleanup |
| ; CHECK-NEXT: unreachable |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %init = invoke noundef i32 @get_i32() |
| to label %loop unwind label %unwind |
| |
| loop: |
| %i = phi i32 [ %init, %entry ], [ %i.next, %loop ] |
| %i.fr = freeze i32 %i |
| %i.next = add nsw nuw i32 %i.fr, 1 |
| %cond = icmp eq i32 %i.next, %n |
| br i1 %cond, label %loop, label %exit |
| |
| unwind: |
| landingpad i8 cleanup |
| unreachable |
| |
| exit: |
| ret void |
| } |
| |
| define ptr @freeze_load_noundef(ptr %ptr) { |
| ; CHECK-LABEL: @freeze_load_noundef( |
| ; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !noundef !0 |
| ; CHECK-NEXT: ret ptr [[P]] |
| ; |
| %p = load ptr, ptr %ptr, !noundef !0 |
| %p.fr = freeze ptr %p |
| ret ptr %p.fr |
| } |
| |
| define ptr @freeze_load_dereferenceable(ptr %ptr) { |
| ; CHECK-LABEL: @freeze_load_dereferenceable( |
| ; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable !1 |
| ; CHECK-NEXT: ret ptr [[P]] |
| ; |
| %p = load ptr, ptr %ptr, !dereferenceable !1 |
| %p.fr = freeze ptr %p |
| ret ptr %p.fr |
| } |
| |
| define ptr @freeze_load_dereferenceable_or_null(ptr %ptr) { |
| ; CHECK-LABEL: @freeze_load_dereferenceable_or_null( |
| ; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable_or_null !1 |
| ; CHECK-NEXT: ret ptr [[P]] |
| ; |
| %p = load ptr, ptr %ptr, !dereferenceable_or_null !1 |
| %p.fr = freeze ptr %p |
| ret ptr %p.fr |
| } |
| |
| define i32 @freeze_load_with_range(ptr %ptr) { |
| ; CHECK-LABEL: @freeze_load_with_range( |
| ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !range [[RNG2:![0-9]+]] |
| ; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: ret i32 [[X_FR]] |
| ; |
| %x = load i32, ptr %ptr, !range !2 |
| %x.fr = freeze i32 %x |
| ret i32 %x.fr |
| } |
| |
| declare i32 @foo.i32() |
| |
| define i32 @freeze_call_with_range() { |
| ; CHECK-LABEL: @freeze_call_with_range( |
| ; CHECK-NEXT: [[X:%.*]] = call i32 @foo.i32(), !range [[RNG2]] |
| ; CHECK-NEXT: [[X_FR:%.*]] = freeze i32 [[X]] |
| ; CHECK-NEXT: ret i32 [[X_FR]] |
| ; |
| %x = call i32 @foo.i32(), !range !2 |
| %x.fr = freeze i32 %x |
| ret i32 %x.fr |
| } |
| |
| declare i32 @llvm.ctpop.i32(i32) |
| |
| define i32 @freeze_ctpop(i32 %x) { |
| ; CHECK-LABEL: @freeze_ctpop( |
| ; CHECK-NEXT: [[Y:%.*]] = lshr i32 2047, [[X:%.*]] |
| ; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y]] |
| ; CHECK-NEXT: [[CTPOP:%.*]] = call i32 @llvm.ctpop.i32(i32 [[Y_FR]]), !range [[RNG3:![0-9]+]] |
| ; CHECK-NEXT: ret i32 [[CTPOP]] |
| ; |
| %y = lshr i32 2047, %x |
| %ctpop = call i32 @llvm.ctpop.i32(i32 %y) |
| %fr = freeze i32 %ctpop |
| ret i32 %fr |
| } |
| |
| !0 = !{} |
| !1 = !{i64 4} |
| !2 = !{i32 0, i32 100} |
| ;. |
| ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } |
| ; CHECK: attributes #[[ATTR1]] = { nounwind } |
| ;. |
| ; CHECK: [[META0:![0-9]+]] = !{} |
| ; CHECK: [[META1:![0-9]+]] = !{i64 4} |
| ; CHECK: [[RNG2]] = !{i32 0, i32 100} |
| ; CHECK: [[RNG3]] = !{i32 0, i32 33} |
| ;. |