CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1744 lines
58 KiB
LLVM
1744 lines
58 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
define i32 @fold(i32 %x) {
|
|
; CHECK-LABEL: define i32 @fold(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define i32 @make_const() {
|
|
; CHECK-NEXT: ret i32 10
|
|
;
|
|
%x = freeze i32 10
|
|
ret i32 %x
|
|
}
|
|
|
|
define i32 @and_freeze_undef(i32 %x) {
|
|
; CHECK-LABEL: define i32 @and_freeze_undef(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define i32 @and_freeze_undef_multipleuses(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define i32 @or_freeze_undef(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define i32 @or_freeze_undef_multipleuses(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define void @or_select_multipleuses(
|
|
; CHECK-SAME: i32 [[X:%.*]], i1 [[Y:%.*]]) {
|
|
; 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: define void @or_select_multipleuses_logical(
|
|
; CHECK-SAME: i32 [[X:%.*]], i1 [[Y:%.*]]) {
|
|
; 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: define <3 x i4> @partial_undef_vec() {
|
|
; CHECK-NEXT: ret <3 x i4> splat (i4 1)
|
|
;
|
|
%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: define i32 @early_freeze_test1(
|
|
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[V4:%.*]] = add i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[V1:%.*]] = freeze i32 [[V4]]
|
|
; CHECK-NEXT: [[V2:%.*]] = shl i32 [[V1]], 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: define i1 @early_freeze_test2(
|
|
; CHECK-SAME: ptr [[PTR:%.*]]) {
|
|
; 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: define i32 @early_freeze_test3(
|
|
; CHECK-SAME: i32 [[V1:%.*]]) {
|
|
; 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
|
|
}
|
|
|
|
define i32 @early_freeze_test4(i32 %v1) {
|
|
; CHECK-LABEL: define i32 @early_freeze_test4(
|
|
; CHECK-SAME: i32 [[V1:%.*]]) {
|
|
; CHECK-NEXT: [[V1_FR:%.*]] = freeze i32 [[V1]]
|
|
; CHECK-NEXT: [[V2:%.*]] = mul i32 [[V1_FR]], [[V1_FR]]
|
|
; CHECK-NEXT: ret i32 [[V2]]
|
|
;
|
|
%v2 = mul i32 %v1, %v1
|
|
%v2.fr = freeze i32 %v2
|
|
ret i32 %v2.fr
|
|
}
|
|
|
|
; If replace all dominated uses of v to freeze(v).
|
|
|
|
define void @freeze_dominated_uses_test1(i32 %v) {
|
|
; CHECK-LABEL: define void @freeze_dominated_uses_test1(
|
|
; CHECK-SAME: i32 [[V:%.*]]) {
|
|
; 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: define void @freeze_dominated_uses_test2(
|
|
; CHECK-SAME: i32 [[V:%.*]]) {
|
|
; 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 %[[BB_0:.*]], label %[[BB_1:.*]]
|
|
; CHECK: [[BB_0]]:
|
|
; CHECK-NEXT: call void @use_i32(i32 [[V_FR]])
|
|
; CHECK-NEXT: call void @use_i32(i32 [[V_FR]])
|
|
; CHECK-NEXT: br label %[[END:.*]]
|
|
; CHECK: [[BB_1]]:
|
|
; 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 %bb.0, label %bb.1
|
|
|
|
bb.0:
|
|
%v.fr = freeze i32 %v
|
|
call void @use_i32(i32 %v.fr)
|
|
call void @use_i32(i32 %v)
|
|
br label %end
|
|
|
|
bb.1:
|
|
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: define void @freeze_dominated_uses_test3(
|
|
; CHECK-SAME: i32 [[V:%.*]], i1 [[COND:%.*]]) {
|
|
; 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 %[[BB_0:.*]], label %[[BB_1:.*]]
|
|
; CHECK: [[BB_0]]:
|
|
; CHECK-NEXT: call void @use_i32(i32 [[V_FR1]])
|
|
; CHECK-NEXT: br label %[[END:.*]]
|
|
; CHECK: [[BB_1]]:
|
|
; 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 %bb.0, label %bb.1
|
|
|
|
bb.0:
|
|
%v.fr2 = freeze i32 %v
|
|
call void @use_i32(i32 %v.fr2)
|
|
br label %end
|
|
|
|
bb.1:
|
|
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: define void @freeze_dominated_uses_catchswitch(
|
|
; CHECK-SAME: i1 [[C:%.*]], i32 [[X:%.*]]) personality ptr @__CxxFrameHandler3 {
|
|
; 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: define i32 @freeze_use_in_different_branches(
|
|
; CHECK-SAME: i1 [[C:%.*]]) {
|
|
; 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: define i32 @freeze_phi_use(
|
|
; CHECK-SAME: i1 [[C:%.*]]) {
|
|
; 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: define i32 @freeze_phi_followed_by_phi(
|
|
; CHECK-SAME: i1 [[C:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
|
|
; 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: define i32 @freeze_invoke_use_in_phi(
|
|
; CHECK-SAME: i1 [[C:%.*]]) personality ptr undef {
|
|
; 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: define i32 @freeze_invoke_use_after_phi(
|
|
; CHECK-SAME: i1 [[C:%.*]]) personality ptr undef {
|
|
; 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: define i32 @freeze_callbr_use_after_phi(
|
|
; CHECK-SAME: i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: [[X:%.*]] = callbr i32 asm sideeffect "", "=r"() #[[ATTR2:[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: define i1 @combine_and_after_freezing_uses(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; 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: define i1 @fully_propagate_freeze(
|
|
; CHECK-SAME: i32 [[TMP0:%.*]], i32 noundef [[TMP1:%.*]]) {
|
|
; CHECK-NEXT: [[DOTFR:%.*]] = freeze i32 [[TMP0]]
|
|
; CHECK-NEXT: [[DR:%.*]] = lshr i32 [[DOTFR]], 2
|
|
; CHECK-NEXT: [[IDX1:%.*]] = zext nneg 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 nneg 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: define i32 @propagate_drop_flags_add(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_flags_add_foldaway(
|
|
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_flags_sub(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_flags_mul(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_flags_udiv(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_flags_sdiv(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_shl1(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_shl2(
|
|
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[UNKNOWN:%.*]]) {
|
|
; 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: define i32 @propagate_drop_ashr1(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_ashr2(
|
|
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[UNKNOWN:%.*]]) {
|
|
; 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: define i32 @propagate_drop_lshr1(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; 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: define i32 @propagate_drop_lshr2(
|
|
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[UNKNOWN:%.*]]) {
|
|
; 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: define ptr @propagate_drop_gep1(
|
|
; CHECK-SAME: ptr [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fneg(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fadd(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fsub(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fmul(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fdiv(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_frem(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define i1 @propagate_drop_fcmp(
|
|
; CHECK-SAME: float [[ARG:%.*]]) {
|
|
; 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: define float @propagate_drop_fmath_select(
|
|
; CHECK-SAME: i1 [[ARG:%.*]]) {
|
|
; 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: define void @fold_phi_noop(
|
|
; CHECK-SAME: i32 noundef [[INIT:%.*]], i32 [[N:%.*]]) {
|
|
; 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: define void @fold_phi_through(
|
|
; CHECK-SAME: i32 [[INIT:%.*]], i32 [[N:%.*]]) {
|
|
; 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: define void @fold_phi_drop_flags(
|
|
; CHECK-SAME: i32 [[INIT:%.*]], i32 [[N:%.*]]) {
|
|
; 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: define void @fold_phi_non_add(
|
|
; CHECK-SAME: i32 [[INIT:%.*]], i32 [[N:%.*]]) {
|
|
; 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: define void @fold_phi_gep(
|
|
; CHECK-SAME: ptr [[INIT:%.*]], ptr [[END:%.*]]) {
|
|
; 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
|
|
}
|
|
|
|
; The recurrence for the GEP offset can't produce poison so the freeze should
|
|
; be pushed through to the ptr.
|
|
define void @fold_phi_gep_phi_offset(ptr %init, ptr %end, i64 noundef %n) {
|
|
; CHECK-LABEL: define void @fold_phi_gep_phi_offset(
|
|
; CHECK-SAME: ptr [[INIT:%.*]], ptr [[END:%.*]], i64 noundef [[N:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[I_NEXT_FR:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N]], %[[ENTRY]] ], [ [[OFF_NEXT:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
|
|
; CHECK-NEXT: [[I_NEXT:%.*]] = getelementptr i8, ptr [[I]], i64 [[OFF_NEXT]]
|
|
; CHECK-NEXT: [[I_NEXT_FR]] = freeze ptr [[I_NEXT]]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[I_NEXT_FR]], [[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.fr, %loop ]
|
|
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
|
|
%off.next = shl i64 %off, 3
|
|
%i.next = getelementptr i8, ptr %i, i64 %off.next
|
|
%i.next.fr = freeze ptr %i.next
|
|
%cond = icmp eq ptr %i.next.fr, %end
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %loop
|
|
ret void
|
|
}
|
|
|
|
; Offset is still guaranteed not to be poison, so the freeze can be moved
|
|
; here if we strip inbounds from the GEP.
|
|
define void @fold_phi_gep_inbounds_phi_offset(ptr %init, ptr %end, i64 noundef %n) {
|
|
; CHECK-LABEL: define void @fold_phi_gep_inbounds_phi_offset(
|
|
; CHECK-SAME: ptr [[INIT:%.*]], ptr [[END:%.*]], i64 noundef [[N:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N]], %[[ENTRY]] ], [ [[OFF_NEXT:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
|
|
; CHECK-NEXT: [[I_NEXT1:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 [[OFF_NEXT]]
|
|
; CHECK-NEXT: [[I_NEXT]] = freeze ptr [[I_NEXT1]]
|
|
; 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.fr, %loop ]
|
|
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
|
|
%off.next = shl i64 %off, 3
|
|
%i.next = getelementptr inbounds i8, ptr %i, i64 %off.next
|
|
%i.next.fr = freeze ptr %i.next
|
|
%cond = icmp eq ptr %i.next.fr, %end
|
|
br i1 %cond, label %loop, label %exit
|
|
|
|
exit: ; preds = %loop
|
|
ret void
|
|
}
|
|
|
|
; Same as previous, but also requires freezing %n.
|
|
define void @fold_phi_gep_phi_offset_multiple(ptr %init, ptr %end, i64 %n) {
|
|
; CHECK-LABEL: define void @fold_phi_gep_phi_offset_multiple(
|
|
; CHECK-SAME: ptr [[INIT:%.*]], ptr [[END:%.*]], i64 [[N:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[I:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF:%.*]] = phi i64 [ [[N]], %[[ENTRY]] ], [ [[OFF_NEXT:%.*]], %[[LOOP]] ]
|
|
; CHECK-NEXT: [[OFF_NEXT]] = shl i64 [[OFF]], 3
|
|
; CHECK-NEXT: [[I_NEXT1:%.*]] = getelementptr inbounds i8, ptr [[I]], i64 [[OFF_NEXT]]
|
|
; CHECK-NEXT: [[I_NEXT]] = freeze ptr [[I_NEXT1]]
|
|
; 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.fr, %loop ]
|
|
%off = phi i64 [ %n, %entry ], [ %off.next, %loop ]
|
|
%off.next = shl i64 %off, 3
|
|
%i.next = getelementptr inbounds i8, ptr %i, i64 %off.next
|
|
%i.next.fr = freeze ptr %i.next
|
|
%cond = icmp eq ptr %i.next.fr, %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: define void @fold_phi_multiple_insts(
|
|
; CHECK-SAME: i32 [[INIT:%.*]], i32 [[N:%.*]]) {
|
|
; 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: define void @fold_phi_multiple_back_edges(
|
|
; CHECK-SAME: i32 [[INIT:%.*]], i32 [[N:%.*]], i32 [[M:%.*]]) {
|
|
; 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: define void @fold_phi_multiple_start_values(
|
|
; CHECK-SAME: i1 [[C:%.*]], i32 [[INIT:%.*]], i32 [[INIT2:%.*]], i32 [[N:%.*]]) {
|
|
; 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
|
|
}
|
|
|
|
; We can remove this freeze as the incoming values to the PHI have the same
|
|
; well-defined start value and the GEP can't produce poison, but this is
|
|
; currently unsupported.
|
|
define void @fold_phi_noundef_start_value(ptr noundef %init, i1 %cond.0, i1 %cond.1, i1 %cond.2) {
|
|
; CHECK-LABEL: define void @fold_phi_noundef_start_value(
|
|
; CHECK-SAME: ptr noundef [[INIT:%.*]], i1 [[COND_0:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[IV_0:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[IV_0_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
|
|
; CHECK-NEXT: br i1 [[COND_0]], label %[[LOOP_LATCH]], label %[[IF_ELSE:.*]]
|
|
; CHECK: [[IF_ELSE]]:
|
|
; CHECK-NEXT: [[IV_1:%.*]] = getelementptr i8, ptr [[IV_0]], i64 -8
|
|
; CHECK-NEXT: br label %[[LOOP_LATCH]]
|
|
; CHECK: [[LOOP_LATCH]]:
|
|
; CHECK-NEXT: [[IV_2:%.*]] = phi ptr [ [[IV_0]], %[[LOOP]] ], [ [[IV_1]], %[[IF_ELSE]] ]
|
|
; CHECK-NEXT: [[IV_2_FR:%.*]] = freeze ptr [[IV_2]]
|
|
; CHECK-NEXT: [[IV_2_FR_INT:%.*]] = ptrtoint ptr [[IV_2_FR]] to i64
|
|
; CHECK-NEXT: [[IV_0_INT:%.*]] = ptrtoint ptr [[IV_0]] to i64
|
|
; CHECK-NEXT: [[IDX:%.*]] = sub i64 [[IV_0_INT]], [[IV_2_FR_INT]]
|
|
; CHECK-NEXT: [[IV_0_NEXT]] = getelementptr i8, ptr [[IV_0]], i64 [[IDX]]
|
|
; CHECK-NEXT: br i1 [[COND_2]], label %[[EXIT:.*]], label %[[LOOP]]
|
|
; CHECK: [[EXIT]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv.0 = phi ptr [ %init, %entry ], [ %iv.0.next, %loop.latch ]
|
|
br i1 %cond.0, label %loop.latch, label %if.else
|
|
|
|
if.else:
|
|
%iv.1 = getelementptr i8, ptr %iv.0, i64 -8
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%iv.2 = phi ptr [ %iv.0, %loop ], [ %iv.1, %if.else ]
|
|
%iv.2.fr = freeze ptr %iv.2
|
|
%iv.2.fr.int = ptrtoint ptr %iv.2.fr to i64
|
|
%iv.0.int = ptrtoint ptr %iv.0 to i64
|
|
%idx = sub i64 %iv.0.int, %iv.2.fr.int
|
|
%iv.0.next = getelementptr i8, ptr %iv.0, i64 %idx
|
|
br i1 %cond.2, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
declare ptr @get_ptr()
|
|
|
|
; When the phi isn't a simple recurrence and has multiple inputs from the same
|
|
; predecessor, we need to be careful to avoid iterator invalidation. The phi
|
|
; must have identical values for the predecessor and at no point should the
|
|
; freeze be pushed to a single one of the uses, e.g.
|
|
;
|
|
; %iv.2 = phi ptr [ %iv.0, %loop ], [ %iv.1.fr, %if.else ], [ %iv.1, %if.else ]
|
|
;
|
|
; We don't support this case, although it could be handled if there's a use
|
|
; case.
|
|
define void @fold_phi_non_simple_recurrence_multiple_forward_edges(ptr noundef %init, i1 %cond.0, i1 %cond.1) {
|
|
; CHECK-LABEL: define void @fold_phi_non_simple_recurrence_multiple_forward_edges(
|
|
; CHECK-SAME: ptr noundef [[INIT:%.*]], i1 [[COND_0:%.*]], i1 [[COND_1:%.*]]) {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[IV_0:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[IV_0_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
|
|
; CHECK-NEXT: br i1 [[COND_0]], label %[[LOOP_LATCH]], label %[[IF_ELSE:.*]]
|
|
; CHECK: [[IF_ELSE]]:
|
|
; CHECK-NEXT: [[IV_1:%.*]] = call ptr @get_ptr()
|
|
; CHECK-NEXT: br i1 false, label %[[LOOP_LATCH]], label %[[LOOP_LATCH]]
|
|
; CHECK: [[LOOP_LATCH]]:
|
|
; CHECK-NEXT: [[IV_2:%.*]] = phi ptr [ [[IV_0]], %[[LOOP]] ], [ [[IV_1]], %[[IF_ELSE]] ], [ [[IV_1]], %[[IF_ELSE]] ]
|
|
; CHECK-NEXT: [[IV_2_FR:%.*]] = freeze ptr [[IV_2]]
|
|
; CHECK-NEXT: [[IV_2_FR_INT:%.*]] = ptrtoint ptr [[IV_2_FR]] to i64
|
|
; CHECK-NEXT: [[IV_0_INT:%.*]] = ptrtoint ptr [[IV_0]] to i64
|
|
; CHECK-NEXT: [[IDX:%.*]] = sub i64 [[IV_0_INT]], [[IV_2_FR_INT]]
|
|
; CHECK-NEXT: [[IV_0_NEXT]] = getelementptr i8, ptr [[IV_0]], i64 [[IDX]]
|
|
; CHECK-NEXT: br i1 [[COND_1]], label %[[EXIT:.*]], label %[[LOOP]]
|
|
; CHECK: [[EXIT]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv.0 = phi ptr [ %init, %entry ], [ %iv.0.next, %loop.latch ]
|
|
br i1 %cond.0, label %loop.latch, label %if.else
|
|
|
|
if.else:
|
|
%iv.1 = call ptr @get_ptr()
|
|
br i1 %cond.0, label %loop.latch, label %loop.latch
|
|
|
|
loop.latch:
|
|
%iv.2 = phi ptr [ %iv.0, %loop ], [ %iv.1, %if.else ], [ %iv.1, %if.else ]
|
|
%iv.2.fr = freeze ptr %iv.2
|
|
%iv.2.fr.int = ptrtoint ptr %iv.2.fr to i64
|
|
%iv.0.int = ptrtoint ptr %iv.0 to i64
|
|
%idx = sub i64 %iv.0.int, %iv.2.fr.int
|
|
%iv.0.next = getelementptr i8, ptr %iv.0, i64 %idx
|
|
br i1 %cond.1, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; When the phi input comes from an invoke, we need to be careful the freeze
|
|
; isn't pushed after the invoke.
|
|
define void @fold_phi_noundef_start_value_with_invoke(ptr noundef %init, i1 %cond.0, i1 %cond.1) personality ptr undef {
|
|
; CHECK-LABEL: define void @fold_phi_noundef_start_value_with_invoke(
|
|
; CHECK-SAME: ptr noundef [[INIT:%.*]], i1 [[COND_0:%.*]], i1 [[COND_1:%.*]]) personality ptr undef {
|
|
; CHECK-NEXT: [[ENTRY:.*]]:
|
|
; CHECK-NEXT: br label %[[LOOP:.*]]
|
|
; CHECK: [[LOOP]]:
|
|
; CHECK-NEXT: [[IV_0:%.*]] = phi ptr [ [[INIT]], %[[ENTRY]] ], [ [[IV_0_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
|
|
; CHECK-NEXT: br i1 [[COND_0]], label %[[LOOP_LATCH]], label %[[IF_ELSE:.*]]
|
|
; CHECK: [[IF_ELSE]]:
|
|
; CHECK-NEXT: [[IV_1:%.*]] = invoke ptr @get_ptr()
|
|
; CHECK-NEXT: to label %[[LOOP_LATCH]] unwind label %[[UNWIND:.*]]
|
|
; CHECK: [[LOOP_LATCH]]:
|
|
; CHECK-NEXT: [[IV_2:%.*]] = phi ptr [ [[IV_0]], %[[LOOP]] ], [ [[IV_1]], %[[IF_ELSE]] ]
|
|
; CHECK-NEXT: [[IV_2_FR:%.*]] = freeze ptr [[IV_2]]
|
|
; CHECK-NEXT: [[IV_2_FR_INT:%.*]] = ptrtoint ptr [[IV_2_FR]] to i64
|
|
; CHECK-NEXT: [[IV_0_INT:%.*]] = ptrtoint ptr [[IV_0]] to i64
|
|
; CHECK-NEXT: [[IDX:%.*]] = sub i64 [[IV_0_INT]], [[IV_2_FR_INT]]
|
|
; CHECK-NEXT: [[IV_0_NEXT]] = getelementptr i8, ptr [[IV_0]], i64 [[IDX]]
|
|
; CHECK-NEXT: br i1 [[COND_1]], label %[[EXIT:.*]], label %[[LOOP]]
|
|
; CHECK: [[UNWIND]]:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = landingpad i8
|
|
; CHECK-NEXT: cleanup
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: [[EXIT]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv.0 = phi ptr [ %init, %entry ], [ %iv.0.next, %loop.latch ]
|
|
br i1 %cond.0, label %loop.latch, label %if.else
|
|
|
|
if.else:
|
|
%iv.1 = invoke ptr @get_ptr()
|
|
to label %loop.latch unwind label %unwind
|
|
|
|
loop.latch:
|
|
%iv.2 = phi ptr [ %iv.0, %loop ], [ %iv.1, %if.else ]
|
|
%iv.2.fr = freeze ptr %iv.2
|
|
%iv.2.fr.int = ptrtoint ptr %iv.2.fr to i64
|
|
%iv.0.int = ptrtoint ptr %iv.0 to i64
|
|
%idx = sub i64 %iv.0.int, %iv.2.fr.int
|
|
%iv.0.next = getelementptr i8, ptr %iv.0, i64 %idx
|
|
br i1 %cond.1, label %exit, label %loop
|
|
|
|
unwind:
|
|
landingpad i8 cleanup
|
|
unreachable
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @fold_phi_invoke_start_value(i32 %n) personality ptr undef {
|
|
; CHECK-LABEL: define void @fold_phi_invoke_start_value(
|
|
; CHECK-SAME: i32 [[N:%.*]]) personality ptr undef {
|
|
; 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: define void @fold_phi_invoke_noundef_start_value(
|
|
; CHECK-SAME: i32 [[N:%.*]]) personality ptr undef {
|
|
; 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: define ptr @freeze_load_noundef(
|
|
; CHECK-SAME: ptr [[PTR:%.*]]) {
|
|
; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR]], align 8, !noundef [[META0:![0-9]+]]
|
|
; 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: define ptr @freeze_load_dereferenceable(
|
|
; CHECK-SAME: ptr [[PTR:%.*]]) {
|
|
; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR]], align 8, !dereferenceable [[META1:![0-9]+]]
|
|
; 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: define ptr @freeze_load_dereferenceable_or_null(
|
|
; CHECK-SAME: ptr [[PTR:%.*]]) {
|
|
; CHECK-NEXT: [[P:%.*]] = load ptr, ptr [[PTR]], align 8, !dereferenceable_or_null [[META1]]
|
|
; 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: define i32 @freeze_load_with_range(
|
|
; CHECK-SAME: ptr [[PTR:%.*]]) {
|
|
; 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: define i32 @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: define i32 @freeze_ctpop(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[Y:%.*]] = lshr i32 2047, [[X]]
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y]]
|
|
; CHECK-NEXT: [[CTPOP:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[Y_FR]])
|
|
; 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
|
|
}
|
|
|
|
define i32 @freeze_zext_nneg(i8 %x) {
|
|
; CHECK-LABEL: define i32 @freeze_zext_nneg(
|
|
; CHECK-SAME: i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X]]
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i8 [[X_FR]] to i32
|
|
; CHECK-NEXT: ret i32 [[ZEXT]]
|
|
;
|
|
%zext = zext nneg i8 %x to i32
|
|
%fr = freeze i32 %zext
|
|
ret i32 %fr
|
|
}
|
|
|
|
define float @freeze_uitofp_nneg(i8 %x) {
|
|
; CHECK-LABEL: define float @freeze_uitofp_nneg(
|
|
; CHECK-SAME: i8 [[X:%.*]]) {
|
|
; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X]]
|
|
; CHECK-NEXT: [[UITOFP:%.*]] = uitofp i8 [[X_FR]] to float
|
|
; CHECK-NEXT: ret float [[UITOFP]]
|
|
;
|
|
%uitofp = uitofp nneg i8 %x to float
|
|
%fr = freeze float %uitofp
|
|
ret float %fr
|
|
}
|
|
|
|
define i32 @propagate_drop_flags_or(i32 %arg) {
|
|
; CHECK-LABEL: define i32 @propagate_drop_flags_or(
|
|
; CHECK-SAME: i32 [[ARG:%.*]]) {
|
|
; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i32 [[ARG]]
|
|
; CHECK-NEXT: [[V1:%.*]] = or i32 [[ARG_FR]], 2
|
|
; CHECK-NEXT: ret i32 [[V1]]
|
|
;
|
|
%v1 = or disjoint i32 %arg, 2
|
|
%v1.fr = freeze i32 %v1
|
|
ret i32 %v1.fr
|
|
}
|
|
|
|
define i32 @propagate_drop_flags_trunc(i64 %arg) {
|
|
; CHECK-LABEL: define i32 @propagate_drop_flags_trunc(
|
|
; CHECK-SAME: i64 [[ARG:%.*]]) {
|
|
; CHECK-NEXT: [[ARG_FR:%.*]] = freeze i64 [[ARG]]
|
|
; CHECK-NEXT: [[V1:%.*]] = trunc i64 [[ARG_FR]] to i32
|
|
; CHECK-NEXT: ret i32 [[V1]]
|
|
;
|
|
%v1 = trunc nsw nuw i64 %arg to i32
|
|
%v1.fr = freeze i32 %v1
|
|
ret i32 %v1.fr
|
|
}
|
|
|
|
define ptr @propagate_drop_flags_gep_nusw(ptr %p) {
|
|
; CHECK-LABEL: define ptr @propagate_drop_flags_gep_nusw(
|
|
; CHECK-SAME: ptr [[P:%.*]]) {
|
|
; CHECK-NEXT: [[P_FR:%.*]] = freeze ptr [[P]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P_FR]], i64 1
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr nusw i8, ptr %p, i64 1
|
|
%gep.fr = freeze ptr %gep
|
|
ret ptr %gep.fr
|
|
}
|
|
|
|
define ptr @propagate_drop_flags_gep_nuw(ptr %p) {
|
|
; CHECK-LABEL: define ptr @propagate_drop_flags_gep_nuw(
|
|
; CHECK-SAME: ptr [[P:%.*]]) {
|
|
; CHECK-NEXT: [[P_FR:%.*]] = freeze ptr [[P]]
|
|
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[P_FR]], i64 1
|
|
; CHECK-NEXT: ret ptr [[GEP]]
|
|
;
|
|
%gep = getelementptr nuw i8, ptr %p, i64 1
|
|
%gep.fr = freeze ptr %gep
|
|
ret ptr %gep.fr
|
|
}
|
|
|
|
define i1 @propagate_drop_flags_icmp(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: define i1 @propagate_drop_flags_icmp(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
|
|
; CHECK-NEXT: [[A_FR:%.*]] = freeze i32 [[A]]
|
|
; CHECK-NEXT: [[RET:%.*]] = icmp ult i32 [[A_FR]], 3
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%ret = icmp samesign ult i32 %a, 3
|
|
%ret.fr = freeze i1 %ret
|
|
ret i1 %ret.fr
|
|
}
|
|
|
|
declare i32 @llvm.umax.i32(i32 %a, i32 %b)
|
|
|
|
define i32 @freeze_call_with_range_attr(i32 %a) {
|
|
; CHECK-LABEL: define i32 @freeze_call_with_range_attr(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: [[Y:%.*]] = lshr i32 2047, [[A]]
|
|
; CHECK-NEXT: [[Y_FR:%.*]] = freeze i32 [[Y]]
|
|
; CHECK-NEXT: [[X:%.*]] = call i32 @llvm.umax.i32(i32 [[Y_FR]], i32 50)
|
|
; CHECK-NEXT: ret i32 [[X]]
|
|
;
|
|
%y = lshr i32 2047, %a
|
|
%x = call range(i32 0, 2048) i32 @llvm.umax.i32(i32 %y, i32 50)
|
|
%x.fr = freeze i32 %x
|
|
ret i32 %x.fr
|
|
}
|
|
|
|
declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
|
|
|
|
define ptr @freeze_ptrmask_align(ptr %p, i64 noundef %m) {
|
|
; CHECK-LABEL: define ptr @freeze_ptrmask_align(
|
|
; CHECK-SAME: ptr [[P:%.*]], i64 noundef [[M:%.*]]) {
|
|
; CHECK-NEXT: [[P_FR:%.*]] = freeze ptr [[P]]
|
|
; CHECK-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P_FR]], i64 [[M]])
|
|
; CHECK-NEXT: ret ptr [[MASK]]
|
|
;
|
|
%mask = call align(4) ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
|
|
%fr = freeze ptr %mask
|
|
ret ptr %fr
|
|
}
|
|
|
|
define ptr @freeze_ptrmask_nonnull(ptr %p, i64 noundef %m) {
|
|
; CHECK-LABEL: define ptr @freeze_ptrmask_nonnull(
|
|
; CHECK-SAME: ptr [[P:%.*]], i64 noundef [[M:%.*]]) {
|
|
; CHECK-NEXT: [[P_FR:%.*]] = freeze ptr [[P]]
|
|
; CHECK-NEXT: [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P_FR]], i64 [[M]])
|
|
; CHECK-NEXT: ret ptr [[MASK]]
|
|
;
|
|
%mask = call nonnull ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
|
|
%fr = freeze ptr %mask
|
|
ret ptr %fr
|
|
}
|
|
|
|
define i64 @pr161492_1(i1 %cond) {
|
|
; CHECK-LABEL: define i64 @pr161492_1(
|
|
; CHECK-SAME: i1 [[COND:%.*]]) {
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%fr1 = freeze i64 poison
|
|
%fr2 = freeze i64 poison
|
|
%ret = select i1 %cond, i64 %fr1, i64 %fr2
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i64 @pr161492_2(i1 %cond) {
|
|
; CHECK-LABEL: define i64 @pr161492_2(
|
|
; CHECK-SAME: i1 [[COND:%.*]]) {
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%fr = freeze i64 poison
|
|
%ret = select i1 %cond, i64 %fr, i64 %fr
|
|
ret i64 %ret
|
|
}
|
|
|
|
; Reduced from: https://github.com/dtcxzyw/llvm-opt-benchmark/blob/main/bench/duckdb/original/miniz.ll
|
|
;
|
|
; This test is sensitive to an infinite combine loop whereby 'nneg' flag can be
|
|
; added to zext and then dropped by the freeze handling code and so on.
|
|
;
|
|
; https://github.com/llvm/llvm-project/pull/171435
|
|
define i32 @pr171435_1(ptr noundef %arg) {
|
|
; CHECK-LABEL: define i32 @pr171435_1(
|
|
; CHECK-SAME: ptr noundef [[ARG:%.*]]) {
|
|
; CHECK-NEXT: [[BB_1:.*]]:
|
|
; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG]], i64 4
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[GETELEMENTPTR]], align 4
|
|
; CHECK-NEXT: [[LOAD1:%.*]] = load i32, ptr [[ARG]], align 8
|
|
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[LOAD1]], 0
|
|
; CHECK-NEXT: br i1 [[ICMP]], label %[[BB_2:.*]], label %[[BB_3:.*]]
|
|
; CHECK: [[BB_2]]:
|
|
; CHECK-NEXT: br label %[[BB_3]]
|
|
; CHECK: [[BB_3]]:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[LOAD]], %[[BB_1]] ], [ 0, %[[BB_2]] ]
|
|
; CHECK-NEXT: [[PHI_FR:%.*]] = freeze i32 [[PHI]]
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[PHI_FR]], -8
|
|
; CHECK-NEXT: store i32 [[ADD]], ptr [[GETELEMENTPTR]], align 4
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
bb.1:
|
|
%getelementptr = getelementptr inbounds nuw i8, ptr %arg, i64 4
|
|
%load = load i32, ptr %getelementptr, align 4
|
|
%load1 = load i32, ptr %arg, align 8
|
|
%icmp = icmp eq i32 %load1, 0
|
|
br i1 %icmp, label %bb.2, label %bb.3
|
|
|
|
bb.2: ; preds = %bb.1
|
|
br label %bb.3
|
|
|
|
bb.3: ; preds = %bb.2, %bb.1
|
|
%phi = phi i32 [ %load, %bb.1 ], [ 0, %bb.2 ]
|
|
%add = add i32 %phi, -8
|
|
%zext = zext i32 %add to i64
|
|
%lshr = lshr i64 %zext, 3
|
|
%freeze = freeze i64 %lshr
|
|
%call = call i64 @llvm.umin.i64(i64 %freeze, i64 0)
|
|
%trunc = trunc i64 %call to i32
|
|
%shl = shl nuw i32 %trunc, 3
|
|
%sub = sub i32 %add, %shl
|
|
store i32 %sub, ptr %getelementptr, align 4
|
|
ret i32 0
|
|
}
|
|
|
|
; Reduced from: https://github.com/dtcxzyw/llvm-opt-benchmark/blob/main/bench/ffmpeg/original/avc.ll
|
|
;
|
|
; This test is sensitive to an infinite combine loop whereby freeze gets pushed
|
|
; around the loop.
|
|
;
|
|
; https://github.com/llvm/llvm-project/pull/171435
|
|
define i32 @pr171435_2(ptr noundef %arg, i32 noundef %arg1) "instcombine-no-verify-fixpoint" {
|
|
; CHECK-LABEL: define i32 @pr171435_2(
|
|
; CHECK-SAME: ptr noundef [[ARG:%.*]], i32 noundef [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: [[BB_1:.*]]:
|
|
; CHECK-NEXT: [[CALL:%.*]] = call ptr @get_ptr()
|
|
; CHECK-NEXT: br label %[[BB_2:.*]]
|
|
; CHECK: [[BB_2]]:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 8, %[[BB_1]] ], [ [[PHI14:%.*]], %[[BB_13:.*]] ]
|
|
; CHECK-NEXT: [[ICMP:%.*]] = phi i1 [ false, %[[BB_1]] ], [ true, %[[BB_13]] ]
|
|
; CHECK-NEXT: br i1 [[ICMP]], label %[[BB_13]], label %[[BB_4:.*]]
|
|
; CHECK: [[BB_4]]:
|
|
; CHECK-NEXT: br i1 true, label %[[BB_5:.*]], label %[[BB_7:.*]]
|
|
; CHECK: [[BB_5]]:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[CALL]], align 1
|
|
; CHECK-NEXT: [[CALL6:%.*]] = call i32 @llvm.bswap.i32(i32 [[LOAD]])
|
|
; CHECK-NEXT: br label %[[BB_8:.*]]
|
|
; CHECK: [[BB_7]]:
|
|
; CHECK-NEXT: br label %[[BB_8]]
|
|
; CHECK: [[BB_8]]:
|
|
; CHECK-NEXT: [[PHI9_FR:%.*]] = phi i32 [ [[CALL6]], %[[BB_5]] ], [ poison, %[[BB_7]] ]
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[PHI9_FR]], 1
|
|
; CHECK-NEXT: [[ASHR:%.*]] = lshr i32 [[PHI9_FR]], 1
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[ASHR]], [[AND]]
|
|
; CHECK-NEXT: [[ADD10:%.*]] = add i32 [[PHI]], [[ADD]]
|
|
; CHECK-NEXT: [[ADD10_FR:%.*]] = freeze i32 [[ADD10]]
|
|
; CHECK-NEXT: [[AND11:%.*]] = and i32 [[ADD10_FR]], 255
|
|
; CHECK-NEXT: [[ICMP12:%.*]] = icmp eq i32 [[AND11]], 0
|
|
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[ICMP12]], i32 [[PHI]], i32 [[AND11]]
|
|
; CHECK-NEXT: br label %[[BB_13]]
|
|
; CHECK: [[BB_13]]:
|
|
; CHECK-NEXT: [[PHI14]] = phi i32 [ [[PHI]], %[[BB_2]] ], [ [[SELECT]], %[[BB_8]] ]
|
|
; CHECK-NEXT: br label %[[BB_2]]
|
|
;
|
|
bb.1:
|
|
%call = call ptr @get_ptr()
|
|
br label %bb.2
|
|
|
|
bb.2: ; preds = %bb.13, %bb.1
|
|
%phi = phi i32 [ 8, %bb.1 ], [ %phi14, %bb.13 ]
|
|
%phi3 = phi i32 [ 8, %bb.1 ], [ 0, %bb.13 ]
|
|
%icmp = icmp eq i32 %phi3, 0
|
|
br i1 %icmp, label %bb.13, label %bb.4
|
|
|
|
bb.4: ; preds = %bb.2
|
|
br i1 true, label %bb.5, label %bb.7
|
|
|
|
bb.5: ; preds = %bb.4
|
|
%load = load i32, ptr %call, align 1
|
|
%call6 = call i32 @llvm.bswap.i32(i32 %load)
|
|
br label %bb.8
|
|
|
|
bb.7: ; preds = %bb.4
|
|
br label %bb.8
|
|
|
|
bb.8: ; preds = %bb.7, %bb.5
|
|
%phi9 = phi i32 [ %call6, %bb.5 ], [ 0, %bb.7 ]
|
|
%and = and i32 %phi9, 1
|
|
%ashr = ashr i32 %phi9, 1
|
|
%add = add nsw i32 %ashr, %and
|
|
%add10 = add nsw i32 %phi, %add
|
|
%and11 = and i32 %add10, 255
|
|
%icmp12 = icmp eq i32 %and11, 0
|
|
%freeze = freeze i1 %icmp12
|
|
%select = select i1 %freeze, i32 %phi, i32 %and11
|
|
br label %bb.13
|
|
|
|
bb.13: ; preds = %bb.8, %bb.2
|
|
%phi14 = phi i32 [ %phi, %bb.2 ], [ %select, %bb.8 ]
|
|
br label %bb.2
|
|
}
|
|
|
|
define float @freeze_fabs_nofpclass(float %a) {
|
|
; CHECK-LABEL: define float @freeze_fabs_nofpclass(
|
|
; CHECK-SAME: float [[A:%.*]]) {
|
|
; CHECK-NEXT: [[A_FR:%.*]] = freeze float [[A]]
|
|
; CHECK-NEXT: [[X:%.*]] = call float @llvm.fabs.f32(float [[A_FR]])
|
|
; CHECK-NEXT: ret float [[X]]
|
|
;
|
|
%x = call nofpclass(nan) float @llvm.fabs.f32(float %a)
|
|
%x.fr = freeze float %x
|
|
ret float %x.fr
|
|
}
|
|
|
|
!0 = !{}
|
|
!1 = !{i64 4}
|
|
!2 = !{i32 0, i32 100}
|
|
;.
|
|
; CHECK: [[META0]] = !{}
|
|
; CHECK: [[META1]] = !{i64 4}
|
|
; CHECK: [[RNG2]] = !{i32 0, i32 100}
|
|
;.
|