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
1026 lines
35 KiB
LLVM
1026 lines
35 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
|
|
; REQUIRES: asserts
|
|
; RUN: opt -S -passes=licm -ipt-expensive-asserts=true < %s | FileCheck %s
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
|
|
declare void @f() nounwind
|
|
declare void @llvm.experimental.guard(i1,...)
|
|
|
|
; constant fold on first ieration
|
|
define i32 @test1(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test1(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ult i32 [[IV]], 2000
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi i32 [ 0, %entry ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue ]
|
|
%r.chk = icmp ult i32 %iv, 2000
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; Same as test1, but with a floating point IR and fcmp
|
|
define i32 @test_fcmp(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test_fcmp(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = fcmp olt float [[IV]], 2.000000e+03
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = fadd float [[IV]], 1.000000e+00
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = fcmp ogt float [[INC]], 1.000000e+03
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi float [ 0.0, %entry ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue ]
|
|
%r.chk = fcmp olt float %iv, 2000.0
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = fadd float %iv, 1.0
|
|
%exitcond = fcmp ogt float %inc, 1000.0
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; Count down from a.length w/entry guard
|
|
; TODO: currently unable to prove the following:
|
|
; ule i32 (add nsw i32 %len, -1), %len where len is [0, 512]
|
|
define i32 @test2(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test2(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A]], align 4, !range [[RNG0:![0-9]+]]
|
|
; CHECK-NEXT: [[IS_NON_POS:%.*]] = icmp eq i32 [[LEN]], 0
|
|
; CHECK-NEXT: br i1 [[IS_NON_POS]], label [[FAIL:%.*]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[LENMINUSONE:%.*]] = add nsw i32 [[LEN]], -1
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[LENMINUSONE]], [[PREHEADER]] ], [ [[DEC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ule i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL_LOOPEXIT:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[DEC]] = add nsw i32 [[IV]], -1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[DEC]], 0
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail.loopexit:
|
|
; CHECK-NEXT: br label [[FAIL]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
%len = load i32, ptr %a, align 4, !range !{i32 0, i32 512}
|
|
%is.non.pos = icmp eq i32 %len, 0
|
|
br i1 %is.non.pos, label %fail, label %preheader
|
|
preheader:
|
|
%lenminusone = add nsw i32 %len, -1
|
|
br label %for.body
|
|
for.body:
|
|
%iv = phi i32 [ %lenminusone, %preheader ], [ %dec, %continue ]
|
|
%acc = phi i32 [ 0, %preheader ], [ %add, %continue ]
|
|
%r.chk = icmp ule i32 %iv, %len
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%dec = add nsw i32 %iv, -1
|
|
%exitcond = icmp eq i32 %dec, 0
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; trivially true for zero
|
|
define i32 @test3(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test3(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0
|
|
; CHECK-NEXT: br i1 [[IS_ZERO]], label [[FAIL:%.*]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ule i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL_LOOPEXIT:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail.loopexit:
|
|
; CHECK-NEXT: br label [[FAIL]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
%len = load i32, ptr %a, align 4, !range !{i32 0, i32 512}
|
|
%is.zero = icmp eq i32 %len, 0
|
|
br i1 %is.zero, label %fail, label %preheader
|
|
preheader:
|
|
br label %for.body
|
|
for.body:
|
|
%iv = phi i32 [ 0, %preheader ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %preheader ], [ %add, %continue ]
|
|
%r.chk = icmp ule i32 %iv, %len
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; Same as previous case, with commuted icmp.
|
|
define i32 @test3_commuted(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test3_commuted(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0
|
|
; CHECK-NEXT: br i1 [[IS_ZERO]], label [[FAIL:%.*]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp uge i32 [[LEN]], [[IV]]
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL_LOOPEXIT:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail.loopexit:
|
|
; CHECK-NEXT: br label [[FAIL]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
%len = load i32, ptr %a, align 4, !range !{i32 0, i32 512}
|
|
%is.zero = icmp eq i32 %len, 0
|
|
br i1 %is.zero, label %fail, label %preheader
|
|
preheader:
|
|
br label %for.body
|
|
for.body:
|
|
%iv = phi i32 [ 0, %preheader ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %preheader ], [ %add, %continue ]
|
|
%r.chk = icmp uge i32 %len, %iv
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; requires fact length is non-zero
|
|
define i32 @test4(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test4(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LEN:%.*]] = load i32, ptr [[A]], align 4, !range [[RNG0]]
|
|
; CHECK-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0
|
|
; CHECK-NEXT: br i1 [[IS_ZERO]], label [[FAIL:%.*]], label [[PREHEADER:%.*]]
|
|
; CHECK: preheader:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ult i32 [[IV]], [[LEN]]
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL_LOOPEXIT:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail.loopexit:
|
|
; CHECK-NEXT: br label [[FAIL]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
%len = load i32, ptr %a, align 4, !range !{i32 0, i32 512}
|
|
%is.zero = icmp eq i32 %len, 0
|
|
br i1 %is.zero, label %fail, label %preheader
|
|
preheader:
|
|
br label %for.body
|
|
for.body:
|
|
%iv = phi i32 [ 0, %preheader ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %preheader ], [ %add, %continue ]
|
|
%r.chk = icmp ult i32 %iv, %len
|
|
br i1 %r.chk, label %continue, label %fail
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; variation on test1 with branch swapped
|
|
define i32 @test-brswap(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test-brswap(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ugt i32 [[IV]], 2000
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[FAIL:%.*]], label [[CONTINUE]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi i32 [ 0, %entry ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue ]
|
|
%r.chk = icmp ugt i32 %iv, 2000
|
|
br i1 %r.chk, label %fail, label %continue
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
define i32 @test-nonphi(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test-nonphi(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[IV]], 72
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ugt i32 [[XOR]], 2000
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[FAIL:%.*]], label [[CONTINUE]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi i32 [ 0, %entry ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue ]
|
|
%xor = xor i32 %iv, 72
|
|
%r.chk = icmp ugt i32 %xor, 2000
|
|
br i1 %r.chk, label %fail, label %continue
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
define i32 @test-wrongphi(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test-wrongphi(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[IV]], 500
|
|
; CHECK-NEXT: br i1 [[COND]], label [[DUMMY_BLOCK1:%.*]], label [[DUMMY_BLOCK2:%.*]]
|
|
; CHECK: dummy_block1:
|
|
; CHECK-NEXT: br label [[DUMMY_BLOCK2]]
|
|
; CHECK: dummy_block2:
|
|
; CHECK-NEXT: [[WRONGPHI:%.*]] = phi i32 [ 11, [[FOR_BODY]] ], [ 12, [[DUMMY_BLOCK1]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ugt i32 [[WRONGPHI]], 2000
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[FAIL:%.*]], label [[CONTINUE]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi i32 [ 0, %entry ], [ %inc, %continue ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue ]
|
|
%cond = icmp ult i32 %iv, 500
|
|
br i1 %cond, label %dummy_block1, label %dummy_block2
|
|
|
|
dummy_block1:
|
|
br label %dummy_block2
|
|
|
|
dummy_block2:
|
|
%wrongphi = phi i32 [11, %for.body], [12, %dummy_block1]
|
|
%r.chk = icmp ugt i32 %wrongphi, 2000
|
|
br i1 %r.chk, label %fail, label %continue
|
|
continue:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
; This works because loop-simplify is run implicitly, but test for it anyways
|
|
define i32 @test-multiple-latch(ptr noalias nocapture readonly %a) nounwind uwtable {
|
|
; CHECK-LABEL: define i32 @test-multiple-latch(
|
|
; CHECK-SAME: ptr noalias readonly captures(none) [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[A]], align 4
|
|
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY_BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ADD:%.*]], [[FOR_BODY_BACKEDGE]] ]
|
|
; CHECK-NEXT: [[R_CHK:%.*]] = icmp ult i32 [[IV]], 2000
|
|
; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE1:%.*]], label [[FAIL:%.*]]
|
|
; CHECK: continue1:
|
|
; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]]
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ADD]], 0
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[CONTINUE2:%.*]], label [[FOR_BODY_BACKEDGE]]
|
|
; CHECK: for.body.backedge:
|
|
; CHECK-NEXT: br label [[FOR_BODY]]
|
|
; CHECK: continue2:
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_BACKEDGE]]
|
|
; CHECK: for.cond.cleanup:
|
|
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[CONTINUE2]] ]
|
|
; CHECK-NEXT: ret i32 [[ADD_LCSSA]]
|
|
; CHECK: fail:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: ret i32 -1
|
|
;
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%iv = phi i32 [ 0, %entry ], [ %inc, %continue1 ], [ %inc, %continue2 ]
|
|
%acc = phi i32 [ 0, %entry ], [ %add, %continue1 ], [ %add, %continue2 ]
|
|
%r.chk = icmp ult i32 %iv, 2000
|
|
br i1 %r.chk, label %continue1, label %fail
|
|
continue1:
|
|
%i1 = load i32, ptr %a, align 4
|
|
%add = add nsw i32 %i1, %acc
|
|
%inc = add nuw nsw i32 %iv, 1
|
|
%cmp = icmp eq i32 %add, 0
|
|
br i1 %cmp, label %continue2, label %for.body
|
|
continue2:
|
|
%exitcond = icmp eq i32 %inc, 1000
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret i32 %add
|
|
|
|
fail:
|
|
call void @f()
|
|
ret i32 -1
|
|
}
|
|
|
|
define void @test-hoisting-in-presence-of-guards(i1 %c, ptr %p) {
|
|
; CHECK-LABEL: define void @test-hoisting-in-presence-of-guards(
|
|
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[INVARIANT_COND:%.*]] = icmp ne i32 [[A]], 100
|
|
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[INVARIANT_COND]]) [ "deopt"() ]
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i32 %iv, 1
|
|
%a = load i32, ptr %p
|
|
%invariant_cond = icmp ne i32 %a, 100
|
|
call void (i1, ...) @llvm.experimental.guard(i1 %invariant_cond) [ "deopt"() ]
|
|
%loop_cond = icmp slt i32 %iv.next, 1000
|
|
br i1 %loop_cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
|
|
declare void @may_throw() inaccessiblememonly
|
|
|
|
; Test that we can sink a mustexecute load from loop header even in presence of
|
|
; throwing instructions after it.
|
|
define void @test_hoist_from_header_01(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_header_01(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%load = load i32, ptr %p
|
|
call void @may_throw()
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_hoist_from_header_02(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_header_02(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%load = load i32, ptr %p
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
call void @may_throw()
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_hoist_from_header_03(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_header_03(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%load = load i32, ptr %p
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
call void @may_throw()
|
|
%iv.next = add i32 %iv, %merge
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that a throwing instruction prohibits hoisting across it.
|
|
define void @test_hoist_from_header_04(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_header_04(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
call void @may_throw()
|
|
%load = load i32, ptr %p
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can hoist a mustexecute load from backedge even if something
|
|
; throws after it.
|
|
define void @test_hoist_from_backedge_01(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_backedge_01(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%load = load i32, ptr %p
|
|
call void @may_throw()
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we don't hoist the load if something before it can throw.
|
|
define void @test_hoist_from_backedge_02(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_backedge_02(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
call void @may_throw()
|
|
%load = load i32, ptr %p
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_hoist_from_backedge_03(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_backedge_03(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
call void @may_throw()
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%load = load i32, ptr %p
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_hoist_from_backedge_04(ptr %p, i32 %n) {
|
|
; CHECK-LABEL: define void @test_hoist_from_backedge_04(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[N:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
|
|
; CHECK-NEXT: call void @may_throw()
|
|
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV]], [[N]]
|
|
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if.true:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: if.false:
|
|
; CHECK-NEXT: [[B:%.*]] = mul i32 [[IV]], [[IV]]
|
|
; CHECK-NEXT: br label [[BACKEDGE]]
|
|
; CHECK: backedge:
|
|
; CHECK-NEXT: [[MERGE:%.*]] = phi i32 [ [[A]], [[IF_TRUE]] ], [ [[B]], [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], [[MERGE]]
|
|
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], [[LOAD]]
|
|
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
|
|
%dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ]
|
|
call void @may_throw()
|
|
%cond = icmp slt i32 %iv, %n
|
|
br i1 %cond, label %if.true, label %if.false
|
|
|
|
if.true:
|
|
%a = add i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
if.false:
|
|
%b = mul i32 %iv, %iv
|
|
br label %backedge
|
|
|
|
backedge:
|
|
%merge = phi i32 [ %a, %if.true ], [ %b, %if.false ]
|
|
%iv.next = add i32 %iv, %merge
|
|
%load = load i32, ptr %p
|
|
%loop.cond = icmp ult i32 %iv.next, %load
|
|
br i1 %loop.cond, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
;.
|
|
; CHECK: [[RNG0]] = !{i32 0, i32 512}
|
|
;.
|