[Attributor] Unify testing (=updates,prefixes,run configurations,...)

When the Attributor was created the test update scripts were not well
suited to deal with the challenges of IR attribute checking. This
partially improved.

Since then we also added three additional configurations that need
testing; in total we now have the following four:
{ TUNIT, CGSCC } x { old pass manager (OPM), new pass manager (NPM) }

Finally, the number of developers and tests grew rapidly (partially due
to the addition of ArgumentPromotion and IPConstantProp tests), which
resulted in tests only being run in some configurations, different
prefixes being used, and different "styles" of checks being used.

Due to the above reasons I believed we needed to take another look at
the test update scripts. While we started to use them, via UTC_ARGS:
--enable/disable, the other problems remained. To improve the testing
situation for *all* configurations, to simplify future updates to the
test, and to help identify subtle effects of future changes, we now use
the test update scripts for (almost) all Attributor tests.

An exhaustive prefix list minimizes the number of check lines and makes
it easy to identify and compare configurations.

Tests have been adjusted in the process but we tried to keep their
intend unchanged.

Reviewed By: sstefan1

Differential Revision: https://reviews.llvm.org/D76588
This commit is contained in:
Johannes Doerfert 2020-04-08 19:04:57 -05:00
parent acfee72a05
commit 3ca54f4595
87 changed files with 9508 additions and 5508 deletions

View File

@ -1,14 +1,29 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 -S < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define internal i32 @deref(i32* %x) nounwind {
; CHECK-LABEL: define {{[^@]+}}@deref
; CHECK-SAME: (i32 [[TMP0:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[X_PRIV]]
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[X_PRIV]], align 4
; CHECK-NEXT: ret i32 [[TMP2]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@deref
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 4
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP2]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@deref
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[X_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[X_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP2]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@deref
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 4
; IS__CGSCC____-NEXT: ret i32 [[TMP2]]
;
entry:
%tmp2 = load i32, i32* %x, align 4
@ -16,14 +31,30 @@ entry:
}
define i32 @f(i32 %x) {
; CHECK-LABEL: define {{[^@]+}}@f
; CHECK-SAME: (i32 [[X:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 1
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @deref(i32 [[TMP0]])
; CHECK-NEXT: ret i32 [[TMP1]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_OPM-SAME: (i32 [[X:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[X_ADDR:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = call i32 @deref(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X_ADDR]])
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP1]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_NPM-SAME: (i32 [[X:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[X_ADDR:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 1
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = call i32 @deref(i32 [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP1]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@f
; IS__CGSCC____-SAME: (i32 [[X:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[X_ADDR:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @deref(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[X_ADDR]])
; IS__CGSCC____-NEXT: ret i32 [[TMP1]]
;
entry:
%x_addr = alloca i32

View File

@ -1,20 +1,24 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 -S < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR2498
; This test tries to convince CHECK about promoting the load from %A + 2,
; because there is a load of %A in the entry block
define internal i32 @callee(i1 %C, i32* %A) {
;
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* %A
; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* [[A]], align 4
; CHECK-NEXT: br label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: unreachable
; CHECK: F:
; CHECK-NEXT: [[A_2:%.*]] = getelementptr i32, i32* %A, i32 2
; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[A_2]]
; CHECK-NEXT: [[A_2:%.*]] = getelementptr i32, i32* [[A]], i32 2
; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[A_2]], align 4
; CHECK-NEXT: ret i32 [[R]]
;
entry:
@ -33,9 +37,15 @@ F:
}
define i32 @foo(i32* %A) {
; CHECK-LABEL: define {{[^@]+}}@foo(
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i32* nocapture nofree readonly align 4 %A)
; CHECK-NEXT: ret i32 [[X]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly [[A:%.*]])
; IS__TUNIT____-NEXT: [[X:%.*]] = call i32 @callee(i32* nocapture nofree readonly align 4 [[A]])
; IS__TUNIT____-NEXT: ret i32 [[X]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]])
; IS__CGSCC____-NEXT: [[X:%.*]] = call i32 @callee(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC____-NEXT: ret i32 [[X]]
;
%X = call i32 @callee(i1 false, i32* %A) ; <i32> [#uses=1]
ret i32 %X

View File

@ -1,12 +1,24 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define internal fastcc i32 @hash(i32* %ts, i32 %mod) nounwind {
; IS__CGSCC____-LABEL: define {{[^@]+}}@hash()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: unreachable
;
entry:
unreachable
}
define void @encode(i32* %m, i32* %ts, i32* %new) nounwind {
; CHECK-LABEL: define {{[^@]+}}@encode
; CHECK-SAME: (i32* nocapture nofree readnone [[M:%.*]], i32* nocapture nofree readnone [[TS:%.*]], i32* nocapture nofree readnone [[NEW:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%0 = call fastcc i32 @hash( i32* %ts, i32 0 ) nounwind ; <i32> [#uses=0]
unreachable

View File

@ -1,7 +1,18 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define internal fastcc i32 @term_SharingList(i32* %Term, i32* %List) nounwind {
; IS__CGSCC____-LABEL: define {{[^@]+}}@term_SharingList()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: br i1 false, label [[BB:%.*]], label [[BB5:%.*]]
; IS__CGSCC____: bb:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: bb5:
; IS__CGSCC____-NEXT: ret i32 undef
;
entry:
br i1 false, label %bb, label %bb5
@ -14,6 +25,15 @@ bb5: ; preds = %entry
}
define i32 @term_Sharing(i32* %Term) nounwind {
; CHECK-LABEL: define {{[^@]+}}@term_Sharing
; CHECK-SAME: (i32* nocapture nofree readnone [[TERM:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 false, label [[BB_I:%.*]], label [[BB14:%.*]]
; CHECK: bb.i:
; CHECK-NEXT: unreachable
; CHECK: bb14:
; CHECK-NEXT: ret i32 0
;
entry:
br i1 false, label %bb.i, label %bb14

View File

@ -1,17 +1,27 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Test that we only promote arguments when the caller/callee have compatible
; function attrubtes.
target triple = "x86_64-unknown-linux-gnu"
define internal fastcc void @no_promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
; CHECK-LABEL: define {{[^@]+}}@no_promote_avx2
; CHECK-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
; CHECK-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; CHECK-NEXT: ret void
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@no_promote_avx2
; NOT_TUNIT_NPM-SAME: (<4 x i64>* nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
; NOT_TUNIT_NPM-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@no_promote_avx2
; IS__TUNIT_NPM-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
; IS__TUNIT_NPM-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <4 x i64>, <4 x i64>* %arg1
@ -20,17 +30,53 @@ bb:
}
define void @no_promote(<4 x i64>* %arg) #1 {
; CHECK-LABEL: define {{[^@]+}}@no_promote
; CHECK-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; CHECK-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@no_promote
; IS__TUNIT_OPM-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* nocapture nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__TUNIT_OPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@no_promote
; IS__TUNIT_NPM-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__TUNIT_NPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@no_promote
; IS__CGSCC_OPM-SAME: (<4 x i64>* nocapture nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__CGSCC_OPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@no_promote
; IS__CGSCC_NPM-SAME: (<4 x i64>* nocapture nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* noalias nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__CGSCC_NPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <4 x i64>, align 32
@ -44,14 +90,21 @@ bb:
}
define internal fastcc void @promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
; CHECK-LABEL: define {{[^@]+}}@promote_avx2
; CHECK-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <4 x i64>
; CHECK-NEXT: store <4 x i64> [[TMP0]], <4 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1_PRIV]], align 32
; CHECK-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; CHECK-NEXT: ret void
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@promote_avx2
; NOT_TUNIT_NPM-SAME: (<4 x i64>* nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
; NOT_TUNIT_NPM-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@promote_avx2
; IS__TUNIT_NPM-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <4 x i64>
; IS__TUNIT_NPM-NEXT: store <4 x i64> [[TMP0]], <4 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1_PRIV]], align 32
; IS__TUNIT_NPM-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <4 x i64>, <4 x i64>* %arg1
@ -60,18 +113,54 @@ bb:
}
define void @promote(<4 x i64>* %arg) #0 {
; CHECK-LABEL: define {{[^@]+}}@promote
; CHECK-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i64>, <4 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @promote_avx2(<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; CHECK-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@promote
; IS__TUNIT_OPM-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @promote_avx2(<4 x i64>* nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* nocapture nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__TUNIT_OPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@promote
; IS__TUNIT_NPM-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <4 x i64>, <4 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @promote_avx2(<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__TUNIT_NPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@promote
; IS__CGSCC_OPM-SAME: (<4 x i64>* nocapture nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @promote_avx2(<4 x i64>* nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__CGSCC_OPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@promote
; IS__CGSCC_NPM-SAME: (<4 x i64>* nocapture nonnull writeonly align 2 dereferenceable(32) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @promote_avx2(<4 x i64>* noalias nofree nonnull writeonly align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nofree nonnull readonly align 32 dereferenceable(32) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
; IS__CGSCC_NPM-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <4 x i64>, align 32

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Test that we only promote arguments when the caller/callee have compatible
; function attrubtes.
@ -7,14 +10,22 @@ target triple = "x86_64-unknown-linux-gnu"
; This should promote
define internal fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #0 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -23,18 +34,55 @@ bb:
}
define void @avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* %arg) #0 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -49,14 +97,22 @@ bb:
; This should promote
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -65,18 +121,55 @@ bb:
}
define void @avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg) #1 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -91,14 +184,22 @@ bb:
; This should promote
define internal fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -107,18 +208,55 @@ bb:
}
define void @avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* %arg) #0 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -133,14 +271,22 @@ bb:
; This should promote
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #0 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -149,18 +295,55 @@ bb:
}
define void @avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* %arg) #1 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -175,12 +358,20 @@ bb:
; This should not promote
define internal fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -189,17 +380,54 @@ bb:
}
define void @avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg) #2 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -214,12 +442,20 @@ bb:
; This should not promote
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #2 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -228,17 +464,54 @@ bb:
}
define void @avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* %arg) #1 {
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -253,14 +526,22 @@ bb:
; This should promote
define internal fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #3 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -269,18 +550,55 @@ bb:
}
define void @avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* %arg) #4 {
; CHECK-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32
@ -295,14 +613,22 @@ bb:
; This should promote
define internal fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #4 {
; CHECK-LABEL: define {{[^@]+}}@callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; CHECK-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; CHECK-NEXT: ret void
;
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256
; NOT_TUNIT_NPM-SAME: (<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[ARG1:%.*]])
; NOT_TUNIT_NPM-NEXT: bb:
; NOT_TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 64
; NOT_TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; NOT_TUNIT_NPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[ARG:%.*]], <8 x i64> [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[ARG1_PRIV:%.*]] = alloca <8 x i64>
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP0]], <8 x i64>* [[ARG1_PRIV]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1_PRIV]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 64
; IS__TUNIT_NPM-NEXT: ret void
;
bb:
%tmp = load <8 x i64>, <8 x i64>* %arg1
@ -311,18 +637,55 @@ bb:
}
define void @avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* %arg) #3 {
; CHECK-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; CHECK-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; CHECK-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
; IS__TUNIT_OPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_OPM-NEXT: bb:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_OPM-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nocapture nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
; IS__TUNIT_NPM-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: bb:
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__TUNIT_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]], align 1
; IS__TUNIT_NPM-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64> [[TMP0]])
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__TUNIT_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
; IS__CGSCC_OPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: bb:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_OPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_OPM-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_OPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
; IS__CGSCC_NPM-SAME: (<8 x i64>* nocapture nonnull writeonly align 2 dereferenceable(64) [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: bb:
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
; IS__CGSCC_NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull writeonly align 64 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
; IS__CGSCC_NPM-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* noalias nofree nonnull writeonly align 64 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nofree nonnull readonly align 64 dereferenceable(64) [[TMP]])
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 64
; IS__CGSCC_NPM-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
; IS__CGSCC_NPM-NEXT: ret void
;
bb:
%tmp = alloca <8 x i64>, align 32

View File

@ -4,8 +4,10 @@
; we don't do that anymore. It also verifies that the combination of
; globalopt and argpromotion is able to optimize the call safely.
;
; RUN: opt -S -argpromotion %s | FileCheck %s --check-prefix=ARGPROMOTION
; RUN: opt -S -globalopt -argpromotion %s | FileCheck %s --check-prefix=GLOBALOPT_ARGPROMOTION
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i386-pc-windows-msvc19.11.0"
@ -13,25 +15,25 @@ target triple = "i386-pc-windows-msvc19.11.0"
%struct.a = type { i8 }
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
; ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca [[TMP0:%.*]])
; ARGPROMOTION-NEXT: entry:
; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
; ARGPROMOTION-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@internalfun
; IS__TUNIT____-SAME: (%struct.a* noalias nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca nonnull align 4 dereferenceable(1) [[TMP0:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; IS__TUNIT____-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* nonnull align 4 dereferenceable(1) [[TMP1]], %struct.a* nonnull align 4 dereferenceable(1) [[A]])
; IS__TUNIT____-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca nonnull align 4 dereferenceable(1) [[ARGMEM]])
; IS__TUNIT____-NEXT: ret void
;
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr
; GLOBALOPT_ARGPROMOTION-NEXT: entry:
; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; GLOBALOPT_ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; GLOBALOPT_ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
; IS__CGSCC____-LABEL: define {{[^@]+}}@internalfun
; IS__CGSCC____-SAME: (%struct.a* nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca nonnull dereferenceable(1) [[TMP0:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* nonnull align 4 dereferenceable(1) [[TMP1]], %struct.a* nonnull dereferenceable(1) [[A]])
; IS__CGSCC____-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca nonnull align 4 dereferenceable(1) [[ARGMEM]])
; IS__CGSCC____-NEXT: ret void
;
entry:
%a = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %0, i32 0, i32 0
@ -44,21 +46,21 @@ entry:
; This is here to ensure @internalfun is live.
define void @exportedfun(%struct.a* %a) {
; ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]])
; ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
; ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
; ARGPROMOTION-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@exportedfun
; IS__TUNIT____-SAME: (%struct.a* nocapture nofree readnone [[A:%.*]])
; IS__TUNIT____-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; IS__TUNIT____-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
; IS__TUNIT____-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nofree readnone undef, <{ [[STRUCT_A]] }>* inalloca nonnull align 4 dereferenceable(1) [[ARGMEM]])
; IS__TUNIT____-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
; IS__TUNIT____-NEXT: ret void
;
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr
; GLOBALOPT_ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
; GLOBALOPT_ARGPROMOTION-NEXT: call fastcc void @internalfun(<{ [[STRUCT_A]] }>* [[ARGMEM]])
; GLOBALOPT_ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
; IS__CGSCC____-LABEL: define {{[^@]+}}@exportedfun
; IS__CGSCC____-SAME: (%struct.a* nocapture nofree readnone [[A:%.*]])
; IS__CGSCC____-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; IS__CGSCC____-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
; IS__CGSCC____-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nocapture nofree readnone [[A]], <{ [[STRUCT_A]] }>* inalloca nonnull align 4 dereferenceable(1) [[ARGMEM]])
; IS__CGSCC____-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
; IS__CGSCC____-NEXT: ret void
;
%inalloca.save = tail call i8* @llvm.stacksave()
%argmem = alloca inalloca <{ %struct.a }>, align 4

View File

@ -1,14 +1,20 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
%T = type { i32, i32, i32, i32 }
@G = constant %T { i32 0, i32 0, i32 17, i32 25 }
define internal i32 @test(%T* %p) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32 [[P_0_2_VAL:%.*]], i32 [[P_0_3_VAL:%.*]])
; CHECK-LABEL: define {{[^@]+}}@test()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[V:%.*]] = add i32 [[P_0_3_VAL]], [[P_0_2_VAL]]
; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* @G, i64 0, i32 3
; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* @G, i64 0, i32 2
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]], align 4
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]], align 4
; CHECK-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT: ret i32 [[V]]
;
entry:
@ -23,11 +29,7 @@ entry:
define i32 @caller() {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[G_IDX:%.*]] = getelementptr [[T:%.*]], %T* @G, i64 0, i32 2
; CHECK-NEXT: [[G_IDX_VAL:%.*]] = load i32, i32* [[G_IDX]]
; CHECK-NEXT: [[G_IDX1:%.*]] = getelementptr [[T]], %T* @G, i64 0, i32 3
; CHECK-NEXT: [[G_IDX1_VAL:%.*]] = load i32, i32* [[G_IDX1]]
; CHECK-NEXT: [[V:%.*]] = call i32 @test(i32 [[G_IDX_VAL]], i32 [[G_IDX1_VAL]])
; CHECK-NEXT: [[V:%.*]] = call i32 @test()
; CHECK-NEXT: ret i32 [[V]]
;
entry:

View File

@ -1,13 +1,28 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define void @f() {
; CHECK-LABEL: define {{[^@]+}}@f()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 1
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 1
; CHECK-NEXT: call void @g(i32 [[TMP0]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@f()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = alloca i32, align 1
; IS__TUNIT_OPM-NEXT: call void @g(i32* noalias nocapture nonnull readonly dereferenceable(4) [[A]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@f()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = alloca i32, align 1
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 1
; IS__TUNIT_NPM-NEXT: call void @g(i32 [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@f()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 1
; IS__CGSCC____-NEXT: call void @g(i32* noalias nonnull readonly dereferenceable(4) [[A]])
; IS__CGSCC____-NEXT: ret void
;
entry:
%a = alloca i32, align 1
@ -16,13 +31,25 @@ entry:
}
define internal void @g(i32* %a) {
; CHECK-LABEL: define {{[^@]+}}@g
; CHECK-SAME: (i32 [[TMP0:%.*]])
; CHECK-NEXT: [[A_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[A_PRIV]]
; CHECK-NEXT: [[AA:%.*]] = load i32, i32* [[A_PRIV]], align 1
; CHECK-NEXT: call void @z(i32 [[AA]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@g
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nonnull readonly dereferenceable(4) [[A:%.*]])
; IS__TUNIT_OPM-NEXT: [[AA:%.*]] = load i32, i32* [[A]], align 1
; IS__TUNIT_OPM-NEXT: call void @z(i32 [[AA]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@g
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: [[A_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[A_PRIV]]
; IS__TUNIT_NPM-NEXT: [[AA:%.*]] = load i32, i32* [[A_PRIV]], align 1
; IS__TUNIT_NPM-NEXT: call void @z(i32 [[AA]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@g
; IS__CGSCC____-SAME: (i32* nocapture nonnull readonly dereferenceable(4) [[A:%.*]])
; IS__CGSCC____-NEXT: [[AA:%.*]] = load i32, i32* [[A]], align 1
; IS__CGSCC____-NEXT: call void @z(i32 [[AA]])
; IS__CGSCC____-NEXT: ret void
;
%aa = load i32, i32* %a, align 1
call void @z(i32 %aa)

View File

@ -1,28 +1,75 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
%struct.ss = type { i32, i64 }
; Don't drop 'byval' on %X here.
define internal i32 @f(%struct.ss* byval %b, i32* byval %X, i32 %i) nounwind {
; CHECK-LABEL: define {{[^@]+}}@f
; CHECK-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[I:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]]
; CHECK-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; CHECK-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; CHECK-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; CHECK-NEXT: store i32 0, i32* [[X_PRIV]], align 4
; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[X_PRIV]], align 4
; CHECK-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
; CHECK-NEXT: ret i32 [[A]]
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[B:%.*]], i32* noalias nocapture nofree nonnull byval align 4 dereferenceable(4) [[X:%.*]], i32 [[I:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__TUNIT_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; IS__TUNIT_OPM-NEXT: store i32 0, i32* [[X]], align 4
; IS__TUNIT_OPM-NEXT: [[L:%.*]] = load i32, i32* [[X]], align 4
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
; IS__TUNIT_OPM-NEXT: ret i32 [[A]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[I:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]]
; IS__TUNIT_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS__TUNIT_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__TUNIT_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; IS__TUNIT_NPM-NEXT: store i32 0, i32* [[X_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[L:%.*]] = load i32, i32* [[X_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
; IS__TUNIT_NPM-NEXT: ret i32 [[A]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 4 dereferenceable(4) [[B:%.*]], i32* noalias nocapture nofree nonnull byval align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: store i32 0, i32* [[X]], align 4
; IS__CGSCC_OPM-NEXT: [[L:%.*]] = load i32, i32* [[X]], align 4
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
; IS__CGSCC_OPM-NEXT: ret i32 [[A]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32
; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[X_PRIV]], align 4
; IS__CGSCC_NPM-NEXT: [[L:%.*]] = load i32, i32* [[X_PRIV]], align 4
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 [[L]], [[TMP2]]
; IS__CGSCC_NPM-NEXT: ret i32 [[A]]
;
entry:
@ -39,21 +86,60 @@ entry:
; Also make sure we don't drop the call zeroext attribute.
define i32 @test(i32* %X) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
; CHECK-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 1
; CHECK-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 1
; CHECK-NEXT: [[C:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]], i32 [[TMP2]], i32 zeroext 0)
; CHECK-NEXT: ret i32 [[C]]
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test
; IS__TUNIT_OPM-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_OPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree nonnull readonly byval align 8 dereferenceable(12) [[S]], i32* nocapture nofree readonly byval align 4 [[X]], i32 zeroext 0)
; IS__TUNIT_OPM-NEXT: ret i32 [[C]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test
; IS__TUNIT_NPM-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 1
; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 1
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]], i32 [[TMP2]], i32 zeroext 0)
; IS__TUNIT_NPM-NEXT: ret i32 [[C]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @f(%struct.ss* noalias nofree nonnull readnone byval align 8 dereferenceable(12) [[S]], i32* noalias nocapture nofree nonnull readnone byval align 4 dereferenceable(4) [[X]])
; IS__CGSCC_OPM-NEXT: ret i32 [[C]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull readonly dereferenceable(4) [[X:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 8
; IS__CGSCC_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 1
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]], i32 [[TMP2]])
; IS__CGSCC_NPM-NEXT: ret i32 [[C]]
;
entry:
%S = alloca %struct.ss

View File

@ -1,18 +1,35 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
define internal i32 @test(i32* %X, i32* %Y) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; CHECK-NEXT: [[Y_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP1]], i32* [[Y_PRIV]]
; CHECK-NEXT: [[X_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[X_PRIV]]
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[X_PRIV]], align 4
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[Y_PRIV]], align 4
; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT: ret i32 [[C]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[Y:%.*]])
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = load i32, i32* [[X]], align 4
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = load i32, i32* [[Y]], align 4
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT_OPM-NEXT: ret i32 [[C]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__TUNIT_NPM-NEXT: [[Y_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP1]], i32* [[Y_PRIV]]
; IS__TUNIT_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[X_PRIV]]
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = load i32, i32* [[X_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = load i32, i32* [[Y_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT_NPM-NEXT: ret i32 [[C]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[Y:%.*]])
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[X]], align 4
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[Y]], align 4
; IS__CGSCC____-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: ret i32 [[C]]
;
%A = load i32, i32* %X
%B = load i32, i32* %Y
@ -21,16 +38,30 @@ define internal i32 @test(i32* %X, i32* %Y) {
}
define internal i32 @caller(i32* %B) {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i32 [[TMP0:%.*]])
; CHECK-NEXT: [[B_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[B_PRIV]]
; CHECK-NEXT: [[A:%.*]] = alloca i32
; CHECK-NEXT: store i32 1, i32* [[A]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[A]], align 1
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[B_PRIV]], align 1
; CHECK-NEXT: [[C:%.*]] = call i32 @test(i32 [[TMP2]], i32 [[TMP3]])
; CHECK-NEXT: ret i32 [[C]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@caller
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT_OPM-NEXT: ret i32 [[C]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@caller
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: [[B_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV]]
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[A]], align 1
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[B_PRIV]], align 1
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = call i32 @test(i32 [[TMP2]], i32 [[TMP3]])
; IS__TUNIT_NPM-NEXT: ret i32 [[C]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 1, i32* [[A]], align 4
; IS__CGSCC____-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: ret i32 [[C]]
;
%A = alloca i32
store i32 1, i32* %A
@ -39,12 +70,24 @@ define internal i32 @caller(i32* %B) {
}
define i32 @callercaller() {
; CHECK-LABEL: define {{[^@]+}}@callercaller()
; CHECK-NEXT: [[B:%.*]] = alloca i32
; CHECK-NEXT: store i32 2, i32* [[B]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 1
; CHECK-NEXT: [[X:%.*]] = call i32 @caller(i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[X]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@callercaller()
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: store i32 2, i32* [[B]], align 4
; IS__TUNIT_OPM-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT_OPM-NEXT: ret i32 [[X]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callercaller()
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 2, i32* [[B]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 1
; IS__TUNIT_NPM-NEXT: [[X:%.*]] = call i32 @caller(i32 [[TMP1]])
; IS__TUNIT_NPM-NEXT: ret i32 [[X]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@callercaller()
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 2, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: ret i32 [[X]]
;
%B = alloca i32
store i32 2, i32* %B

View File

@ -1,9 +1,39 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
%struct.ss = type { i32, i64 }
define internal void @f(%struct.ss* byval %b, i32* byval %X) nounwind {
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 4 dereferenceable(4) [[B:%.*]], i32* noalias nocapture nofree nonnull writeonly byval align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: store i32 0, i32* [[X]], align 4
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32
; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[X_PRIV]], align 4
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
%tmp1 = load i32, i32* %tmp, align 4
@ -15,15 +45,36 @@ entry:
}
define i32 @test(i32* %X) {
; CHECK-LABEL: define {{[^@]+}}@test
; CHECK-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
; CHECK-NEXT: ret i32 0
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@test
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT____-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT____-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT____-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__TUNIT____-NEXT: ret i32 0
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_OPM-NEXT: ret i32 0
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull readonly dereferenceable(4) [[X:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_NPM-NEXT: ret i32 0
;
entry:
%S = alloca %struct.ss

View File

@ -1,24 +1,59 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
%struct.ss = type { i32, i64 }
define internal i32 @f(%struct.ss* byval %b) nounwind {
; CHECK-LABEL: define {{[^@]+}}@f
; CHECK-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; CHECK-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; CHECK-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; CHECK-NEXT: ret i32 [[TMP1]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[B:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__TUNIT_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP1]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@f
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS__TUNIT_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__TUNIT_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP1]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_OPM-NEXT: ret i32 [[TMP1]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@f
; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4
; IS__CGSCC_NPM-NEXT: ret i32 [[TMP1]]
;
entry:
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
@ -30,19 +65,37 @@ entry:
define internal i32 @g(%struct.ss* byval align 32 %b) nounwind {
; CHECK-LABEL: define {{[^@]+}}@g
; CHECK-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; CHECK-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; CHECK-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
; CHECK-NEXT: ret i32 [[TMP2]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@g
; IS__TUNIT_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 32 dereferenceable(12) [[B:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__TUNIT_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP2]]
;
; IS________NPM-LABEL: define {{[^@]+}}@g
; IS________NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; IS________NPM-NEXT: entry:
; IS________NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS________NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32*
; IS________NPM-NEXT: store i32 [[TMP0]], i32* [[B_PRIV_CAST]]
; IS________NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 1
; IS________NPM-NEXT: store i64 [[TMP1]], i64* [[B_PRIV_0_1]]
; IS________NPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i32 0, i32 0
; IS________NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
; IS________NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS________NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
; IS________NPM-NEXT: ret i32 [[TMP2]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@g
; IS__CGSCC_OPM-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 32 dereferenceable(4) [[B:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; IS__CGSCC_OPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
; IS__CGSCC_OPM-NEXT: ret i32 [[TMP2]]
;
entry:
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
@ -54,25 +107,69 @@ entry:
define i32 @main() nounwind {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
; CHECK-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 1
; CHECK-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; CHECK-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]])
; CHECK-NEXT: [[S_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32*
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST1]], align 1
; CHECK-NEXT: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; CHECK-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 1
; CHECK-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]])
; CHECK-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; CHECK-NEXT: ret i32 [[A]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@main()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_OPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__TUNIT_OPM-NEXT: [[C0:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree nonnull readonly byval align 8 dereferenceable(12) [[S]])
; IS__TUNIT_OPM-NEXT: [[C1:%.*]] = call i32 @g(%struct.ss* noalias nocapture nofree nonnull readonly byval align 32 dereferenceable(12) [[S]])
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[A]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@main()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 1
; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]])
; IS__TUNIT_NPM-NEXT: [[S_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST1]], align 1
; IS__TUNIT_NPM-NEXT: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 1
; IS__TUNIT_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]])
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; IS__TUNIT_NPM-NEXT: ret i32 [[A]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@main()
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[TMP1]], align 32
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_OPM-NEXT: [[C0:%.*]] = call i32 @f(%struct.ss* noalias nofree nonnull readnone byval align 32 dereferenceable(12) [[S]])
; IS__CGSCC_OPM-NEXT: [[C1:%.*]] = call i32 @g(%struct.ss* noalias nofree nonnull readnone byval align 32 dereferenceable(12) [[S]])
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; IS__CGSCC_OPM-NEXT: ret i32 [[A]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@main()
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[TMP1]], align 8
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 2, i64* [[TMP4]], align 4
; IS__CGSCC_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 8
; IS__CGSCC_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 1
; IS__CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]])
; IS__CGSCC_NPM-NEXT: [[S_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32*
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST1]], align 8
; IS__CGSCC_NPM-NEXT: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 1
; IS__CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]])
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]]
; IS__CGSCC_NPM-NEXT: ret i32 [[A]]
;
entry:
%S = alloca %struct.ss

View File

@ -1,10 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@G1 = constant i32 0
@G2 = constant i32* @G1
define internal i32 @test(i32** %x) {
;
; CHECK-LABEL: define {{[^@]+}}@test()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[Y:%.*]] = load i32*, i32** @G2, align 8

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Don't promote around control flow.
define internal i32 @callee(i1 %C, i32* %P) {

View File

@ -1,19 +1,40 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
define internal i32 @callee(i1 %C, i32* %P) {
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i1 [[C:%.*]], i32 [[TMP0:%.*]])
; CHECK-NEXT: [[P_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[P_PRIV]]
; CHECK-NEXT: br label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: unreachable
; CHECK: F:
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P_PRIV]], align 4
; CHECK-NEXT: ret i32 [[X]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@callee
; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; IS__TUNIT_OPM-NEXT: br label [[F:%.*]]
; IS__TUNIT_OPM: T:
; IS__TUNIT_OPM-NEXT: unreachable
; IS__TUNIT_OPM: F:
; IS__TUNIT_OPM-NEXT: [[X:%.*]] = load i32, i32* [[P]], align 4
; IS__TUNIT_OPM-NEXT: ret i32 [[X]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee
; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]], i32 [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: [[P_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[P_PRIV]]
; IS__TUNIT_NPM-NEXT: br label [[F:%.*]]
; IS__TUNIT_NPM: T:
; IS__TUNIT_NPM-NEXT: unreachable
; IS__TUNIT_NPM: F:
; IS__TUNIT_NPM-NEXT: [[X:%.*]] = load i32, i32* [[P_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: ret i32 [[X]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee
; IS__CGSCC____-SAME: (i32* nocapture nofree readonly [[P:%.*]])
; IS__CGSCC____-NEXT: br label [[F:%.*]]
; IS__CGSCC____: T:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: F:
; IS__CGSCC____-NEXT: [[X:%.*]] = load i32, i32* [[P]]
; IS__CGSCC____-NEXT: ret i32 [[X]]
;
br i1 %C, label %T, label %F
@ -26,12 +47,24 @@ F: ; preds = %0
}
define i32 @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: [[A:%.*]] = alloca i32
; CHECK-NEXT: store i32 17, i32* [[A]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[A]], align 1
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[X]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@foo()
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: store i32 17, i32* [[A]], align 4
; IS__TUNIT_OPM-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]])
; IS__TUNIT_OPM-NEXT: ret i32 [[X]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@foo()
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 17, i32* [[A]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[A]], align 1
; IS__TUNIT_NPM-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32 [[TMP1]])
; IS__TUNIT_NPM-NEXT: ret i32 [[X]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo()
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 17, i32* [[A]], align 4
; IS__CGSCC____-NEXT: [[X:%.*]] = call i32 @callee(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC____-NEXT: ret i32 [[X]]
;
%A = alloca i32 ; <i32*> [#uses=2]
store i32 17, i32* %A

View File

@ -1,30 +1,22 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
; RUN: opt -S -passes='cgscc(inline),attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,INLINE_ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
%S = type { %S* }
; Inlining should nuke the invoke (and any inlined calls) here even with
; argument promotion running along with it.
define void @zot() personality i32 (...)* @wibble {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@zot() #0 personality i32 (...)* @wibble
; ATTRIBUTOR-NEXT: bb:
; ATTRIBUTOR-NEXT: call void @hoge()
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: bb1:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: bb2:
; ATTRIBUTOR-NEXT: unreachable
;
; INLINE_ATTRIBUTOR-LABEL: define {{[^@]+}}@zot() #0 personality i32 (...)* @wibble
; INLINE_ATTRIBUTOR-NEXT: bb:
; INLINE_ATTRIBUTOR-NEXT: unreachable
; INLINE_ATTRIBUTOR: hoge.exit:
; INLINE_ATTRIBUTOR-NEXT: unreachable
; INLINE_ATTRIBUTOR: bb1:
; INLINE_ATTRIBUTOR-NEXT: unreachable
; INLINE_ATTRIBUTOR: bb2:
; INLINE_ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@zot() #0 personality i32 (...)* @wibble
; CHECK-NEXT: bb:
; CHECK-NEXT: call void @hoge()
; CHECK-NEXT: unreachable
; CHECK: bb1:
; CHECK-NEXT: unreachable
; CHECK: bb2:
; CHECK-NEXT: unreachable
;
bb:
invoke void @hoge()
@ -40,9 +32,9 @@ bb2:
}
define internal void @hoge() {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@hoge()
; ATTRIBUTOR-NEXT: bb:
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@hoge()
; CHECK-NEXT: bb:
; CHECK-NEXT: unreachable
;
bb:
%tmp = call fastcc i8* @spam(i1 (i8*)* @eggs)
@ -51,6 +43,10 @@ bb:
}
define internal fastcc i8* @spam(i1 (i8*)* %arg) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@spam()
; IS__CGSCC____-NEXT: bb:
; IS__CGSCC____-NEXT: unreachable
;
bb:
unreachable
}
@ -62,15 +58,26 @@ bb:
}
define internal i1 @barney(i8* %arg) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@barney()
; IS__CGSCC____-NEXT: bb:
; IS__CGSCC____-NEXT: ret i1 undef
;
bb:
ret i1 undef
}
define i32 @test_inf_promote_caller(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@test_inf_promote_caller
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: bb:
; CHECK-NEXT: unreachable
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_inf_promote_caller
; IS__TUNIT____-SAME: (i32 [[ARG:%.*]])
; IS__TUNIT____-NEXT: bb:
; IS__TUNIT____-NEXT: unreachable
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inf_promote_caller
; IS__CGSCC____-SAME: (i32 [[ARG:%.*]])
; IS__CGSCC____-NEXT: bb:
; IS__CGSCC____-NEXT: [[TMP:%.*]] = alloca [[S:%.*]]
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = alloca [[S]]
; IS__CGSCC____-NEXT: unreachable
;
bb:
%tmp = alloca %S
@ -81,6 +88,10 @@ bb:
}
define internal i32 @test_inf_promote_callee(%S* %arg, %S* %arg1) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inf_promote_callee()
; IS__CGSCC____-NEXT: bb:
; IS__CGSCC____-NEXT: unreachable
;
bb:
%tmp = getelementptr %S, %S* %arg1, i32 0, i32 0
%tmp2 = load %S*, %S** %tmp

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
declare void @sink(i32)
@ -29,11 +32,17 @@ define internal void @test_byval(%struct.pair* byval %P) {
}
define void @caller(i32** %Y, %struct.pair* %P) {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i32** nocapture readonly [[Y:%.*]], %struct.pair* nocapture nofree readnone [[P:%.*]])
; CHECK-NEXT: call void @test(i32** nocapture readonly align 8 [[Y]]), !dbg !4
; CHECK-NEXT: call void @test_byval(), !dbg !5
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller
; IS__TUNIT____-SAME: (i32** nocapture readonly [[Y:%.*]], %struct.pair* nocapture nofree readnone [[P:%.*]])
; IS__TUNIT____-NEXT: call void @test(i32** nocapture readonly align 8 [[Y]]), !dbg !4
; IS__TUNIT____-NEXT: call void @test_byval(), !dbg !5
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller
; IS__CGSCC____-SAME: (i32** nocapture nonnull readonly align 8 dereferenceable(8) [[Y:%.*]], %struct.pair* nocapture nofree readnone [[P:%.*]])
; IS__CGSCC____-NEXT: call void @test(i32** nocapture nonnull readonly align 8 dereferenceable(8) [[Y]]), !dbg !4
; IS__CGSCC____-NEXT: call void @test_byval(), !dbg !5
; IS__CGSCC____-NEXT: ret void
;
call void @test(i32** %Y), !dbg !1

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@ -26,6 +29,10 @@ entry:
}
define internal i8 @UseLongDoubleUnsafely(%union.u* byval align 16 %arg) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@UseLongDoubleUnsafely()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: ret i8 undef
;
entry:
%bitcast = bitcast %union.u* %arg to %struct.s*
%gep = getelementptr inbounds %struct.s, %struct.s* %bitcast, i64 0, i32 2
@ -34,18 +41,53 @@ entry:
}
define internal x86_fp80 @UseLongDoubleSafely(%union.u* byval align 16 %arg) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@UseLongDoubleSafely()
; IS__CGSCC____-NEXT: ret x86_fp80 undef
;
%gep = getelementptr inbounds %union.u, %union.u* %arg, i64 0, i32 0
%fp80 = load x86_fp80, x86_fp80* %gep
ret x86_fp80 %fp80
}
define internal i64 @AccessPaddingOfStruct(%struct.Foo* byval %a) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@AccessPaddingOfStruct()
; IS__CGSCC____-NEXT: ret i64 undef
;
%p = bitcast %struct.Foo* %a to i64*
%v = load i64, i64* %p
ret i64 %v
}
define internal i64 @CaptureAStruct(%struct.Foo* byval %a) {
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@CaptureAStruct
; IS__CGSCC_OPM-SAME: (%struct.Foo* noalias nofree byval [[A:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*
; IS__CGSCC_OPM-NEXT: br label [[LOOP:%.*]]
; IS__CGSCC_OPM: loop:
; IS__CGSCC_OPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ]
; IS__CGSCC_OPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
; IS__CGSCC_OPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
; IS__CGSCC_OPM-NEXT: br label [[LOOP]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@CaptureAStruct
; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_FOO:%.*]]
; IS__CGSCC_NPM-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.Foo* [[A_PRIV]] to i32*
; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[A_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[A_PRIV_0_1:%.*]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i64 [[TMP1]], i64* [[A_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*
; IS__CGSCC_NPM-NEXT: br label [[LOOP:%.*]]
; IS__CGSCC_NPM: loop:
; IS__CGSCC_NPM-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = phi %struct.Foo* [ [[A_PRIV]], [[ENTRY]] ], [ [[TMP2]], [[LOOP]] ]
; IS__CGSCC_NPM-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
; IS__CGSCC_NPM-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO]], %struct.Foo* [[A_PRIV]], i64 0
; IS__CGSCC_NPM-NEXT: br label [[LOOP]]
;
entry:
%a_ptr = alloca %struct.Foo*
br label %loop

View File

@ -1,6 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
; RUN: opt -S -passes='globalopt,attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s --check-prefixes=GLOBALOPT_ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
@ -8,30 +10,25 @@ target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:1
; Argpromote + sroa should change this to passing the two integers by value.
define internal i32 @f(%struct.ss* inalloca %s) {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f
; ATTRIBUTOR-SAME: (%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S:%.*]])
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
; ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; ATTRIBUTOR-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; ATTRIBUTOR-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
; ATTRIBUTOR-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
; ATTRIBUTOR-NEXT: ret i32 [[R]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@f
; IS__TUNIT____-SAME: (%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; IS__TUNIT____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
; IS__TUNIT____-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT____-NEXT: ret i32 [[R]]
;
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@f
; GLOBALOPT_ATTRIBUTOR-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) unnamed_addr
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]]
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S_PRIV_CAST:%.*]] = bitcast %struct.ss* [[S_PRIV]] to i32*
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 [[TMP0]], i32* [[S_PRIV_CAST]]
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S_PRIV]], i32 0, i32 1
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 [[TMP1]], i32* [[S_PRIV_0_1]]
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S_PRIV]], i32 0, i32 0
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S_PRIV]], i32 0, i32 1
; GLOBALOPT_ATTRIBUTOR-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; GLOBALOPT_ATTRIBUTOR-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
; GLOBALOPT_ATTRIBUTOR-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 [[R]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@f
; IS__CGSCC____-SAME: (%struct.ss* inalloca nocapture nofree nonnull align 4 dereferenceable(8) [[S:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
; IS__CGSCC____-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: ret i32 [[R]]
;
entry:
%f0 = getelementptr %struct.ss, %struct.ss* %s, i32 0, i32 0
@ -43,29 +40,25 @@ entry:
}
define i32 @main() {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@main()
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
; ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; ATTRIBUTOR-NEXT: store i32 1, i32* [[F0]], align 4
; ATTRIBUTOR-NEXT: store i32 2, i32* [[F1]], align 4
; ATTRIBUTOR-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S]])
; ATTRIBUTOR-NEXT: ret i32 [[R]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@main()
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT____-NEXT: store i32 1, i32* [[F0]], align 4
; IS__TUNIT____-NEXT: store i32 2, i32* [[F1]], align 4
; IS__TUNIT____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S]])
; IS__TUNIT____-NEXT: ret i32 [[R]]
;
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@main() local_unnamed_addr
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 1, i32* [[F0]], align 4
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 2, i32* [[F1]], align 4
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32*
; GLOBALOPT_ATTRIBUTOR-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 1
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; GLOBALOPT_ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, i32* [[S_0_1]], align 1
; GLOBALOPT_ATTRIBUTOR-NEXT: [[R:%.*]] = call fastcc i32 @f(i32 [[TMP0]], i32 [[TMP1]])
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 [[R]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@main()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC____-NEXT: store i32 1, i32* [[F0]], align 4
; IS__CGSCC____-NEXT: store i32 2, i32* [[F1]], align 4
; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nofree nonnull align 4 dereferenceable(8) [[S]])
; IS__CGSCC____-NEXT: ret i32 [[R]]
;
entry:
%S = alloca inalloca %struct.ss
@ -79,19 +72,20 @@ entry:
; Argpromote can't promote %a because of the icmp use.
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
; IS__CGSCC____-LABEL: define {{[^@]+}}@g
; IS__CGSCC____-SAME: (%struct.ss* nocapture nofree readnone [[A:%.*]], %struct.ss* inalloca nocapture nofree writeonly [[B:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: ret i1 undef
;
entry:
%c = icmp eq %struct.ss* %a, %b
ret i1 %c
}
define i32 @test() {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test()
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: ret i32 0
;
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@test() local_unnamed_addr
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 0
; CHECK-LABEL: define {{[^@]+}}@test()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 0
;
entry:
%S = alloca inalloca %struct.ss

View File

@ -1,13 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -basicaa -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_MODULE
; RUN: opt -S -basicaa -attributor-cgscc -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_CGSCC
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_MODULE
; RUN: opt -S -passes='attributor-cgscc' -aa-pipeline='basic-aa' -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_CGSCC
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; OLDPM_MODULE-NOT: @dead
; NEWPM_MODULE-NOT: @dead
; OLDPM_CGSCC-NOT: @dead
; NEWPM_CGSCC-NOT: @dead
define internal void @dead() {
call i32 @test(i32* null, i32* null)
@ -15,23 +11,23 @@ define internal void @dead() {
}
define internal i32 @test(i32* %X, i32* %Y) {
; OLDPM_CGSCC-LABEL: define {{[^@]+}}@test
; OLDPM_CGSCC-SAME: (i32* noalias nocapture nofree writeonly align 4 [[X:%.*]])
; OLDPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; OLDPM_CGSCC: live:
; OLDPM_CGSCC-NEXT: store i32 0, i32* [[X]], align 4
; OLDPM_CGSCC-NEXT: ret i32 undef
; OLDPM_CGSCC: dead:
; OLDPM_CGSCC-NEXT: unreachable
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_OPM-SAME: (i32* noalias nocapture nofree writeonly align 4 [[X:%.*]])
; IS__CGSCC_OPM-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; IS__CGSCC_OPM: live:
; IS__CGSCC_OPM-NEXT: store i32 0, i32* [[X]], align 4
; IS__CGSCC_OPM-NEXT: ret i32 undef
; IS__CGSCC_OPM: dead:
; IS__CGSCC_OPM-NEXT: unreachable
;
; NEWPM_CGSCC-LABEL: define {{[^@]+}}@test
; NEWPM_CGSCC-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[X:%.*]])
; NEWPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; NEWPM_CGSCC: live:
; NEWPM_CGSCC-NEXT: store i32 0, i32* [[X]], align 4
; NEWPM_CGSCC-NEXT: ret i32 undef
; NEWPM_CGSCC: dead:
; NEWPM_CGSCC-NEXT: unreachable
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test
; IS__CGSCC_NPM-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[X:%.*]])
; IS__CGSCC_NPM-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; IS__CGSCC_NPM: live:
; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[X]], align 4
; IS__CGSCC_NPM-NEXT: ret i32 undef
; IS__CGSCC_NPM: dead:
; IS__CGSCC_NPM-NEXT: unreachable
;
br i1 true, label %live, label %dead
live:
@ -44,17 +40,17 @@ dead:
}
define internal i32 @caller(i32* %B) {
; OLDPM_CGSCC-LABEL: define {{[^@]+}}@caller()
; OLDPM_CGSCC-NEXT: [[A:%.*]] = alloca i32
; OLDPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4
; OLDPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; OLDPM_CGSCC-NEXT: ret i32 0
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller()
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC_OPM-NEXT: ret i32 0
;
; NEWPM_CGSCC-LABEL: define {{[^@]+}}@caller()
; NEWPM_CGSCC-NEXT: [[A:%.*]] = alloca i32
; NEWPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4
; NEWPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; NEWPM_CGSCC-NEXT: ret i32 undef
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller()
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC_NPM-NEXT: ret i32 undef
;
%A = alloca i32
store i32 1, i32* %A

View File

@ -1,13 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -basicaa -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_MODULE
; RUN: opt -S -basicaa -attributor-cgscc -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,OLDPM,OLDPM_CGSCC
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_MODULE
; RUN: opt -S -passes='attributor-cgscc' -aa-pipeline='basic-aa' -attributor-disable=false < %s | FileCheck %s --check-prefixes=CHECK,NEWPM,NEWPM_CGSCC
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; OLDPM_MODULE-NOT: @dead
; NEWPM_MODULE-NOT: @dead
; OLDPM_CGSCC-NOT: @dead
; NEWPM_CGSCC-NOT: @dead
define internal void @dead() {
call i32 @test(i32* null, i32* null)
@ -15,41 +11,23 @@ define internal void @dead() {
}
define internal i32 @test(i32* %X, i32* %Y) {
; OLDPM_MODULE-LABEL: define {{[^@]+}}@test
; OLDPM_MODULE-SAME: (i32* noalias nocapture nofree writeonly align 4 [[X:%.*]])
; OLDPM_MODULE-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; OLDPM_MODULE: live:
; OLDPM_MODULE-NEXT: store i32 0, i32* [[X]], align 4
; OLDPM_MODULE-NEXT: ret i32 undef
; OLDPM_MODULE: dead:
; OLDPM_MODULE-NEXT: unreachable
; IS__TUNIT____-LABEL: define {{[^@]+}}@test
; IS__TUNIT____-SAME: (i32* noalias nocapture nofree writeonly align 4 [[X:%.*]])
; IS__TUNIT____-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; IS__TUNIT____: live:
; IS__TUNIT____-NEXT: store i32 0, i32* [[X]], align 4
; IS__TUNIT____-NEXT: ret i32 undef
; IS__TUNIT____: dead:
; IS__TUNIT____-NEXT: unreachable
;
; OLDPM_CGSCC-LABEL: define {{[^@]+}}@test
; OLDPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[X:%.*]])
; OLDPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; OLDPM_CGSCC: live:
; OLDPM_CGSCC-NEXT: store i32 0, i32* [[X]]
; OLDPM_CGSCC-NEXT: ret i32 undef
; OLDPM_CGSCC: dead:
; OLDPM_CGSCC-NEXT: unreachable
;
; NEWPM_MODULE-LABEL: define {{[^@]+}}@test
; NEWPM_MODULE-SAME: (i32* noalias nocapture nofree writeonly align 4 [[X:%.*]])
; NEWPM_MODULE-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; NEWPM_MODULE: live:
; NEWPM_MODULE-NEXT: store i32 0, i32* [[X]], align 4
; NEWPM_MODULE-NEXT: ret i32 undef
; NEWPM_MODULE: dead:
; NEWPM_MODULE-NEXT: unreachable
;
; NEWPM_CGSCC-LABEL: define {{[^@]+}}@test
; NEWPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[X:%.*]])
; NEWPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; NEWPM_CGSCC: live:
; NEWPM_CGSCC-NEXT: store i32 0, i32* [[X]]
; NEWPM_CGSCC-NEXT: ret i32 undef
; NEWPM_CGSCC: dead:
; NEWPM_CGSCC-NEXT: unreachable
; IS__CGSCC____-LABEL: define {{[^@]+}}@test
; IS__CGSCC____-SAME: (i32* nocapture nofree writeonly [[X:%.*]])
; IS__CGSCC____-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]]
; IS__CGSCC____: live:
; IS__CGSCC____-NEXT: store i32 0, i32* [[X]]
; IS__CGSCC____-NEXT: ret i32 undef
; IS__CGSCC____: dead:
; IS__CGSCC____-NEXT: unreachable
;
br i1 true, label %live, label %dead
live:
@ -62,33 +40,26 @@ dead:
}
define internal i32 @caller(i32* %B) {
; OLDPM_MODULE-LABEL: define {{[^@]+}}@caller
; OLDPM_MODULE-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B:%.*]])
; OLDPM_MODULE-NEXT: [[A:%.*]] = alloca i32
; OLDPM_MODULE-NEXT: store i32 1, i32* [[A]], align 4
; OLDPM_MODULE-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; OLDPM_MODULE-NEXT: ret i32 undef
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller
; IS__TUNIT____-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32
; IS__TUNIT____-NEXT: store i32 1, i32* [[A]], align 4
; IS__TUNIT____-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: ret i32 undef
;
; OLDPM_CGSCC-LABEL: define {{[^@]+}}@caller
; OLDPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[B:%.*]])
; OLDPM_CGSCC-NEXT: [[A:%.*]] = alloca i32
; OLDPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4
; OLDPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]])
; OLDPM_CGSCC-NEXT: ret i32 0
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[B:%.*]])
; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]])
; IS__CGSCC_OPM-NEXT: ret i32 0
;
; NEWPM_MODULE-LABEL: define {{[^@]+}}@caller
; NEWPM_MODULE-SAME: (i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B:%.*]])
; NEWPM_MODULE-NEXT: [[A:%.*]] = alloca i32
; NEWPM_MODULE-NEXT: store i32 1, i32* [[A]], align 4
; NEWPM_MODULE-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; NEWPM_MODULE-NEXT: ret i32 undef
;
; NEWPM_CGSCC-LABEL: define {{[^@]+}}@caller
; NEWPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[B:%.*]])
; NEWPM_CGSCC-NEXT: [[A:%.*]] = alloca i32
; NEWPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4
; NEWPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]])
; NEWPM_CGSCC-NEXT: ret i32 undef
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[B:%.*]])
; IS__CGSCC_NPM-NEXT: [[A:%.*]] = alloca i32
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[A]], align 4
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]])
; IS__CGSCC_NPM-NEXT: ret i32 undef
;
%A = alloca i32
store i32 1, i32* %A
@ -97,29 +68,17 @@ define internal i32 @caller(i32* %B) {
}
define i32 @callercaller() {
; OLDPM_MODULE-LABEL: define {{[^@]+}}@callercaller()
; OLDPM_MODULE-NEXT: [[B:%.*]] = alloca i32
; OLDPM_MODULE-NEXT: store i32 2, i32* [[B]], align 4
; OLDPM_MODULE-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; OLDPM_MODULE-NEXT: ret i32 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@callercaller()
; IS__TUNIT____-NEXT: [[B:%.*]] = alloca i32
; IS__TUNIT____-NEXT: store i32 2, i32* [[B]], align 4
; IS__TUNIT____-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: ret i32 0
;
; OLDPM_CGSCC-LABEL: define {{[^@]+}}@callercaller()
; OLDPM_CGSCC-NEXT: [[B:%.*]] = alloca i32
; OLDPM_CGSCC-NEXT: store i32 2, i32* [[B]], align 4
; OLDPM_CGSCC-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; OLDPM_CGSCC-NEXT: ret i32 0
;
; NEWPM_MODULE-LABEL: define {{[^@]+}}@callercaller()
; NEWPM_MODULE-NEXT: [[B:%.*]] = alloca i32
; NEWPM_MODULE-NEXT: store i32 2, i32* [[B]], align 4
; NEWPM_MODULE-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; NEWPM_MODULE-NEXT: ret i32 0
;
; NEWPM_CGSCC-LABEL: define {{[^@]+}}@callercaller()
; NEWPM_CGSCC-NEXT: [[B:%.*]] = alloca i32
; NEWPM_CGSCC-NEXT: store i32 2, i32* [[B]], align 4
; NEWPM_CGSCC-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; NEWPM_CGSCC-NEXT: ret i32 0
; IS__CGSCC____-LABEL: define {{[^@]+}}@callercaller()
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 2, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nofree nonnull writeonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: ret i32 0
;
%B = alloca i32
store i32 2, i32* %B

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR36543
; Don't promote arguments of musttail callee
@ -45,6 +48,16 @@ define i32 @foo(%T* %p, i32 %v) {
}
define internal i32 @test2(%T* %p, i32 %p2) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@test2
; IS__CGSCC____-SAME: (%T* nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]])
; IS__CGSCC____-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3
; IS__CGSCC____-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]], align 4
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]], align 4
; IS__CGSCC____-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: [[CA:%.*]] = musttail call i32 @foo(%T* undef, i32 [[V]])
; IS__CGSCC____-NEXT: ret i32 [[CA]]
;
%a.gep = getelementptr %T, %T* %p, i64 0, i32 3
%b.gep = getelementptr %T, %T* %p, i64 0, i32 2
%a = load i32, i32* %a.gep
@ -55,9 +68,14 @@ define internal i32 @test2(%T* %p, i32 %p2) {
}
define i32 @caller2(%T* %g) {
; CHECK-LABEL: define {{[^@]+}}@caller2
; CHECK-SAME: (%T* nocapture nofree readnone [[G:%.*]])
; CHECK-NEXT: ret i32 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller2
; IS__TUNIT____-SAME: (%T* nocapture nofree readnone [[G:%.*]])
; IS__TUNIT____-NEXT: ret i32 0
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller2
; IS__CGSCC____-SAME: (%T* nocapture nofree readonly [[G:%.*]])
; IS__CGSCC____-NEXT: [[V:%.*]] = call i32 @test2(%T* nocapture nofree readonly [[G]], i32 0)
; IS__CGSCC____-NEXT: ret i32 [[V]]
;
%v = call i32 @test2(%T* %g, i32 0)
ret i32 %v
@ -100,10 +118,15 @@ define internal i32 @test2b(%T* %p, i32 %p2) {
}
define i32 @caller2b(%T* %g) {
; CHECK-LABEL: define {{[^@]+}}@caller2b
; CHECK-SAME: (%T* nocapture nofree readonly [[G:%.*]])
; CHECK-NEXT: [[V:%.*]] = call i32 @test2b(%T* nocapture nofree readonly [[G]], i32 undef)
; CHECK-NEXT: ret i32 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller2b
; IS__TUNIT____-SAME: (%T* nocapture nofree readonly [[G:%.*]])
; IS__TUNIT____-NEXT: [[V:%.*]] = call i32 @test2b(%T* nocapture nofree readonly [[G]], i32 undef)
; IS__TUNIT____-NEXT: ret i32 0
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller2b
; IS__CGSCC____-SAME: (%T* nocapture nofree readonly [[G:%.*]])
; IS__CGSCC____-NEXT: [[V:%.*]] = call i32 @test2b(%T* nocapture nofree readonly [[G]], i32 0)
; IS__CGSCC____-NEXT: ret i32 [[V]]
;
%v = call i32 @test2b(%T* %g, i32 0)
ret i32 %v

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Don't promote paramaters of/arguments to naked functions

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; ArgumentPromotion should preserve the default function address space
; from the data layout.

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target triple = "x86_64-pc-windows-msvc"
define internal void @callee(i8*) {

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,27 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR 32917
@b = common local_unnamed_addr global i32 0, align 4
@a = common local_unnamed_addr global i32 0, align 4
define i32 @fn2() local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32*
; CHECK-NEXT: call fastcc void @fn1(i32* nofree readonly align 4 [[TMP3]])
; CHECK-NEXT: ret i32 undef
; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
; IS__TUNIT____-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64
; IS__TUNIT____-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32*
; IS__TUNIT____-NEXT: call fastcc void @fn1(i32* nofree readonly align 4 [[TMP3]])
; IS__TUNIT____-NEXT: ret i32 undef
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64
; IS__CGSCC____-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32*
; IS__CGSCC____-NEXT: call fastcc void @fn1(i32* nofree nonnull readonly align 4 [[TMP3]])
; IS__CGSCC____-NEXT: ret i32 undef
;
%1 = load i32, i32* @b, align 4
%2 = sext i32 %1 to i64

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Fix for PR33641. ArgumentPromotion removed the argument to bar but left the call to
; dbg.value which still used the removed argument.

View File

@ -1,16 +1,31 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
; Checks if !prof metadata is corret in deadargelim.
define void @caller() #0 {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: [[X:%.*]] = alloca i32
; CHECK-NEXT: store i32 42, i32* [[X]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[X]], align 1
; CHECK-NEXT: call void @promote_i32_ptr(i32 [[TMP1]]), !prof !0
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@caller()
; IS__TUNIT_OPM-NEXT: [[X:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[X]], align 4
; IS__TUNIT_OPM-NEXT: call void @promote_i32_ptr(i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[X]]), !prof !0
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@caller()
; IS__TUNIT_NPM-NEXT: [[X:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[X]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[X]], align 1
; IS__TUNIT_NPM-NEXT: call void @promote_i32_ptr(i32 [[TMP1]]), !prof !0
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller()
; IS__CGSCC____-NEXT: [[X:%.*]] = alloca i32
; IS__CGSCC____-NEXT: store i32 42, i32* [[X]], align 4
; IS__CGSCC____-NEXT: call void @promote_i32_ptr(i32* noalias nonnull readonly align 4 dereferenceable(4) [[X]]), !prof !0
; IS__CGSCC____-NEXT: ret void
;
%x = alloca i32
store i32 42, i32* %x
@ -19,13 +34,25 @@ define void @caller() #0 {
}
define internal void @promote_i32_ptr(i32* %xp) {
; CHECK-LABEL: define {{[^@]+}}@promote_i32_ptr
; CHECK-SAME: (i32 [[TMP0:%.*]])
; CHECK-NEXT: [[XP_PRIV:%.*]] = alloca i32
; CHECK-NEXT: store i32 [[TMP0]], i32* [[XP_PRIV]]
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[XP_PRIV]], align 4
; CHECK-NEXT: call void @use_i32(i32 [[X]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@promote_i32_ptr
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[XP:%.*]])
; IS__TUNIT_OPM-NEXT: [[X:%.*]] = load i32, i32* [[XP]], align 4
; IS__TUNIT_OPM-NEXT: call void @use_i32(i32 [[X]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@promote_i32_ptr
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]])
; IS__TUNIT_NPM-NEXT: [[XP_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[XP_PRIV]]
; IS__TUNIT_NPM-NEXT: [[X:%.*]] = load i32, i32* [[XP_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: call void @use_i32(i32 [[X]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@promote_i32_ptr
; IS__CGSCC____-SAME: (i32* nocapture nonnull readonly align 4 dereferenceable(4) [[XP:%.*]])
; IS__CGSCC____-NEXT: [[X:%.*]] = load i32, i32* [[XP]], align 4
; IS__CGSCC____-NEXT: call void @use_i32(i32 [[X]])
; IS__CGSCC____-NEXT: ret void
;
%x = load i32, i32* %xp
call void @use_i32(i32 %x)

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR17906
; When we promote two arguments in a single function with different types,
@ -14,13 +17,20 @@
@d = global i8 0, align 1
define internal fastcc void @fn(i32* nocapture readonly %p1, i64* nocapture readonly %p2) {
; CHECK-LABEL: define {{[^@]+}}@fn
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @g, align 4, !tbaa !0
; CHECK-NEXT: [[CONV1:%.*]] = trunc i32 [[TMP0]] to i8
; CHECK-NEXT: store i8 [[CONV1]], i8* @d, align 1, !tbaa !4
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@fn
; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P1:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* @g, align 4, !tbaa !0
; IS__TUNIT____-NEXT: [[CONV1:%.*]] = trunc i32 [[TMP0]] to i8
; IS__TUNIT____-NEXT: store i8 [[CONV1]], i8* @d, align 1, !tbaa !4
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* @g, align 4, !tbaa !0
; IS__CGSCC____-NEXT: [[CONV1:%.*]] = trunc i32 [[TMP0]] to i8
; IS__CGSCC____-NEXT: store i8 [[CONV1]], i8* @d, align 1, !tbaa !4
; IS__CGSCC____-NEXT: ret void
;
entry:
%0 = load i64, i64* %p2, align 8, !tbaa !1
@ -32,14 +42,23 @@ entry:
}
define i32 @main() {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32**, i32*** @e, align 8, !tbaa !5
; CHECK-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !5
; CHECK-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !5
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !0
; CHECK-NEXT: call fastcc void @fn(i32* nofree nonnull readonly align 4 dereferenceable(4) @g)
; CHECK-NEXT: ret i32 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@main()
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32**, i32*** @e, align 8, !tbaa !5
; IS__TUNIT____-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !5
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !5
; IS__TUNIT____-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !0
; IS__TUNIT____-NEXT: call fastcc void @fn(i32* nofree nonnull readonly align 4 dereferenceable(4) @g)
; IS__TUNIT____-NEXT: ret i32 0
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@main()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32**, i32*** @e, align 8, !tbaa !5
; IS__CGSCC____-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !5
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !5
; IS__CGSCC____-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !0
; IS__CGSCC____-NEXT: call fastcc void @fn()
; IS__CGSCC____-NEXT: ret i32 0
;
entry:
%0 = load i32**, i32*** @e, align 8, !tbaa !8

View File

@ -1,19 +1,43 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define internal void @add({i32, i32}* %this, i32* sret %r) {
; CHECK-LABEL: define {{[^@]+}}@add
; CHECK-SAME: ({ i32, i32 }* noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]])
; CHECK-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
; CHECK-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP]], align 4
; CHECK-NEXT: [[AB:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT: store i32 [[AB]], i32* [[R]], align 4
; CHECK-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@add
; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]])
; IS__TUNIT_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = load i32, i32* [[BP]], align 4
; IS__TUNIT_OPM-NEXT: [[AB:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT_OPM-NEXT: store i32 [[AB]], i32* [[R]], align 4
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@add
; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]])
; IS__TUNIT_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = load i32, i32* [[BP]], align 4
; IS__TUNIT_NPM-NEXT: [[AB:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT_NPM-NEXT: store i32 [[AB]], i32* [[R]], align 4
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@add
; IS__CGSCC____-SAME: ({ i32, i32 }* nocapture nofree nonnull readonly align 4 dereferenceable(8) [[THIS:%.*]], i32* nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]])
; IS__CGSCC____-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 4
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[BP]], align 4
; IS__CGSCC____-NEXT: [[AB:%.*]] = add i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: store i32 [[AB]], i32* [[R]], align 4
; IS__CGSCC____-NEXT: ret void
;
%ap = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 0
%bp = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 1
@ -25,11 +49,29 @@ define internal void @add({i32, i32}* %this, i32* sret %r) {
}
define void @f() {
; CHECK-LABEL: define {{[^@]+}}@f()
; CHECK-NEXT: [[R:%.*]] = alloca i32
; CHECK-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
; CHECK-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@f()
; IS__TUNIT_OPM-NEXT: [[R:%.*]] = alloca i32
; IS__TUNIT_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@f()
; IS__TUNIT_NPM-NEXT: [[R:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@f()
; IS__CGSCC_OPM-NEXT: [[R:%.*]] = alloca i32
; IS__CGSCC_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nofree nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* nofree nonnull sret writeonly align 4 dereferenceable(4) [[R]])
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@f()
; IS__CGSCC_NPM-NEXT: [[R:%.*]] = alloca i32
; IS__CGSCC_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nofree nonnull readonly align 8 dereferenceable(8) [[PAIR]], i32* noalias nofree nonnull sret writeonly align 4 dereferenceable(4) [[R]])
; IS__CGSCC_NPM-NEXT: ret void
;
%r = alloca i32
%pair = alloca {i32, i32}

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR14710
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@ -9,29 +12,48 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
declare i8* @foo(%pair*)
define internal void @bar(%pair* byval %Data) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; CHECK-NEXT: [[DATA_PRIV:%.*]] = alloca [[PAIR:%.*]]
; CHECK-NEXT: [[DATA_PRIV_CAST:%.*]] = bitcast %pair* [[DATA_PRIV]] to i32*
; CHECK-NEXT: store i32 [[TMP0]], i32* [[DATA_PRIV_CAST]]
; CHECK-NEXT: [[DATA_PRIV_0_1:%.*]] = getelementptr [[PAIR]], %pair* [[DATA_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i32 [[TMP1]], i32* [[DATA_PRIV_0_1]]
; CHECK-NEXT: [[TMP3:%.*]] = call i8* @foo(%pair* [[DATA_PRIV]])
; CHECK-NEXT: ret void
; IS________OPM-LABEL: define {{[^@]+}}@bar
; IS________OPM-SAME: (%pair* noalias byval [[DATA:%.*]])
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call i8* @foo(%pair* [[DATA]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@bar
; IS________NPM-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS________NPM-NEXT: [[DATA_PRIV:%.*]] = alloca [[PAIR:%.*]]
; IS________NPM-NEXT: [[DATA_PRIV_CAST:%.*]] = bitcast %pair* [[DATA_PRIV]] to i32*
; IS________NPM-NEXT: store i32 [[TMP0]], i32* [[DATA_PRIV_CAST]]
; IS________NPM-NEXT: [[DATA_PRIV_0_1:%.*]] = getelementptr [[PAIR]], %pair* [[DATA_PRIV]], i32 0, i32 1
; IS________NPM-NEXT: store i32 [[TMP1]], i32* [[DATA_PRIV_0_1]]
; IS________NPM-NEXT: [[TMP3:%.*]] = call i8* @foo(%pair* [[DATA_PRIV]])
; IS________NPM-NEXT: ret void
;
tail call i8* @foo(%pair* %Data)
ret void
}
define void @zed(%pair* byval %Data) {
; CHECK-LABEL: define {{[^@]+}}@zed
; CHECK-SAME: (%pair* noalias nocapture readonly byval [[DATA:%.*]])
; CHECK-NEXT: [[DATA_CAST:%.*]] = bitcast %pair* [[DATA]] to i32*
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[DATA_CAST]], align 1
; CHECK-NEXT: [[DATA_0_1:%.*]] = getelementptr [[PAIR:%.*]], %pair* [[DATA]], i32 0, i32 1
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[DATA_0_1]], align 1
; CHECK-NEXT: call void @bar(i32 [[TMP1]], i32 [[TMP2]])
; CHECK-NEXT: ret void
; IS________OPM-LABEL: define {{[^@]+}}@zed
; IS________OPM-SAME: (%pair* noalias nocapture readonly byval [[DATA:%.*]])
; IS________OPM-NEXT: call void @bar(%pair* noalias nocapture readonly byval [[DATA]])
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@zed
; IS__TUNIT_NPM-SAME: (%pair* noalias nocapture readonly byval [[DATA:%.*]])
; IS__TUNIT_NPM-NEXT: [[DATA_CAST:%.*]] = bitcast %pair* [[DATA]] to i32*
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[DATA_CAST]], align 1
; IS__TUNIT_NPM-NEXT: [[DATA_0_1:%.*]] = getelementptr [[PAIR:%.*]], %pair* [[DATA]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[DATA_0_1]], align 1
; IS__TUNIT_NPM-NEXT: call void @bar(i32 [[TMP1]], i32 [[TMP2]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@zed
; IS__CGSCC_NPM-SAME: (%pair* noalias nocapture nonnull readonly byval dereferenceable(8) [[DATA:%.*]])
; IS__CGSCC_NPM-NEXT: [[DATA_CAST:%.*]] = bitcast %pair* [[DATA]] to i32*
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[DATA_CAST]], align 1
; IS__CGSCC_NPM-NEXT: [[DATA_0_1:%.*]] = getelementptr [[PAIR:%.*]], %pair* [[DATA]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[DATA_0_1]], align 1
; IS__CGSCC_NPM-NEXT: call void @bar(i32 [[TMP1]], i32 [[TMP2]])
; IS__CGSCC_NPM-NEXT: ret void
;
call void @bar(%pair* byval %Data)
ret void

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Unused arguments from variadic functions cannot be eliminated as that changes
; their classiciation according to the SysV amd64 ABI. Clang and other frontends
@ -28,11 +31,17 @@ entry:
; Function Attrs: nounwind uwtable
define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) {
; CHECK-LABEL: define {{[^@]+}}@callee_t0f
; CHECK-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @sink(i32 0)
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@callee_t0f
; IS__TUNIT____-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...)
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: call void @sink(i32 0)
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee_t0f
; IS__CGSCC____-SAME: (i8* nocapture nofree nonnull readnone [[TP13:%.*]], i8* nocapture nofree nonnull readnone [[TP14:%.*]], i8* nocapture nofree nonnull readnone [[TP15:%.*]], i8* nocapture nofree nonnull readnone [[TP16:%.*]], i8* nocapture nofree nonnull readnone [[TP17:%.*]], ...)
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: call void @sink(i32 0)
; IS__CGSCC____-NEXT: ret void
;
entry:
call void @sink(i32 0)

View File

@ -1,5 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt < %s -passes=attributor -S | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Should not propagate the result of a weak function.
; PR2411

View File

@ -1,10 +1,41 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Don't constant-propagate byval pointers, since they are not pointers!
; PR5038
%struct.MYstr = type { i8, i32 }
@mystr = internal global %struct.MYstr zeroinitializer ; <%struct.MYstr*> [#uses=3]
define internal void @vfu1(%struct.MYstr* byval align 4 %u) nounwind {
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@vfu1
; IS__CGSCC_OPM-SAME: (%struct.MYstr* noalias nocapture nofree nonnull writeonly byval align 4 dereferenceable(1) [[U:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* [[U]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: store i32 99, i32* [[TMP0]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: store i8 97, i8* [[TMP1]], align 4
; IS__CGSCC_OPM-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC_OPM: return:
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@vfu1
; IS__CGSCC_NPM-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; IS__CGSCC_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; IS__CGSCC_NPM-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i32 99, i32* [[TMP2]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: store i8 97, i8* [[TMP3]], align 4
; IS__CGSCC_NPM-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC_NPM: return:
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
store i32 99, i32* %0, align 4
@ -17,21 +48,42 @@ return: ; preds = %entry
}
define internal i32 @vfu2(%struct.MYstr* byval align 4 %u) nounwind readonly {
; CHECK-LABEL: define {{[^@]+}}@vfu2
; CHECK-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; CHECK-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; CHECK-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; CHECK-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; CHECK-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; CHECK-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; CHECK-NEXT: ret i32 [[TMP7]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@vfu2
; IS__TUNIT_OPM-SAME: (%struct.MYstr* noalias nocapture nofree nonnull readonly byval align 8 dereferenceable(8) [[U:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__TUNIT_OPM-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP5]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@vfu2
; IS__TUNIT_NPM-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; IS__TUNIT_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; IS__TUNIT_NPM-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; IS__TUNIT_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; IS__TUNIT_NPM-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP7]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@vfu2()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0
; IS__CGSCC____-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 4
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__CGSCC____-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__CGSCC____-NEXT: ret i32 [[TMP5]]
;
entry:
%0 = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 ; <i32*> [#uses=1]
@ -44,14 +96,24 @@ entry:
}
define i32 @unions() nounwind {
; CHECK-LABEL: define {{[^@]+}}@unions()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 1
; CHECK-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 1
; CHECK-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[RESULT]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@unions()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* nofree nonnull readonly byval align 8 dereferenceable(8) @mystr)
; IS__TUNIT_OPM-NEXT: ret i32 [[RESULT]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 1
; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 1
; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP0]], i32 [[TMP1]])
; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@unions()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[RESULT:%.*]] = call i32 @vfu2()
; IS__CGSCC____-NEXT: ret i32 [[RESULT]]
;
entry:
call void @vfu1(%struct.MYstr* byval align 4 @mystr) nounwind
@ -60,23 +122,67 @@ entry:
}
define internal i32 @vfu2_v2(%struct.MYstr* byval align 4 %u) nounwind readonly {
; CHECK-LABEL: define {{[^@]+}}@vfu2_v2
; CHECK-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; CHECK-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; CHECK-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; CHECK-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; CHECK-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; CHECK-NEXT: store i32 99, i32* [[Z]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 0
; CHECK-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; CHECK-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; CHECK-NEXT: ret i32 [[TMP7]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@vfu2_v2
; IS__TUNIT_OPM-SAME: (%struct.MYstr* noalias nocapture nofree nonnull byval align 8 dereferenceable(8) [[U:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* [[U]], i32 0, i32 1
; IS__TUNIT_OPM-NEXT: store i32 99, i32* [[Z]], align 4
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 1
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 0
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 8
; IS__TUNIT_OPM-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__TUNIT_OPM-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[TMP5]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@vfu2_v2
; IS__TUNIT_NPM-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; IS__TUNIT_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; IS__TUNIT_NPM-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; IS__TUNIT_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; IS__TUNIT_NPM-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: store i32 99, i32* [[Z]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 0
; IS__TUNIT_NPM-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; IS__TUNIT_NPM-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; IS__TUNIT_NPM-NEXT: ret i32 [[TMP7]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@vfu2_v2
; IS__CGSCC_OPM-SAME: (%struct.MYstr* noalias nocapture nofree nonnull byval align 4 dereferenceable(1) [[U:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* [[U]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: store i32 99, i32* [[Z]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 1
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = load i8, i8* [[TMP2]], align 4
; IS__CGSCC_OPM-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32
; IS__CGSCC_OPM-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], [[TMP1]]
; IS__CGSCC_OPM-NEXT: ret i32 [[TMP5]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@vfu2_v2
; IS__CGSCC_NPM-SAME: (i8 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]]
; IS__CGSCC_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8*
; IS__CGSCC_NPM-NEXT: store i8 [[TMP0]], i8* [[U_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i32 [[TMP1]], i32* [[U_PRIV_0_1]]
; IS__CGSCC_NPM-NEXT: [[Z:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: store i32 99, i32* [[Z]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: [[TMP5:%.*]] = load i8, i8* [[TMP4]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP6:%.*]] = zext i8 [[TMP5]] to i32
; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3]]
; IS__CGSCC_NPM-NEXT: ret i32 [[TMP7]]
;
entry:
%z = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1
@ -91,14 +197,33 @@ entry:
}
define i32 @unions_v2() nounwind {
; CHECK-LABEL: define {{[^@]+}}@unions_v2()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 1
; CHECK-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 1
; CHECK-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[RESULT]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@unions_v2()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* nofree nonnull readonly byval align 8 dereferenceable(8) @mystr)
; IS__TUNIT_OPM-NEXT: ret i32 [[RESULT]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions_v2()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST]], align 1
; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 1
; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP0]], i32 [[TMP1]])
; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@unions_v2()
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* noalias nofree nonnull readnone byval align 8 dereferenceable(8) @mystr)
; IS__CGSCC_OPM-NEXT: ret i32 [[RESULT]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@unions_v2()
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8*
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8
; IS__CGSCC_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i32 0, i32 1
; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 1
; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP0]], i32 [[TMP1]])
; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]]
;
entry:
call void @vfu1(%struct.MYstr* byval align 4 @mystr) nounwind

View File

@ -1,14 +1,22 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define i64 @fn2() {
; CHECK-LABEL: define {{[^@]+}}@fn2()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #1, !range !0
; CHECK-NEXT: ret i64 [[CALL2]]
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@fn2()
; NOT_TUNIT_NPM-NEXT: entry:
; NOT_TUNIT_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef)
; NOT_TUNIT_NPM-NEXT: ret i64 [[CALL2]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #1, !range !0
; IS__TUNIT_NPM-NEXT: ret i64 [[CALL2]]
;
entry:
%conv = sext i32 undef to i64
@ -18,13 +26,21 @@ entry:
}
define i64 @fn2b(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@fn2b
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #1, !range !0
; CHECK-NEXT: ret i64 [[CALL2]]
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@fn2b
; NOT_TUNIT_NPM-SAME: (i32 [[ARG:%.*]])
; NOT_TUNIT_NPM-NEXT: entry:
; NOT_TUNIT_NPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64
; NOT_TUNIT_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
; NOT_TUNIT_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]])
; NOT_TUNIT_NPM-NEXT: ret i64 [[CALL2]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2b
; IS__TUNIT_NPM-SAME: (i32 [[ARG:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64
; IS__TUNIT_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
; IS__TUNIT_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #1, !range !0
; IS__TUNIT_NPM-NEXT: ret i64 [[CALL2]]
;
entry:
%conv = sext i32 %arg to i64
@ -34,10 +50,19 @@ entry:
}
define i64 @fn2c() {
; CHECK-LABEL: define {{[^@]+}}@fn2c()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 42) #1, !range !0
; CHECK-NEXT: ret i64 [[CALL2]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn2c()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 42)
; IS__TUNIT_OPM-NEXT: ret i64 [[CALL2]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2c()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 42) #1, !range !0
; IS__TUNIT_NPM-NEXT: ret i64 [[CALL2]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2c()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: ret i64 42
;
entry:
%conv = sext i32 undef to i64

View File

@ -1,21 +1,42 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @fn2(i32* %P, i1 %C) {
; CHECK-LABEL: define {{[^@]+}}@fn2
; CHECK-SAME: (i32* nocapture nofree [[P:%.*]], i1 %C)
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: for.cond1:
; CHECK-NEXT: br i1 %C, label %if.end, label %exit
; CHECK: if.end:
; CHECK-NEXT: [[E_2:%.*]] = phi i32* [ %P, %entry ], [ null, %for.cond1 ]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
; CHECK-NEXT: br label %for.cond1
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2
; IS__TUNIT____-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: br label [[IF_END:%.*]]
; IS__TUNIT____: for.cond1:
; IS__TUNIT____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
; IS__TUNIT____-NEXT: store i32 [[CALL]], i32* [[P]]
; IS__TUNIT____-NEXT: br label [[FOR_COND1]]
; IS__TUNIT____: exit:
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: br label [[IF_END:%.*]]
; IS__CGSCC____: for.cond1:
; IS__CGSCC____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
; IS__CGSCC____-NEXT: store i32 [[CALL]], i32* [[P]], align 4
; IS__CGSCC____-NEXT: br label [[FOR_COND1]]
; IS__CGSCC____: exit:
; IS__CGSCC____-NEXT: ret void
;
entry:
br label %if.end
@ -48,18 +69,51 @@ entry:
}
define void @fn_no_null_opt(i32* %P, i1 %C) "null-pointer-is-valid"="true" {
; CHECK-LABEL: define {{[^@]+}}@fn_no_null_opt
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 %C)
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[IF_END:%.*]]
; CHECK: for.cond1:
; CHECK-NEXT: br i1 %C, label %if.end, label %exit
; CHECK: if.end:
; CHECK-NEXT: [[E_2:%.*]] = phi i32* [ undef, %entry ], [ null, %for.cond1 ]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
; CHECK-NEXT: br label %for.cond1
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@fn_no_null_opt
; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: br label [[IF_END:%.*]]
; IS__TUNIT____: for.cond1:
; IS__TUNIT____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
; IS__TUNIT____-NEXT: store i32 [[CALL]], i32* [[P]]
; IS__TUNIT____-NEXT: br label [[FOR_COND1]]
; IS__TUNIT____: exit:
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn_no_null_opt
; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: br label [[IF_END:%.*]]
; IS__CGSCC_OPM: for.cond1:
; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
; IS__CGSCC_OPM: if.end:
; IS__CGSCC_OPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4
; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
; IS__CGSCC_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4
; IS__CGSCC_OPM-NEXT: br label [[FOR_COND1]]
; IS__CGSCC_OPM: exit:
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn_no_null_opt
; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: br label [[IF_END:%.*]]
; IS__CGSCC_NPM: for.cond1:
; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
; IS__CGSCC_NPM: if.end:
; IS__CGSCC_NPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 536870912
; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
; IS__CGSCC_NPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4
; IS__CGSCC_NPM-NEXT: br label [[FOR_COND1]]
; IS__CGSCC_NPM: exit:
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
br label %if.end

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
%struct.wobble = type { i32 }
%struct.zot = type { %struct.wobble, %struct.wobble, %struct.wobble }
@ -17,10 +20,16 @@ bb:
}
define void @baz(<8 x i32> %arg) local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@baz
; CHECK-SAME: (<8 x i32> [[ARG:%.*]]) local_unnamed_addr
; CHECK-NEXT: bb:
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@baz
; IS__TUNIT____-SAME: (<8 x i32> [[ARG:%.*]]) local_unnamed_addr
; IS__TUNIT____-NEXT: bb:
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@baz
; IS__CGSCC____-SAME: (<8 x i32> [[ARG:%.*]]) local_unnamed_addr
; IS__CGSCC____-NEXT: bb:
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = extractvalue [[STRUCT_ZOT:%.*]] undef, 0, 0
; IS__CGSCC____-NEXT: ret void
;
bb:
%tmp = call %struct.zot @widget(<8 x i32> %arg)

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; The original C source looked like this:
;
@ -76,11 +79,18 @@ define internal i16 @bar2(i16 %p1, i16 %p2) {
; been provided),
define dso_local i16 @vararg_tests(i16 %a) {
; CHECK-LABEL: define {{[^@]+}}@vararg_tests
; CHECK-SAME: (i16 [[A:%.*]])
; CHECK-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
; CHECK-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
; CHECK-NEXT: ret i16 [[ADD]]
; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@vararg_tests
; NOT_CGSCC_OPM-SAME: (i16 [[A:%.*]])
; NOT_CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
; NOT_CGSCC_OPM-NEXT: [[ADD:%.*]] = add i16 7, [[CALL2]]
; NOT_CGSCC_OPM-NEXT: ret i16 [[ADD]]
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@vararg_tests
; IS__CGSCC_OPM-SAME: (i16 [[A:%.*]])
; IS__CGSCC_OPM-NEXT: [[CALL1:%.*]] = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 [[A]])
; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i16 bitcast (i16 (i16, i16, ...)* @vararg_no_prop to i16 (i16)*)(i16 7)
; IS__CGSCC_OPM-NEXT: [[ADD:%.*]] = add i16 [[CALL1]], [[CALL2]]
; IS__CGSCC_OPM-NEXT: ret i16 [[ADD]]
;
%call1 = call i16 (i16, ...) @vararg_prop(i16 7, i16 8, i16 %a)
%call2 = call i16 bitcast (i16 (i16, i16, ...) * @vararg_no_prop to i16 (i16) *) (i16 7)
@ -89,6 +99,10 @@ define dso_local i16 @vararg_tests(i16 %a) {
}
define internal i16 @vararg_prop(i16 %p1, ...) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@vararg_prop
; IS__CGSCC____-SAME: (i16 returned [[P1:%.*]], ...)
; IS__CGSCC____-NEXT: ret i16 7
;
ret i16 %p1
}

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; This test is just to verify that we do not crash/assert due to mismatch in
; argument type between the caller and callee.

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; See PR26774

View File

@ -1,23 +1,51 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes='internalize,attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR5569
; IPSCCP should prove that the blocks are dead and delete them, and
; properly handle the dangling blockaddress constants.
; CHECK: @bar.l = internal constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]
; NOT_CGSCC_OPM: @bar.l = internal constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]
; IS__CGSCC_OPM: @bar.l = internal constant [2 x i8*] [i8* blockaddress(@bar, %lab0), i8* blockaddress(@bar, %end)]
@code = global [5 x i32] [i32 0, i32 0, i32 0, i32 0, i32 1], align 4 ; <[5 x i32]*> [#uses=0]
@bar.l = internal constant [2 x i8*] [i8* blockaddress(@bar, %lab0), i8* blockaddress(@bar, %end)] ; <[2 x i8*]*> [#uses=1]
define void @foo(i32 %x) nounwind readnone {
define internal void @foo(i32 %x) nounwind readnone {
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
; IS__CGSCC____-SAME: (i32 [[X:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: store volatile i32 -1, i32* [[B]]
; IS__CGSCC____-NEXT: ret void
;
entry:
%b = alloca i32, align 4 ; <i32*> [#uses=1]
store volatile i32 -1, i32* %b
ret void
}
define void @bar(i32* nocapture %pc) nounwind readonly {
define internal void @bar(i32* nocapture %pc) nounwind readonly {
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar
; IS__CGSCC_OPM-SAME: (i32* nocapture [[PC:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO:%.*]]
; IS__CGSCC_OPM: lab0:
; IS__CGSCC_OPM-NEXT: [[INDVAR_NEXT:%.*]] = add i32 [[INDVAR:%.*]], 1
; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO]]
; IS__CGSCC_OPM: end:
; IS__CGSCC_OPM-NEXT: ret void
; IS__CGSCC_OPM: indirectgoto:
; IS__CGSCC_OPM-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; IS__CGSCC_OPM-NEXT: [[PC_ADDR_0:%.*]] = getelementptr i32, i32* [[PC]], i32 [[INDVAR]]
; IS__CGSCC_OPM-NEXT: [[TMP1_PN:%.*]] = load i32, i32* [[PC_ADDR_0]]
; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST_IN:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @bar.l, i32 0, i32 [[TMP1_PN]]
; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]]
; IS__CGSCC_OPM-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
;
entry:
br label %indirectgoto
@ -38,6 +66,10 @@ indirectgoto: ; preds = %lab0, %entry
}
define i32 @main() nounwind readnone {
; CHECK-LABEL: define {{[^@]+}}@main()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 0
;
entry:
ret i32 0
}

View File

@ -1,6 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 -disable-output < %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define internal void @foo(i32 %X) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i32 [[X:%.*]])
; CHECK-NEXT: call void @foo(i32 [[X]])
; CHECK-NEXT: ret void
;
call void @foo( i32 %X )
ret void
}

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "E-m:e-i64:64-n32:64"
target triple = "powerpc64-bgq-linux"

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@_ZL6test1g = internal global i32 42, align 4

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
;
; /---------------------------------------|

View File

@ -1,26 +1,46 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR36485
; musttail call result can't be replaced with a constant, unless the call can be removed
declare i32 @external()
define i8* @start(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@start
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
; CHECK-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; CHECK: true:
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 [[V]])
; CHECK-NEXT: ret i8* [[CA]]
; CHECK: false:
; CHECK-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
; CHECK-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
; CHECK: c2_true:
; CHECK-NEXT: ret i8* null
; CHECK: c2_false:
; CHECK-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 undef)
; CHECK-NEXT: ret i8* [[CA2]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@start
; IS__TUNIT____-SAME: (i8 [[V:%.*]])
; IS__TUNIT____-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
; IS__TUNIT____-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; IS__TUNIT____: true:
; IS__TUNIT____-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 [[V]])
; IS__TUNIT____-NEXT: ret i8* [[CA]]
; IS__TUNIT____: false:
; IS__TUNIT____-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
; IS__TUNIT____-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
; IS__TUNIT____: c2_true:
; IS__TUNIT____-NEXT: ret i8* null
; IS__TUNIT____: c2_false:
; IS__TUNIT____-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 undef)
; IS__TUNIT____-NEXT: ret i8* [[CA2]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@start
; IS__CGSCC____-SAME: (i8 [[V:%.*]])
; IS__CGSCC____-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
; IS__CGSCC____-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
; IS__CGSCC____: true:
; IS__CGSCC____-NEXT: [[CA:%.*]] = musttail call noalias align 536870912 i8* @side_effects(i8 [[V]])
; IS__CGSCC____-NEXT: ret i8* [[CA]]
; IS__CGSCC____: false:
; IS__CGSCC____-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
; IS__CGSCC____-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
; IS__CGSCC____: c2_true:
; IS__CGSCC____-NEXT: [[CA1:%.*]] = musttail call noalias align 536870912 i8* @no_side_effects(i8 [[V]])
; IS__CGSCC____-NEXT: ret i8* [[CA1]]
; IS__CGSCC____: c2_false:
; IS__CGSCC____-NEXT: [[CA2:%.*]] = musttail call noalias align 536870912 i8* @dont_zap_me(i8 [[V]])
; IS__CGSCC____-NEXT: ret i8* [[CA2]]
;
%c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false
@ -41,11 +61,17 @@ c2_false:
}
define internal i8* @side_effects(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@side_effects
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @start(i8 [[V]])
; CHECK-NEXT: ret i8* [[CA]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@side_effects
; IS__TUNIT____-SAME: (i8 [[V:%.*]])
; IS__TUNIT____-NEXT: [[I1:%.*]] = call i32 @external()
; IS__TUNIT____-NEXT: [[CA:%.*]] = musttail call i8* @start(i8 [[V]])
; IS__TUNIT____-NEXT: ret i8* [[CA]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@side_effects
; IS__CGSCC____-SAME: (i8 [[V:%.*]])
; IS__CGSCC____-NEXT: [[I1:%.*]] = call i32 @external()
; IS__CGSCC____-NEXT: [[CA:%.*]] = musttail call noalias align 536870912 i8* @start(i8 [[V]])
; IS__CGSCC____-NEXT: ret i8* [[CA]]
;
%i1 = call i32 @external()
@ -60,14 +86,23 @@ define internal i8* @side_effects(i8 %v) {
}
define internal i8* @no_side_effects(i8 %v) readonly nounwind {
; IS__CGSCC____-LABEL: define {{[^@]+}}@no_side_effects
; IS__CGSCC____-SAME: (i8 [[V:%.*]])
; IS__CGSCC____-NEXT: ret i8* null
;
ret i8* null
}
define internal i8* @dont_zap_me(i8 %v) {
; CHECK-LABEL: define {{[^@]+}}@dont_zap_me
; CHECK-SAME: (i8 [[V:%.*]])
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
; CHECK-NEXT: ret i8* undef
; IS__TUNIT____-LABEL: define {{[^@]+}}@dont_zap_me
; IS__TUNIT____-SAME: (i8 [[V:%.*]])
; IS__TUNIT____-NEXT: [[I1:%.*]] = call i32 @external()
; IS__TUNIT____-NEXT: ret i8* undef
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@dont_zap_me
; IS__CGSCC____-SAME: (i8 [[V:%.*]])
; IS__CGSCC____-NEXT: [[I1:%.*]] = call i32 @external()
; IS__CGSCC____-NEXT: ret i8* null
;
%i1 = call i32 @external()
ret i8* null

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc19.0.24215"

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; void bar(int, float, double);
;
@ -25,16 +28,49 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@1 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8
define dso_local void @foo(i32 %N) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[P:%.*]] = alloca float, align 4
; CHECK-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; CHECK-NEXT: store float 3.000000e+00, float* [[P]], align 4
; CHECK-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[P]], i64 undef)
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@foo
; IS__TUNIT_OPM-SAME: (i32 [[N:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; IS__TUNIT_OPM-NEXT: [[P:%.*]] = alloca float, align 4
; IS__TUNIT_OPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; IS__TUNIT_OPM-NEXT: store float 3.000000e+00, float* [[P]], align 4
; IS__TUNIT_OPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; IS__TUNIT_OPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* nocapture nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* nocapture nonnull readonly align 4 dereferenceable(4) [[P]], i64 undef)
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@foo
; IS__TUNIT_NPM-SAME: (i32 [[N:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: [[P:%.*]] = alloca float, align 4
; IS__TUNIT_NPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; IS__TUNIT_NPM-NEXT: store float 3.000000e+00, float* [[P]], align 4
; IS__TUNIT_NPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; IS__TUNIT_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[P]], i64 undef)
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@foo
; IS__CGSCC_OPM-SAME: (i32 [[N:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; IS__CGSCC_OPM-NEXT: [[P:%.*]] = alloca float, align 4
; IS__CGSCC_OPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; IS__CGSCC_OPM-NEXT: store float 3.000000e+00, float* [[P]], align 4
; IS__CGSCC_OPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; IS__CGSCC_OPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* nonnull align 4 dereferenceable(4) [[N_ADDR]], float* nonnull align 4 dereferenceable(4) [[P]], i64 4617315517961601024)
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo
; IS__CGSCC_NPM-SAME: (i32 [[N:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: [[P:%.*]] = alloca float, align 4
; IS__CGSCC_NPM-NEXT: store i32 [[N]], i32* [[N_ADDR]], align 4
; IS__CGSCC_NPM-NEXT: store float 3.000000e+00, float* [[P]], align 4
; IS__CGSCC_NPM-NEXT: store i32 7, i32* [[N_ADDR]], align 4
; IS__CGSCC_NPM-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @1, i32 3, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, float*, i64)* @.omp_outlined. to void (i32*, i32*, ...)*), i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], float* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[P]], i64 4617315517961601024)
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%N.addr = alloca i32, align 4
@ -47,13 +83,195 @@ entry:
}
define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %N, float* dereferenceable(4) %p, i64 %q) {
; IS________OPM-LABEL: define {{[^@]+}}@.omp_outlined.
; IS________OPM-SAME: (i32* noalias nocapture readonly [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture nonnull readonly align 4 dereferenceable(4) [[N:%.*]], float* nocapture nonnull readonly align 4 dereferenceable(4) [[P:%.*]], i64 [[Q:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[Q_ADDR:%.*]] = alloca i64, align 8
; IS________OPM-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
; IS________OPM-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
; IS________OPM-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
; IS________OPM-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
; IS________OPM-NEXT: store i64 4617315517961601024, i64* [[Q_ADDR]], align 8
; IS________OPM-NEXT: [[CONV:%.*]] = bitcast i64* [[Q_ADDR]] to double*
; IS________OPM-NEXT: [[TMP:%.*]] = load i32, i32* [[N]], align 4
; IS________OPM-NEXT: [[SUB3:%.*]] = add nsw i32 [[TMP]], -3
; IS________OPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP]], 2
; IS________OPM-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
; IS________OPM: omp.precond.then:
; IS________OPM-NEXT: store i32 0, i32* [[DOTOMP_LB]], align 4
; IS________OPM-NEXT: store i32 [[SUB3]], i32* [[DOTOMP_UB]], align 4
; IS________OPM-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4
; IS________OPM-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4
; IS________OPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS________OPM-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP5]], i32 34, i32* nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 1, i32 1)
; IS________OPM-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS________OPM-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], [[SUB3]]
; IS________OPM-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS________OPM: cond.true:
; IS________OPM-NEXT: br label [[COND_END:%.*]]
; IS________OPM: cond.false:
; IS________OPM-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS________OPM-NEXT: br label [[COND_END]]
; IS________OPM: cond.end:
; IS________OPM-NEXT: [[COND:%.*]] = phi i32 [ [[SUB3]], [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
; IS________OPM-NEXT: store i32 [[COND]], i32* [[DOTOMP_UB]], align 4
; IS________OPM-NEXT: [[TMP8:%.*]] = load i32, i32* [[DOTOMP_LB]], align 4
; IS________OPM-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
; IS________OPM: omp.inner.for.cond:
; IS________OPM-NEXT: [[DOTOMP_IV_0:%.*]] = phi i32 [ [[TMP8]], [[COND_END]] ], [ [[ADD11:%.*]], [[OMP_INNER_FOR_INC:%.*]] ]
; IS________OPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS________OPM-NEXT: [[CMP8:%.*]] = icmp sgt i32 [[DOTOMP_IV_0]], [[TMP9]]
; IS________OPM-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]], label [[OMP_INNER_FOR_BODY:%.*]]
; IS________OPM: omp.inner.for.cond.cleanup:
; IS________OPM-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
; IS________OPM: omp.inner.for.body:
; IS________OPM-NEXT: [[ADD10:%.*]] = add nsw i32 [[DOTOMP_IV_0]], 2
; IS________OPM-NEXT: [[TMP10:%.*]] = load float, float* [[P]], align 4
; IS________OPM-NEXT: [[TMP11:%.*]] = load double, double* [[CONV]], align 8
; IS________OPM-NEXT: call void @bar(i32 [[ADD10]], float [[TMP10]], double [[TMP11]])
; IS________OPM-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
; IS________OPM: omp.body.continue:
; IS________OPM-NEXT: br label [[OMP_INNER_FOR_INC]]
; IS________OPM: omp.inner.for.inc:
; IS________OPM-NEXT: [[ADD11]] = add nsw i32 [[DOTOMP_IV_0]], 1
; IS________OPM-NEXT: br label [[OMP_INNER_FOR_COND]]
; IS________OPM: omp.inner.for.end:
; IS________OPM-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
; IS________OPM: omp.loop.exit:
; IS________OPM-NEXT: [[TMP12:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS________OPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP12]])
; IS________OPM-NEXT: br label [[OMP_PRECOND_END]]
; IS________OPM: omp.precond.end:
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@.omp_outlined.
; IS__TUNIT_NPM-SAME: (i32* noalias nocapture readonly [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[N:%.*]], float* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[P:%.*]], i64 [[Q:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[Q_ADDR:%.*]] = alloca i64, align 8
; IS__TUNIT_NPM-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: store i64 4617315517961601024, i64* [[Q_ADDR]], align 8
; IS__TUNIT_NPM-NEXT: [[CONV:%.*]] = bitcast i64* [[Q_ADDR]] to double*
; IS__TUNIT_NPM-NEXT: [[TMP:%.*]] = load i32, i32* [[N]], align 4
; IS__TUNIT_NPM-NEXT: [[SUB3:%.*]] = add nsw i32 [[TMP]], -3
; IS__TUNIT_NPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP]], 2
; IS__TUNIT_NPM-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
; IS__TUNIT_NPM: omp.precond.then:
; IS__TUNIT_NPM-NEXT: store i32 0, i32* [[DOTOMP_LB]], align 4
; IS__TUNIT_NPM-NEXT: store i32 [[SUB3]], i32* [[DOTOMP_UB]], align 4
; IS__TUNIT_NPM-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4
; IS__TUNIT_NPM-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS__TUNIT_NPM-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP5]], i32 34, i32* nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 1, i32 1)
; IS__TUNIT_NPM-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__TUNIT_NPM-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], [[SUB3]]
; IS__TUNIT_NPM-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__TUNIT_NPM: cond.true:
; IS__TUNIT_NPM-NEXT: br label [[COND_END:%.*]]
; IS__TUNIT_NPM: cond.false:
; IS__TUNIT_NPM-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__TUNIT_NPM-NEXT: br label [[COND_END]]
; IS__TUNIT_NPM: cond.end:
; IS__TUNIT_NPM-NEXT: [[COND:%.*]] = phi i32 [ [[SUB3]], [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
; IS__TUNIT_NPM-NEXT: store i32 [[COND]], i32* [[DOTOMP_UB]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP8:%.*]] = load i32, i32* [[DOTOMP_LB]], align 4
; IS__TUNIT_NPM-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
; IS__TUNIT_NPM: omp.inner.for.cond:
; IS__TUNIT_NPM-NEXT: [[DOTOMP_IV_0:%.*]] = phi i32 [ [[TMP8]], [[COND_END]] ], [ [[ADD11:%.*]], [[OMP_INNER_FOR_INC:%.*]] ]
; IS__TUNIT_NPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__TUNIT_NPM-NEXT: [[CMP8:%.*]] = icmp sgt i32 [[DOTOMP_IV_0]], [[TMP9]]
; IS__TUNIT_NPM-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]], label [[OMP_INNER_FOR_BODY:%.*]]
; IS__TUNIT_NPM: omp.inner.for.cond.cleanup:
; IS__TUNIT_NPM-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
; IS__TUNIT_NPM: omp.inner.for.body:
; IS__TUNIT_NPM-NEXT: [[ADD10:%.*]] = add nsw i32 [[DOTOMP_IV_0]], 2
; IS__TUNIT_NPM-NEXT: [[TMP10:%.*]] = load float, float* [[P]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP11:%.*]] = load double, double* [[CONV]], align 8
; IS__TUNIT_NPM-NEXT: call void @bar(i32 [[ADD10]], float [[TMP10]], double [[TMP11]])
; IS__TUNIT_NPM-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
; IS__TUNIT_NPM: omp.body.continue:
; IS__TUNIT_NPM-NEXT: br label [[OMP_INNER_FOR_INC]]
; IS__TUNIT_NPM: omp.inner.for.inc:
; IS__TUNIT_NPM-NEXT: [[ADD11]] = add nsw i32 [[DOTOMP_IV_0]], 1
; IS__TUNIT_NPM-NEXT: br label [[OMP_INNER_FOR_COND]]
; IS__TUNIT_NPM: omp.inner.for.end:
; IS__TUNIT_NPM-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
; IS__TUNIT_NPM: omp.loop.exit:
; IS__TUNIT_NPM-NEXT: [[TMP12:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS__TUNIT_NPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP12]])
; IS__TUNIT_NPM-NEXT: br label [[OMP_PRECOND_END]]
; IS__TUNIT_NPM: omp.precond.end:
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@.omp_outlined.
; IS__CGSCC_NPM-SAME: (i32* noalias nocapture readonly [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture nonnull readonly align 4 dereferenceable(4) [[N:%.*]], float* nocapture nonnull readonly dereferenceable(4) [[P:%.*]], i64 [[Q:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[Q_ADDR:%.*]] = alloca i64, align 8
; IS__CGSCC_NPM-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
; IS__CGSCC_NPM-NEXT: store i64 4617315517961601024, i64* [[Q_ADDR]], align 8
; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = bitcast i64* [[Q_ADDR]] to double*
; IS__CGSCC_NPM-NEXT: [[TMP:%.*]] = load i32, i32* [[N]], align 4
; IS__CGSCC_NPM-NEXT: [[SUB3:%.*]] = add nsw i32 [[TMP]], -3
; IS__CGSCC_NPM-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP]], 2
; IS__CGSCC_NPM-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
; IS__CGSCC_NPM: omp.precond.then:
; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[DOTOMP_LB]], align 4
; IS__CGSCC_NPM-NEXT: store i32 [[SUB3]], i32* [[DOTOMP_UB]], align 4
; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[DOTOMP_STRIDE]], align 4
; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[DOTOMP_IS_LAST]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS__CGSCC_NPM-NEXT: call void @__kmpc_for_static_init_4(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP5]], i32 34, i32* nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], i32* nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 1, i32 1)
; IS__CGSCC_NPM-NEXT: [[TMP6:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__CGSCC_NPM-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], [[SUB3]]
; IS__CGSCC_NPM-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__CGSCC_NPM: cond.true:
; IS__CGSCC_NPM-NEXT: br label [[COND_END:%.*]]
; IS__CGSCC_NPM: cond.false:
; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__CGSCC_NPM-NEXT: br label [[COND_END]]
; IS__CGSCC_NPM: cond.end:
; IS__CGSCC_NPM-NEXT: [[COND:%.*]] = phi i32 [ [[SUB3]], [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
; IS__CGSCC_NPM-NEXT: store i32 [[COND]], i32* [[DOTOMP_UB]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP8:%.*]] = load i32, i32* [[DOTOMP_LB]], align 4
; IS__CGSCC_NPM-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
; IS__CGSCC_NPM: omp.inner.for.cond:
; IS__CGSCC_NPM-NEXT: [[DOTOMP_IV_0:%.*]] = phi i32 [ [[TMP8]], [[COND_END]] ], [ [[ADD11:%.*]], [[OMP_INNER_FOR_INC:%.*]] ]
; IS__CGSCC_NPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[DOTOMP_UB]], align 4
; IS__CGSCC_NPM-NEXT: [[CMP8:%.*]] = icmp sgt i32 [[DOTOMP_IV_0]], [[TMP9]]
; IS__CGSCC_NPM-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]], label [[OMP_INNER_FOR_BODY:%.*]]
; IS__CGSCC_NPM: omp.inner.for.cond.cleanup:
; IS__CGSCC_NPM-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
; IS__CGSCC_NPM: omp.inner.for.body:
; IS__CGSCC_NPM-NEXT: [[ADD10:%.*]] = add nsw i32 [[DOTOMP_IV_0]], 2
; IS__CGSCC_NPM-NEXT: [[TMP10:%.*]] = load float, float* [[P]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP11:%.*]] = load double, double* [[CONV]], align 8
; IS__CGSCC_NPM-NEXT: call void @bar(i32 [[ADD10]], float [[TMP10]], double [[TMP11]])
; IS__CGSCC_NPM-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
; IS__CGSCC_NPM: omp.body.continue:
; IS__CGSCC_NPM-NEXT: br label [[OMP_INNER_FOR_INC]]
; IS__CGSCC_NPM: omp.inner.for.inc:
; IS__CGSCC_NPM-NEXT: [[ADD11]] = add nsw i32 [[DOTOMP_IV_0]], 1
; IS__CGSCC_NPM-NEXT: br label [[OMP_INNER_FOR_COND]]
; IS__CGSCC_NPM: omp.inner.for.end:
; IS__CGSCC_NPM-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
; IS__CGSCC_NPM: omp.loop.exit:
; IS__CGSCC_NPM-NEXT: [[TMP12:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
; IS__CGSCC_NPM-NEXT: call void @__kmpc_for_static_fini(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 [[TMP12]])
; IS__CGSCC_NPM-NEXT: br label [[OMP_PRECOND_END]]
; IS__CGSCC_NPM: omp.precond.end:
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%q.addr = alloca i64, align 8
%.omp.lb = alloca i32, align 4
%.omp.ub = alloca i32, align 4
%.omp.stride = alloca i32, align 4
%.omp.is_last = alloca i32, align 4
; CHECK: store i64 4617315517961601024, i64* %q.addr, align 8
store i64 %q, i64* %q.addr, align 8
%conv = bitcast i64* %q.addr to double*
%tmp = load i32, i32* %N, align 4

View File

@ -1,6 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s --check-prefixes=CHECK,MODULE
; RUN: opt -S -passes=attributor-cgscc -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; #include <pthread.h>
;
@ -29,27 +31,38 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; FIXME: nocapture & noalias for %alloc2 in %call3
define dso_local i32 @main() {
; MODULE-LABEL: define {{[^@]+}}@main()
; MODULE-NEXT: entry:
; MODULE-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; MODULE-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; MODULE-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; MODULE-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 undef)
; MODULE-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) undef)
; MODULE-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; MODULE-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; MODULE-NEXT: ret i32 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@main()
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; IS__TUNIT____-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; IS__TUNIT____-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 undef)
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) undef)
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; IS__TUNIT____-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[ALLOC2]])
; IS__TUNIT____-NEXT: ret i32 0
;
; CGSCC-LABEL: define {{[^@]+}}@main()
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; CGSCC-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; CGSCC-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; CGSCC-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CGSCC-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CGSCC-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CGSCC-NEXT: ret i32 0
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@main()
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; IS__CGSCC_OPM-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; IS__CGSCC_OPM-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias align 536870912 null)
; IS__CGSCC_OPM-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* nonnull align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* nocapture nonnull align 8 dereferenceable(1) [[ALLOC1]])
; IS__CGSCC_OPM-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* nonnull align 8 dereferenceable(1) [[ALLOC2]])
; IS__CGSCC_OPM-NEXT: ret i32 0
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@main()
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[ALLOC1:%.*]] = alloca i8, align 8
; IS__CGSCC_NPM-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8
; IS__CGSCC_NPM-NEXT: [[THREAD:%.*]] = alloca i64, align 8
; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; IS__CGSCC_NPM-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; IS__CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; IS__CGSCC_NPM-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; IS__CGSCC_NPM-NEXT: ret i32 0
;
entry:
%alloc1 = alloca i8, align 8
@ -65,60 +78,75 @@ entry:
declare !callback !0 dso_local i32 @pthread_create(i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*)
define internal i8* @foo(i8* %arg) {
; MODULE-LABEL: define {{[^@]+}}@foo
; MODULE-SAME: (i8* noalias nofree readnone returned align 536870912 [[ARG:%.*]])
; MODULE-NEXT: entry:
; MODULE-NEXT: ret i8* null
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@foo
; NOT_CGSCC_NPM-SAME: (i8* noalias nofree readnone returned align 536870912 "no-capture-maybe-returned" [[ARG:%.*]])
; NOT_CGSCC_NPM-NEXT: entry:
; NOT_CGSCC_NPM-NEXT: ret i8* null
;
; CGSCC-LABEL: define {{[^@]+}}@foo
; CGSCC-SAME: (i8* noalias nofree readnone returned [[ARG:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i8* null
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo
; IS__CGSCC_NPM-SAME: (i8* noalias nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: ret i8* null
;
entry:
ret i8* %arg
}
define internal i8* @bar(i8* %arg) {
; MODULE-LABEL: define {{[^@]+}}@bar
; MODULE-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]])
; MODULE-NEXT: entry:
; MODULE-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
; IS__TUNIT____-LABEL: define {{[^@]+}}@bar
; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
;
; CGSCC-LABEL: define {{[^@]+}}@bar
; CGSCC-SAME: (i8* nofree readnone returned [[ARG:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar
; IS__CGSCC_OPM-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(8) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@bar
; IS__CGSCC_NPM-SAME: (i8* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*)
;
entry:
ret i8* %arg
}
define internal i8* @baz(i8* %arg) {
; MODULE-LABEL: define {{[^@]+}}@baz
; MODULE-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]])
; MODULE-NEXT: entry:
; MODULE-NEXT: ret i8* [[ARG]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@baz
; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: ret i8* [[ARG]]
;
; CGSCC-LABEL: define {{[^@]+}}@baz
; CGSCC-SAME: (i8* nofree readnone returned [[ARG:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i8* [[ARG]]
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@baz
; IS__CGSCC_OPM-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: ret i8* [[ARG]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@baz
; IS__CGSCC_NPM-SAME: (i8* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: ret i8* [[ARG]]
;
entry:
ret i8* %arg
}
define internal i8* @buz(i8* %arg) {
; MODULE-LABEL: define {{[^@]+}}@buz
; MODULE-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]])
; MODULE-NEXT: entry:
; MODULE-NEXT: ret i8* [[ARG]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@buz
; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: ret i8* [[ARG]]
;
; CGSCC-LABEL: define {{[^@]+}}@buz
; CGSCC-SAME: (i8* nofree readnone returned [[ARG:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: ret i8* [[ARG]]
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@buz
; IS__CGSCC_OPM-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(1) "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: ret i8* [[ARG]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@buz
; IS__CGSCC_NPM-SAME: (i8* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: ret i8* [[ARG]]
;
entry:
ret i8* %arg

View File

@ -1,9 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; CHECK-NOT: %X
define internal i32 @foo(i32 %X) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo()
; IS__CGSCC____-NEXT: unreachable
;
%Y = call i32 @foo( i32 %X ) ; <i32> [#uses=1]
%Z = add i32 %Y, 1 ; <i32> [#uses=1]
ret i32 %Z

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; PR5596
; IPSCCP should propagate the 0 argument, eliminate the switch, and propagate
@ -18,6 +21,17 @@ entry:
}
define internal i32 @wwrite(i64 %i) nounwind readnone {
; IS__CGSCC____-LABEL: define {{[^@]+}}@wwrite()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [
; IS__CGSCC____-NEXT: i64 3, label [[RETURN:%.*]]
; IS__CGSCC____-NEXT: i64 10, label [[RETURN]]
; IS__CGSCC____-NEXT: ]
; IS__CGSCC____: sw.default:
; IS__CGSCC____-NEXT: ret i32 123
; IS__CGSCC____: return:
; IS__CGSCC____-NEXT: unreachable
;
entry:
switch i64 %i, label %sw.default [
i64 3, label %return

View File

@ -1,20 +1,36 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=8 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=8 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=8 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;; This function returns its second argument on all return statements
define internal i32* @incdec(i1 %C, i32* %V) {
; CHECK-LABEL: define {{[^@]+}}@incdec
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nofree nonnull returned align 4 dereferenceable(4) [[V:%.*]])
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: [[X1:%.*]] = add i32 [[X]], 1
; CHECK-NEXT: store i32 [[X1]], i32* [[V]], align 4
; CHECK-NEXT: ret i32* [[V]]
; CHECK: F:
; CHECK-NEXT: [[X2:%.*]] = sub i32 [[X]], 1
; CHECK-NEXT: store i32 [[X2]], i32* [[V]], align 4
; CHECK-NEXT: ret i32* [[V]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@incdec
; IS__TUNIT____-SAME: (i1 [[C:%.*]], i32* noalias nofree nonnull returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]])
; IS__TUNIT____-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4
; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__TUNIT____: T:
; IS__TUNIT____-NEXT: [[X1:%.*]] = add i32 [[X]], 1
; IS__TUNIT____-NEXT: store i32 [[X1]], i32* [[V]], align 4
; IS__TUNIT____-NEXT: ret i32* [[V]]
; IS__TUNIT____: F:
; IS__TUNIT____-NEXT: [[X2:%.*]] = sub i32 [[X]], 1
; IS__TUNIT____-NEXT: store i32 [[X2]], i32* [[V]], align 4
; IS__TUNIT____-NEXT: ret i32* [[V]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@incdec
; IS__CGSCC____-SAME: (i1 [[C:%.*]], i32* nofree nonnull returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]])
; IS__CGSCC____-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__CGSCC____: T:
; IS__CGSCC____-NEXT: [[X1:%.*]] = add i32 [[X]], 1
; IS__CGSCC____-NEXT: store i32 [[X1]], i32* [[V]], align 4
; IS__CGSCC____-NEXT: ret i32* [[V]]
; IS__CGSCC____: F:
; IS__CGSCC____-NEXT: [[X2:%.*]] = sub i32 [[X]], 1
; IS__CGSCC____-NEXT: store i32 [[X2]], i32* [[V]], align 4
; IS__CGSCC____-NEXT: ret i32* [[V]]
;
%X = load i32, i32* %V
br i1 %C, label %T, label %F
@ -47,25 +63,43 @@ define internal { i32, i32 } @foo(i32 %A, i32 %B) {
}
define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 {
; CHECK-LABEL: define {{[^@]+}}@caller
; CHECK-SAME: (i1 [[C:%.*]]) #2 personality i32 (...)* @__gxx_personality_v0
; CHECK-NEXT: [[Q:%.*]] = alloca i32
; CHECK-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) [[Q]])
; CHECK-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2)
; CHECK-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
; CHECK-NEXT: [[S2:%.*]] = invoke { i32, i32 } @foo(i32 3, i32 4)
; CHECK-NEXT: to label [[OK:%.*]] unwind label [[LPAD:%.*]]
; CHECK: OK:
; CHECK-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
; CHECK-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]]
; CHECK-NEXT: store i32 [[Z]], i32* [[W]], align 4
; CHECK-NEXT: br label [[RET:%.*]]
; CHECK: LPAD:
; CHECK-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: br label [[RET]]
; CHECK: RET:
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller
; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #2 personality i32 (...)* @__gxx_personality_v0
; IS__TUNIT____-NEXT: [[Q:%.*]] = alloca i32
; IS__TUNIT____-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]])
; IS__TUNIT____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2)
; IS__TUNIT____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
; IS__TUNIT____-NEXT: [[S2:%.*]] = invoke { i32, i32 } @foo(i32 3, i32 4)
; IS__TUNIT____-NEXT: to label [[OK:%.*]] unwind label [[LPAD:%.*]]
; IS__TUNIT____: OK:
; IS__TUNIT____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
; IS__TUNIT____-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]]
; IS__TUNIT____-NEXT: store i32 [[Z]], i32* [[W]], align 4
; IS__TUNIT____-NEXT: br label [[RET:%.*]]
; IS__TUNIT____: LPAD:
; IS__TUNIT____-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 }
; IS__TUNIT____-NEXT: cleanup
; IS__TUNIT____-NEXT: br label [[RET]]
; IS__TUNIT____: RET:
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller
; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #1 personality i32 (...)* @__gxx_personality_v0
; IS__CGSCC____-NEXT: [[Q:%.*]] = alloca i32
; IS__CGSCC____-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree nonnull align 4 dereferenceable(4) [[Q]])
; IS__CGSCC____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 1, i32 2)
; IS__CGSCC____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
; IS__CGSCC____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 3, i32 4)
; IS__CGSCC____-NEXT: br label [[OK:%.*]]
; IS__CGSCC____: OK:
; IS__CGSCC____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
; IS__CGSCC____-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]]
; IS__CGSCC____-NEXT: store i32 [[Z]], i32* [[W]], align 4
; IS__CGSCC____-NEXT: br label [[RET:%.*]]
; IS__CGSCC____: LPAD:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: RET:
; IS__CGSCC____-NEXT: ret void
;
%Q = alloca i32
;; Call incdec to see if %W is properly replaced by %Q

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; FIXME: icmp folding is missing
@ -24,13 +27,21 @@ FAIL:
}
define internal i32 @foo(i1 %C) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: ret i32 undef
; CHECK: F:
; CHECK-NEXT: ret i32 undef
; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
; IS__TUNIT____-SAME: (i1 [[C:%.*]])
; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__TUNIT____: T:
; IS__TUNIT____-NEXT: ret i32 undef
; IS__TUNIT____: F:
; IS__TUNIT____-NEXT: ret i32 undef
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
; IS__CGSCC____-SAME: (i1 [[C:%.*]])
; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; IS__CGSCC____: T:
; IS__CGSCC____-NEXT: ret i32 52
; IS__CGSCC____: F:
; IS__CGSCC____-NEXT: ret i32 52
;
br i1 %C, label %T, label %F

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=7 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;; FIXME: support for extractvalue and insertvalue missing.

View File

@ -1,7 +1,21 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define internal i32 @testf(i1 %c) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@testf
; IS__CGSCC____-SAME: (i1 [[C:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: br i1 [[C]], label [[IF_COND:%.*]], label [[IF_END:%.*]]
; IS__CGSCC____: if.cond:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: ret i32 10
;
entry:
br i1 %c, label %if.cond, label %if.end
@ -16,6 +30,17 @@ if.end: ; preds = %if.then1, %entry
}
define internal i32 @test1(i1 %c) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@test1
; IS__CGSCC____-SAME: (i1 [[C:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: br label [[IF_THEN:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: br label [[RET1:%.*]]
; IS__CGSCC____: ret1:
; IS__CGSCC____-NEXT: ret i32 99
; IS__CGSCC____: ret2:
; IS__CGSCC____-NEXT: unreachable
;
entry:
br label %if.then

View File

@ -1,5 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; #include <threads.h>
; thread_local int gtl = 0;
@ -37,10 +40,15 @@ entry:
}
define dso_local void @caller() {
; CHECK-LABEL: define {{[^@]+}}@caller()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @broker(i32* nofree nonnull readonly align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nofree nonnull readonly align 4 dereferenceable(4) undef)
; CHECK-NEXT: ret void
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller()
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: call void @broker(i32* nofree nonnull readonly align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nofree nonnull readonly align 4 dereferenceable(4) undef)
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: call void @broker(i32* nofree nonnull readonly align 4 dereferenceable(4) @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nofree nonnull readonly align 4 dereferenceable(4) @gsh)
; IS__CGSCC____-NEXT: ret void
;
entry:
call void @broker(i32* nonnull @gtl, i32 (i32*, i32*)* nonnull @callee, i32* nonnull @gsh)

View File

@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --disable --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
; RUN: opt -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@ -11,27 +11,41 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; TEST 1
; ATTRIBUTOR: define align 8 i32* @test1(i32* nofree readnone returned align 8 "no-capture-maybe-returned" %0)
define i32* @test1(i32* align 8 %0) #0 {
; CHECK-LABEL: define {{[^@]+}}@test1
; CHECK-SAME: (i32* nofree readnone returned align 8 "no-capture-maybe-returned" [[TMP0:%.*]])
; CHECK-NEXT: ret i32* [[TMP0]]
;
ret i32* %0
}
; TEST 2
; ATTRIBUTOR: define i32* @test2(i32* nofree readnone returned "no-capture-maybe-returned" %0)
define i32* @test2(i32* %0) #0 {
; CHECK-LABEL: define {{[^@]+}}@test2
; CHECK-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[TMP0:%.*]])
; CHECK-NEXT: ret i32* [[TMP0]]
;
ret i32* %0
}
; TEST 3
; ATTRIBUTOR: define align 4 i32* @test3(i32* nofree readnone align 8 "no-capture-maybe-returned" %0, i32* nofree readnone align 4 "no-capture-maybe-returned" %1, i1 %2)
define i32* @test3(i32* align 8 %0, i32* align 4 %1, i1 %2) #0 {
; CHECK-LABEL: define {{[^@]+}}@test3
; CHECK-SAME: (i32* nofree readnone align 8 "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree readnone align 4 "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]])
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP1]]
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = select i1 %2, i32* %0, i32* %1
ret i32* %ret
}
; TEST 4
; ATTRIBUTOR: define align 32 i32* @test4(i32* nofree readnone align 32 "no-capture-maybe-returned" %0, i32* nofree readnone align 32 "no-capture-maybe-returned" %1, i1 %2)
define i32* @test4(i32* align 32 %0, i32* align 32 %1, i1 %2) #0 {
; CHECK-LABEL: define {{[^@]+}}@test4
; CHECK-SAME: (i32* nofree readnone align 32 "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree readnone align 32 "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]])
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP1]]
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = select i1 %2, i32* %0, i32* %1
ret i32* %ret
}
@ -41,28 +55,38 @@ declare i32* @unknown()
declare align 8 i32* @align8()
; ATTRIBUTOR: define align 8 i32* @test5_1()
define i32* @test5_1() {
; CHECK-LABEL: define {{[^@]+}}@test5_1()
; CHECK-NEXT: [[RET:%.*]] = tail call align 8 i32* @unknown()
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = tail call align 8 i32* @unknown()
ret i32* %ret
}
; ATTRIBUTOR: define align 8 i32* @test5_2()
define i32* @test5_2() {
; CHECK-LABEL: define {{[^@]+}}@test5_2()
; CHECK-NEXT: [[RET:%.*]] = tail call align 8 i32* @align8()
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = tail call i32* @align8()
ret i32* %ret
}
; TEST 6
; SCC
; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_1()
define i32* @test6_1() #0 {
; CHECK-LABEL: define {{[^@]+}}@test6_1()
; CHECK-NEXT: unreachable
;
%ret = tail call i32* @test6_2()
ret i32* %ret
}
; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @test6_2()
define i32* @test6_2() #0 {
; CHECK-LABEL: define {{[^@]+}}@test6_2()
; CHECK-NEXT: unreachable
;
%ret = tail call i32* @test6_1()
ret i32* %ret
}
@ -87,6 +111,28 @@ define i32* @test6_2() #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@f1
; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; IS__TUNIT____-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; IS__TUNIT____-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; IS__TUNIT____: 3:
; IS__TUNIT____-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2()
; IS__TUNIT____-NEXT: br label [[TMP5]]
; IS__TUNIT____: 5:
; IS__TUNIT____-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; IS__TUNIT____-NEXT: ret i8* [[TMP6]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@f1
; IS__CGSCC____-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; IS__CGSCC____-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; IS__CGSCC____: 3:
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2()
; IS__CGSCC____-NEXT: br label [[TMP5]]
; IS__CGSCC____: 5:
; IS__CGSCC____-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; IS__CGSCC____-NEXT: ret i8* [[TMP6]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@ -102,6 +148,19 @@ define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@f2() local_unnamed_addr
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* @a1, null
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
; CHECK: 2:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; CHECK-NEXT: br label [[TMP6:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = tail call i8* @f3()
; CHECK-NEXT: br label [[TMP6]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
; CHECK-NEXT: ret i8* [[TMP7]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3
@ -121,6 +180,16 @@ define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@f3() local_unnamed_addr
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* @a2, null
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
; CHECK: 2:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; CHECK-NEXT: br label [[TMP4]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ @a1, [[TMP0:%.*]] ]
; CHECK-NEXT: ret i8* [[TMP5]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@ -133,18 +202,16 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
ret i8* %6
}
; UTC_ARGS: --enable
; TEST 7
; Better than IR information
define align 4 i8* @test7() #0 {
; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@test7()
; ATTRIBUTOR_MODULE-NEXT: [[C:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_MODULE-NEXT: ret i8* [[C]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@test7()
; IS__TUNIT____-NEXT: [[C:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; IS__TUNIT____-NEXT: ret i8* [[C]]
;
; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@test7()
; ATTRIBUTOR_CGSCC-NEXT: [[C:%.*]] = tail call nonnull align 8 dereferenceable(1) i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR_CGSCC-NEXT: ret i8* [[C]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@test7()
; IS__CGSCC____-NEXT: [[C:%.*]] = tail call nonnull align 8 dereferenceable(1) i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; IS__CGSCC____-NEXT: ret i8* [[C]]
;
%c = tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
ret i8* %c
@ -153,31 +220,31 @@ define align 4 i8* @test7() #0 {
; TEST 7b
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@f1b
; ATTRIBUTOR_MODULE-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR_MODULE-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; ATTRIBUTOR_MODULE-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR_MODULE: 3:
; ATTRIBUTOR_MODULE-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; ATTRIBUTOR_MODULE-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; ATTRIBUTOR_MODULE-NEXT: store i8 [[L]], i8* @a1, align 8
; ATTRIBUTOR_MODULE-NEXT: br label [[TMP5]]
; ATTRIBUTOR_MODULE: 5:
; ATTRIBUTOR_MODULE-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; ATTRIBUTOR_MODULE-NEXT: ret i8* [[TMP6]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@f1b
; IS__TUNIT____-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; IS__TUNIT____-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; IS__TUNIT____-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; IS__TUNIT____: 3:
; IS__TUNIT____-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; IS__TUNIT____-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__TUNIT____-NEXT: store i8 [[L]], i8* @a1, align 8
; IS__TUNIT____-NEXT: br label [[TMP5]]
; IS__TUNIT____: 5:
; IS__TUNIT____-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; IS__TUNIT____-NEXT: ret i8* [[TMP6]]
;
; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@f1b
; ATTRIBUTOR_CGSCC-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; ATTRIBUTOR_CGSCC-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; ATTRIBUTOR_CGSCC-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; ATTRIBUTOR_CGSCC: 3:
; ATTRIBUTOR_CGSCC-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; ATTRIBUTOR_CGSCC-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; ATTRIBUTOR_CGSCC-NEXT: store i8 [[L]], i8* @a1, align 8
; ATTRIBUTOR_CGSCC-NEXT: br label [[TMP5]]
; ATTRIBUTOR_CGSCC: 5:
; ATTRIBUTOR_CGSCC-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; ATTRIBUTOR_CGSCC-NEXT: ret i8* [[TMP6]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@f1b
; IS__CGSCC____-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; IS__CGSCC____-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; IS__CGSCC____: 3:
; IS__CGSCC____-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b()
; IS__CGSCC____-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8
; IS__CGSCC____-NEXT: store i8 [[L]], i8* @a1, align 8
; IS__CGSCC____-NEXT: br label [[TMP5]]
; IS__CGSCC____: 5:
; IS__CGSCC____-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; IS__CGSCC____-NEXT: ret i8* [[TMP6]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@ -196,18 +263,18 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b() local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq i8* @a1, null
; ATTRIBUTOR-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
; ATTRIBUTOR: 2:
; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; ATTRIBUTOR-NEXT: br label [[TMP6:%.*]]
; ATTRIBUTOR: 4:
; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i8* @f3b()
; ATTRIBUTOR-NEXT: br label [[TMP6]]
; ATTRIBUTOR: 6:
; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP7]]
; CHECK-LABEL: define {{[^@]+}}@f2b() local_unnamed_addr
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* @a1, null
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP4:%.*]], label [[TMP2:%.*]]
; CHECK: 2:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1)
; CHECK-NEXT: br label [[TMP6:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = tail call i8* @f3b()
; CHECK-NEXT: br label [[TMP6]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ [[TMP5]], [[TMP4]] ]
; CHECK-NEXT: ret i8* [[TMP7]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3
@ -229,15 +296,15 @@ define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b() local_unnamed_addr
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq i8* @a2, null
; ATTRIBUTOR-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
; ATTRIBUTOR: 2:
; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; ATTRIBUTOR-NEXT: br label [[TMP4]]
; ATTRIBUTOR: 4:
; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ @a1, [[TMP0:%.*]] ]
; ATTRIBUTOR-NEXT: ret i8* [[TMP5]]
; CHECK-LABEL: define {{[^@]+}}@f3b() local_unnamed_addr
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* @a2, null
; CHECK-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
; CHECK: 2:
; CHECK-NEXT: [[TMP3:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2)
; CHECK-NEXT: br label [[TMP4]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = phi i8* [ [[TMP3]], [[TMP2]] ], [ @a1, [[TMP0:%.*]] ]
; CHECK-NEXT: ret i8* [[TMP5]]
;
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@ -252,36 +319,52 @@ define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 {
}
define align 4 i32* @test7b(i32* align 32 %p) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b
; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; ATTRIBUTOR-NEXT: ret i32* [[P]]
; CHECK-LABEL: define {{[^@]+}}@test7b
; CHECK-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
; CHECK-NEXT: ret i32* [[P]]
;
tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1)
ret i32* %p
}
; UTC_ARGS: --disable
; TEST 8
define void @test8_helper() {
; CHECK-LABEL: define {{[^@]+}}@test8_helper()
; CHECK-NEXT: [[PTR0:%.*]] = tail call i32* @unknown()
; CHECK-NEXT: [[PTR1:%.*]] = tail call align 4 i32* @unknown()
; CHECK-NEXT: [[PTR2:%.*]] = tail call align 8 i32* @unknown()
; CHECK-NEXT: tail call void @test8(i32* noalias readnone align 4 [[PTR1]], i32* noalias readnone align 4 [[PTR1]], i32* noalias readnone [[PTR0]])
; CHECK-NEXT: tail call void @test8(i32* noalias readnone align 8 [[PTR2]], i32* noalias readnone align 4 [[PTR1]], i32* noalias readnone align 4 [[PTR1]])
; CHECK-NEXT: tail call void @test8(i32* noalias readnone align 8 [[PTR2]], i32* noalias readnone align 4 [[PTR1]], i32* noalias readnone align 4 [[PTR1]])
; CHECK-NEXT: ret void
;
%ptr0 = tail call i32* @unknown()
%ptr1 = tail call align 4 i32* @unknown()
%ptr2 = tail call align 8 i32* @unknown()
tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1, i32* noalias readnone %ptr0)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1)
; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1)
ret void
}
declare void @user_i32_ptr(i32* nocapture readnone) nounwind
define internal void @test8(i32* %a, i32* %b, i32* %c) {
; ATTRIBUTOR_MODULE: define internal void @test8(i32* noalias nocapture readnone align 4 %a, i32* noalias nocapture readnone align 4 %b, i32* noalias nocapture readnone %c)
; ATTRIBUTOR_CGSCC: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c)
; IS__TUNIT____-LABEL: define {{[^@]+}}@test8
; IS__TUNIT____-SAME: (i32* noalias nocapture readnone align 4 [[A:%.*]], i32* noalias nocapture readnone align 4 [[B:%.*]], i32* noalias nocapture readnone [[C:%.*]])
; IS__TUNIT____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone align 4 [[A]])
; IS__TUNIT____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone align 4 [[B]])
; IS__TUNIT____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone [[C]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test8
; IS__CGSCC____-SAME: (i32* nocapture readnone align 4 [[A:%.*]], i32* nocapture readnone align 4 [[B:%.*]], i32* nocapture readnone [[C:%.*]])
; IS__CGSCC____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone align 4 [[A]])
; IS__CGSCC____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone align 4 [[B]])
; IS__CGSCC____-NEXT: call void @user_i32_ptr(i32* noalias nocapture readnone [[C]])
; IS__CGSCC____-NEXT: ret void
;
call void @user_i32_ptr(i32* %a)
call void @user_i32_ptr(i32* %b)
call void @user_i32_ptr(i32* %c)
@ -289,33 +372,53 @@ define internal void @test8(i32* %a, i32* %b, i32* %c) {
}
declare void @test9_helper(i32* %A)
define void @test9_traversal(i1 %c, i32* align 4 %B, i32* align 8 %C) {
%sel = select i1 %c, i32* %B, i32* %C
define void @test9_traversal(i1 %cnd, i32* align 4 %B, i32* align 8 %C) {
; CHECK-LABEL: define {{[^@]+}}@test9_traversal
; CHECK-SAME: (i1 [[CND:%.*]], i32* align 4 [[B:%.*]], i32* align 8 [[C:%.*]])
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CND]], i32* [[B]], i32* [[C]]
; CHECK-NEXT: call void @test9_helper(i32* align 4 [[SEL]])
; CHECK-NEXT: ret void
;
%sel = select i1 %cnd, i32* %B, i32* %C
call void @test9_helper(i32* %sel)
ret void
}
; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10a(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10a(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
define i32* @test10a(i32* align 32 %p) {
; ATTRIBUTOR: %l = load i32, i32* %p, align 32
; CHECK-LABEL: define {{[^@]+}}@test10a
; CHECK-SAME: (i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[P]], align 32
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[L]], 0
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: [[R:%.*]] = call i32* @test10a(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" [[P]])
; CHECK-NEXT: store i32 1, i32* [[R]]
; CHECK-NEXT: [[G0:%.*]] = getelementptr i32, i32* [[P]], i32 8
; CHECK-NEXT: br label [[E:%.*]]
; CHECK: f:
; CHECK-NEXT: [[G1:%.*]] = getelementptr i32, i32* [[P]], i32 8
; CHECK-NEXT: store i32 -1, i32* [[G1]], align 4
; CHECK-NEXT: br label [[E]]
; CHECK: e:
; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[G0]], [[T]] ], [ [[G1]], [[F]] ]
; CHECK-NEXT: ret i32* [[PHI]]
;
%l = load i32, i32* %p
%c = icmp eq i32 %l, 0
br i1 %c, label %t, label %f
t:
%r = call i32* @test10a(i32* %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; ATTRIBUTOR: store i32 1, i32* %r
store i32 1, i32* %r
%g0 = getelementptr i32, i32* %p, i32 8
br label %e
f:
%g1 = getelementptr i32, i32* %p, i32 8
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
; ATTRIBUTOR: store i32 -1, i32* %g1
store i32 -1, i32* %g1
br label %e
e:
@ -325,25 +428,39 @@ e:
; FIXME: This will work with an upcoming patch (D66618 or similar)
; define align 32 i32* @test10b(i32* align 32 "no-capture-maybe-returned" %p)
; ATTRIBUTOR: define i32* @test10b(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
define i32* @test10b(i32* align 32 %p) {
; ATTRIBUTOR: %l = load i32, i32* %p, align 32
; CHECK-LABEL: define {{[^@]+}}@test10b
; CHECK-SAME: (i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[P]], align 32
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[L]], 0
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: [[R:%.*]] = call i32* @test10b(i32* nofree nonnull align 32 dereferenceable(4) "no-capture-maybe-returned" [[P]])
; CHECK-NEXT: store i32 1, i32* [[R]]
; CHECK-NEXT: [[G0:%.*]] = getelementptr i32, i32* [[P]], i32 8
; CHECK-NEXT: br label [[E:%.*]]
; CHECK: f:
; CHECK-NEXT: [[G1:%.*]] = getelementptr i32, i32* [[P]], i32 -8
; CHECK-NEXT: store i32 -1, i32* [[G1]], align 4
; CHECK-NEXT: br label [[E]]
; CHECK: e:
; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[G0]], [[T]] ], [ [[G1]], [[F]] ]
; CHECK-NEXT: ret i32* [[PHI]]
;
%l = load i32, i32* %p
%c = icmp eq i32 %l, 0
br i1 %c, label %t, label %f
t:
%r = call i32* @test10b(i32* %p)
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 1, i32* %r, align 32
; ATTRIBUTOR: store i32 1, i32* %r
store i32 1, i32* %r
%g0 = getelementptr i32, i32* %p, i32 8
br label %e
f:
%g1 = getelementptr i32, i32* %p, i32 -8
; FIXME: This will work with an upcoming patch (D66618 or similar)
; store i32 -1, i32* %g1, align 32
; ATTRIBUTOR: store i32 -1, i32* %g1
store i32 -1, i32* %g1
br label %e
e:
@ -352,8 +469,13 @@ e:
}
; ATTRIBUTOR: define i64 @test11(i32* nocapture nofree nonnull readonly align 8 dereferenceable(8) %p)
define i64 @test11(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@test11
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[RET:%.*]] = load i64, i64* [[P_CAST]], align 8
; CHECK-NEXT: ret i64 [[RET]]
;
%p-cast = bitcast i32* %p to i64*
%ret = load i64, i64* %p-cast, align 8
ret i64 %ret
@ -363,8 +485,15 @@ define i64 @test11(i32* %p) {
; Test for deduction using must-be-executed-context and GEP instruction
; FXIME: %p should have nonnull
; ATTRIBUTOR: define i64 @test12-1(i32* nocapture nofree readonly align 16 %p)
define i64 @test12-1(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-1
; CHECK-SAME: (i32* nocapture nofree readonly align 16 [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 1
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr i64, i64* [[ARRAYIDX0]], i64 3
; CHECK-NEXT: [[RET:%.*]] = load i64, i64* [[ARRAYIDX1]], align 16
; CHECK-NEXT: ret i64 [[RET]]
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
@ -372,8 +501,14 @@ define i64 @test12-1(i32* align 4 %p) {
ret i64 %ret
}
; ATTRIBUTOR: define i64 @test12-2(i32* nocapture nofree nonnull readonly align 16 dereferenceable(8) %p)
define i64 @test12-2(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-2
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 16 dereferenceable(8) [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 0
; CHECK-NEXT: [[RET:%.*]] = load i64, i64* [[ARRAYIDX0]], align 16
; CHECK-NEXT: ret i64 [[RET]]
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
%ret = load i64, i64* %arrayidx0, align 16
@ -381,8 +516,15 @@ define i64 @test12-2(i32* align 4 %p) {
}
; FXIME: %p should have nonnull
; ATTRIBUTOR: define void @test12-3(i32* nocapture nofree writeonly align 16 %p)
define void @test12-3(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-3
; CHECK-SAME: (i32* nocapture nofree writeonly align 16 [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 1
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr i64, i64* [[ARRAYIDX0]], i64 3
; CHECK-NEXT: store i64 0, i64* [[ARRAYIDX1]], align 16
; CHECK-NEXT: ret void
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
@ -390,8 +532,14 @@ define void @test12-3(i32* align 4 %p) {
ret void
}
; ATTRIBUTOR: define void @test12-4(i32* nocapture nofree nonnull writeonly align 16 dereferenceable(8) %p)
define void @test12-4(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-4
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 16 dereferenceable(8) [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 0
; CHECK-NEXT: store i64 0, i64* [[ARRAYIDX0]], align 16
; CHECK-NEXT: ret void
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
store i64 0, i64* %arrayidx0, align 16
@ -400,8 +548,15 @@ define void @test12-4(i32* align 4 %p) {
declare void @use(i64*) willreturn nounwind
; ATTRIBUTOR: define void @test12-5(i32* align 16 %p)
define void @test12-5(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-5
; CHECK-SAME: (i32* align 16 [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 1
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr i64, i64* [[ARRAYIDX0]], i64 3
; CHECK-NEXT: tail call void @use(i64* align 16 [[ARRAYIDX1]])
; CHECK-NEXT: ret void
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 1
%arrayidx1 = getelementptr i64, i64* %arrayidx0, i64 3
@ -409,8 +564,14 @@ define void @test12-5(i32* align 4 %p) {
ret void
}
; ATTRIBUTOR: define void @test12-6(i32* align 16 %p)
define void @test12-6(i32* align 4 %p) {
; CHECK-LABEL: define {{[^@]+}}@test12-6
; CHECK-SAME: (i32* align 16 [[P:%.*]])
; CHECK-NEXT: [[P_CAST:%.*]] = bitcast i32* [[P]] to i64*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i64, i64* [[P_CAST]], i64 0
; CHECK-NEXT: tail call void @use(i64* align 16 [[ARRAYIDX0]])
; CHECK-NEXT: ret void
;
%p-cast = bitcast i32* %p to i64*
%arrayidx0 = getelementptr i64, i64* %p-cast, i64 0
tail call void @use(i64* align 16 %arrayidx0)
@ -418,17 +579,17 @@ define void @test12-6(i32* align 4 %p) {
}
define void @test13(i1 %c, i32* align 32 %dst) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test13
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; ATTRIBUTOR-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ null, [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@test13
; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; CHECK: truebb:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: falsebb:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ null, [[FALSEBB]] ]
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 32
; CHECK-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
@ -442,16 +603,17 @@ end:
}
define void @test13-1(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-1(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 48 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 16
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@test13-1
; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; CHECK: truebb:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: falsebb:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ inttoptr (i64 48 to i32*), [[FALSEBB]] ]
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 16
; CHECK-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
@ -465,16 +627,17 @@ end:
}
define void @test13-2(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-2(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 160 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@test13-2
; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; CHECK: truebb:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: falsebb:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ inttoptr (i64 160 to i32*), [[FALSEBB]] ]
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 32
; CHECK-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
@ -488,16 +651,17 @@ end:
}
define void @test13-3(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-3(
; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR: truebb:
; ATTRIBUTOR-NEXT: br label [[END:%.*]]
; ATTRIBUTOR: falsebb:
; ATTRIBUTOR-NEXT: br label [[END]]
; ATTRIBUTOR: end:
; ATTRIBUTOR-NEXT: [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 128 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT: store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@test13-3
; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; CHECK: truebb:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: falsebb:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ inttoptr (i64 128 to i32*), [[FALSEBB]] ]
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 32
; CHECK-NEXT: ret void
;
br i1 %c, label %truebb, label %falsebb
truebb:
@ -512,29 +676,42 @@ end:
; Don't crash on ptr2int/int2ptr uses.
define i64 @ptr2int(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@ptr2int
; CHECK-SAME: (i32* nofree readnone [[P:%.*]])
; CHECK-NEXT: [[P2I:%.*]] = ptrtoint i32* [[P]] to i64
; CHECK-NEXT: ret i64 [[P2I]]
;
%p2i = ptrtoint i32* %p to i64
ret i64 %p2i
}
define i64* @int2ptr(i64 %i) {
; CHECK-LABEL: define {{[^@]+}}@int2ptr
; CHECK-SAME: (i64 [[I:%.*]])
; CHECK-NEXT: [[I2P:%.*]] = inttoptr i64 [[I]] to i64*
; CHECK-NEXT: ret i64* [[I2P]]
;
%i2p = inttoptr i64 %i to i64*
ret i64* %i2p
}
; Use the store alignment only for the pointer operand.
define void @aligned_store(i8* %Value, i8** %Ptr) {
; ATTRIBUTOR: define void @aligned_store(i8* nofree writeonly %Value, i8** nocapture nofree nonnull writeonly align 32 dereferenceable(8) %Ptr)
; CHECK-LABEL: define {{[^@]+}}@aligned_store
; CHECK-SAME: (i8* nofree writeonly [[VALUE:%.*]], i8** nocapture nofree nonnull writeonly align 32 dereferenceable(8) [[PTR:%.*]])
; CHECK-NEXT: store i8* [[VALUE]], i8** [[PTR]], align 32
; CHECK-NEXT: ret void
;
store i8* %Value, i8** %Ptr, align 32
ret void
}
; UTC_ARGS: --enable
declare i8* @some_func(i8*)
define void @align_call_op_not_store(i8* align 2048 %arg) {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@align_call_op_not_store
; ATTRIBUTOR-SAME: (i8* align 2048 [[ARG:%.*]])
; ATTRIBUTOR-NEXT: [[UNKNOWN:%.*]] = call i8* @some_func(i8* align 2048 [[ARG]])
; ATTRIBUTOR-NEXT: store i8 0, i8* [[UNKNOWN]]
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@align_call_op_not_store
; CHECK-SAME: (i8* align 2048 [[ARG:%.*]])
; CHECK-NEXT: [[UNKNOWN:%.*]] = call i8* @some_func(i8* align 2048 [[ARG]])
; CHECK-NEXT: store i8 0, i8* [[UNKNOWN]]
; CHECK-NEXT: ret void
;
%unknown = call i8* @some_func(i8* %arg)
store i8 0, i8* %unknown
@ -542,11 +719,11 @@ define void @align_call_op_not_store(i8* align 2048 %arg) {
}
define void @align_store_after_bc(i32* align 2048 %arg) {
;
; ATTRIBUTOR-LABEL: define {{[^@]+}}@align_store_after_bc
; ATTRIBUTOR-SAME: (i32* nocapture nofree nonnull writeonly align 2048 dereferenceable(1) [[ARG:%.*]])
; ATTRIBUTOR-NEXT: [[BC:%.*]] = bitcast i32* [[ARG]] to i8*
; ATTRIBUTOR-NEXT: store i8 0, i8* [[BC]], align 2048
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@align_store_after_bc
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 2048 dereferenceable(1) [[ARG:%.*]])
; CHECK-NEXT: [[BC:%.*]] = bitcast i32* [[ARG]] to i8*
; CHECK-NEXT: store i8 0, i8* [[BC]], align 2048
; CHECK-NEXT: ret void
;
%bc = bitcast i32* %arg to i8*
store i8 0, i8* %bc
@ -557,10 +734,35 @@ define void @align_store_after_bc(i32* align 2048 %arg) {
; we cannot also put on the caller.
@cnd = external global i1
define i32 @musttail_callee_1(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@musttail_callee_1
; CHECK-SAME: (i32* nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]])
; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P]], align 32
; CHECK-NEXT: ret i32 [[V]]
;
%v = load i32, i32* %p, align 32
ret i32 %v
}
define i32 @musttail_caller_1(i32* %p) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@musttail_caller_1
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly [[P:%.*]])
; IS__TUNIT____-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
; IS__TUNIT____-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
; IS__TUNIT____: mt:
; IS__TUNIT____-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree readonly [[P]])
; IS__TUNIT____-NEXT: ret i32 [[V]]
; IS__TUNIT____: exit:
; IS__TUNIT____-NEXT: ret i32 0
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@musttail_caller_1
; IS__CGSCC____-SAME: (i32* nocapture nofree readonly [[P:%.*]])
; IS__CGSCC____-NEXT: [[C:%.*]] = load i1, i1* @cnd, align 1
; IS__CGSCC____-NEXT: br i1 [[C]], label [[MT:%.*]], label [[EXIT:%.*]]
; IS__CGSCC____: mt:
; IS__CGSCC____-NEXT: [[V:%.*]] = musttail call i32 @musttail_callee_1(i32* nocapture nofree nonnull readonly dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: ret i32 [[V]]
; IS__CGSCC____: exit:
; IS__CGSCC____-NEXT: ret i32 0
;
%c = load i1, i1* @cnd
br i1 %c, label %mt, label %exit
mt:
@ -569,7 +771,6 @@ mt:
exit:
ret i32 0
}
; UTC_ARGS: --disable
attributes #0 = { nounwind uwtable noinline }
attributes #1 = { uwtable noinline }

View File

@ -1,14 +1,18 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -attributor -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefix=CHECK
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; When a function is marked `alwaysinline` and is able to be inlined,
; we can IPO its boundaries
; the function is not exactly defined, and marked alwaysinline and can be inlined,
; so the function can be analyzed
; CHECK: Function Attrs: alwaysinline nofree nosync nounwind readnone willreturn
; CHECK: Function Attrs: alwaysinline
; CHECK-SAME: willreturn
define linkonce void @inner1() alwaysinline {
; CHECK-LABEL: @inner1(
; CHECK-LABEL: define {{[^@]+}}@inner1()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
@ -16,9 +20,10 @@ entry:
ret void
}
; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK: Function Attrs:
; CHECK-SAME: willreturn
define void @outer1() {
; CHECK-LABEL: @outer1(
; CHECK-LABEL: define {{[^@]+}}@outer1()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
;
@ -31,7 +36,7 @@ entry:
; so it will not be analyzed
; CHECK-NOT: Function Attrs:
define linkonce i32 @inner2() {
; CHECK-LABEL: @inner2(
; CHECK-LABEL: define {{[^@]+}}@inner2()
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 1
;
@ -41,9 +46,9 @@ entry:
; CHECK-NOT: Function Attrs
define i32 @outer2() {
; CHECK-LABEL: @outer2(
; CHECK-LABEL: define {{[^@]+}}@outer2()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[R:%.*]] = call i32 @inner2() #2
; CHECK-NEXT: [[R:%.*]] = call i32 @inner2()
; CHECK-NEXT: ret i32 [[R]]
;
entry:
@ -55,11 +60,15 @@ entry:
; it is `unexactly defined` and alwaysinline but cannot be inlined.
; so it will not be analyzed
; CHECK: Function Attrs:
; CHECK-NOT: nofree nosync nounwind readnone
; CHECK-NOT: nofree
; CHECK-NOT: nosync
; CHECK-NOT: nounwind
; CHECK-NOT: readnone
define linkonce i32 @inner3(i8* %addr) alwaysinline {
; CHECK-LABEL: @inner3(
; CHECK-LABEL: define {{[^@]+}}@inner3
; CHECK-SAME: (i8* [[ADDR:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: indirectbr i8* [[ADDR:%.*]], [label [[ONE:%.*]], label %two]
; CHECK-NEXT: indirectbr i8* [[ADDR]], [label [[ONE:%.*]], label %two]
; CHECK: one:
; CHECK-NEXT: ret i32 42
; CHECK: two:
@ -77,8 +86,9 @@ two:
; CHECK-NOT: Function Attrs:
define i32 @outer3(i32 %x) {
; CHECK-LABEL: @outer3(
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 42
; CHECK-LABEL: define {{[^@]+}}@outer3
; CHECK-SAME: (i32 [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 42
; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[CMP]], i8* blockaddress(@inner3, [[ONE:%.*]]), i8* blockaddress(@inner3, [[TWO:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = call i32 @inner3(i8* [[ADDR]])
; CHECK-NEXT: ret i32 [[CALL]]

View File

@ -1,8 +1,9 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; FIXME: Add -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations below.
; This flag was removed because max iterations is 2 in most cases, but in windows it is 1.
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s
; ModuleID = 'callback_simple.c'
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
; Test 0
@ -15,19 +16,54 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
; transfer in both directions.
define void @t0_caller(i32* %a) {
; CHECK-LABEL: define {{[^@]+}}@t0_caller
; CHECK-SAME: (i32* align 256 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32
; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64
; CHECK-NEXT: [[PTR:%.*]] = alloca i32, align 128
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT: store i32 42, i32* [[B]], align 32
; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64
; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t0_caller
; IS__TUNIT_OPM-SAME: (i32* align 256 [[A:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t0_caller
; IS__TUNIT_NPM-SAME: (i32* align 256 [[A:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t0_caller
; IS__CGSCC_OPM-SAME: (i32* [[A:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]])
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t0_caller
; IS__CGSCC_NPM-SAME: (i32* align 256 [[A:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%b = alloca i32, align 32
%c = alloca i32*, align 64
@ -42,14 +78,33 @@ entry:
; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
define internal void @t0_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) {
; CHECK-LABEL: define {{[^@]+}}@t0_callback_callee
; CHECK-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; CHECK-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]])
; CHECK-NEXT: ret void
;
; IS________OPM-LABEL: define {{[^@]+}}@t0_callback_callee
; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS________OPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]])
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t0_callback_callee
; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t0_callback_callee
; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8
; IS__CGSCC_NPM-NEXT: tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%ptr_val = load i32, i32* %ptr, align 8
@ -69,17 +124,53 @@ declare !callback !0 void @t0_callback_broker(i32*, i32*, void (i32*, i32*, ...)
; we deduce and propagate noalias and others properly.
define void @t1_caller(i32* noalias %a) {
; CHECK-LABEL: define {{[^@]+}}@t1_caller
; CHECK-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32
; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64
; CHECK-NEXT: [[PTR:%.*]] = alloca i32, align 128
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT: store i32 42, i32* [[B]], align 32
; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64
; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t1_caller
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t1_caller
; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t1_caller
; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]])
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t1_caller
; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t1_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t1_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%b = alloca i32, align 32
@ -95,14 +186,33 @@ entry:
; Note that the first two arguments are provided by the callback_broker according to the callback in !1 below!
; The others are annotated with alignment information, amongst others, or even replaced by the constants passed to the call.
define internal void @t1_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) {
; CHECK-LABEL: define {{[^@]+}}@t1_callback_callee
; CHECK-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* noalias nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; CHECK-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; CHECK-NEXT: ret void
;
; IS________OPM-LABEL: define {{[^@]+}}@t1_callback_callee
; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS________OPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t1_callback_callee
; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* noalias nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t1_callback_callee
; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8
; IS__CGSCC_NPM-NEXT: tail call void @t1_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%ptr_val = load i32, i32* %ptr, align 8
@ -121,17 +231,53 @@ declare !callback !0 void @t1_callback_broker(i32* nocapture , i32* nocapture ,
; Similar to test 1 but checking that the noalias is only placed if potential synchronization through @t2_check is preserved.
define void @t2_caller(i32* noalias %a) {
; CHECK-LABEL: define {{[^@]+}}@t2_caller
; CHECK-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32
; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64
; CHECK-NEXT: [[PTR:%.*]] = alloca i32, align 128
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT: store i32 42, i32* [[B]], align 32
; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64
; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t2_caller
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t2_caller
; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t2_caller
; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]])
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t2_caller
; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t2_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t2_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%b = alloca i32, align 32
@ -149,14 +295,33 @@ entry:
;
; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
define internal void @t2_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) {
; CHECK-LABEL: define {{[^@]+}}@t2_callback_callee
; CHECK-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; CHECK-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; CHECK-NEXT: ret void
;
; IS________OPM-LABEL: define {{[^@]+}}@t2_callback_callee
; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS________OPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t2_callback_callee
; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t2_callback_callee
; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8
; IS__CGSCC_NPM-NEXT: tail call void @t2_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%ptr_val = load i32, i32* %ptr, align 8
@ -175,18 +340,57 @@ declare !callback !0 void @t2_callback_broker(i32* nocapture , i32* nocapture ,
; Basically test 2 with the casted callback callee used twice.
define void @t3_caller(i32* noalias %a) {
; CHECK-LABEL: define {{[^@]+}}@t3_caller
; CHECK-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 32
; CHECK-NEXT: [[C:%.*]] = alloca i32*, align 64
; CHECK-NEXT: [[PTR:%.*]] = alloca i32, align 128
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT: store i32 42, i32* [[B]], align 32
; CHECK-NEXT: store i32* [[B]], i32** [[C]], align 64
; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT: ret void
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@t3_caller
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* nocapture align 256 [[A]], i64 undef, i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t3_caller
; IS__TUNIT_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__TUNIT_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__TUNIT_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__TUNIT_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__TUNIT_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 undef, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@t3_caller
; IS__CGSCC_OPM-SAME: (i32* noalias [[A:%.*]])
; IS__CGSCC_OPM-NEXT: entry:
; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_OPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_OPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_OPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_OPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]])
; IS__CGSCC_OPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* [[A]], i64 99, i32** nonnull align 64 dereferenceable(8) [[C]])
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t3_caller
; IS__CGSCC_NPM-SAME: (i32* noalias nocapture align 256 [[A:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 32
; IS__CGSCC_NPM-NEXT: [[C:%.*]] = alloca i32*, align 64
; IS__CGSCC_NPM-NEXT: [[PTR:%.*]] = alloca i32, align 128
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; IS__CGSCC_NPM-NEXT: store i32 42, i32* [[B]], align 32
; IS__CGSCC_NPM-NEXT: store i32* [[B]], i32** [[C]], align 64
; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__CGSCC_NPM-NEXT: call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t3_callback_broker(i32* noalias align 536870912 null, i32* noalias nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*, i64, i32**)* @t3_callback_callee to void (i32*, i32*, ...)*), i32* noalias nocapture align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%b = alloca i32, align 32
@ -205,14 +409,33 @@ entry:
;
; FIXME: We should derive noalias for %a and add a "fake use" of %a in all potentially synchronizing calls.
define internal void @t3_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a, i64 %b, i32** %c) {
; CHECK-LABEL: define {{[^@]+}}@t3_callback_callee
; CHECK-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; CHECK-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; CHECK-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; CHECK-NEXT: ret void
;
; IS________OPM-LABEL: define {{[^@]+}}@t3_callback_callee
; IS________OPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS________OPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS________OPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS________OPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS________OPM-NEXT: ret void
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@t3_callback_callee
; IS__TUNIT_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__TUNIT_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; IS__TUNIT_NPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__TUNIT_NPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@t3_callback_callee
; IS__CGSCC_NPM-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* nocapture align 256 [[A:%.*]], i64 [[B:%.*]], i32** nocapture nonnull readonly align 8 dereferenceable(8) [[C:%.*]])
; IS__CGSCC_NPM-NEXT: entry:
; IS__CGSCC_NPM-NEXT: [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; IS__CGSCC_NPM-NEXT: store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]], align 4
; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32*, i32** [[C]], align 8
; IS__CGSCC_NPM-NEXT: tail call void @t3_check(i32* nocapture align 256 [[A]], i64 99, i32* [[TMP0]])
; IS__CGSCC_NPM-NEXT: ret void
;
entry:
%ptr_val = load i32, i32* %ptr, align 8

View File

@ -1,16 +1,22 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; FIXME: Figure out why we need 16 iterations here.
; UTC_ARGS: --disable
declare void @deref_phi_user(i32* %a);
; TEST 1
; take mininimum of return values
;
define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test1(i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" %0, double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
; CHECK-LABEL: define {{[^@]+}}@test1
; CHECK-SAME: (i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
; CHECK-NEXT: ret i32* [[TMP5]]
;
%4 = bitcast double* %1 to i32*
%5 = select i1 %2, i32* %0, i32* %4
ret i32* %5
@ -18,7 +24,12 @@ define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1
; TEST 2
define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
; ATTRIBUTOR: define dereferenceable_or_null(4) i32* @test2(i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" %0, double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %1, i1 zeroext %2)
; CHECK-LABEL: define {{[^@]+}}@test2
; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
; CHECK-NEXT: ret i32* [[TMP5]]
;
%4 = bitcast double* %1 to i32*
%5 = select i1 %2, i32* %0, i32* %4
ret i32* %5
@ -27,19 +38,33 @@ define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8
; TEST 3
; GEP inbounds
define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0)
; CHECK-LABEL: define {{[^@]+}}@test3_1
; CHECK-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = getelementptr inbounds i32, i32* %0, i64 1
ret i32* %ret
}
define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" %0)
; CHECK-LABEL: define {{[^@]+}}@test3_2
; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 4
; CHECK-NEXT: ret i32* [[RET]]
;
%ret = getelementptr inbounds i32, i32* %0, i64 4
ret i32* %ret
}
define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" %0, i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" %1, i1 %2) local_unnamed_addr
; CHECK-LABEL: define {{[^@]+}}@test3_3
; CHECK-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[RET1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
; CHECK-NEXT: [[RET2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 2
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP2]], i32* [[RET1]], i32* [[RET2]]
; CHECK-NEXT: ret i32* [[RET]]
;
%ret1 = getelementptr inbounds i32, i32* %0, i64 1
%ret2 = getelementptr inbounds i32, i32* %1, i64 2
%ret = select i1 %2, i32* %ret1, i32* %ret2
@ -50,20 +75,44 @@ define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1
; Better than known in IR.
define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_addr {
; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @test4(i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" %0)
; CHECK-LABEL: define {{[^@]+}}@test4
; CHECK-SAME: (i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: ret i32* [[TMP0]]
;
ret i32* %0
}
; TEST 5
; loop in which dereferenceabily "grows"
define void @deref_phi_growing(i32* dereferenceable(4000) %a) {
; CHECK-LABEL: define {{[^@]+}}@deref_phi_growing
; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
; CHECK-NEXT: call void @deref_phi_user(i32* nonnull dereferenceable(4000) [[A_ADDR_0]])
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: br label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 -1
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull dereferenceable(4000) %a.addr.0)
call void @deref_phi_user(i32* %a.addr.0)
%tmp = load i32, i32* %a.addr.0, align 4
%cmp = icmp slt i32 %i.0, %tmp
@ -87,13 +136,34 @@ for.end: ; preds = %for.cond.cleanup
; TEST 6
; loop in which dereferenceabily "shrinks"
define void @deref_phi_shrinking(i32* dereferenceable(4000) %a) {
; CHECK-LABEL: define {{[^@]+}}@deref_phi_shrinking
; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
; CHECK-NEXT: call void @deref_phi_user(i32* nonnull [[A_ADDR_0]])
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: br label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 1
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
; ATTRIBUTOR: call void @deref_phi_user(i32* nonnull %a.addr.0)
call void @deref_phi_user(i32* %a.addr.0)
%tmp = load i32, i32* %a.addr.0, align 4
%cmp = icmp slt i32 %i.0, %tmp
@ -119,96 +189,108 @@ for.end: ; preds = %for.cond.cleanup
declare i32* @unkown_ptr() willreturn nounwind
declare i32 @unkown_f(i32*) willreturn nounwind
define i32* @f7_0(i32* %ptr) {
; ATTRIBUTOR: define nonnull dereferenceable(8) i32* @f7_0(i32* nonnull returned dereferenceable(8) %ptr)
; CHECK-LABEL: define {{[^@]+}}@f7_0
; CHECK-SAME: (i32* nonnull returned dereferenceable(8) [[PTR:%.*]])
; CHECK-NEXT: [[T:%.*]] = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) [[PTR]])
; CHECK-NEXT: ret i32* [[PTR]]
;
%T = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
ret i32* %ptr
}
; ATTRIBUTOR: define void @f7_1(i32* nonnull align 4 dereferenceable(4) %ptr, i1 %c)
define void @f7_1(i32* %ptr, i1 %c) {
; ATTRIBUTOR: %A = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) %ptr)
; CHECK-LABEL: define {{[^@]+}}@f7_1
; CHECK-SAME: (i32* nonnull align 4 dereferenceable(4) [[PTR:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]])
; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]])
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: ret void
; CHECK: if.false:
; CHECK-NEXT: ret void
;
%A = tail call i32 @unkown_f(i32* %ptr)
%ptr.0 = load i32, i32* %ptr
; deref 4 hold
; FIXME: this should be %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
; ATTRIBUTOR: %B = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) %ptr)
%B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
br i1%c, label %if.true, label %if.false
if.true:
; ATTRIBUTOR: %C = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
%C = tail call i32 @unkown_f(i32* %ptr)
; ATTRIBUTOR: %D = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
%D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
; ATTRIBUTOR: %E = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
%E = tail call i32 @unkown_f(i32* %ptr)
ret void
if.false:
ret void
}
; ATTRIBUTOR: define void @f7_2(i1 %c)
define void @f7_2(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@f7_2
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: [[PTR:%.*]] = tail call nonnull align 4 dereferenceable(4) i32* @unkown_ptr()
; CHECK-NEXT: [[A:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]])
; CHECK-NEXT: [[B:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]])
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[C:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: [[D:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: [[E:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]])
; CHECK-NEXT: ret void
; CHECK: if.false:
; CHECK-NEXT: ret void
;
%ptr = tail call i32* @unkown_ptr()
; ATTRIBUTOR: %A = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) %ptr)
%A = tail call i32 @unkown_f(i32* %ptr)
%arg_a.0 = load i32, i32* %ptr
; deref 4 hold
; ATTRIBUTOR: %B = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) %ptr)
%B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
br i1%c, label %if.true, label %if.false
if.true:
; ATTRIBUTOR: %C = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
%C = tail call i32 @unkown_f(i32* %ptr)
; ATTRIBUTOR: %D = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
%D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
%E = tail call i32 @unkown_f(i32* %ptr)
; ATTRIBUTOR: %E = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) %ptr)
ret void
if.false:
ret void
}
define i32* @f7_3() {
; ATTRIBUTOR: define nonnull align 16 dereferenceable(4) i32* @f7_3()
; CHECK-LABEL: define {{[^@]+}}@f7_3()
; CHECK-NEXT: [[PTR:%.*]] = tail call nonnull align 16 dereferenceable(4) i32* @unkown_ptr()
; CHECK-NEXT: store i32 10, i32* [[PTR]], align 16
; CHECK-NEXT: ret i32* [[PTR]]
;
%ptr = tail call i32* @unkown_ptr()
store i32 10, i32* %ptr, align 16
ret i32* %ptr
}
define i32* @test_for_minus_index(i32* %p) {
; FIXME: This should have a return dereferenceable(8) but we need to make sure it will work in loops as well.
; ATTRIBUTOR: define nonnull align 4 i32* @test_for_minus_index(i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" %p)
define i32* @test_for_minus_index(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@test_for_minus_index
; CHECK-SAME: (i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 -2
; CHECK-NEXT: store i32 1, i32* [[Q]], align 4
; CHECK-NEXT: ret i32* [[Q]]
;
%q = getelementptr inbounds i32, i32* %p, i32 -2
store i32 1, i32* %q
ret i32* %q
}
define void @deref_or_null_and_nonnull(i32* dereferenceable_or_null(100) %0) {
; ATTRIBUTOR: define void @deref_or_null_and_nonnull(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(100) %0)
; CHECK-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(100) [[TMP0:%.*]])
; CHECK-NEXT: store i32 1, i32* [[TMP0]], align 4
; CHECK-NEXT: ret void
;
store i32 1, i32* %0
ret void
}
; UTC_ARGS: --enable
; TEST 8
; Use Constant range in deereferenceable
; void g(int *p, long long int *range){
@ -223,24 +305,24 @@ define void @deref_or_null_and_nonnull(i32* dereferenceable_or_null(100) %0) {
; }
; }
define internal void @fill_range_not_inbounds(i32* %p, i64 %start){
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fill_range_not_inbounds
; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]])
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
; ATTRIBUTOR-NEXT: br label [[FOR_BODY:%.*]]
; ATTRIBUTOR: for.cond.cleanup:
; ATTRIBUTOR-NEXT: ret void
; ATTRIBUTOR: for.body:
; ATTRIBUTOR-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; ATTRIBUTOR-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
; ATTRIBUTOR-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
; ATTRIBUTOR-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
; ATTRIBUTOR-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
;
; NOTE: %p should not be dereferenceable
define internal void @fill_range_not_inbounds(i32* %p, i64 %start){
; CHECK-LABEL: define {{[^@]+}}@fill_range_not_inbounds
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
; CHECK-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
; CHECK-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
;
entry:
%0 = add nsw i64 %start, 9
br label %for.body
@ -257,24 +339,25 @@ for.body: ; preds = %entry, %for.body
%cmp = icmp slt i64 %i.06, %0
br i1 %cmp, label %for.body, label %for.cond.cleanup
}
define internal void @fill_range_inbounds(i32* %p, i64 %start){
; ATTRIBUTOR-LABEL: define {{[^@]+}}@fill_range_inbounds
; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]])
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
; ATTRIBUTOR-NEXT: br label [[FOR_BODY:%.*]]
; ATTRIBUTOR: for.cond.cleanup:
; ATTRIBUTOR-NEXT: ret void
; ATTRIBUTOR: for.body:
; ATTRIBUTOR-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; ATTRIBUTOR-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
; ATTRIBUTOR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
; ATTRIBUTOR-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
; ATTRIBUTOR-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
;
; FIXME: %p should be dereferenceable(40)
define internal void @fill_range_inbounds(i32* %p, i64 %start){
; CHECK-LABEL: define {{[^@]+}}@fill_range_inbounds
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[START]], 9
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[I_06]] to i32
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
; CHECK-NEXT: store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
; CHECK-NEXT: [[INC]] = add nsw i64 [[I_06]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
;
entry:
%0 = add nsw i64 %start, 9
br label %for.body
@ -293,13 +376,13 @@ for.body: ; preds = %entry, %for.body
}
define void @call_fill_range(i32* nocapture %p, i64* nocapture readonly %range) {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@call_fill_range
; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]])
; ATTRIBUTOR-NEXT: entry:
; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range !0
; ATTRIBUTOR-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]])
; ATTRIBUTOR-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]])
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@call_fill_range
; CHECK-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, !range !0
; CHECK-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]])
; CHECK-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]])
; CHECK-NEXT: ret void
;
entry:
%0 = load i64, i64* %range, align 8, !range !0
@ -312,6 +395,7 @@ declare void @use0() willreturn nounwind
declare void @use1(i8*) willreturn nounwind
declare void @use2(i8*, i8*) willreturn nounwind
declare void @use3(i8*, i8*, i8*) willreturn nounwind
; simple path test
; if(..)
; fun2(dereferenceable(8) %a, dereferenceable(8) %b)
@ -319,7 +403,17 @@ declare void @use3(i8*, i8*, i8*) willreturn nounwind
; fun2(dereferenceable(4) %a, %b)
; We can say that %a is dereferenceable(4) but %b is not.
define void @simple-path(i8* %a, i8 * %b, i8 %c) {
; ATTRIBUTOR: define void @simple-path(i8* nonnull dereferenceable(4) %a, i8* %b, i8 %c)
; CHECK-LABEL: define {{[^@]+}}@simple-path
; CHECK-SAME: (i8* nonnull dereferenceable(4) [[A:%.*]], i8* [[B:%.*]], i8 [[C:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: tail call void @use2(i8* nonnull dereferenceable(8) [[A]], i8* nonnull dereferenceable(8) [[B]])
; CHECK-NEXT: ret void
; CHECK: if.else:
; CHECK-NEXT: tail call void @use2(i8* nonnull dereferenceable(4) [[A]], i8* [[B]])
; CHECK-NEXT: ret void
;
%cmp = icmp eq i8 %c, 0
br i1 %cmp, label %if.then, label %if.else
if.then:
@ -329,6 +423,7 @@ if.else:
tail call void @use2(i8* dereferenceable(4) %a, i8* %b)
ret void
}
; More complex test
; {
; fun1(dereferenceable(4) %a)
@ -341,9 +436,22 @@ if.else:
; fun1(dereferenceable(8) %a)
; }
; %a is dereferenceable(12)
define void @complex-path(i8* %a, i8* %b, i8 %c) {
; ATTRIBUTOR: define void @complex-path(i8* nonnull dereferenceable(12) %a, i8* nocapture nofree readnone %b, i8 %c)
; CHECK-LABEL: define {{[^@]+}}@complex-path
; CHECK-SAME: (i8* nonnull dereferenceable(12) [[A:%.*]], i8* nocapture nofree readnone [[B:%.*]], i8 [[C:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
; CHECK-NEXT: tail call void @use1(i8* nonnull dereferenceable(12) [[A]])
; CHECK-NEXT: br i1 [[CMP]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
; CHECK: cont.then:
; CHECK-NEXT: tail call void @use1(i8* nonnull dereferenceable(12) [[A]])
; CHECK-NEXT: br label [[CONT2:%.*]]
; CHECK: cont.else:
; CHECK-NEXT: tail call void @use1(i8* nonnull dereferenceable(16) [[A]])
; CHECK-NEXT: br label [[CONT2]]
; CHECK: cont2:
; CHECK-NEXT: tail call void @use1(i8* nonnull dereferenceable(12) [[A]])
; CHECK-NEXT: ret void
;
%cmp = icmp eq i8 %c, 0
tail call void @use1(i8* dereferenceable(4) %a)
br i1 %cmp, label %cont.then, label %cont.else
@ -373,8 +481,33 @@ cont2:
; }
;
; FIXME: %ptr should be dereferenceable(4)
; ATTRIBUTOR: define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, i32* nocapture nofree writeonly %ptr)
define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, i32* %ptr) {
; CHECK-LABEL: define {{[^@]+}}@rec-branch-1
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; CHECK: if.then2:
; CHECK-NEXT: store i32 1, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8:%.*]]
; CHECK: if.else:
; CHECK-NEXT: store i32 2, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.else3:
; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
; CHECK-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; CHECK: if.then5:
; CHECK-NEXT: store i32 3, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.else6:
; CHECK-NEXT: store i32 4, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.end8:
; CHECK-NEXT: ret void
;
entry:
%tobool = icmp eq i32 %a, 0
br i1 %tobool, label %if.else3, label %if.then
@ -421,8 +554,33 @@ if.end8: ; preds = %if.then5, %if.else6
; }
; }
; FIXME: %ptr should be dereferenceable(4)
; ATTRIBUTOR: define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, i32* nocapture nofree writeonly %ptr)
define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, i32* %ptr) {
; CHECK-LABEL: define {{[^@]+}}@rec-branch-2
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
; CHECK: if.then2:
; CHECK-NEXT: store i32 1, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8:%.*]]
; CHECK: if.else:
; CHECK-NEXT: store i32 2, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.else3:
; CHECK-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
; CHECK-NEXT: br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
; CHECK: if.then5:
; CHECK-NEXT: store i32 3, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.else6:
; CHECK-NEXT: tail call void @rec-branch-2(i32 1, i32 1, i32 1, i32* nocapture nofree writeonly [[PTR]])
; CHECK-NEXT: br label [[IF_END8]]
; CHECK: if.end8:
; CHECK-NEXT: ret void
;
entry:
%tobool = icmp eq i32 %a, 0
br i1 %tobool, label %if.else3, label %if.then
@ -462,6 +620,24 @@ define void @nonnull_assume_pos(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #6 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
; ATTRIBUTOR-NEXT: call void @unknown()
; ATTRIBUTOR-NEXT: ret void
;
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
; IS__TUNIT_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])
; IS__TUNIT_OPM-NEXT: call void @llvm.assume(i1 true) #6 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
; IS__TUNIT_OPM-NEXT: call void @unknown()
; IS__TUNIT_OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
; IS________NPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])
; IS________NPM-NEXT: call void @llvm.assume(i1 true) #7 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
; IS________NPM-NEXT: call void @unknown()
; IS________NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])
; IS__CGSCC_OPM-NEXT: call void @llvm.assume(i1 true) #8 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
; IS__CGSCC_OPM-NEXT: call void @unknown()
; IS__CGSCC_OPM-NEXT: ret void
;
call void @llvm.assume(i1 true) [ "nonnull"(i8* %arg3), "dereferenceable"(i8* %arg1, i64 1), "dereferenceable"(i8* %arg1, i64 2), "dereferenceable"(i8* %arg1, i64 101), "dereferenceable_or_null"(i8* %arg2, i64 31), "dereferenceable_or_null"(i8* %arg4, i64 42)]
call void @unknown()
@ -473,6 +649,12 @@ define void @nonnull_assume_neg(i8* %arg1, i8* %arg2, i8* %arg3) {
; ATTRIBUTOR-NEXT: call void @unknown()
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* undef, i64 101), "dereferenceable"(i8* undef, i64 -2), "dereferenceable_or_null"(i8* undef, i64 31) ]
; ATTRIBUTOR-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
; CHECK-SAME: (i8* nocapture nofree readnone [[ARG1:%.*]], i8* nocapture nofree readnone [[ARG2:%.*]], i8* nocapture nofree readnone [[ARG3:%.*]])
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i8* undef, i64 101), "dereferenceable"(i8* undef, i64 -2), "dereferenceable_or_null"(i8* undef, i64 31) ]
; CHECK-NEXT: ret void
;
call void @unknown()
call void @llvm.assume(i1 true) ["dereferenceable"(i8* %arg1, i64 101), "dereferenceable"(i8* %arg2, i64 -2), "dereferenceable_or_null"(i8* %arg3, i64 31)]
@ -496,6 +678,24 @@ define void @nonnull_assume_call(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
; ATTRIBUTOR-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
; ATTRIBUTOR-NEXT: call void @unknown()
; ATTRIBUTOR-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
; CHECK-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr()
; CHECK-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull [[ARG3]])
; CHECK-NEXT: call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
; CHECK-NEXT: call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret void
;
call void @unknown()
%p = call i32* @unkown_ptr()

View File

@ -1,12 +1,29 @@
; RUN: opt < %s -attributor --attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt < %s -passes=attributor --attributor-disable=false -S | FileCheck %s --check-prefix=ATTRIBUTOR_CGSCC_NPM
; Copied from Transforms/InferFunctionAttrs/dereferenceable.ll
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Determine dereference-ability before unused loads get deleted:
; https://bugs.llvm.org/show_bug.cgi?id=21780
define <4 x double> @PR21780(double* %ptr) {
; ATTRIBUTOR-LABEL: @PR21780(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
; CHECK-LABEL: define {{[^@]+}}@PR21780
; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 1
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 2
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 3
; CHECK-NEXT: [[T0:%.*]] = load double, double* [[PTR]], align 8
; CHECK-NEXT: [[T1:%.*]] = load double, double* [[ARRAYIDX1]], align 8
; CHECK-NEXT: [[T2:%.*]] = load double, double* [[ARRAYIDX2]], align 8
; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8
; CHECK-NEXT: [[VECINIT0:%.*]] = insertelement <4 x double> undef, double [[T0]], i32 0
; CHECK-NEXT: [[VECINIT1:%.*]] = insertelement <4 x double> [[VECINIT0]], double [[T1]], i32 1
; CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x double> [[VECINIT1]], double [[T2]], i32 2
; CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x double> [[VECINIT2]], double [[T3]], i32 3
; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x double> [[VECINIT3]], <4 x double> [[VECINIT3]], <4 x i32> <i32 0, i32 0, i32 2, i32 2>
; CHECK-NEXT: ret <4 x double> [[SHUFFLE]]
;
; GEP of index 0 is simplified away.
%arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1
@ -28,7 +45,12 @@ define <4 x double> @PR21780(double* %ptr) {
define double @PR21780_only_access3_with_inbounds(double* %ptr) {
; ATTRIBUTOR-LABEL: @PR21780_only_access3_with_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_with_inbounds
; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds double, double* [[PTR]], i64 3
; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret double [[T3]]
;
%arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3
%t3 = load double, double* %arrayidx3, align 8
@ -36,14 +58,24 @@ define double @PR21780_only_access3_with_inbounds(double* %ptr) {
}
define double @PR21780_only_access3_without_inbounds(double* %ptr) {
; ATTRIBUTOR-LABEL: @PR21780_only_access3_without_inbounds(double* nocapture nofree readonly align 8 %ptr)
; CHECK-LABEL: define {{[^@]+}}@PR21780_only_access3_without_inbounds
; CHECK-SAME: (double* nocapture nofree readonly align 8 [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, double* [[PTR]], i64 3
; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret double [[T3]]
;
%arrayidx3 = getelementptr double, double* %ptr, i64 3
%t3 = load double, double* %arrayidx3, align 8
ret double %t3
}
define double @PR21780_without_inbounds(double* %ptr) {
; ATTRIBUTOR-LABEL: @PR21780_without_inbounds(double* nocapture nofree nonnull readonly align 8 dereferenceable(32) %ptr)
; CHECK-LABEL: define {{[^@]+}}@PR21780_without_inbounds
; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(32) [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr double, double* [[PTR]], i64 3
; CHECK-NEXT: [[T3:%.*]] = load double, double* [[ARRAYIDX3]], align 8
; CHECK-NEXT: ret double [[T3]]
;
%arrayidx1 = getelementptr double, double* %ptr, i64 1
%arrayidx2 = getelementptr double, double* %ptr, i64 2
@ -60,7 +92,13 @@ define double @PR21780_without_inbounds(double* %ptr) {
; Unsimplified, but still valid. Also, throw in some bogus arguments.
define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
; ATTRIBUTOR-LABEL: @gep0(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull writeonly dereferenceable(1) %other, i8* nocapture nofree nonnull readonly dereferenceable(3) %ptr)
; CHECK-LABEL: define {{[^@]+}}@gep0
; CHECK-SAME: (i8* nocapture nofree readnone [[UNUSED:%.*]], i8* nocapture nofree nonnull writeonly dereferenceable(1) [[OTHER:%.*]], i8* nocapture nofree nonnull readonly dereferenceable(3) [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr i8, i8* [[PTR]], i64 2
; CHECK-NEXT: [[T2:%.*]] = load i8, i8* [[ARRAYIDX2]]
; CHECK-NEXT: store i8 [[T2]], i8* [[OTHER]]
; CHECK-NEXT: ret void
;
%arrayidx0 = getelementptr i8, i8* %ptr, i64 0
%arrayidx1 = getelementptr i8, i8* %ptr, i64 1
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
@ -75,7 +113,10 @@ define void @gep0(i8* %unused, i8* %other, i8* %ptr) {
; Multiple arguments may be dereferenceable.
define void @ordering(i8* %ptr1, i32* %ptr2) {
; ATTRIBUTOR-LABEL: @ordering(i8* nocapture nofree nonnull readnone dereferenceable(3) %ptr1, i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) %ptr2)
; CHECK-LABEL: define {{[^@]+}}@ordering
; CHECK-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(3) [[PTR1:%.*]], i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[PTR2:%.*]])
; CHECK-NEXT: ret void
;
%a20 = getelementptr i32, i32* %ptr2, i64 0
%a12 = getelementptr i8, i8* %ptr1, i64 2
%t12 = load i8, i8* %a12
@ -92,7 +133,13 @@ define void @ordering(i8* %ptr1, i32* %ptr2) {
; Not in entry block.
define void @not_entry_but_guaranteed_to_execute(i8* %ptr) {
; ATTRIBUTOR-LABEL: @not_entry_but_guaranteed_to_execute(i8* nocapture nofree nonnull readnone dereferenceable(3) %ptr)
; CHECK-LABEL: define {{[^@]+}}@not_entry_but_guaranteed_to_execute
; CHECK-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(3) [[PTR:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %exit
exit:
@ -108,7 +155,15 @@ exit:
; Not in entry block and not guaranteed to execute.
define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) {
; ATTRIBUTOR-LABEL: @not_entry_not_guaranteed_to_execute(i8* nocapture nofree readnone %ptr, i1 %cond)
; CHECK-LABEL: define {{[^@]+}}@not_entry_not_guaranteed_to_execute
; CHECK-SAME: (i8* nocapture nofree readnone [[PTR:%.*]], i1 [[COND:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]]
; CHECK: loads:
; CHECK-NEXT: ret void
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br i1 %cond, label %loads, label %exit
loads:
@ -126,7 +181,15 @@ exit:
; The last load may not execute, so derefenceable bytes only covers the 1st two loads.
define void @partial_in_entry(i16* %ptr, i1 %cond) {
; ATTRIBUTOR-LABEL: @partial_in_entry(i16* nocapture nofree nonnull readnone align 2 dereferenceable(4) %ptr, i1 %cond)
; CHECK-LABEL: define {{[^@]+}}@partial_in_entry
; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(4) [[PTR:%.*]], i1 [[COND:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND]], label [[LOADS:%.*]], label [[EXIT:%.*]]
; CHECK: loads:
; CHECK-NEXT: ret void
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
@ -145,7 +208,12 @@ exit:
; The 2nd and 3rd loads may never execute.
define void @volatile_is_not_dereferenceable(i16* %ptr) {
; ATTRIBUTOR-LABEL: @volatile_is_not_dereferenceable(i16* nofree align 2 %ptr)
; CHECK-LABEL: define {{[^@]+}}@volatile_is_not_dereferenceable
; CHECK-SAME: (i16* nofree align 2 [[PTR:%.*]])
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr i16, i16* [[PTR]], i64 0
; CHECK-NEXT: [[T0:%.*]] = load volatile i16, i16* [[ARRAYIDX0]], align 2
; CHECK-NEXT: ret void
;
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@ -158,7 +226,10 @@ define void @volatile_is_not_dereferenceable(i16* %ptr) {
; TODO: We should allow inference for atomic (but not volatile) ops.
define void @atomic_is_alright(i16* %ptr) {
; ATTRIBUTOR-LABEL: @atomic_is_alright(i16* nocapture nofree nonnull readnone align 2 dereferenceable(6) %ptr)
; CHECK-LABEL: define {{[^@]+}}@atomic_is_alright
; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(6) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@ -171,7 +242,11 @@ define void @atomic_is_alright(i16* %ptr) {
declare void @may_not_return()
define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
; ATTRIBUTOR-LABEL: @not_guaranteed_to_transfer_execution(i16* nocapture nofree nonnull readnone align 2 dereferenceable(2) %ptr)
; CHECK-LABEL: define {{[^@]+}}@not_guaranteed_to_transfer_execution
; CHECK-SAME: (i16* nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]])
; CHECK-NEXT: call void @may_not_return()
; CHECK-NEXT: ret void
;
%arrayidx0 = getelementptr i16, i16* %ptr, i64 0
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
@ -185,7 +260,10 @@ define void @not_guaranteed_to_transfer_execution(i16* %ptr) {
; We must have consecutive accesses.
define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
; ATTRIBUTOR-LABEL: @variable_gep_index(i8* nocapture nofree readnone %unused, i8* nocapture nofree nonnull readnone dereferenceable(1) %ptr, i64 %variable_index)
; CHECK-LABEL: define {{[^@]+}}@variable_gep_index
; CHECK-SAME: (i8* nocapture nofree readnone [[UNUSED:%.*]], i8* nocapture nofree nonnull readnone dereferenceable(1) [[PTR:%.*]], i64 [[VARIABLE_INDEX:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index
%arrayidx2 = getelementptr i8, i8* %ptr, i64 2
%t0 = load i8, i8* %ptr
@ -198,7 +276,10 @@ define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) {
define void @multi_index_gep(<4 x i8>* %ptr) {
; FIXME: %ptr should be dereferenceable(4)
; ATTRIBUTOR-LABEL: @multi_index_gep(<4 x i8>* nocapture nofree nonnull readnone dereferenceable(1) %ptr)
; CHECK-LABEL: define {{[^@]+}}@multi_index_gep
; CHECK-SAME: (<4 x i8>* nocapture nofree nonnull readnone dereferenceable(1) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0
%t0 = load i8, i8* %arrayidx00
ret void
@ -207,7 +288,10 @@ define void @multi_index_gep(<4 x i8>* %ptr) {
; Could round weird bitwidths down?
define void @not_byte_multiple(i9* %ptr) {
; ATTRIBUTOR-LABEL: @not_byte_multiple(i9* nocapture nofree nonnull readnone align 2 dereferenceable(2) %ptr)
; CHECK-LABEL: define {{[^@]+}}@not_byte_multiple
; CHECK-SAME: (i9* nocapture nofree nonnull readnone align 2 dereferenceable(2) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx0 = getelementptr i9, i9* %ptr, i64 0
%t0 = load i9, i9* %arrayidx0
ret void
@ -216,7 +300,10 @@ define void @not_byte_multiple(i9* %ptr) {
; Missing direct access from the pointer.
define void @no_pointer_deref(i16* %ptr) {
; ATTRIBUTOR-LABEL: @no_pointer_deref(i16* nocapture nofree readnone align 2 %ptr)
; CHECK-LABEL: define {{[^@]+}}@no_pointer_deref
; CHECK-SAME: (i16* nocapture nofree readnone align 2 [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx1 = getelementptr i16, i16* %ptr, i64 1
%arrayidx2 = getelementptr i16, i16* %ptr, i64 2
%t1 = load i16, i16* %arrayidx1
@ -227,7 +314,10 @@ define void @no_pointer_deref(i16* %ptr) {
; Out-of-order is ok, but missing access concludes dereferenceable range.
define void @non_consecutive(i32* %ptr) {
; ATTRIBUTOR-LABEL: @non_consecutive(i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) %ptr)
; CHECK-LABEL: define {{[^@]+}}@non_consecutive
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
@ -240,7 +330,10 @@ define void @non_consecutive(i32* %ptr) {
; Improve on existing dereferenceable attribute.
define void @more_bytes(i32* dereferenceable(8) %ptr) {
; ATTRIBUTOR-LABEL: @more_bytes(i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) %ptr)
; CHECK-LABEL: define {{[^@]+}}@more_bytes
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@ -255,7 +348,10 @@ define void @more_bytes(i32* dereferenceable(8) %ptr) {
; Improve on existing dereferenceable_or_null attribute.
define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
; ATTRIBUTOR-LABEL: @more_bytes_and_not_null(i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) %ptr)
; CHECK-LABEL: define {{[^@]+}}@more_bytes_and_not_null
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@ -270,7 +366,10 @@ define void @more_bytes_and_not_null(i32* dereferenceable_or_null(8) %ptr) {
; But don't pessimize existing dereferenceable attribute.
define void @better_bytes(i32* dereferenceable(100) %ptr) {
; ATTRIBUTOR-LABEL: @better_bytes(i32* nocapture nofree nonnull readnone align 4 dereferenceable(100) %ptr)
; CHECK-LABEL: define {{[^@]+}}@better_bytes
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(100) [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%arrayidx3 = getelementptr i32, i32* %ptr, i64 3
%arrayidx1 = getelementptr i32, i32* %ptr, i64 1
%arrayidx0 = getelementptr i32, i32* %ptr, i64 0
@ -283,7 +382,10 @@ define void @better_bytes(i32* dereferenceable(100) %ptr) {
}
define void @bitcast(i32* %arg) {
; ATTRIBUTOR-LABEL: @bitcast(i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) %arg)
; CHECK-LABEL: define {{[^@]+}}@bitcast
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: ret void
;
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@ -293,7 +395,10 @@ define void @bitcast(i32* %arg) {
}
define void @bitcast_different_sizes(double* %arg1, i8* %arg2) {
; ATTRIBUTOR-LABEL: @bitcast_different_sizes(double* nocapture nofree nonnull readnone align 4 dereferenceable(12) %arg1, i8* nocapture nofree nonnull readnone align 4 dereferenceable(16) %arg2)
; CHECK-LABEL: define {{[^@]+}}@bitcast_different_sizes
; CHECK-SAME: (double* nocapture nofree nonnull readnone align 4 dereferenceable(12) [[ARG1:%.*]], i8* nocapture nofree nonnull readnone align 4 dereferenceable(16) [[ARG2:%.*]])
; CHECK-NEXT: ret void
;
%ptr1 = bitcast double* %arg1 to float*
%a10 = getelementptr float, float* %ptr1, i64 0
%a11 = getelementptr float, float* %ptr1, i64 1
@ -311,7 +416,10 @@ define void @bitcast_different_sizes(double* %arg1, i8* %arg2) {
}
define void @negative_offset(i32* %arg) {
; ATTRIBUTOR-LABEL: @negative_offset(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) %arg)
; CHECK-LABEL: define {{[^@]+}}@negative_offset
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: ret void
;
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 -1
@ -321,7 +429,15 @@ define void @negative_offset(i32* %arg) {
}
define void @stores(i32* %arg) {
; ATTRIBUTOR-LABEL: @stores(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) %arg)
; CHECK-LABEL: define {{[^@]+}}@stores
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: [[PTR:%.*]] = bitcast i32* [[ARG]] to float*
; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr float, float* [[PTR]], i64 0
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, float* [[PTR]], i64 1
; CHECK-NEXT: store float 1.000000e+00, float* [[ARRAYIDX0]], align 4
; CHECK-NEXT: store float 2.000000e+00, float* [[ARRAYIDX1]], align 4
; CHECK-NEXT: ret void
;
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@ -331,7 +447,13 @@ define void @stores(i32* %arg) {
}
define void @load_store(i32* %arg) {
; ATTRIBUTOR-LABEL: @load_store(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) %arg)
; CHECK-LABEL: define {{[^@]+}}@load_store
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: [[PTR:%.*]] = bitcast i32* [[ARG]] to float*
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr float, float* [[PTR]], i64 1
; CHECK-NEXT: store float 2.000000e+00, float* [[ARRAYIDX1]], align 4
; CHECK-NEXT: ret void
;
%ptr = bitcast i32* %arg to float*
%arrayidx0 = getelementptr float, float* %ptr, i64 0
%arrayidx1 = getelementptr float, float* %ptr, i64 1
@ -341,7 +463,13 @@ define void @load_store(i32* %arg) {
}
define void @different_size1(i32* %arg) {
; ATTRIBUTOR-LABEL: @different_size1(i32* nocapture nofree nonnull writeonly align 8 dereferenceable(8) %arg)
; CHECK-LABEL: define {{[^@]+}}@different_size1
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: [[ARG_CAST:%.*]] = bitcast i32* [[ARG]] to double*
; CHECK-NEXT: store double 0.000000e+00, double* [[ARG_CAST]], align 8
; CHECK-NEXT: store i32 0, i32* [[ARG]], align 8
; CHECK-NEXT: ret void
;
%arg-cast = bitcast i32* %arg to double*
store double 0.000000e+00, double* %arg-cast
store i32 0, i32* %arg
@ -349,7 +477,13 @@ define void @different_size1(i32* %arg) {
}
define void @different_size2(i32* %arg) {
; ATTRIBUTOR-LABEL: @different_size2(i32* nocapture nofree nonnull writeonly align 8 dereferenceable(8) %arg)
; CHECK-LABEL: define {{[^@]+}}@different_size2
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[ARG:%.*]])
; CHECK-NEXT: store i32 0, i32* [[ARG]], align 8
; CHECK-NEXT: [[ARG_CAST:%.*]] = bitcast i32* [[ARG]] to double*
; CHECK-NEXT: store double 0.000000e+00, double* [[ARG_CAST]], align 8
; CHECK-NEXT: ret void
;
store i32 0, i32* %arg
%arg-cast = bitcast i32* %arg to double*
store double 0.000000e+00, double* %arg-cast
@ -375,12 +509,63 @@ define void @different_size2(i32* %arg) {
;
; ATTRIBUTOR_CGSCC_NPM-LABEL: define i32 @require_cfg_analysis(i32 %c, i32* {{.*}} dereferenceable(4) %p)
define i32 @require_cfg_analysis(i32 %c, i32* %p) {
; IS________OPM-LABEL: define {{[^@]+}}@require_cfg_analysis
; IS________OPM-SAME: (i32 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]])
; IS________OPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0
; IS________OPM-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]]
; IS________OPM: l1:
; IS________OPM-NEXT: [[TOBOOL2:%.*]] = icmp eq i32 [[C]], 1
; IS________OPM-NEXT: br i1 [[TOBOOL2]], label [[L3:%.*]], label [[L4:%.*]]
; IS________OPM: l2:
; IS________OPM-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2
; IS________OPM-NEXT: br i1 [[TOBOOL3]], label [[L3]], label [[L4]]
; IS________OPM: l3:
; IS________OPM-NEXT: br label [[L5:%.*]]
; IS________OPM: l4:
; IS________OPM-NEXT: br label [[L5]]
; IS________OPM: l5:
; IS________OPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4
; IS________OPM-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]]
; IS________OPM: l6:
; IS________OPM-NEXT: store i32 0, i32* [[P]]
; IS________OPM-NEXT: br label [[END:%.*]]
; IS________OPM: l7:
; IS________OPM-NEXT: store i32 1, i32* [[P]]
; IS________OPM-NEXT: br label [[END]]
; IS________OPM: end:
; IS________OPM-NEXT: ret i32 1
;
; IS________NPM-LABEL: define {{[^@]+}}@require_cfg_analysis
; IS________NPM-SAME: (i32 [[C:%.*]], i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]])
; IS________NPM-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C]], 0
; IS________NPM-NEXT: br i1 [[TOBOOL1]], label [[L1:%.*]], label [[L2:%.*]]
; IS________NPM: l1:
; IS________NPM-NEXT: br label [[L4:%.*]]
; IS________NPM: l2:
; IS________NPM-NEXT: [[TOBOOL3:%.*]] = icmp eq i32 [[C]], 2
; IS________NPM-NEXT: br i1 [[TOBOOL3]], label [[L3:%.*]], label [[L4]]
; IS________NPM: l3:
; IS________NPM-NEXT: br label [[L5:%.*]]
; IS________NPM: l4:
; IS________NPM-NEXT: br label [[L5]]
; IS________NPM: l5:
; IS________NPM-NEXT: [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 4
; IS________NPM-NEXT: br i1 [[TOBOOL4]], label [[L6:%.*]], label [[L7:%.*]]
; IS________NPM: l6:
; IS________NPM-NEXT: store i32 0, i32* [[P]], align 4
; IS________NPM-NEXT: br label [[END:%.*]]
; IS________NPM: l7:
; IS________NPM-NEXT: store i32 1, i32* [[P]], align 4
; IS________NPM-NEXT: br label [[END]]
; IS________NPM: end:
; IS________NPM-NEXT: ret i32 1
;
%tobool1 = icmp eq i32 %c, 0
br i1 %tobool1, label %l1, label %l2
l1:
l1:
%tobool2 = icmp eq i32 %c, 1
br i1 %tobool2, label %l3, label %l4
l2:
l2:
%tobool3 = icmp eq i32 %c, 2
br i1 %tobool3, label %l3, label %l4
l3:

View File

@ -1,4 +1,8 @@
; RUN: opt -passes=attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
declare noalias i8* @malloc(i64)
@ -24,8 +28,13 @@ declare void @free(i8* nocapture)
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind
; CHECK: @nofree_arg_only(i8* nocapture nofree %p1, i8* nocapture %p2)
define void @nofree_arg_only(i8* %p1, i8* %p2) {
; CHECK-LABEL: define {{[^@]+}}@nofree_arg_only
; CHECK-SAME: (i8* nocapture nofree [[P1:%.*]], i8* nocapture [[P2:%.*]])
; CHECK-NEXT: tail call void @free(i8* nocapture [[P2]])
; CHECK-NEXT: tail call void @nofree_func(i8* nocapture nofree [[P1]])
; CHECK-NEXT: ret void
;
tail call void @free(i8* %p2)
tail call void @nofree_func(i8* %p1)
ret void
@ -34,9 +43,21 @@ define void @nofree_arg_only(i8* %p1, i8* %p2) {
; TEST 1 - negative, pointer freed in another function.
define void @test1() {
; IS________OPM-LABEL: define {{[^@]+}}@test1()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @nocapture_func_frees_pointer(i8* noalias [[TMP1]])
; IS________OPM-NEXT: tail call void (...) @func_throws()
; IS________OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test1()
; IS________NPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: tail call void @nocapture_func_frees_pointer(i8* noalias nocapture [[TMP1]])
; IS________NPM-NEXT: tail call void (...) @func_throws()
; IS________NPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: @malloc(i64 4)
; CHECK-NEXT: @nocapture_func_frees_pointer(i8* noalias nocapture %1)
tail call void @nocapture_func_frees_pointer(i8* %1)
tail call void (...) @func_throws()
tail call void @free(i8* %1)
@ -46,9 +67,13 @@ define void @test1() {
; TEST 2 - negative, call to a sync function.
define void @test2() {
; CHECK-LABEL: define {{[^@]+}}@test2()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: tail call void @sync_func(i8* [[TMP1]])
; CHECK-NEXT: tail call void @free(i8* [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: @malloc(i64 4)
; CHECK-NEXT: @sync_func(i8* %1)
tail call void @sync_func(i8* %1)
tail call void @free(i8* %1)
ret void
@ -57,21 +82,46 @@ define void @test2() {
; TEST 3 - 1 malloc, 1 free
define void @test3() {
; IS________OPM-LABEL: define {{[^@]+}}@test3()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test3()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = alloca i8, i64 4
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
define void @test3a(i8* %p) {
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test3a
; IS__TUNIT_OPM-SAME: (i8* nocapture [[P:%.*]])
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS__TUNIT_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP1]], i8* nocapture [[P]])
; IS__TUNIT_OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test3a
; IS________NPM-SAME: (i8* nocapture [[P:%.*]])
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP1]], i8* nocapture [[P]])
; IS________NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test3a
; IS__CGSCC_OPM-SAME: (i8* nocapture [[P:%.*]])
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS__CGSCC_OPM-NEXT: tail call void @nofree_arg_only(i8* nofree [[TMP1]], i8* nocapture [[P]])
; IS__CGSCC_OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS__CGSCC_OPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = alloca i8, i64 4
; CHECK-NEXT: tail call void @nofree_arg_only
tail call void @nofree_arg_only(i8* %1, i8* %p)
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
@ -79,19 +129,41 @@ define void @test3a(i8* %p) {
declare noalias i8* @aligned_alloc(i64, i64)
define void @test3b(i8* %p) {
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test3b
; IS__TUNIT_OPM-SAME: (i8* nocapture [[P:%.*]])
; IS__TUNIT_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @aligned_alloc(i64 32, i64 128)
; IS__TUNIT_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP1]], i8* nocapture [[P]])
; IS__TUNIT_OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS__TUNIT_OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test3b
; IS________NPM-SAME: (i8* nocapture [[P:%.*]])
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 128, align 32
; IS________NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP1]], i8* nocapture [[P]])
; IS________NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test3b
; IS__CGSCC_OPM-SAME: (i8* nocapture [[P:%.*]])
; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @aligned_alloc(i64 32, i64 128)
; IS__CGSCC_OPM-NEXT: tail call void @nofree_arg_only(i8* nofree [[TMP1]], i8* nocapture [[P]])
; IS__CGSCC_OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS__CGSCC_OPM-NEXT: ret void
;
%1 = tail call noalias i8* @aligned_alloc(i64 32, i64 128)
; CHECK: %1 = alloca i8, i64 128, align 32
; CHECK-NEXT: tail call void @nofree_arg_only
tail call void @nofree_arg_only(i8* %1, i8* %p)
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
; leave alone non-constant alignments.
define void @test3c(i64 %alignment) {
; CHECK-LABEL: define {{[^@]+}}@test3c
; CHECK-SAME: (i64 [[ALIGNMENT:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @aligned_alloc(i64 [[ALIGNMENT]], i64 128)
; CHECK-NEXT: tail call void @free(i8* noalias [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @aligned_alloc(i64 %alignment, i64 128)
; CHECK: tail call noalias i8* @aligned_alloc
tail call void @free(i8* %1)
ret void
}
@ -99,22 +171,38 @@ define void @test3c(i64 %alignment) {
declare noalias i8* @calloc(i64, i64)
define void @test0() {
; IS________OPM-LABEL: define {{[^@]+}}@test0()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @calloc(i64 2, i64 4)
; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* noalias [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test0()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 8
; IS________NPM-NEXT: [[CALLOC_BC:%.*]] = bitcast i8* [[TMP1]] to i8*
; IS________NPM-NEXT: call void @llvm.memset.p0i8.i64(i8* [[CALLOC_BC]], i8 0, i64 8, i1 false)
; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @calloc(i64 2, i64 4)
; CHECK: %1 = alloca i8, i64 8
; CHECK-NEXT: %calloc_bc = bitcast i8* %1 to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* %calloc_bc, i8 0, i64 8, i1 false)
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
; TEST 4
define void @test4() {
; IS________OPM-LABEL: define {{[^@]+}}@test4()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @nofree_func(i8* noalias nofree [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test4()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = alloca i8, i64 4
; CHECK-NEXT: @nofree_func(i8* noalias nocapture nofree %1)
tail call void @nofree_func(i8* %1)
ret void
}
@ -123,9 +211,51 @@ define void @test4() {
; are in nofree functions and are not captured
define void @test5(i32, i8* %p) {
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test5
; IS__TUNIT_OPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]])
; IS__TUNIT_OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS__TUNIT_OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; IS__TUNIT_OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; IS__TUNIT_OPM: 4:
; IS__TUNIT_OPM-NEXT: tail call void @nofree_func(i8* noalias nofree [[TMP2]])
; IS__TUNIT_OPM-NEXT: br label [[TMP6:%.*]]
; IS__TUNIT_OPM: 5:
; IS__TUNIT_OPM-NEXT: tail call void @nofree_arg_only(i8* nocapture nofree [[TMP2]], i8* nocapture [[P]])
; IS__TUNIT_OPM-NEXT: tail call void @free(i8* noalias [[TMP2]])
; IS__TUNIT_OPM-NEXT: br label [[TMP6]]
; IS__TUNIT_OPM: 6:
; IS__TUNIT_OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test5
; IS________NPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]])
; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; IS________NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; IS________NPM: 4:
; IS________NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]])
; IS________NPM-NEXT: br label [[TMP6:%.*]]
; IS________NPM: 5:
; IS________NPM-NEXT: tail call void @nofree_arg_only(i8* noalias nocapture nofree [[TMP2]], i8* nocapture [[P]])
; IS________NPM-NEXT: br label [[TMP6]]
; IS________NPM: 6:
; IS________NPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test5
; IS__CGSCC_OPM-SAME: (i32 [[TMP0:%.*]], i8* nocapture [[P:%.*]])
; IS__CGSCC_OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS__CGSCC_OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; IS__CGSCC_OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; IS__CGSCC_OPM: 4:
; IS__CGSCC_OPM-NEXT: tail call void @nofree_func(i8* noalias nofree [[TMP2]])
; IS__CGSCC_OPM-NEXT: br label [[TMP6:%.*]]
; IS__CGSCC_OPM: 5:
; IS__CGSCC_OPM-NEXT: tail call void @nofree_arg_only(i8* nofree [[TMP2]], i8* nocapture [[P]])
; IS__CGSCC_OPM-NEXT: tail call void @free(i8* noalias [[TMP2]])
; IS__CGSCC_OPM-NEXT: br label [[TMP6]]
; IS__CGSCC_OPM: 6:
; IS__CGSCC_OPM-NEXT: ret void
;
%2 = tail call noalias i8* @malloc(i64 4)
; CHECK: %2 = alloca i8, i64 4
; CHECK-NEXT: icmp eq i32 %0, 0
%3 = icmp eq i32 %0, 0
br i1 %3, label %5, label %4
@ -136,7 +266,6 @@ define void @test5(i32, i8* %p) {
5: ; preds = %1
tail call void @nofree_arg_only(i8* %2, i8* %p)
tail call void @free(i8* %2)
; CHECK-NOT: @free(i8* %2)
br label %6
6: ; preds = %5, %4
@ -146,21 +275,45 @@ define void @test5(i32, i8* %p) {
; TEST 6 - all exit paths have a call to free
define void @test6(i32) {
; IS________OPM-LABEL: define {{[^@]+}}@test6
; IS________OPM-SAME: (i32 [[TMP0:%.*]])
; IS________OPM-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; IS________OPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; IS________OPM: 4:
; IS________OPM-NEXT: tail call void @nofree_func(i8* noalias nofree [[TMP2]])
; IS________OPM-NEXT: tail call void @free(i8* noalias [[TMP2]])
; IS________OPM-NEXT: br label [[TMP6:%.*]]
; IS________OPM: 5:
; IS________OPM-NEXT: tail call void @free(i8* noalias [[TMP2]])
; IS________OPM-NEXT: br label [[TMP6]]
; IS________OPM: 6:
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test6
; IS________NPM-SAME: (i32 [[TMP0:%.*]])
; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; IS________NPM-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; IS________NPM: 4:
; IS________NPM-NEXT: tail call void @nofree_func(i8* noalias nocapture nofree [[TMP2]])
; IS________NPM-NEXT: br label [[TMP6:%.*]]
; IS________NPM: 5:
; IS________NPM-NEXT: br label [[TMP6]]
; IS________NPM: 6:
; IS________NPM-NEXT: ret void
;
%2 = tail call noalias i8* @malloc(i64 4)
; CHECK: %2 = alloca i8, i64 4
; CHECK-NEXT: icmp eq i32 %0, 0
%3 = icmp eq i32 %0, 0
br i1 %3, label %5, label %4
4: ; preds = %1
tail call void @nofree_func(i8* %2)
tail call void @free(i8* %2)
; CHECK-NOT: @free(i8* %2)
br label %6
5: ; preds = %1
tail call void @free(i8* %2)
; CHECK-NOT: @free(i8* %2)
br label %6
6: ; preds = %5, %4
@ -170,11 +323,18 @@ define void @test6(i32) {
; TEST 7 - free is dead.
define void @test7() {
; IS________OPM-LABEL: define {{[^@]+}}@test7()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call()
; IS________OPM-NEXT: unreachable
;
; IS________NPM-LABEL: define {{[^@]+}}@test7()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: [[TMP2:%.*]] = tail call i32 @no_return_call()
; IS________NPM-NEXT: unreachable
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: alloca i8, i64 4
; CHECK-NEXT: tail call i32 @no_return_call()
tail call i32 @no_return_call()
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
@ -182,30 +342,42 @@ define void @test7() {
; TEST 8 - Negative: bitcast pointer used in capture function
define void @test8() {
; CHECK-LABEL: define {{[^@]+}}@test8()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @foo(i32* align 4 [[TMP2]])
; CHECK-NEXT: tail call void @free(i8* nonnull align 4 dereferenceable(4) [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
tail call void @foo(i32* %2)
; CHECK: @free(i8* nonnull align 4 dereferenceable(4) %1)
tail call void @free(i8* %1)
ret void
}
; TEST 9 - FIXME: malloc should be converted.
define void @test9() {
; CHECK-LABEL: define {{[^@]+}}@test9()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @foo_nounw(i32* nofree align 4 [[TMP2]])
; CHECK-NEXT: tail call void @free(i8* nonnull align 4 dereferenceable(4) [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
tail call void @foo_nounw(i32* %2)
; CHECK: @free(i8* nonnull align 4 dereferenceable(4) %1)
tail call void @free(i8* %1)
ret void
}
@ -213,28 +385,58 @@ define void @test9() {
; TEST 10 - 1 malloc, 1 free
define i32 @test10() {
; IS________OPM-LABEL: define {{[^@]+}}@test10()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________OPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________OPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________OPM-NEXT: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; IS________OPM-NEXT: ret i32 [[TMP3]]
;
; IS________NPM-LABEL: define {{[^@]+}}@test10()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; IS________NPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________NPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________NPM-NEXT: ret i32 [[TMP3]]
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = alloca i8, i64 4
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret i32 %3
}
define i32 @test_lifetime() {
; IS________OPM-LABEL: define {{[^@]+}}@test_lifetime()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; IS________OPM-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________OPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________OPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________OPM-NEXT: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; IS________OPM-NEXT: ret i32 [[TMP3]]
;
; IS________NPM-LABEL: define {{[^@]+}}@test_lifetime()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]])
; IS________NPM-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; IS________NPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; IS________NPM-NEXT: store i32 10, i32* [[TMP2]], align 4
; IS________NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________NPM-NEXT: ret i32 [[TMP3]]
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: %1 = alloca i8, i64 4
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
call void @llvm.lifetime.start.p0i8(i64 4, i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* %1)
ret i32 %3
}
@ -242,10 +444,18 @@ define i32 @test_lifetime() {
; TEST 11
define void @test11() {
; IS________OPM-LABEL: define {{[^@]+}}@test11()
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test11()
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: tail call void @sync_will_return(i8* [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK: test11
; CHECK-NEXT: alloc
; CHECK-NEXT: @sync_will_return(i8* %1)
tail call void @sync_will_return(i8* %1)
tail call void @free(i8* %1)
ret void
@ -253,8 +463,67 @@ define void @test11() {
; TEST 12
define i32 @irreducible_cfg(i32 %0) {
; CHECK: alloca i8, i64 4
; CHECK-NEXT: %3 = bitcast
; IS________OPM-LABEL: define {{[^@]+}}@irreducible_cfg
; IS________OPM-SAME: (i32 [[TMP0:%.*]])
; IS________OPM-NEXT: [[TMP2:%.*]] = call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
; IS________OPM-NEXT: store i32 10, i32* [[TMP3]], align 4
; IS________OPM-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1
; IS________OPM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]]
; IS________OPM: 5:
; IS________OPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5
; IS________OPM-NEXT: br label [[TMP13:%.*]]
; IS________OPM: 7:
; IS________OPM-NEXT: br label [[TMP8:%.*]]
; IS________OPM: 8:
; IS________OPM-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ]
; IS________OPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4
; IS________OPM-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1
; IS________OPM-NEXT: store i32 [[TMP10]], i32* [[TMP3]], align 4
; IS________OPM-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0
; IS________OPM-NEXT: br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]]
; IS________OPM: 12:
; IS________OPM-NEXT: br label [[TMP13]]
; IS________OPM: 13:
; IS________OPM-NEXT: [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ]
; IS________OPM-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1
; IS________OPM-NEXT: br label [[TMP8]]
; IS________OPM: 15:
; IS________OPM-NEXT: [[TMP16:%.*]] = bitcast i32* [[TMP3]] to i8*
; IS________OPM-NEXT: call void @free(i8* [[TMP16]])
; IS________OPM-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4
; IS________OPM-NEXT: ret i32 [[TMP17]]
;
; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg
; IS________NPM-SAME: (i32 [[TMP0:%.*]])
; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
; IS________NPM-NEXT: store i32 10, i32* [[TMP3]], align 4
; IS________NPM-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1
; IS________NPM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]]
; IS________NPM: 5:
; IS________NPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5
; IS________NPM-NEXT: br label [[TMP13:%.*]]
; IS________NPM: 7:
; IS________NPM-NEXT: br label [[TMP8:%.*]]
; IS________NPM: 8:
; IS________NPM-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ]
; IS________NPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4
; IS________NPM-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1
; IS________NPM-NEXT: store i32 [[TMP10]], i32* [[TMP3]], align 4
; IS________NPM-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0
; IS________NPM-NEXT: br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]]
; IS________NPM: 12:
; IS________NPM-NEXT: br label [[TMP13]]
; IS________NPM: 13:
; IS________NPM-NEXT: [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ]
; IS________NPM-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1
; IS________NPM-NEXT: br label [[TMP8]]
; IS________NPM: 15:
; IS________NPM-NEXT: [[TMP16:%.*]] = bitcast i32* [[TMP3]] to i8*
; IS________NPM-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4
; IS________NPM-NEXT: ret i32 [[TMP17]]
;
%2 = call noalias i8* @malloc(i64 4)
%3 = bitcast i8* %2 to i32*
store i32 10, i32* %3, align 4
@ -294,6 +563,46 @@ define i32 @irreducible_cfg(i32 %0) {
define i32 @malloc_in_loop(i32 %0) {
; IS________OPM-LABEL: define {{[^@]+}}@malloc_in_loop
; IS________OPM-SAME: (i32 [[TMP0:%.*]])
; IS________OPM-NEXT: [[TMP2:%.*]] = alloca i32, align 4
; IS________OPM-NEXT: [[TMP3:%.*]] = alloca i32*, align 8
; IS________OPM-NEXT: store i32 [[TMP0]], i32* [[TMP2]], align 4
; IS________OPM-NEXT: br label [[TMP4:%.*]]
; IS________OPM: 4:
; IS________OPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________OPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP5]], -1
; IS________OPM-NEXT: store i32 [[TMP6]], i32* [[TMP2]], align 4
; IS________OPM-NEXT: [[TMP7:%.*]] = icmp sgt i32 [[TMP6]], 0
; IS________OPM-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP11:%.*]]
; IS________OPM: 8:
; IS________OPM-NEXT: [[TMP9:%.*]] = call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[TMP10:%.*]] = bitcast i8* [[TMP9]] to i32*
; IS________OPM-NEXT: store i32 1, i32* [[TMP10]], align 8
; IS________OPM-NEXT: br label [[TMP4]]
; IS________OPM: 11:
; IS________OPM-NEXT: ret i32 5
;
; IS________NPM-LABEL: define {{[^@]+}}@malloc_in_loop
; IS________NPM-SAME: (i32 [[TMP0:%.*]])
; IS________NPM-NEXT: [[TMP2:%.*]] = alloca i32, align 4
; IS________NPM-NEXT: [[TMP3:%.*]] = alloca i32*, align 8
; IS________NPM-NEXT: store i32 [[TMP0]], i32* [[TMP2]], align 4
; IS________NPM-NEXT: br label [[TMP4:%.*]]
; IS________NPM: 4:
; IS________NPM-NEXT: [[TMP5:%.*]] = load i32, i32* [[TMP2]], align 4
; IS________NPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP5]], -1
; IS________NPM-NEXT: store i32 [[TMP6]], i32* [[TMP2]], align 4
; IS________NPM-NEXT: [[TMP7:%.*]] = icmp sgt i32 [[TMP6]], 0
; IS________NPM-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP11:%.*]]
; IS________NPM: 8:
; IS________NPM-NEXT: [[TMP9:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: [[TMP10:%.*]] = bitcast i8* [[TMP9]] to i32*
; IS________NPM-NEXT: store i32 1, i32* [[TMP10]], align 8
; IS________NPM-NEXT: br label [[TMP4]]
; IS________NPM: 11:
; IS________NPM-NEXT: ret i32 5
;
%2 = alloca i32, align 4
%3 = alloca i32*, align 8
store i32 %0, i32* %2, align 4
@ -308,7 +617,6 @@ define i32 @malloc_in_loop(i32 %0) {
8: ; preds = %4
%9 = call noalias i8* @malloc(i64 4)
; CHECK: alloca i8, i64 4
%10 = bitcast i8* %9 to i32*
store i32 1, i32* %10, align 8
br label %4
@ -319,104 +627,167 @@ define i32 @malloc_in_loop(i32 %0) {
; Malloc/Calloc too large
define i32 @test13() {
; CHECK-LABEL: define {{[^@]+}}@test13()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 256)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
%1 = tail call noalias i8* @malloc(i64 256)
; CHECK: %1 = tail call noalias i8* @malloc(i64 256)
; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
tail call void @free(i8* %1)
; CHECK: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) %1)
ret i32 %3
}
define i32 @test_sle() {
; CHECK-LABEL: define {{[^@]+}}@test_sle()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 -1)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
%1 = tail call noalias i8* @malloc(i64 -1)
; CHECK: %1 = tail call noalias i8* @malloc(i64 -1)
; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
tail call void @free(i8* %1)
; CHECK: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) %1)
ret i32 %3
}
define i32 @test_overflow() {
; CHECK-LABEL: define {{[^@]+}}@test_overflow()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @calloc(i64 65537, i64 65537)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
; CHECK-NEXT: store i32 10, i32* [[TMP2]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
; CHECK-NEXT: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
%1 = tail call noalias i8* @calloc(i64 65537, i64 65537)
; CHECK: %1 = tail call noalias i8* @calloc(i64 65537, i64 65537)
; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1)
tail call void @no_sync_func(i8* %1)
%2 = bitcast i8* %1 to i32*
store i32 10, i32* %2
%3 = load i32, i32* %2
tail call void @free(i8* %1)
; CHECK: tail call void @free(i8* noalias nonnull align 4 dereferenceable(4) %1)
ret i32 %3
}
define void @test14() {
; CHECK-LABEL: define {{[^@]+}}@test14()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @calloc(i64 64, i64 4)
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; CHECK-NEXT: tail call void @free(i8* noalias [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @calloc(i64 64, i64 4)
; CHECK: %1 = tail call noalias i8* @calloc(i64 64, i64 4)
; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1)
tail call void @no_sync_func(i8* %1)
tail call void @free(i8* %1)
; CHECK: tail call void @free(i8* noalias %1)
ret void
}
define void @test15(i64 %S) {
; CHECK: %1 = tail call noalias i8* @malloc(i64 %S)
; CHECK-LABEL: define {{[^@]+}}@test15
; CHECK-SAME: (i64 [[S:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 [[S]])
; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nofree [[TMP1]])
; CHECK-NEXT: tail call void @free(i8* noalias [[TMP1]])
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 %S)
; CHECK-NEXT: @no_sync_func(i8* noalias nofree %1)
tail call void @no_sync_func(i8* %1)
; CHECK-NEXT: @free(i8* noalias %1)
tail call void @free(i8* %1)
ret void
}
define void @test16a(i8 %v, i8** %P) {
; CHECK: %1 = alloca
; IS________OPM-LABEL: define {{[^@]+}}@test16a
; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]])
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: store i8 [[V]], i8* [[TMP1]]
; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nofree nonnull dereferenceable(1) [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* noalias nonnull dereferenceable(1) [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test16a
; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture nofree readnone [[P:%.*]])
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: store i8 [[V]], i8* [[TMP1]]
; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree nonnull dereferenceable(1) [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8 %v, i8* %1
store i8 %v, i8* %1
; CHECK-NEXT: @no_sync_func(i8* noalias nocapture nofree nonnull dereferenceable(1) %1)
tail call void @no_sync_func(i8* %1)
; CHECK-NOT: @free(i8* %1)
tail call void @free(i8* nonnull dereferenceable(1) %1)
ret void
}
define void @test16b(i8 %v, i8** %P) {
; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
; IS________OPM-LABEL: define {{[^@]+}}@test16b
; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]])
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: store i8* [[TMP1]], i8** [[P]]
; IS________OPM-NEXT: tail call void @no_sync_func(i8* nofree [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test16b
; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]])
; IS________NPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: store i8* [[TMP1]], i8** [[P]]
; IS________NPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; IS________NPM-NEXT: tail call void @free(i8* [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8* %1, i8** %P
store i8* %1, i8** %P
; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1)
tail call void @no_sync_func(i8* %1)
; CHECK-NEXT: @free(i8* %1)
tail call void @free(i8* %1)
ret void
}
define void @test16c(i8 %v, i8** %P) {
; CHECK: %1 = alloca
; IS________OPM-LABEL: define {{[^@]+}}@test16c
; IS________OPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]])
; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: store i8* [[TMP1]], i8** [[P]]
; IS________OPM-NEXT: tail call void @no_sync_func(i8* nofree [[TMP1]])
; IS________OPM-NEXT: tail call void @free(i8* [[TMP1]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test16c
; IS________NPM-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]])
; IS________NPM-NEXT: [[TMP1:%.*]] = alloca i8, i64 4
; IS________NPM-NEXT: store i8* [[TMP1]], i8** [[P]]
; IS________NPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]])
; IS________NPM-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8* %1, i8** %P
store i8* %1, i8** %P
; CHECK-NEXT: @no_sync_func(i8* nocapture nofree %1)
tail call void @no_sync_func(i8* %1) nounwind
; CHECK-NOT: @free
tail call void @free(i8* %1)
ret void
}
define void @test16d(i8 %v, i8** %P) {
; CHECK: %1 = tail call noalias i8* @malloc(i64 4)
; CHECK-LABEL: define {{[^@]+}}@test16d
; CHECK-SAME: (i8 [[V:%.*]], i8** nocapture writeonly [[P:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8* [[TMP1]], i8** [[P]]
; CHECK-NEXT: ret void
;
%1 = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8* %1, i8** %P
store i8* %1, i8** %P
ret void
}

View File

@ -1,6 +1,26 @@
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define dso_local i32 @visible(i32* noalias %A, i32* noalias %B) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@visible
; IS__TUNIT____-SAME: (i32* noalias nocapture nofree readonly [[A:%.*]], i32* noalias nocapture nofree readonly [[B:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(i32* noalias nocapture nofree readonly align 4 [[A]], i32* noalias nocapture nofree readonly align 4 [[B]])
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(i32* noalias nocapture nofree readonly align 4 [[A]], i32* noalias nocapture nofree readonly align 4 [[B]])
; IS__TUNIT____-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; IS__TUNIT____-NEXT: ret i32 [[ADD]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@visible
; IS__CGSCC____-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; IS__CGSCC____-NEXT: ret i32 [[ADD]]
;
entry:
%call1 = call i32 @noalias_args(i32* %A, i32* %B)
%call2 = call i32 @noalias_args_argmem(i32* %A, i32* %B)
@ -8,9 +28,27 @@ entry:
ret i32 %add
}
; CHECK: define private i32 @noalias_args(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B)
define private i32 @noalias_args(i32* %A, i32* %B) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@noalias_args
; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 4
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 4
; IS__TUNIT____-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[CALL]]
; IS__TUNIT____-NEXT: ret i32 [[ADD2]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@noalias_args
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 4
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[CALL]]
; IS__CGSCC____-NEXT: ret i32 [[ADD2]]
;
entry:
%0 = load i32, i32* %A, align 4
%1 = load i32, i32* %B, align 4
@ -21,8 +59,23 @@ entry:
}
; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B)
define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@noalias_args_argmem
; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 4
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 4
; IS__TUNIT____-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
; IS__TUNIT____-NEXT: ret i32 [[ADD]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@noalias_args_argmem
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[A]], align 4
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
; IS__CGSCC____-NEXT: ret i32 [[ADD]]
;
entry:
%0 = load i32, i32* %A, align 4
%1 = load i32, i32* %B, align 4
@ -31,6 +84,26 @@ entry:
}
define dso_local i32 @visible_local(i32* %A) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@visible_local
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: store i32 5, i32* [[B]], align 4
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(i32* nocapture nofree readonly align 4 [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(i32* nocapture nofree readonly align 4 [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; IS__TUNIT____-NEXT: ret i32 [[ADD]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@visible_local
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: store i32 5, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A]], i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; IS__CGSCC____-NEXT: ret i32 [[ADD]]
;
entry:
%B = alloca i32, align 4
store i32 5, i32* %B, align 4
@ -40,8 +113,32 @@ entry:
ret i32 %add
}
; CHECK: define internal i32 @noalias_args_argmem_ro(i32 %0, i32 %1)
define internal i32 @noalias_args_argmem_ro(i32* %A, i32* %B) #1 {
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@noalias_args_argmem_ro
; IS__TUNIT_OPM-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT_OPM-NEXT: [[T0:%.*]] = load i32, i32* [[A]], align 4
; IS__TUNIT_OPM-NEXT: [[T1:%.*]] = load i32, i32* [[B]], align 4
; IS__TUNIT_OPM-NEXT: [[ADD:%.*]] = add nsw i32 [[T0]], [[T1]]
; IS__TUNIT_OPM-NEXT: ret i32 [[ADD]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@noalias_args_argmem_ro
; IS__TUNIT_NPM-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]])
; IS__TUNIT_NPM-NEXT: [[B_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP1]], i32* [[B_PRIV]]
; IS__TUNIT_NPM-NEXT: [[A_PRIV:%.*]] = alloca i32
; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[A_PRIV]]
; IS__TUNIT_NPM-NEXT: [[T0:%.*]] = load i32, i32* [[A_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[T1:%.*]] = load i32, i32* [[B_PRIV]], align 4
; IS__TUNIT_NPM-NEXT: [[ADD:%.*]] = add nsw i32 [[T0]], [[T1]]
; IS__TUNIT_NPM-NEXT: ret i32 [[ADD]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@noalias_args_argmem_ro
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[A:%.*]], i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: [[T0:%.*]] = load i32, i32* [[A]], align 4
; IS__CGSCC____-NEXT: [[T1:%.*]] = load i32, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[T0]], [[T1]]
; IS__CGSCC____-NEXT: ret i32 [[ADD]]
;
%t0 = load i32, i32* %A, align 4
%t1 = load i32, i32* %B, align 4
%add = add nsw i32 %t0, %t1
@ -49,20 +146,63 @@ define internal i32 @noalias_args_argmem_ro(i32* %A, i32* %B) #1 {
}
define i32 @visible_local_2() {
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@visible_local_2()
; IS__TUNIT_OPM-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__TUNIT_OPM-NEXT: store i32 5, i32* [[B]], align 4
; IS__TUNIT_OPM-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_ro(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__TUNIT_OPM-NEXT: ret i32 [[CALL]]
;
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@visible_local_2()
; IS__TUNIT_NPM-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__TUNIT_NPM-NEXT: store i32 5, i32* [[B]], align 4
; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[B]], align 1
; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[B]], align 1
; IS__TUNIT_NPM-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_ro(i32 [[TMP1]], i32 [[TMP2]])
; IS__TUNIT_NPM-NEXT: ret i32 [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@visible_local_2()
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: store i32 5, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_ro(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[B]], i32* noalias nofree nonnull readonly align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: ret i32 [[CALL]]
;
%B = alloca i32, align 4
store i32 5, i32* %B, align 4
%call = call i32 @noalias_args_argmem_ro(i32* %B, i32* %B)
ret i32 %call
}
; CHECK: define internal i32 @noalias_args_argmem_rn(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) %B)
define internal i32 @noalias_args_argmem_rn(i32* %A, i32* %B) #1 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@noalias_args_argmem_rn
; IS__TUNIT____-SAME: (i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[B:%.*]])
; IS__TUNIT____-NEXT: [[T0:%.*]] = load i32, i32* [[B]], align 4
; IS__TUNIT____-NEXT: store i32 0, i32* [[B]], align 4
; IS__TUNIT____-NEXT: ret i32 [[T0]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@noalias_args_argmem_rn
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[B:%.*]])
; IS__CGSCC____-NEXT: [[T0:%.*]] = load i32, i32* [[B]], align 4
; IS__CGSCC____-NEXT: store i32 0, i32* [[B]], align 4
; IS__CGSCC____-NEXT: ret i32 [[T0]]
;
%t0 = load i32, i32* %B, align 4
store i32 0, i32* %B
ret i32 %t0
}
define i32 @visible_local_3() {
; IS__TUNIT____-LABEL: define {{[^@]+}}@visible_local_3()
; IS__TUNIT____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: store i32 5, i32* [[B]], align 4
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_rn(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[B]])
; IS__TUNIT____-NEXT: ret i32 [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@visible_local_3()
; IS__CGSCC____-NEXT: [[B:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: store i32 5, i32* [[B]], align 4
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_rn(i32* noalias nofree nonnull align 4 dereferenceable(4) [[B]])
; IS__CGSCC____-NEXT: ret i32 [[CALL]]
;
%B = alloca i32, align 4
store i32 5, i32* %B, align 4
%call = call i32 @noalias_args_argmem_rn(i32* %B, i32* %B)

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
; RUN: opt -attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
; RUN: opt -passes='attributor-cgscc' --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Make sure we need a single iteration to determine the chains are dead/alive.

View File

@ -1,20 +1,38 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=attributor -attributor-disable=false -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
define i8 @test1(i32 %a, i32 %length) {
; CHECK-LABEL: define {{[^@]+}}@test1
; CHECK-SAME: (i32 [[A:%.*]], i32 [[LENGTH:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
; CHECK-NEXT: [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400
; CHECK-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i8 0
; IS________OPM-LABEL: define {{[^@]+}}@test1
; IS________OPM-SAME: (i32 [[A:%.*]], i32 [[LENGTH:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: br label [[LOOP:%.*]]
; IS________OPM: loop:
; IS________OPM-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; IS________OPM-NEXT: [[CND:%.*]] = icmp sge i32 [[IV]], 0
; IS________OPM-NEXT: br i1 [[CND]], label [[BACKEDGE]], label [[EXIT:%.*]]
; IS________OPM: backedge:
; IS________OPM-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
; IS________OPM-NEXT: [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400
; IS________OPM-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT]]
; IS________OPM: exit:
; IS________OPM-NEXT: ret i8 0
;
; IS________NPM-LABEL: define {{[^@]+}}@test1
; IS________NPM-SAME: (i32 [[A:%.*]], i32 [[LENGTH:%.*]])
; IS________NPM-NEXT: entry:
; IS________NPM-NEXT: br label [[LOOP:%.*]]
; IS________NPM: loop:
; IS________NPM-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; IS________NPM-NEXT: br label [[BACKEDGE]]
; IS________NPM: backedge:
; IS________NPM-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
; IS________NPM-NEXT: [[CONT:%.*]] = icmp slt i32 [[IV_NEXT]], 400
; IS________NPM-NEXT: br i1 [[CONT]], label [[LOOP]], label [[EXIT:%.*]]
; IS________NPM: exit:
; IS________NPM-NEXT: ret i8 0
;
entry:
br label %loop
@ -40,7 +58,7 @@ define i8 @test2(i32 %n) {
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ [[N:%.*]], [[ENTRY]] ], [ [[IV2_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[IV2_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[CND1:%.*]] = icmp sge i32 [[IV]], 0
; CHECK-NEXT: [[CND2:%.*]] = icmp sgt i32 [[IV2]], 0
; CHECK-NEXT: [[CND:%.*]] = and i1 [[CND1]], [[CND2]]
@ -81,25 +99,46 @@ exit:
; Merging cont block into do block.
define i32 @test3(i32 %i, i1 %f, i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@test3
; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I:%.*]], -2134
; CHECK-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42
; CHECK-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
; CHECK: cont:
; CHECK-NEXT: [[COND_3:%.*]] = icmp sgt i32 [[I]], [[N:%.*]]
; CHECK-NEXT: br i1 [[COND_3]], label [[EXIT2]], label [[EXIT]]
; CHECK: do:
; CHECK-NEXT: [[COND_0:%.*]] = icmp sgt i32 [[I]], 0
; CHECK-NEXT: [[CONSUME:%.*]] = call i32 @consume(i1 [[COND_0]])
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 0
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ]
; CHECK-NEXT: br label [[CONT:%.*]]
; CHECK: exit2:
; CHECK-NEXT: ret i32 30
; IS________OPM-LABEL: define {{[^@]+}}@test3
; IS________OPM-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]])
; IS________OPM-NEXT: entry:
; IS________OPM-NEXT: [[C:%.*]] = icmp ne i32 [[I]], -2134
; IS________OPM-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
; IS________OPM: exit:
; IS________OPM-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42
; IS________OPM-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
; IS________OPM: cont:
; IS________OPM-NEXT: [[COND_3:%.*]] = icmp sgt i32 [[I]], [[N]]
; IS________OPM-NEXT: br i1 [[COND_3]], label [[EXIT2]], label [[EXIT]]
; IS________OPM: do:
; IS________OPM-NEXT: [[COND_0:%.*]] = icmp sgt i32 [[I]], 0
; IS________OPM-NEXT: [[CONSUME:%.*]] = call i32 @consume(i1 [[COND_0]])
; IS________OPM-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 0
; IS________OPM-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ]
; IS________OPM-NEXT: [[COND_2:%.*]] = icmp sgt i32 [[I]], 0
; IS________OPM-NEXT: br i1 [[COND_2]], label [[EXIT]], label [[CONT:%.*]]
; IS________OPM: exit2:
; IS________OPM-NEXT: ret i32 30
;
; IS________NPM-LABEL: define {{[^@]+}}@test3
; IS________NPM-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]])
; IS________NPM-NEXT: entry:
; IS________NPM-NEXT: [[C:%.*]] = icmp ne i32 [[I]], -2134
; IS________NPM-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
; IS________NPM: exit:
; IS________NPM-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42
; IS________NPM-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
; IS________NPM: cont:
; IS________NPM-NEXT: [[COND_3:%.*]] = icmp sgt i32 [[I]], [[N]]
; IS________NPM-NEXT: br i1 [[COND_3]], label [[EXIT2]], label [[EXIT]]
; IS________NPM: do:
; IS________NPM-NEXT: [[COND_0:%.*]] = icmp sgt i32 [[I]], 0
; IS________NPM-NEXT: [[CONSUME:%.*]] = call i32 @consume(i1 [[COND_0]])
; IS________NPM-NEXT: [[COND:%.*]] = icmp eq i32 [[I]], 0
; IS________NPM-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND]]) [ "deopt"() ]
; IS________NPM-NEXT: br label [[CONT:%.*]]
; IS________NPM: exit2:
; IS________NPM-NEXT: ret i32 30
;
entry:
%c = icmp ne i32 %i, -2134
@ -129,17 +168,18 @@ exit2:
}
; FIXME: We should be able to merge cont into do.
; FIXME: COND should be replaced with false. This will be fixed by improving LVI.
define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@test4
; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I:%.*]], -2134
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I]], -2134
; CHECK-NEXT: br i1 [[C]], label [[DO:%.*]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[I]], -42
; CHECK-NEXT: br i1 [[C1]], label [[EXIT2:%.*]], label [[EXIT]]
; CHECK: cont:
; CHECK-NEXT: call void @dummy(i1 [[F:%.*]])
; CHECK-NEXT: call void @dummy(i1 [[F]])
; CHECK-NEXT: br label [[EXIT2]]
; CHECK: do:
; CHECK-NEXT: call void @dummy(i1 [[F]])
@ -150,7 +190,6 @@ define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK: exit2:
; CHECK-NEXT: ret i32 30
;
; FIXME: COND should be replaced with false. This will be fixed by improving LVI.
entry:
%c = icmp ne i32 %i, -2134
br i1 %c, label %do, label %exit

View File

@ -1,10 +1,16 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=attributor -attributor-disable=false -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; FIXME: DOT should be replaced with 3
define i32 @test-ashr(i32 %c) {
; CHECK-LABEL: define {{[^@]+}}@test-ashr
; CHECK-SAME: (i32 [[C:%.*]])
; CHECK-NEXT: chk65:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[C:%.*]], 65
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[C]], 65
; CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[CHK0:%.*]]
; CHECK: chk0:
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[C]], 0
@ -21,7 +27,6 @@ define i32 @test-ashr(i32 %c) {
; CHECK-NEXT: [[RETVAL:%.*]] = phi i32 [ 0, [[CHK65:%.*]] ], [ 1, [[CHK0]] ], [ [[DOT]], [[BB_THEN]] ], [ 4, [[BB_IF]] ]
; CHECK-NEXT: ret i32 [[RETVAL]]
;
; FIXME: DOT should be replaced with 3
chk65:
%cmp = icmp sgt i32 %c, 65
br i1 %cmp, label %return, label %chk0

View File

@ -1,15 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,MODULE,OLD_MODULE
; RUN: opt -attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC,OLD_CGSCC
; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,MODULE,NEW_MODULE
; RUN: opt -passes='attributor-cgscc' --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC,NEW_CGSCC
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
; CHECK: Function Attrs: inaccessiblememonly
declare noalias i8* @malloc(i64) inaccessiblememonly
define dso_local i8* @internal_only(i32 %arg) {
; CHECK: Function Attrs: inaccessiblememonly
define dso_local i8* @internal_only(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_only
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -23,8 +23,8 @@ entry:
ret i8* %call
}
define dso_local i8* @internal_only_rec(i32 %arg) {
; CHECK: Function Attrs: inaccessiblememonly
define dso_local i8* @internal_only_rec(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_only_rec
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -63,8 +63,8 @@ return: ; preds = %if.end, %if.then
ret i8* %retval.0
}
define dso_local i8* @internal_only_rec_static_helper(i32 %arg) {
; CHECK: Function Attrs: inaccessiblememonly
define dso_local i8* @internal_only_rec_static_helper(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_only_rec_static_helper
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -76,8 +76,8 @@ entry:
ret i8* %call
}
define internal i8* @internal_only_rec_static(i32 %arg) {
; CHECK: Function Attrs: inaccessiblememonly
define internal i8* @internal_only_rec_static(i32 %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_only_rec_static
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -118,7 +118,6 @@ return: ; preds = %if.end, %if.then
define dso_local i8* @internal_only_rec_static_helper_malloc_noescape(i32 %arg) {
; FIXME: This is actually inaccessiblememonly because the malloced memory does not escape
; CHECK-NOT: inaccessiblememonly
; CHECK-LABEL: define {{[^@]+}}@internal_only_rec_static_helper_malloc_noescape
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -132,7 +131,6 @@ entry:
define internal i8* @internal_only_rec_static_malloc_noescape(i32 %arg) {
; FIXME: This is actually inaccessiblememonly because the malloced memory does not escape
; CHECK-NOT: inaccessiblememonly
; CHECK-LABEL: define {{[^@]+}}@internal_only_rec_static_malloc_noescape
; CHECK-SAME: (i32 [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -173,8 +171,8 @@ return: ; preds = %if.end, %if.then
ret i8* %retval.0
}
define dso_local i8* @internal_argmem_only_read(i32* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
define dso_local i8* @internal_argmem_only_read(i32* %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_read
; CHECK-SAME: (i32* nocapture nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -190,8 +188,8 @@ entry:
ret i8* %call
}
define dso_local i8* @internal_argmem_only_write(i32* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
define dso_local i8* @internal_argmem_only_write(i32* %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_write
; CHECK-SAME: (i32* nocapture nonnull writeonly align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -205,27 +203,27 @@ entry:
ret i8* %call
}
define dso_local i8* @internal_argmem_only_rec(i32* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
; MODULE-LABEL: define {{[^@]+}}@internal_argmem_only_rec
; MODULE-SAME: (i32* nocapture align 4 [[ARG:%.*]])
; MODULE-NEXT: entry:
; MODULE-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture align 4 [[ARG]])
; MODULE-NEXT: ret i8* [[CALL]]
define dso_local i8* @internal_argmem_only_rec(i32* %arg) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@internal_argmem_only_rec
; IS__TUNIT____-SAME: (i32* nocapture align 4 [[ARG:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture align 4 [[ARG]])
; IS__TUNIT____-NEXT: ret i8* [[CALL]]
;
; CGSCC-LABEL: define {{[^@]+}}@internal_argmem_only_rec
; CGSCC-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture nonnull align 4 dereferenceable(4) [[ARG]])
; CGSCC-NEXT: ret i8* [[CALL]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@internal_argmem_only_rec
; IS__CGSCC____-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture nonnull align 4 dereferenceable(4) [[ARG]])
; IS__CGSCC____-NEXT: ret i8* [[CALL]]
;
entry:
%call = call i8* @internal_argmem_only_rec_1(i32* %arg)
ret i8* %call
}
define internal i8* @internal_argmem_only_rec_1(i32* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
define internal i8* @internal_argmem_only_rec_1(i32* %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_rec_1
; CHECK-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -280,8 +278,8 @@ return: ; preds = %if.end3, %if.then2,
ret i8* %retval.0
}
define internal i8* @internal_argmem_only_rec_2(i32* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
define internal i8* @internal_argmem_only_rec_2(i32* %arg) {
; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_rec_2
; CHECK-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: entry:
@ -302,8 +300,8 @@ declare i8* @argmem_only(i8* %arg) argmemonly
declare i8* @inaccesible_argmem_only_decl(i8* %arg) inaccessiblemem_or_argmemonly
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) nounwind argmemonly willreturn
define void @callerA1(i8* %arg) {
; CHECK: Function Attrs: argmemonly
define void @callerA1(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@callerA1
; CHECK-SAME: (i8* [[ARG:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @argmem_only(i8* [[ARG]])
@ -312,8 +310,8 @@ define void @callerA1(i8* %arg) {
call i8* @argmem_only(i8* %arg)
ret void
}
define void @callerA2(i8* %arg) {
; CHECK: Function Attrs: inaccessiblemem_or_argmemonly
define void @callerA2(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@callerA2
; CHECK-SAME: (i8* [[ARG:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @inaccesible_argmem_only_decl(i8* [[ARG]])
@ -322,8 +320,8 @@ define void @callerA2(i8* %arg) {
call i8* @inaccesible_argmem_only_decl(i8* %arg)
ret void
}
define void @callerB1() {
; CHECK: Function Attrs: readnone
define void @callerB1() {
; CHECK-LABEL: define {{[^@]+}}@callerB1()
; CHECK-NEXT: [[STACK:%.*]] = alloca i8
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @argmem_only(i8* nonnull dereferenceable(1) [[STACK]])
@ -333,8 +331,8 @@ define void @callerB1() {
call i8* @argmem_only(i8* %stack)
ret void
}
define void @callerB2() {
; CHECK: Function Attrs: inaccessiblememonly
define void @callerB2() {
; CHECK-LABEL: define {{[^@]+}}@callerB2()
; CHECK-NEXT: [[STACK:%.*]] = alloca i8
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @inaccesible_argmem_only_decl(i8* nonnull dereferenceable(1) [[STACK]])
@ -344,8 +342,8 @@ define void @callerB2() {
call i8* @inaccesible_argmem_only_decl(i8* %stack)
ret void
}
define void @callerC1() {
; CHECK-NOT: Function Attrs
define void @callerC1() {
; CHECK-LABEL: define {{[^@]+}}@callerC1()
; CHECK-NEXT: [[UNKNOWN:%.*]] = call i8* @unknown_ptr()
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @argmem_only(i8* [[UNKNOWN]])
@ -355,8 +353,8 @@ define void @callerC1() {
call i8* @argmem_only(i8* %unknown)
ret void
}
define void @callerC2() {
; CHECK-NOT: Function Attrs
define void @callerC2() {
; CHECK-LABEL: define {{[^@]+}}@callerC2()
; CHECK-NEXT: [[UNKNOWN:%.*]] = call i8* @unknown_ptr()
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @inaccesible_argmem_only_decl(i8* [[UNKNOWN]])
@ -366,8 +364,8 @@ define void @callerC2() {
call i8* @inaccesible_argmem_only_decl(i8* %unknown)
ret void
}
define void @callerD1() {
; CHECK-NOT: Function Attrs
define void @callerD1() {
; CHECK-LABEL: define {{[^@]+}}@callerD1()
; CHECK-NEXT: [[UNKNOWN:%.*]] = call i8* @argmem_only(i8* noalias align 536870912 null)
; CHECK-NEXT: store i8 0, i8* [[UNKNOWN]]
@ -377,8 +375,8 @@ define void @callerD1() {
store i8 0, i8* %unknown
ret void
}
define void @callerD2() {
; CHECK-NOT: Function Attrs
define void @callerD2() {
; CHECK-LABEL: define {{[^@]+}}@callerD2()
; CHECK-NEXT: [[UNKNOWN:%.*]] = call i8* @inaccesible_argmem_only_decl(i8* noalias align 536870912 null)
; CHECK-NEXT: store i8 0, i8* [[UNKNOWN]]
@ -388,8 +386,8 @@ define void @callerD2() {
store i8 0, i8* %unknown
ret void
}
define void @callerE(i8* %arg) {
; CHECK: Function Attrs: argmemonly nounwind willreturn
define void @callerE(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@callerE
; CHECK-SAME: (i8* nocapture [[ARG:%.*]])
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nocapture [[ARG]])

View File

@ -1,35 +1,39 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -S -attributor -attributor-disable=false < %s | FileCheck %s --check-prefixes=ALL,CHECK
; RUN: opt -S -aa-pipeline='basic-aa' -passes=attributor -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ALL,DECL_CS
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; Mostly check we do not crash on these uses
define internal void @internal(void (i8*)* %fp) {
; CHECK-LABEL: define {{[^@]+}}@internal
; CHECK-SAME: (void (i8*)* nonnull [[FP:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; CHECK-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; CHECK-NEXT: call void [[FP]](i8* [[TMP1]])
; CHECK-NEXT: ret void
;
; DECL_CS-LABEL: define {{[^@]+}}@internal
; DECL_CS-SAME: (void (i8*)* nonnull [[FP:%.*]])
; DECL_CS-NEXT: entry:
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull [[FP]])
; DECL_CS-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; DECL_CS-NEXT: call void [[FP]](i8* [[TMP1]])
; DECL_CS-NEXT: ret void
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@internal
; IS__TUNIT____-SAME: (void (i8*)* nonnull [[FP:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__TUNIT____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* nonnull [[FP]])
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; IS__TUNIT____-NEXT: call void [[FP]](i8* [[TMP1]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@internal
; IS__CGSCC____-SAME: (void (i8*)* nonnull [[FP:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* nonnull [[FP]])
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; IS__CGSCC____-NEXT: call void [[FP]](i8* [[TMP1]])
; IS__CGSCC____-NEXT: ret void
;
entry:
%a = alloca i32, align 4
@ -45,33 +49,35 @@ entry:
}
define void @external(void (i8*)* %fp) {
; CHECK-LABEL: define {{[^@]+}}@external
; CHECK-SAME: (void (i8*)* [[FP:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]])
; CHECK-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; CHECK-NEXT: call void [[FP]](i8* [[TMP1]])
; CHECK-NEXT: call void @internal(void (i8*)* nonnull [[FP]])
; CHECK-NEXT: ret void
;
; DECL_CS-LABEL: define {{[^@]+}}@external
; DECL_CS-SAME: (void (i8*)* [[FP:%.*]])
; DECL_CS-NEXT: entry:
; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4
; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]])
; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; DECL_CS-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; DECL_CS-NEXT: call void [[FP]](i8* [[TMP1]])
; DECL_CS-NEXT: call void @internal(void (i8*)* nonnull [[FP]])
; DECL_CS-NEXT: ret void
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@external
; IS__TUNIT____-SAME: (void (i8*)* [[FP:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* [[FP]])
; IS__TUNIT____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; IS__TUNIT____-NEXT: call void [[FP]](i8* [[TMP1]])
; IS__TUNIT____-NEXT: call void @internal(void (i8*)* nonnull [[FP]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@external
; IS__CGSCC____-SAME: (void (i8*)* [[FP:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* nonnull @foo)
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* [[FP]])
; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8*
; IS__CGSCC____-NEXT: call void [[FP]](i8* [[TMP1]])
; IS__CGSCC____-NEXT: call void @internal(void (i8*)* nonnull [[FP]])
; IS__CGSCC____-NEXT: ret void
;
entry:
%a = alloca i32, align 4
@ -88,11 +94,12 @@ entry:
}
define internal void @foo(i32* %a) {
; ALL-LABEL: define {{[^@]+}}@foo
; ALL-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A:%.*]])
; ALL-NEXT: entry:
; ALL-NEXT: store i32 0, i32* [[A]], align 4
; ALL-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: store i32 0, i32* [[A]], align 4
; CHECK-NEXT: ret void
;
entry:
store i32 0, i32* %a

View File

@ -1,4 +1,8 @@
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; TEST 1 - negative.
@ -11,8 +15,12 @@
@G = external global i8*
; CHECK: define i8* @foo()
define i8* @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: store i8* [[TMP1]], i8** @G, align 8
; CHECK-NEXT: ret i8* [[TMP1]]
;
%1 = tail call noalias i8* @malloc(i64 4)
store i8* %1, i8** @G, align 8
ret i8* %1
@ -23,25 +31,39 @@ declare noalias i8* @malloc(i64)
; TEST 2
; call noalias function in return instruction.
; CHECK: define noalias i8* @return_noalias()
define i8* @return_noalias(){
; CHECK-LABEL: define {{[^@]+}}@return_noalias()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: ret i8* [[TMP1]]
;
%1 = tail call noalias i8* @malloc(i64 4)
ret i8* %1
}
define void @nocapture(i8* %a){
; CHECK-LABEL: define {{[^@]+}}@nocapture
; CHECK-SAME: (i8* nocapture nofree readnone [[A:%.*]])
; CHECK-NEXT: ret void
;
ret void
}
; CHECK: define noalias i8* @return_noalias_looks_like_capture()
define i8* @return_noalias_looks_like_capture(){
; CHECK-LABEL: define {{[^@]+}}@return_noalias_looks_like_capture()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: ret i8* [[TMP1]]
;
%1 = tail call noalias i8* @malloc(i64 4)
call void @nocapture(i8* %1)
ret i8* %1
}
; CHECK: define noalias i16* @return_noalias_casted()
define i16* @return_noalias_casted(){
; CHECK-LABEL: define {{[^@]+}}@return_noalias_casted()
; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: [[C:%.*]] = bitcast i8* [[TMP1]] to i16*
; CHECK-NEXT: ret i16* [[C]]
;
%1 = tail call noalias i8* @malloc(i64 4)
%c = bitcast i8* %1 to i16*
ret i16* %c
@ -50,9 +72,11 @@ define i16* @return_noalias_casted(){
declare i8* @alias()
; TEST 3
; CHECK: define i8* @call_alias()
; CHECK-NOT: noalias
define i8* @call_alias(){
; CHECK-LABEL: define {{[^@]+}}@call_alias()
; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @alias()
; CHECK-NEXT: ret i8* [[TMP1]]
;
%1 = tail call i8* @alias()
ret i8* %1
}
@ -72,14 +96,27 @@ define i8* @call_alias(){
; return malloc(4);
; }
; CHECK: define i8* @bar()
define i8* @bar() nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@bar()
; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* (...) @baz()
; CHECK-NEXT: ret i8* [[TMP1]]
;
%1 = tail call i8* (...) @baz()
ret i8* %1
}
; CHECK: define noalias i8* @foo1(i32 %0)
define i8* @foo1(i32 %0) nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@foo1
; CHECK-SAME: (i32 [[TMP0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* (...) @baz()
; CHECK-NEXT: br label [[TMP5]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: ret i8* [[TMP6]]
;
%2 = icmp eq i32 %0, 0
br i1 %2, label %5, label %3
@ -97,14 +134,18 @@ declare i8* @baz(...) nounwind uwtable
; TEST 5
; Returning global pointer. Should not be noalias.
; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter()
define i8** @getter() {
; CHECK-LABEL: define {{[^@]+}}@getter()
; CHECK-NEXT: ret i8** @G
;
ret i8** @G
}
; Returning global pointer. Should not be noalias.
; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1()
define i8** @calle1(){
; CHECK-LABEL: define {{[^@]+}}@calle1()
; CHECK-NEXT: ret i8** @G
;
%1 = call i8** @getter()
ret i8** %1
}
@ -112,8 +153,16 @@ define i8** @calle1(){
; TEST 6
declare noalias i8* @strdup(i8* nocapture) nounwind
; CHECK: define noalias i8* @test6()
define i8* @test6() nounwind uwtable ssp {
; CHECK-LABEL: define {{[^@]+}}@test6()
; CHECK-NEXT: [[X:%.*]] = alloca [2 x i8], align 1
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* [[X]], i64 0, i64 0
; CHECK-NEXT: store i8 97, i8* [[ARRAYIDX]], align 1
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [2 x i8], [2 x i8]* [[X]], i64 0, i64 1
; CHECK-NEXT: store i8 0, i8* [[ARRAYIDX1]], align 1
; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @strdup(i8* nonnull dereferenceable(2) [[ARRAYIDX]])
; CHECK-NEXT: ret i8* [[CALL]]
;
%x = alloca [2 x i8], align 1
%arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 0
store i8 97, i8* %arrayidx, align 1
@ -125,8 +174,19 @@ define i8* @test6() nounwind uwtable ssp {
; TEST 7
; CHECK: define noalias i8* @test7()
define i8* @test7() nounwind {
; CHECK-LABEL: define {{[^@]+}}@test7()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = call noalias i8* @malloc(i64 4)
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[A]], null
; CHECK-NEXT: br i1 [[TOBOOL]], label [[RETURN:%.*]], label [[IF_END:%.*]]
; CHECK: if.end:
; CHECK-NEXT: store i8 7, i8* [[A]]
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ [[A]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8* [[RETVAL_0]]
;
entry:
%A = call noalias i8* @malloc(i64 4) nounwind
%tobool = icmp eq i8* %A, null
@ -143,8 +203,18 @@ return:
; TEST 8
; CHECK: define noalias i8* @test8(i32* %0)
define i8* @test8(i32* %0) nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@test8
; CHECK-SAME: (i32* [[TMP0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32* [[TMP0]], null
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; CHECK: 4:
; CHECK-NEXT: store i8 10, i8* [[TMP2]]
; CHECK-NEXT: br label [[TMP5]]
; CHECK: 5:
; CHECK-NEXT: ret i8* [[TMP2]]
;
%2 = tail call noalias i8* @malloc(i64 4)
%3 = icmp ne i32* %0, null
br i1 %3, label %4, label %5
@ -161,32 +231,59 @@ define i8* @test8(i32* %0) nounwind uwtable {
; Simple Argument Test
declare void @use_i8(i8* nocapture)
define internal void @test9a(i8* %a, i8* %b) {
; CHECK: define internal void @test9a()
; CHECK-LABEL: define {{[^@]+}}@test9a()
; CHECK-NEXT: call void @use_i8(i8* noalias align 536870912 null)
; CHECK-NEXT: ret void
;
call void @use_i8(i8* null)
ret void
}
define internal void @test9b(i8* %a, i8* %b) {
; FIXME: %b should be noalias
; CHECK: define internal void @test9b(i8* noalias nocapture %a, i8* nocapture %b)
; CHECK-LABEL: define {{[^@]+}}@test9b
; CHECK-SAME: (i8* noalias nocapture [[A:%.*]], i8* nocapture [[B:%.*]])
; CHECK-NEXT: call void @use_i8(i8* noalias nocapture [[A]])
; CHECK-NEXT: call void @use_i8(i8* nocapture [[B]])
; CHECK-NEXT: ret void
;
call void @use_i8(i8* %a)
call void @use_i8(i8* %b)
ret void
}
define internal void @test9c(i8* %a, i8* %b, i8* %c) {
; CHECK: define internal void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %c)
; CHECK-LABEL: define {{[^@]+}}@test9c
; CHECK-SAME: (i8* noalias nocapture [[A:%.*]], i8* nocapture [[B:%.*]], i8* nocapture [[C:%.*]])
; CHECK-NEXT: call void @use_i8(i8* noalias nocapture [[A]])
; CHECK-NEXT: call void @use_i8(i8* nocapture [[B]])
; CHECK-NEXT: call void @use_i8(i8* nocapture [[C]])
; CHECK-NEXT: ret void
;
call void @use_i8(i8* %a)
call void @use_i8(i8* %b)
call void @use_i8(i8* %c)
ret void
}
define void @test9_helper(i8* %a, i8* %b) {
; CHECK: define void @test9_helper(i8* nocapture %a, i8* nocapture %b)
; CHECK: tail call void @test9a()
; CHECK: tail call void @test9a()
; CHECK: tail call void @test9b(i8* noalias nocapture %a, i8* nocapture %b)
; CHECK: tail call void @test9b(i8* noalias nocapture %b, i8* noalias nocapture %a)
; CHECK: tail call void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %b)
; CHECK: tail call void @test9c(i8* noalias nocapture %b, i8* noalias nocapture %a, i8* noalias nocapture %a)
; IS__TUNIT____-LABEL: define {{[^@]+}}@test9_helper
; IS__TUNIT____-SAME: (i8* nocapture [[A:%.*]], i8* nocapture [[B:%.*]])
; IS__TUNIT____-NEXT: tail call void @test9a()
; IS__TUNIT____-NEXT: tail call void @test9a()
; IS__TUNIT____-NEXT: tail call void @test9b(i8* noalias nocapture [[A]], i8* nocapture [[B]])
; IS__TUNIT____-NEXT: tail call void @test9b(i8* noalias nocapture [[B]], i8* noalias nocapture [[A]])
; IS__TUNIT____-NEXT: tail call void @test9c(i8* noalias nocapture [[A]], i8* nocapture [[B]], i8* nocapture [[B]])
; IS__TUNIT____-NEXT: tail call void @test9c(i8* noalias nocapture [[B]], i8* noalias nocapture [[A]], i8* noalias nocapture [[A]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test9_helper
; IS__CGSCC____-SAME: (i8* nocapture [[A:%.*]], i8* nocapture [[B:%.*]])
; IS__CGSCC____-NEXT: tail call void @test9a()
; IS__CGSCC____-NEXT: tail call void @test9a()
; IS__CGSCC____-NEXT: tail call void @test9b(i8* noalias [[A]], i8* [[B]])
; IS__CGSCC____-NEXT: tail call void @test9b(i8* noalias [[B]], i8* noalias [[A]])
; IS__CGSCC____-NEXT: tail call void @test9c(i8* noalias [[A]], i8* [[B]], i8* [[B]])
; IS__CGSCC____-NEXT: tail call void @test9c(i8* noalias nocapture [[B]], i8* noalias [[A]], i8* noalias nocapture [[A]])
; IS__CGSCC____-NEXT: ret void
;
tail call void @test9a(i8* noalias %a, i8* %b)
tail call void @test9a(i8* noalias %b, i8* noalias %a)
tail call void @test9b(i8* noalias %a, i8* %b)
@ -202,17 +299,24 @@ define void @test9_helper(i8* %a, i8* %b) {
declare void @test10_helper_1(i8* %a)
define void @test10_helper_2(i8* noalias %a) {
; CHECK: tail call void @test10_helper_1(i8* %a)
; CHECK-LABEL: define {{[^@]+}}@test10_helper_2
; CHECK-SAME: (i8* noalias [[A:%.*]])
; CHECK-NEXT: tail call void @test10_helper_1(i8* [[A]])
; CHECK-NEXT: ret void
;
tail call void @test10_helper_1(i8* %a)
ret void
}
define void @test10(i8* noalias %a) {
; CHECK: define void @test10(i8* noalias %a)
; CHECK-LABEL: define {{[^@]+}}@test10
; CHECK-SAME: (i8* noalias [[A:%.*]])
; CHECK-NEXT: tail call void @test10_helper_1(i8* [[A]])
; CHECK-NEXT: tail call void @test10_helper_2(i8* noalias [[A]])
; CHECK-NEXT: ret void
;
; FIXME: missing noalias
; CHECK-NEXT: tail call void @test10_helper_1(i8* %a)
tail call void @test10_helper_1(i8* %a)
; CHECK-NEXT: tail call void @test10_helper_2(i8* noalias %a)
tail call void @test10_helper_2(i8* %a)
ret void
}
@ -222,8 +326,11 @@ define void @test10(i8* noalias %a) {
declare void @test11_helper(i8* %a, i8 *%b)
define void @test11(i8* noalias %a) {
; CHECK: define void @test11(i8* noalias %a)
; CHECK-NEXT: tail call void @test11_helper(i8* %a, i8* %a)
; CHECK-LABEL: define {{[^@]+}}@test11
; CHECK-SAME: (i8* noalias [[A:%.*]])
; CHECK-NEXT: tail call void @test11_helper(i8* [[A]], i8* [[A]])
; CHECK-NEXT: ret void
;
tail call void @test11_helper(i8* %a, i8* %a)
ret void
}
@ -234,14 +341,23 @@ define void @test11(i8* noalias %a) {
declare void @use_nocapture(i8* nocapture)
declare void @use(i8*)
define void @test12_1() {
; CHECK-LABEL: @test12_1(
; CHECK-NEXT: [[A:%.*]] = alloca i8, align 4
; CHECK-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]])
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]])
; CHECK-NEXT: ret void
; IS________OPM-LABEL: define {{[^@]+}}@test12_1()
; IS________OPM-NEXT: [[A:%.*]] = alloca i8, align 4
; IS________OPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias [[B]])
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias [[B]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test12_1()
; IS________NPM-NEXT: [[A:%.*]] = alloca i8, align 4
; IS________NPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]])
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]])
; IS________NPM-NEXT: ret void
;
%A = alloca i8, align 4
%B = tail call noalias i8* @malloc(i64 4)
@ -253,14 +369,24 @@ define void @test12_1() {
}
define void @test12_2(){
; CHECK-LABEL: @test12_2(
; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; CHECK-NEXT: tail call void @use(i8* [[A]])
; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]])
; CHECK-NEXT: ret void
; IS________OPM-LABEL: define {{[^@]+}}@test12_2()
; IS________OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; IS________OPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; IS________OPM-NEXT: tail call void @use(i8* [[A]])
; IS________OPM-NEXT: tail call void @use_nocapture(i8* [[A]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test12_2()
; IS________NPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; IS________NPM-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[A]])
; IS________NPM-NEXT: tail call void @use(i8* [[A]])
; IS________NPM-NEXT: tail call void @use_nocapture(i8* nocapture [[A]])
; IS________NPM-NEXT: ret void
;
; FIXME: This should be @use_nocapture(i8* noalias [[A]])
; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]])
%A = tail call noalias i8* @malloc(i64 4)
tail call void @use_nocapture(i8* %A)
tail call void @use_nocapture(i8* %A)
@ -271,58 +397,119 @@ define void @test12_2(){
declare void @two_args(i8* nocapture , i8* nocapture)
define void @test12_3(){
; CHECK-LABEL: @test12_3(
; IS________OPM-LABEL: define {{[^@]+}}@test12_3()
; IS________OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: tail call void @two_args(i8* [[A]], i8* [[A]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test12_3()
; IS________NPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A]])
; IS________NPM-NEXT: ret void
;
%A = tail call noalias i8* @malloc(i64 4)
; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A)
tail call void @two_args(i8* %A, i8* %A)
ret void
}
define void @test12_4(){
; CHECK-LABEL: @test12_4(
; IS________OPM-LABEL: define {{[^@]+}}@test12_4()
; IS________OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0
; IS________OPM-NEXT: [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1
; IS________OPM-NEXT: [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0
; IS________OPM-NEXT: tail call void @two_args(i8* [[A]], i8* [[B]])
; IS________OPM-NEXT: tail call void @two_args(i8* [[A]], i8* [[A_0]])
; IS________OPM-NEXT: tail call void @two_args(i8* [[A]], i8* [[A_1]])
; IS________OPM-NEXT: tail call void @two_args(i8* [[A_0]], i8* [[B_0]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test12_4()
; IS________NPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0
; IS________NPM-NEXT: [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1
; IS________NPM-NEXT: [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0
; IS________NPM-NEXT: tail call void @two_args(i8* noalias nocapture [[A]], i8* noalias nocapture [[B]])
; IS________NPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_0]])
; IS________NPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_1]])
; IS________NPM-NEXT: tail call void @two_args(i8* nocapture [[A_0]], i8* nocapture [[B_0]])
; IS________NPM-NEXT: ret void
;
%A = tail call noalias i8* @malloc(i64 4)
%B = tail call noalias i8* @malloc(i64 4)
%A_0 = getelementptr i8, i8* %A, i64 0
%A_1 = getelementptr i8, i8* %A, i64 1
%B_0 = getelementptr i8, i8* %B, i64 0
; CHECK: tail call void @two_args(i8* noalias nocapture %A, i8* noalias nocapture %B)
tail call void @two_args(i8* %A, i8* %B)
; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_0)
tail call void @two_args(i8* %A, i8* %A_0)
; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_1)
tail call void @two_args(i8* %A, i8* %A_1)
; FIXME: This should be @two_args(i8* noalias nocapture %A_0, i8* noalias nocapture %B_0)
; CHECK: tail call void @two_args(i8* nocapture %A_0, i8* nocapture %B_0)
tail call void @two_args(i8* %A_0, i8* %B_0)
ret void
}
; TEST 13
define void @use_i8_internal(i8* %a) {
; CHECK-LABEL: define {{[^@]+}}@use_i8_internal
; CHECK-SAME: (i8* nocapture [[A:%.*]])
; CHECK-NEXT: call void @use_i8(i8* nocapture [[A]])
; CHECK-NEXT: ret void
;
call void @use_i8(i8* %a)
ret void
}
define void @test13_use_noalias(){
; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@test13_use_noalias()
; NOT_CGSCC_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4)
; NOT_CGSCC_OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16*
; NOT_CGSCC_OPM-NEXT: [[C2:%.*]] = bitcast i16* [[C1]] to i8*
; NOT_CGSCC_OPM-NEXT: call void @use_i8_internal(i8* noalias nocapture [[C2]])
; NOT_CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test13_use_noalias()
; IS__CGSCC_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS__CGSCC_OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16*
; IS__CGSCC_OPM-NEXT: [[C2:%.*]] = bitcast i16* [[C1]] to i8*
; IS__CGSCC_OPM-NEXT: call void @use_i8_internal(i8* noalias [[C2]])
; IS__CGSCC_OPM-NEXT: ret void
;
%m1 = tail call noalias i8* @malloc(i64 4)
%c1 = bitcast i8* %m1 to i16*
%c2 = bitcast i16* %c1 to i8*
; CHECK: call void @use_i8_internal(i8* noalias nocapture %c2)
call void @use_i8_internal(i8* %c2)
ret void
}
define void @test13_use_alias(){
; IS________OPM-LABEL: define {{[^@]+}}@test13_use_alias()
; IS________OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16*
; IS________OPM-NEXT: [[C2A:%.*]] = bitcast i16* [[C1]] to i8*
; IS________OPM-NEXT: [[C2B:%.*]] = bitcast i16* [[C1]] to i8*
; IS________OPM-NEXT: call void @use_i8_internal(i8* [[C2A]])
; IS________OPM-NEXT: call void @use_i8_internal(i8* [[C2B]])
; IS________OPM-NEXT: ret void
;
; IS________NPM-LABEL: define {{[^@]+}}@test13_use_alias()
; IS________NPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4)
; IS________NPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16*
; IS________NPM-NEXT: [[C2A:%.*]] = bitcast i16* [[C1]] to i8*
; IS________NPM-NEXT: [[C2B:%.*]] = bitcast i16* [[C1]] to i8*
; IS________NPM-NEXT: call void @use_i8_internal(i8* nocapture [[C2A]])
; IS________NPM-NEXT: call void @use_i8_internal(i8* nocapture [[C2B]])
; IS________NPM-NEXT: ret void
;
%m1 = tail call noalias i8* @malloc(i64 4)
%c1 = bitcast i8* %m1 to i16*
%c2a = bitcast i16* %c1 to i8*
%c2b = bitcast i16* %c1 to i8*
; CHECK: call void @use_i8_internal(i8* nocapture %c2a)
; CHECK: call void @use_i8_internal(i8* nocapture %c2b)
call void @use_i8_internal(i8* %c2a)
call void @use_i8_internal(i8* %c2b)
ret void
@ -330,11 +517,37 @@ define void @test13_use_alias(){
; TEST 14 i2p casts
define internal i32 @p2i(i32* %arg) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@p2i
; IS__TUNIT____-SAME: (i32* noalias nofree readnone [[ARG:%.*]])
; IS__TUNIT____-NEXT: [[P2I:%.*]] = ptrtoint i32* [[ARG]] to i32
; IS__TUNIT____-NEXT: ret i32 [[P2I]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@p2i
; IS__CGSCC____-SAME: (i32* nofree readnone [[ARG:%.*]])
; IS__CGSCC____-NEXT: [[P2I:%.*]] = ptrtoint i32* [[ARG]] to i32
; IS__CGSCC____-NEXT: ret i32 [[P2I]]
;
%p2i = ptrtoint i32* %arg to i32
ret i32 %p2i
}
define i32 @i2p(i32* %arg) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@i2p
; IS__TUNIT____-SAME: (i32* nofree readonly [[ARG:%.*]])
; IS__TUNIT____-NEXT: [[C:%.*]] = call i32 @p2i(i32* noalias nofree readnone [[ARG]])
; IS__TUNIT____-NEXT: [[I2P:%.*]] = inttoptr i32 [[C]] to i8*
; IS__TUNIT____-NEXT: [[BC:%.*]] = bitcast i8* [[I2P]] to i32*
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @ret(i32* nofree readonly align 4 [[BC]])
; IS__TUNIT____-NEXT: ret i32 [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@i2p
; IS__CGSCC____-SAME: (i32* nofree readonly [[ARG:%.*]])
; IS__CGSCC____-NEXT: [[C:%.*]] = call i32 @p2i(i32* noalias nofree readnone [[ARG]])
; IS__CGSCC____-NEXT: [[I2P:%.*]] = inttoptr i32 [[C]] to i8*
; IS__CGSCC____-NEXT: [[BC:%.*]] = bitcast i8* [[I2P]] to i32*
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @ret(i32* nofree nonnull readonly align 4 dereferenceable(4) [[BC]])
; IS__CGSCC____-NEXT: ret i32 [[CALL]]
;
%c = call i32 @p2i(i32* %arg)
%i2p = inttoptr i32 %c to i8*
%bc = bitcast i8* %i2p to i32*
@ -342,6 +555,11 @@ define i32 @i2p(i32* %arg) {
ret i32 %call
}
define internal i32 @ret(i32* %arg) {
; CHECK-LABEL: define {{[^@]+}}@ret
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]])
; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[ARG]], align 4
; CHECK-NEXT: ret i32 [[L]]
;
%l = load i32, i32* %arg
ret i32 %l
}
@ -355,8 +573,31 @@ define internal i32 @ret(i32* %arg) {
%struct.__locale_map = type opaque
; Function Attrs: nounwind optsize
; CHECK: define internal fastcc double @strtox(i8* noalias %s) unnamed_addr
define internal fastcc double @strtox(i8* %s, i8** %p, i32 %prec) unnamed_addr {
; IS__TUNIT____-LABEL: define {{[^@]+}}@strtox
; IS__TUNIT____-SAME: (i8* noalias [[S:%.*]]) unnamed_addr
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[F:%.*]] = alloca [[STRUCT__IO_FILE:%.*]], align 8
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = bitcast %struct._IO_FILE* [[F]] to i8*
; IS__TUNIT____-NEXT: call void @llvm.lifetime.start.p0i8(i64 144, i8* nonnull align 8 dereferenceable(240) [[TMP0]])
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 bitcast (i32 (...)* @sh_fromstring to i32 (%struct._IO_FILE*, i8*)*)(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i8* [[S]])
; IS__TUNIT____-NEXT: call void @__shlim(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i64 0)
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call double @__floatscan(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i32 1, i32 1)
; IS__TUNIT____-NEXT: call void @llvm.lifetime.end.p0i8(i64 144, i8* nonnull align 8 dereferenceable(240) [[TMP0]])
; IS__TUNIT____-NEXT: ret double [[CALL1]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@strtox
; IS__CGSCC____-SAME: (i8* [[S:%.*]]) unnamed_addr
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[F:%.*]] = alloca [[STRUCT__IO_FILE:%.*]], align 8
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = bitcast %struct._IO_FILE* [[F]] to i8*
; IS__CGSCC____-NEXT: call void @llvm.lifetime.start.p0i8(i64 144, i8* nonnull align 8 dereferenceable(240) [[TMP0]])
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 bitcast (i32 (...)* @sh_fromstring to i32 (%struct._IO_FILE*, i8*)*)(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i8* [[S]])
; IS__CGSCC____-NEXT: call void @__shlim(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i64 0)
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call double @__floatscan(%struct._IO_FILE* nonnull align 8 dereferenceable(240) [[F]], i32 1, i32 1)
; IS__CGSCC____-NEXT: call void @llvm.lifetime.end.p0i8(i64 144, i8* nonnull align 8 dereferenceable(240) [[TMP0]])
; IS__CGSCC____-NEXT: ret double [[CALL1]]
;
entry:
%f = alloca %struct._IO_FILE, align 8
%0 = bitcast %struct._IO_FILE* %f to i8*
@ -371,8 +612,13 @@ entry:
; Function Attrs: nounwind optsize
define dso_local double @strtod(i8* noalias %s, i8** noalias %p) {
; CHECK-LABEL: define {{[^@]+}}@strtod
; CHECK-SAME: (i8* noalias [[S:%.*]], i8** noalias nocapture nofree readnone [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = tail call fastcc double @strtox(i8* noalias [[S]])
; CHECK-NEXT: ret double [[CALL]]
;
entry:
; CHECK: %call = tail call fastcc double @strtox(i8* noalias %s)
%call = tail call fastcc double @strtox(i8* %s, i8** %p, i32 1)
ret double %call
}
@ -393,27 +639,56 @@ declare dso_local double @__floatscan(%struct._IO_FILE*, i32, i32) local_unnamed
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
; Test 15
; propagate noalias to some callsite arguments that there is no possibly reachable capture before it
; propagate noalias to some callsite arguments that there is no possibly reachable capture before it
@alias_of_p = external global i32*
define void @make_alias(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@make_alias
; CHECK-SAME: (i32* nofree writeonly [[P:%.*]])
; CHECK-NEXT: store i32* [[P]], i32** @alias_of_p, align 8
; CHECK-NEXT: ret void
;
store i32* %p, i32** @alias_of_p
ret void
}
define void @only_store(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@only_store
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P:%.*]])
; CHECK-NEXT: store i32 0, i32* [[P]], align 4
; CHECK-NEXT: ret void
;
store i32 0, i32* %p
ret void
}
; CHECK-LABEL: define void @test15_caller(i32* noalias nofree writeonly %p, i32 %c)
define void @test15_caller(i32* noalias %p, i32 %c) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@test15_caller
; IS__TUNIT____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]])
; IS__TUNIT____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0
; IS__TUNIT____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]])
; IS__TUNIT____-NEXT: br label [[IF_END]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test15_caller
; IS__CGSCC____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C:%.*]])
; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0
; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: tail call void @only_store(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: br label [[IF_END]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]])
; IS__CGSCC____-NEXT: ret void
;
%tobool = icmp eq i32 %c, 0
br i1 %tobool, label %if.end, label %if.then
; CHECK: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 %p)
; CHECK: tail call void @make_alias(i32* nofree writeonly %p)
if.then:
tail call void @only_store(i32* %p)
@ -438,26 +713,58 @@ if.end:
; void test16_caller(int * restrict p, int c) {
; test16_sub(p, c, c);
; }
;
; FIXME: this should be tail @only_store(i32* noalias %p)
; when test16_caller is called, c1 always equals to c2. (Note that linkage is internal)
; Therefore, only one of the two conditions of if statementes will be fulfilled.
; CHECK-LABEL: define internal void @test16_sub(i32* noalias nofree writeonly %p, i32 %c1, i32 %c2)
define internal void @test16_sub(i32* noalias %p, i32 %c1, i32 %c2) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@test16_sub
; IS__TUNIT____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C1:%.*]], i32 [[C2:%.*]])
; IS__TUNIT____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0
; IS__TUNIT____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]])
; IS__TUNIT____-NEXT: tail call void @make_alias(i32* nofree writeonly align 4 [[P]])
; IS__TUNIT____-NEXT: br label [[IF_END]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C2]], 0
; IS__TUNIT____-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
; IS__TUNIT____: if.then2:
; IS__TUNIT____-NEXT: tail call void @only_store(i32* nofree writeonly align 4 [[P]])
; IS__TUNIT____-NEXT: br label [[IF_END3]]
; IS__TUNIT____: if.end3:
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test16_sub
; IS__CGSCC____-SAME: (i32* noalias nofree writeonly [[P:%.*]], i32 [[C1:%.*]], i32 [[C2:%.*]])
; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0
; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: tail call void @only_store(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: tail call void @make_alias(i32* nofree nonnull writeonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: br label [[IF_END]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[C2]], 0
; IS__CGSCC____-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
; IS__CGSCC____: if.then2:
; IS__CGSCC____-NEXT: tail call void @only_store(i32* nofree nonnull writeonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: br label [[IF_END3]]
; IS__CGSCC____: if.end3:
; IS__CGSCC____-NEXT: ret void
;
%tobool = icmp eq i32 %c1, 0
br i1 %tobool, label %if.end, label %if.then
; CHECK: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 %p)
if.then:
tail call void @only_store(i32* %p)
tail call void @make_alias(i32* %p)
tail call void @only_store(i32* %p)
tail call void @make_alias(i32* %p)
br label %if.end
if.end:
%tobool1 = icmp eq i32 %c2, 0
br i1 %tobool1, label %if.then2, label %if.end3
; FIXME: this should be tail @only_store(i32* noalias %p)
; when test16_caller is called, c1 always equals to c2. (Note that linkage is internal)
; Therefore, only one of the two conditions of if statementes will be fulfilled.
; CHECK: tail call void @only_store(i32* nofree writeonly align 4 %p)
if.then2:
tail call void @only_store(i32* %p)
br label %if.end3
@ -467,6 +774,11 @@ if.end3:
}
define void @test16_caller(i32* %p, i32 %c) {
; CHECK-LABEL: define {{[^@]+}}@test16_caller
; CHECK-SAME: (i32* nofree writeonly [[P:%.*]], i32 [[C:%.*]])
; CHECK-NEXT: tail call void @test16_sub(i32* noalias nofree writeonly [[P]], i32 [[C]], i32 [[C]])
; CHECK-NEXT: ret void
;
tail call void @test16_sub(i32* %p, i32 %c, i32 %c)
ret void
}

View File

@ -1,166 +1,297 @@
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -S -attributor-annotate-decl-cs < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
; Copied from Transforms/FunctoinAttrs/nocapture.ll
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@g = global i32* null ; <i32**> [#uses=1]
; ATTRIBUTOR: define i32* @c1(i32* nofree readnone returned "no-capture-maybe-returned" %q)
define i32* @c1(i32* %q) {
ret i32* %q
; CHECK-LABEL: define {{[^@]+}}@c1
; CHECK-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[Q:%.*]])
; CHECK-NEXT: ret i32* [[Q]]
;
ret i32* %q
}
; ATTRIBUTOR: define void @c2(i32* nofree writeonly %q)
; It would also be acceptable to mark %q as readnone. Update @c3 too.
define void @c2(i32* %q) {
store i32* %q, i32** @g
ret void
; CHECK-LABEL: define {{[^@]+}}@c2
; CHECK-SAME: (i32* nofree writeonly [[Q:%.*]])
; CHECK-NEXT: store i32* [[Q]], i32** @g, align 8
; CHECK-NEXT: ret void
;
store i32* %q, i32** @g
ret void
}
; ATTRIBUTOR: define void @c3(i32* nofree writeonly %q)
define void @c3(i32* %q) {
call void @c2(i32* %q)
ret void
; CHECK-LABEL: define {{[^@]+}}@c3
; CHECK-SAME: (i32* nofree writeonly [[Q:%.*]])
; CHECK-NEXT: call void @c2(i32* nofree writeonly [[Q]])
; CHECK-NEXT: ret void
;
call void @c2(i32* %q)
ret void
}
; ATTRIBUTOR: define i1 @c4(i32* nofree readnone %q, i32 %bitno)
define i1 @c4(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = trunc i32 %tmp2 to i1
br i1 %bit, label %l1, label %l0
; CHECK-LABEL: define {{[^@]+}}@c4
; CHECK-SAME: (i32* nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]])
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint i32* [[Q]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
; CHECK-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
; CHECK: l0:
; CHECK-NEXT: ret i1 false
; CHECK: l1:
; CHECK-NEXT: ret i1 true
;
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = trunc i32 %tmp2 to i1
br i1 %bit, label %l1, label %l0
l0:
ret i1 0 ; escaping value not caught by def-use chaining.
ret i1 0 ; escaping value not caught by def-use chaining.
l1:
ret i1 1 ; escaping value not caught by def-use chaining.
ret i1 1 ; escaping value not caught by def-use chaining.
}
; c4b is c4 but without the escaping part
; ATTRIBUTOR: define i1 @c4b(i32* nocapture nofree readnone %q, i32 %bitno)
define i1 @c4b(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = trunc i32 %tmp2 to i1
br i1 %bit, label %l1, label %l0
; CHECK-LABEL: define {{[^@]+}}@c4b
; CHECK-SAME: (i32* nocapture nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]])
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint i32* [[Q]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
; CHECK-NEXT: [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
; CHECK-NEXT: br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
; CHECK: l0:
; CHECK-NEXT: ret i1 false
; CHECK: l1:
; CHECK-NEXT: ret i1 false
;
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = trunc i32 %tmp2 to i1
br i1 %bit, label %l1, label %l0
l0:
ret i1 0 ; not escaping!
ret i1 0 ; not escaping!
l1:
ret i1 0 ; not escaping!
ret i1 0 ; not escaping!
}
@lookup_table = global [2 x i1] [ i1 0, i1 1 ]
; ATTRIBUTOR: define i1 @c5(i32* nofree readonly %q, i32 %bitno)
define i1 @c5(i32* %q, i32 %bitno) {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = and i32 %tmp2, 1
; subtle escape mechanism follows
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
%val = load i1, i1* %lookup
ret i1 %val
; CHECK-LABEL: define {{[^@]+}}@c5
; CHECK-SAME: (i32* nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]])
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint i32* [[Q]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
; CHECK-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1
; CHECK-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 [[BIT]]
; CHECK-NEXT: [[VAL:%.*]] = load i1, i1* [[LOOKUP]]
; CHECK-NEXT: ret i1 [[VAL]]
;
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = and i32 %tmp2, 1
; subtle escape mechanism follows
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
%val = load i1, i1* %lookup
ret i1 %val
}
declare void @throw_if_bit_set(i8*, i8) readonly
; ATTRIBUTOR: define i1 @c6(i8* readonly %q, i8 %bit)
define i1 @c6(i8* %q, i8 %bit) personality i32 (...)* @__gxx_personality_v0 {
invoke void @throw_if_bit_set(i8* %q, i8 %bit)
to label %ret0 unwind label %ret1
; IS__TUNIT____-LABEL: define {{[^@]+}}@c6
; IS__TUNIT____-SAME: (i8* readonly [[Q:%.*]], i8 [[BIT:%.*]]) #5 personality i32 (...)* @__gxx_personality_v0
; IS__TUNIT____-NEXT: invoke void @throw_if_bit_set(i8* readonly [[Q]], i8 [[BIT]])
; IS__TUNIT____-NEXT: to label [[RET0:%.*]] unwind label [[RET1:%.*]]
; IS__TUNIT____: ret0:
; IS__TUNIT____-NEXT: ret i1 false
; IS__TUNIT____: ret1:
; IS__TUNIT____-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 }
; IS__TUNIT____-NEXT: cleanup
; IS__TUNIT____-NEXT: ret i1 true
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@c6
; IS__CGSCC____-SAME: (i8* readonly [[Q:%.*]], i8 [[BIT:%.*]]) #4 personality i32 (...)* @__gxx_personality_v0
; IS__CGSCC____-NEXT: invoke void @throw_if_bit_set(i8* readonly [[Q]], i8 [[BIT]])
; IS__CGSCC____-NEXT: to label [[RET0:%.*]] unwind label [[RET1:%.*]]
; IS__CGSCC____: ret0:
; IS__CGSCC____-NEXT: ret i1 false
; IS__CGSCC____: ret1:
; IS__CGSCC____-NEXT: [[EXN:%.*]] = landingpad { i8*, i32 }
; IS__CGSCC____-NEXT: cleanup
; IS__CGSCC____-NEXT: ret i1 true
;
invoke void @throw_if_bit_set(i8* %q, i8 %bit)
to label %ret0 unwind label %ret1
ret0:
ret i1 0
ret i1 0
ret1:
%exn = landingpad {i8*, i32}
cleanup
ret i1 1
%exn = landingpad {i8*, i32}
cleanup
ret i1 1
}
declare i32 @__gxx_personality_v0(...)
define i1* @lookup_bit(i32* %q, i32 %bitno) readnone nounwind {
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = and i32 %tmp2, 1
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
ret i1* %lookup
; CHECK-LABEL: define {{[^@]+}}@lookup_bit
; CHECK-SAME: (i32* nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]])
; CHECK-NEXT: [[TMP:%.*]] = ptrtoint i32* [[Q]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
; CHECK-NEXT: [[BIT:%.*]] = and i32 [[TMP2]], 1
; CHECK-NEXT: [[LOOKUP:%.*]] = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 [[BIT]]
; CHECK-NEXT: ret i1* [[LOOKUP]]
;
%tmp = ptrtoint i32* %q to i32
%tmp2 = lshr i32 %tmp, %bitno
%bit = and i32 %tmp2, 1
%lookup = getelementptr [2 x i1], [2 x i1]* @lookup_table, i32 0, i32 %bit
ret i1* %lookup
}
; ATTRIBUTOR: define i1 @c7(i32* nofree readonly %q, i32 %bitno)
define i1 @c7(i32* %q, i32 %bitno) {
%ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
%val = load i1, i1* %ptr
ret i1 %val
; CHECK-LABEL: define {{[^@]+}}@c7
; CHECK-SAME: (i32* nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]])
; CHECK-NEXT: [[PTR:%.*]] = call i1* @lookup_bit(i32* noalias nofree readnone [[Q]], i32 [[BITNO]])
; CHECK-NEXT: [[VAL:%.*]] = load i1, i1* [[PTR]]
; CHECK-NEXT: ret i1 [[VAL]]
;
%ptr = call i1* @lookup_bit(i32* %q, i32 %bitno)
%val = load i1, i1* %ptr
ret i1 %val
}
; ATTRIBUTOR: define i32 @nc1(i32* nofree %q, i32* nocapture nofree %p, i1 %b)
define i32 @nc1(i32* %q, i32* %p, i1 %b) {
; CHECK-LABEL: define {{[^@]+}}@nc1
; CHECK-SAME: (i32* nofree [[Q:%.*]], i32* nocapture nofree [[P:%.*]], i1 [[B:%.*]])
; CHECK-NEXT: e:
; CHECK-NEXT: br label [[L:%.*]]
; CHECK: l:
; CHECK-NEXT: [[X:%.*]] = phi i32* [ [[P]], [[E:%.*]] ]
; CHECK-NEXT: [[Y:%.*]] = phi i32* [ [[Q]], [[E]] ]
; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[X]] to i32*
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[B]], i32* [[TMP]], i32* [[Y]]
; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[TMP2]], align 4
; CHECK-NEXT: store i32 0, i32* [[TMP]], align 4
; CHECK-NEXT: store i32* [[Y]], i32** @g, align 8
; CHECK-NEXT: ret i32 [[VAL]]
;
e:
br label %l
br label %l
l:
%x = phi i32* [ %p, %e ]
%y = phi i32* [ %q, %e ]
%tmp = bitcast i32* %x to i32* ; <i32*> [#uses=2]
%tmp2 = select i1 %b, i32* %tmp, i32* %y
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
store i32 0, i32* %tmp
store i32* %y, i32** @g
ret i32 %val
%x = phi i32* [ %p, %e ]
%y = phi i32* [ %q, %e ]
%tmp = bitcast i32* %x to i32* ; <i32*> [#uses=2]
%tmp2 = select i1 %b, i32* %tmp, i32* %y
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
store i32 0, i32* %tmp
store i32* %y, i32** @g
ret i32 %val
}
; ATTRIBUTOR: define i32 @nc1_addrspace(i32* nofree %q, i32 addrspace(1)* nocapture nofree %p, i1 %b)
define i32 @nc1_addrspace(i32* %q, i32 addrspace(1)* %p, i1 %b) {
; CHECK-LABEL: define {{[^@]+}}@nc1_addrspace
; CHECK-SAME: (i32* nofree [[Q:%.*]], i32 addrspace(1)* nocapture nofree [[P:%.*]], i1 [[B:%.*]])
; CHECK-NEXT: e:
; CHECK-NEXT: br label [[L:%.*]]
; CHECK: l:
; CHECK-NEXT: [[X:%.*]] = phi i32 addrspace(1)* [ [[P]], [[E:%.*]] ]
; CHECK-NEXT: [[Y:%.*]] = phi i32* [ [[Q]], [[E]] ]
; CHECK-NEXT: [[TMP:%.*]] = addrspacecast i32 addrspace(1)* [[X]] to i32*
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[B]], i32* [[TMP]], i32* [[Y]]
; CHECK-NEXT: [[VAL:%.*]] = load i32, i32* [[TMP2]], align 4
; CHECK-NEXT: store i32 0, i32* [[TMP]], align 4
; CHECK-NEXT: store i32* [[Y]], i32** @g, align 8
; CHECK-NEXT: ret i32 [[VAL]]
;
e:
br label %l
br label %l
l:
%x = phi i32 addrspace(1)* [ %p, %e ]
%y = phi i32* [ %q, %e ]
%tmp = addrspacecast i32 addrspace(1)* %x to i32* ; <i32*> [#uses=2]
%tmp2 = select i1 %b, i32* %tmp, i32* %y
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
store i32 0, i32* %tmp
store i32* %y, i32** @g
ret i32 %val
%x = phi i32 addrspace(1)* [ %p, %e ]
%y = phi i32* [ %q, %e ]
%tmp = addrspacecast i32 addrspace(1)* %x to i32* ; <i32*> [#uses=2]
%tmp2 = select i1 %b, i32* %tmp, i32* %y
%val = load i32, i32* %tmp2 ; <i32> [#uses=1]
store i32 0, i32* %tmp
store i32* %y, i32** @g
ret i32 %val
}
; ATTRIBUTOR: define void @nc2(i32* nocapture nofree %p, i32* nofree %q)
define void @nc2(i32* %p, i32* %q) {
%1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
ret void
; CHECK-LABEL: define {{[^@]+}}@nc2
; CHECK-SAME: (i32* nocapture nofree [[P:%.*]], i32* nofree [[Q:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @nc1(i32* nofree [[Q]], i32* nocapture nofree [[P]], i1 false)
; CHECK-NEXT: ret void
;
%1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
ret void
}
; ATTRIBUTOR: define void @nc3(void ()* nocapture nofree nonnull %p)
define void @nc3(void ()* %p) {
call void %p()
ret void
; CHECK-LABEL: define {{[^@]+}}@nc3
; CHECK-SAME: (void ()* nocapture nofree nonnull [[P:%.*]])
; CHECK-NEXT: call void [[P]]()
; CHECK-NEXT: ret void
;
call void %p()
ret void
}
; The following test is tricky because improvements to AAIsDead can cause the call to be removed.
; FIXME: readonly and nocapture missing on the pointer.
declare void @external(i8* readonly) nounwind argmemonly
; ATTRIBUTOR: define void @nc4(i8* %p)
define void @nc4(i8* %p) {
call void @external(i8* %p)
ret void
; CHECK-LABEL: define {{[^@]+}}@nc4
; CHECK-SAME: (i8* [[P:%.*]])
; CHECK-NEXT: call void @external(i8* readonly [[P]])
; CHECK-NEXT: ret void
;
call void @external(i8* %p)
ret void
}
; ATTRIBUTOR: define void @nc5(void (i8*)* nocapture nofree nonnull %f, i8* nocapture %p)
define void @nc5(void (i8*)* %f, i8* %p) {
call void %f(i8* %p) readonly nounwind
call void %f(i8* nocapture %p)
ret void
; CHECK-LABEL: define {{[^@]+}}@nc5
; CHECK-SAME: (void (i8*)* nocapture nofree nonnull [[F:%.*]], i8* nocapture [[P:%.*]])
; CHECK-NEXT: call void [[F]](i8* nocapture [[P]])
; CHECK-NEXT: ret void
;
call void %f(i8* %p) readonly nounwind
call void %f(i8* nocapture %p)
ret void
}
; ATTRIBUTOR: define void @test1_1(i8* nocapture nofree readnone %x1_1, i8* nocapture nofree readnone %y1_1, i1 %c)
; It would be acceptable to add readnone to %y1_1 and %y1_2.
define void @test1_1(i8* %x1_1, i8* %y1_1, i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test1_1
; CHECK-SAME: (i8* nocapture nofree readnone [[X1_1:%.*]], i8* nocapture nofree readnone [[Y1_1:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @test1_2(i8* noalias nofree readnone undef, i8* noalias nofree readnone "no-capture-maybe-returned" [[Y1_1]], i1 [[C]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: ret void
;
call i8* @test1_2(i8* %x1_1, i8* %y1_1, i1 %c)
store i32* null, i32** @g
ret void
}
; ATTRIBUTOR: define i8* @test1_2(i8* nocapture nofree readnone %x1_2, i8* nofree readnone returned "no-capture-maybe-returned" %y1_2, i1 %c)
define i8* @test1_2(i8* %x1_2, i8* %y1_2, i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test1_2
; CHECK-SAME: (i8* nocapture nofree readnone [[X1_2:%.*]], i8* nofree readnone returned "no-capture-maybe-returned" [[Y1_2:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: call void @test1_1(i8* noalias nofree readnone undef, i8* noalias nocapture nofree readnone [[Y1_2]], i1 [[C]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: br label [[F]]
; CHECK: f:
; CHECK-NEXT: ret i8* [[Y1_2]]
;
br i1 %c, label %t, label %f
t:
call void @test1_1(i8* %x1_2, i8* %y1_2, i1 %c)
@ -170,29 +301,49 @@ f:
ret i8* %y1_2
}
; ATTRIBUTOR: define void @test2(i8* nocapture nofree readnone %x2)
define void @test2(i8* %x2) {
; CHECK-LABEL: define {{[^@]+}}@test2
; CHECK-SAME: (i8* nocapture nofree readnone [[X2:%.*]])
; CHECK-NEXT: unreachable
;
call void @test2(i8* %x2)
store i32* null, i32** @g
ret void
}
; ATTRIBUTOR: define void @test3(i8* nocapture nofree readnone %x3, i8* nocapture nofree readnone %y3, i8* nocapture nofree readnone %z3)
define void @test3(i8* %x3, i8* %y3, i8* %z3) {
; CHECK-LABEL: define {{[^@]+}}@test3
; CHECK-SAME: (i8* nocapture nofree readnone [[X3:%.*]], i8* nocapture nofree readnone [[Y3:%.*]], i8* nocapture nofree readnone [[Z3:%.*]])
; CHECK-NEXT: unreachable
;
call void @test3(i8* %z3, i8* %y3, i8* %x3)
store i32* null, i32** @g
ret void
}
; ATTRIBUTOR: define void @test4_1(i8* nocapture nofree readnone %x4_1, i1 %c)
define void @test4_1(i8* %x4_1, i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test4_1
; CHECK-SAME: (i8* nocapture nofree readnone [[X4_1:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @test4_2(i8* noalias nofree readnone undef, i8* noalias nofree readnone "no-capture-maybe-returned" [[X4_1]], i8* noalias nofree readnone undef, i1 [[C]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: ret void
;
call i8* @test4_2(i8* %x4_1, i8* %x4_1, i8* %x4_1, i1 %c)
store i32* null, i32** @g
ret void
}
; ATTRIBUTOR: define i8* @test4_2(i8* nocapture nofree readnone %x4_2, i8* nofree readnone returned "no-capture-maybe-returned" %y4_2, i8* nocapture nofree readnone %z4_2, i1 %c)
define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2, i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test4_2
; CHECK-SAME: (i8* nocapture nofree readnone [[X4_2:%.*]], i8* nofree readnone returned "no-capture-maybe-returned" [[Y4_2:%.*]], i8* nocapture nofree readnone [[Z4_2:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: call void @test4_1(i8* noalias nofree readnone align 536870912 null, i1 [[C]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: br label [[F]]
; CHECK: f:
; CHECK-NEXT: ret i8* [[Y4_2]]
;
br i1 %c, label %t, label %f
t:
call void @test4_1(i8* null, i1 %c)
@ -204,8 +355,13 @@ f:
declare i8* @test5_1(i8* %x5_1)
; ATTRIBUTOR: define void @test5_2(i8* %x5_2)
define void @test5_2(i8* %x5_2) {
; CHECK-LABEL: define {{[^@]+}}@test5_2
; CHECK-SAME: (i8* [[X5_2:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8* @test5_1(i8* [[X5_2]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: ret void
;
call i8* @test5_1(i8* %x5_2)
store i32* null, i32** @g
ret void
@ -213,41 +369,70 @@ define void @test5_2(i8* %x5_2) {
declare void @test6_1(i8* %x6_1, i8* nocapture %y6_1, ...)
; ATTRIBUTOR: define void @test6_2(i8* %x6_2, i8* nocapture %y6_2, i8* %z6_2)
define void @test6_2(i8* %x6_2, i8* %y6_2, i8* %z6_2) {
; CHECK-LABEL: define {{[^@]+}}@test6_2
; CHECK-SAME: (i8* [[X6_2:%.*]], i8* nocapture [[Y6_2:%.*]], i8* [[Z6_2:%.*]])
; CHECK-NEXT: call void (i8*, i8*, ...) @test6_1(i8* [[X6_2]], i8* nocapture [[Y6_2]], i8* [[Z6_2]])
; CHECK-NEXT: store i32* null, i32** @g, align 8
; CHECK-NEXT: ret void
;
call void (i8*, i8*, ...) @test6_1(i8* %x6_2, i8* %y6_2, i8* %z6_2)
store i32* null, i32** @g
ret void
}
; ATTRIBUTOR: define void @test_cmpxchg(i32* nocapture nofree nonnull dereferenceable(4) %p)
define void @test_cmpxchg(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@test_cmpxchg
; CHECK-SAME: (i32* nocapture nofree nonnull dereferenceable(4) [[P:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = cmpxchg i32* [[P]], i32 0, i32 1 acquire monotonic
; CHECK-NEXT: ret void
;
cmpxchg i32* %p, i32 0, i32 1 acquire monotonic
ret void
}
; ATTRIBUTOR: define void @test_cmpxchg_ptr(i32** nocapture nofree nonnull dereferenceable(8) %p, i32* nofree %q)
define void @test_cmpxchg_ptr(i32** %p, i32* %q) {
; CHECK-LABEL: define {{[^@]+}}@test_cmpxchg_ptr
; CHECK-SAME: (i32** nocapture nofree nonnull dereferenceable(8) [[P:%.*]], i32* nofree [[Q:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = cmpxchg i32** [[P]], i32* null, i32* [[Q]] acquire monotonic
; CHECK-NEXT: ret void
;
cmpxchg i32** %p, i32* null, i32* %q acquire monotonic
ret void
}
; ATTRIBUTOR: define void @test_atomicrmw(i32* nocapture nofree nonnull dereferenceable(4) %p)
define void @test_atomicrmw(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@test_atomicrmw
; CHECK-SAME: (i32* nocapture nofree nonnull dereferenceable(4) [[P:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add i32* [[P]], i32 1 seq_cst
; CHECK-NEXT: ret void
;
atomicrmw add i32* %p, i32 1 seq_cst
ret void
}
; ATTRIBUTOR: define void @test_volatile(i32* nofree align 4 %x)
define void @test_volatile(i32* %x) {
; CHECK-LABEL: define {{[^@]+}}@test_volatile
; CHECK-SAME: (i32* nofree align 4 [[X:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, i32* [[X]], i64 1
; CHECK-NEXT: store volatile i32 0, i32* [[GEP]], align 4
; CHECK-NEXT: ret void
;
entry:
%gep = getelementptr i32, i32* %x, i64 1
store volatile i32 0, i32* %gep, align 4
ret void
}
; ATTRIBUTOR: nocaptureLaunder(i8* nocapture %p)
define void @nocaptureLaunder(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@nocaptureLaunder
; CHECK-SAME: (i8* nocapture [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* [[P]])
; CHECK-NEXT: store i8 42, i8* [[B]]
; CHECK-NEXT: ret void
;
entry:
%b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
store i8 42, i8* %b
@ -255,15 +440,26 @@ entry:
}
@g2 = global i8* null
; ATTRIBUTOR: define void @captureLaunder(i8* %p)
define void @captureLaunder(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@captureLaunder
; CHECK-SAME: (i8* [[P:%.*]])
; CHECK-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* [[P]])
; CHECK-NEXT: store i8* [[B]], i8** @g2, align 8
; CHECK-NEXT: ret void
;
%b = call i8* @llvm.launder.invariant.group.p0i8(i8* %p)
store i8* %b, i8** @g2
ret void
}
; ATTRIBUTOR: @nocaptureStrip(i8* nocapture writeonly %p)
define void @nocaptureStrip(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@nocaptureStrip
; CHECK-SAME: (i8* nocapture writeonly [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias readnone [[P]])
; CHECK-NEXT: store i8 42, i8* [[B]]
; CHECK-NEXT: ret void
;
entry:
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
store i8 42, i8* %b
@ -271,74 +467,123 @@ entry:
}
@g3 = global i8* null
; ATTRIBUTOR: define void @captureStrip(i8* writeonly %p)
define void @captureStrip(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@captureStrip
; CHECK-SAME: (i8* writeonly [[P:%.*]])
; CHECK-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias readnone [[P]])
; CHECK-NEXT: store i8* [[B]], i8** @g3, align 8
; CHECK-NEXT: ret void
;
%b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
store i8* %b, i8** @g3
ret void
}
; ATTRIBUTOR: define i1 @captureICmp(i32* nofree readnone %x)
define i1 @captureICmp(i32* %x) {
; CHECK-LABEL: define {{[^@]+}}@captureICmp
; CHECK-SAME: (i32* nofree readnone [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32* [[X]], null
; CHECK-NEXT: ret i1 [[TMP1]]
;
%1 = icmp eq i32* %x, null
ret i1 %1
}
; ATTRIBUTOR: define i1 @captureICmpRev(i32* nofree readnone %x)
define i1 @captureICmpRev(i32* %x) {
; CHECK-LABEL: define {{[^@]+}}@captureICmpRev
; CHECK-SAME: (i32* nofree readnone [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32* null, [[X]]
; CHECK-NEXT: ret i1 [[TMP1]]
;
%1 = icmp eq i32* null, %x
ret i1 %1
}
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmp(i32* nocapture nofree readnone %x)
define i1 @nocaptureInboundsGEPICmp(i32* %x) {
; CHECK-LABEL: define {{[^@]+}}@nocaptureInboundsGEPICmp
; CHECK-SAME: (i32* nocapture nofree readnone [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, i32* [[X]], i32 5
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32* [[TMP1]] to i8*
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8* [[TMP2]], null
; CHECK-NEXT: ret i1 [[TMP3]]
;
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* %2, null
ret i1 %3
}
; ATTRIBUTOR: define i1 @nocaptureInboundsGEPICmpRev(i32* nocapture nofree readnone %x)
define i1 @nocaptureInboundsGEPICmpRev(i32* %x) {
; CHECK-LABEL: define {{[^@]+}}@nocaptureInboundsGEPICmpRev
; CHECK-SAME: (i32* nocapture nofree readnone [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, i32* [[X]], i32 5
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32* [[TMP1]] to i8*
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8* null, [[TMP2]]
; CHECK-NEXT: ret i1 [[TMP3]]
;
%1 = getelementptr inbounds i32, i32* %x, i32 5
%2 = bitcast i32* %1 to i8*
%3 = icmp eq i8* null, %2
ret i1 %3
}
; ATTRIBUTOR: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture nofree readnone dereferenceable_or_null(4) %x)
define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) {
; CHECK-LABEL: define {{[^@]+}}@nocaptureDereferenceableOrNullICmp
; CHECK-SAME: (i32* nocapture nofree readnone dereferenceable_or_null(4) [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[X]] to i8*
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP1]], null
; CHECK-NEXT: ret i1 [[TMP2]]
;
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1, null
ret i1 %2
}
; ATTRIBUTOR: define i1 @captureDereferenceableOrNullICmp(i32* nofree readnone dereferenceable_or_null(4) %x)
define i1 @captureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) "null-pointer-is-valid"="true" {
; CHECK-LABEL: define {{[^@]+}}@captureDereferenceableOrNullICmp
; CHECK-SAME: (i32* nofree readnone dereferenceable_or_null(4) [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[X]] to i8*
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP1]], null
; CHECK-NEXT: ret i1 [[TMP2]]
;
%1 = bitcast i32* %x to i8*
%2 = icmp eq i8* %1, null
ret i1 %2
}
declare void @unknown(i8*)
define void @test_callsite() {
entry:
; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm.
; ATTRIBUTOR: call void @unknown(i8* noalias align 536870912 null)
define void @test_callsite() {
; CHECK-LABEL: define {{[^@]+}}@test_callsite()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @unknown(i8* noalias align 536870912 null)
; CHECK-NEXT: ret void
;
entry:
call void @unknown(i8* null)
ret void
}
declare i8* @unknownpi8pi8(i8*,i8* returned)
define i8* @test_returned1(i8* %A, i8* returned %B) nounwind readonly {
; ATTRIBUTOR: define i8* @test_returned1(i8* nocapture readonly %A, i8* readonly returned %B)
; CHECK-LABEL: define {{[^@]+}}@test_returned1
; CHECK-SAME: (i8* nocapture readonly [[A:%.*]], i8* readonly returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P:%.*]] = call i8* @unknownpi8pi8(i8* [[A]], i8* [[B]])
; CHECK-NEXT: ret i8* [[P]]
;
entry:
%p = call i8* @unknownpi8pi8(i8* %A, i8* %B)
ret i8* %p
}
define i8* @test_returned2(i8* %A, i8* %B) {
; ATTRIBUTOR: define i8* @test_returned2(i8* nocapture readonly %A, i8* readonly returned %B)
; CHECK-LABEL: define {{[^@]+}}@test_returned2
; CHECK-SAME: (i8* nocapture readonly [[A:%.*]], i8* readonly returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P:%.*]] = call i8* @unknownpi8pi8(i8* readonly [[A]], i8* readonly [[B]])
; CHECK-NEXT: ret i8* [[P]]
;
entry:
%p = call i8* @unknownpi8pi8(i8* %A, i8* %B) nounwind readonly
ret i8* %p
@ -350,7 +595,11 @@ declare void @val_use(i8 %ptr) readonly nounwind
; FIXME: Both pointers should be nocapture
define void @ptr_uses(i8* %ptr, i8* %wptr) {
; CHECK: define void @ptr_uses(i8* %ptr, i8* nocapture nonnull writeonly dereferenceable(1) %wptr)
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
; CHECK-SAME: (i8* [[PTR:%.*]], i8* nocapture nonnull writeonly dereferenceable(1) [[WPTR:%.*]])
; CHECK-NEXT: store i8 0, i8* [[WPTR]]
; CHECK-NEXT: ret void
;
%call_ptr = call i8* @maybe_returned_ptr(i8* %ptr)
%call_val = call i8 @maybe_returned_val(i8* %call_ptr)
call void @val_use(i8 %call_val)

View File

@ -1,9 +1,14 @@
; RUN: opt -functionattrs -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; Test cases specifically designed for the "no-capture" argument attribute.
; We use FIXME's to indicate problems and missing attributes.
;
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
declare i32* @unknown()
; TEST comparison against NULL
;
@ -11,9 +16,15 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; return p == 0;
; }
;
; FIXME: no-capture missing for %p
; CHECK: define i32 @is_null_return(i32* nofree readnone %p)
; no-capture is missing on %p because it is not dereferenceable
define i32 @is_null_return(i32* %p) #0 {
; CHECK-LABEL: define {{[^@]+}}@is_null_return
; CHECK-SAME: (i32* nofree readnone [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
; CHECK-NEXT: ret i32 [[CONV]]
;
entry:
%cmp = icmp eq i32* %p, null
%conv = zext i1 %cmp to i32
@ -30,9 +41,30 @@ entry:
; return 0;
; }
;
; FIXME: no-capture missing for %p
; CHECK: define i32 @is_null_control(i32* nofree readnone %p)
; no-capture is missing on %p because it is not dereferenceable
define i32 @is_null_control(i32* %p) #0 {
; CHECK-LABEL: define {{[^@]+}}@is_null_control
; CHECK-SAME: (i32* nofree [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: store i32 1, i32* [[RETVAL]], align 4
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32* null, [[P]]
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]]
; CHECK: if.then2:
; CHECK-NEXT: store i32 1, i32* [[RETVAL]], align 4
; CHECK-NEXT: br label [[RETURN]]
; CHECK: if.end3:
; CHECK-NEXT: store i32 0, i32* [[RETVAL]], align 4
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[RETVAL]], align 4
; CHECK-NEXT: ret i32 [[TMP0]]
;
entry:
%retval = alloca i32, align 4
%cmp = icmp eq i32* %p, null
@ -66,8 +98,12 @@ return: ; preds = %if.end3, %if.then2,
; return 0;
; }
;
; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) double* @srec0(double* nocapture nofree readnone %a)
define double* @srec0(double* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@srec0
; CHECK-SAME: (double* nocapture nofree readnone [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%call = call double* @srec0(double* %a)
ret double* null
@ -86,12 +122,14 @@ entry:
;
; Other arguments are possible here due to the no-return behavior.
;
; CHECK: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @srec16(i32* nocapture nofree readnone %a)
define i32* @srec16(i32* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@srec16
; CHECK-SAME: (i32* nocapture nofree readnone [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%call = call i32* @srec16(i32* %a)
; CHECK-NOT: %call
; CHECK: unreachable
%call1 = call i32* @srec16(i32* %call)
%call2 = call i32* @srec16(i32* %call1)
%call3 = call i32* @srec16(i32* %call2)
@ -112,12 +150,6 @@ entry:
; TEST SCC with various calls, casts, and comparisons agains NULL
;
; CHECK: define dereferenceable_or_null(4) float* @scc_A(i32* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a)
;
; CHECK: define dereferenceable_or_null(8) i64* @scc_B(double* nofree readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" %a)
;
; CHECK: define dereferenceable_or_null(4) i8* @scc_C(i16* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" %a)
;
; float *scc_A(int *a) {
; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a);
; }
@ -130,6 +162,27 @@ entry:
; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a)));
; }
define float* @scc_A(i32* dereferenceable_or_null(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@scc_A
; CHECK-SAME: (i32* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[A]], null
; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.true:
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[A]] to i16*
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[CALL]] to double*
; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i32*
; CHECK-NEXT: [[CALL2:%.*]] = call float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP2]])
; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL2]] to i32*
; CHECK-NEXT: br label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32* [ [[TMP3]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ]
; CHECK-NEXT: [[TMP4:%.*]] = bitcast i32* [[COND]] to float*
; CHECK-NEXT: ret float* [[TMP4]]
;
entry:
%tobool = icmp ne i32* %a, null
br i1 %tobool, label %cond.true, label %cond.false
@ -154,6 +207,27 @@ cond.end: ; preds = %cond.false, %cond.t
}
define i64* @scc_B(double* dereferenceable_or_null(8) %a) {
; CHECK-LABEL: define {{[^@]+}}@scc_B
; CHECK-SAME: (double* nofree readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne double* [[A]], null
; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.true:
; CHECK-NEXT: [[TMP0:%.*]] = bitcast double* [[A]] to i32*
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[CALL]] to double*
; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i16*
; CHECK-NEXT: [[CALL2:%.*]] = call i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP2]])
; CHECK-NEXT: br label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP3:%.*]] = bitcast double* [[A]] to i8*
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[CALL2]], [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ]
; CHECK-NEXT: [[TMP4:%.*]] = bitcast i8* [[COND]] to i64*
; CHECK-NEXT: ret i64* [[TMP4]]
;
entry:
%tobool = icmp ne double* %a, null
br i1 %tobool, label %cond.true, label %cond.false
@ -178,6 +252,29 @@ cond.end: ; preds = %cond.false, %cond.t
}
define i8* @scc_C(i16* dereferenceable_or_null(2) %a) {
; CHECK-LABEL: define {{[^@]+}}@scc_C
; CHECK-SAME: (i16* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC:%.*]] = bitcast i16* [[A]] to i32*
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[BC]])
; CHECK-NEXT: [[BC2:%.*]] = bitcast float* [[CALL]] to i8*
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[BC2]], null
; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.true:
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i16* [[A]] to double*
; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64* [[CALL1]] to i8*
; CHECK-NEXT: br label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]])
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[TMP1]], [[COND_TRUE]] ], [ [[CALL2]], [[COND_FALSE]] ]
; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[COND]] to i32*
; CHECK-NEXT: [[CALL3:%.*]] = call float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP2]])
; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL3]] to i8*
; CHECK-NEXT: ret i8* [[TMP3]]
;
entry:
%bc = bitcast i16* %a to i32*
%call = call float* @scc_A(i32* %bc)
@ -211,10 +308,15 @@ cond.end: ; preds = %cond.false, %cond.t
; external_no_capture(p);
; }
;
; CHECK: define void @test_external_no_capture(i32* nocapture %p)
declare void @external_no_capture(i32* nocapture)
define void @test_external_no_capture(i32* %p) #0 {
; CHECK-LABEL: define {{[^@]+}}@test_external_no_capture
; CHECK-SAME: (i32* nocapture [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @external_no_capture(i32* nocapture [[P]])
; CHECK-NEXT: ret void
;
entry:
call void @external_no_capture(i32* %p)
ret void
@ -226,8 +328,13 @@ entry:
; printf(p, a);
; }
;
; CHECK: define void @test_var_arg_call(i8* nocapture %p, i32 %a)
define void @test_var_arg_call(i8* %p, i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@test_var_arg_call
; CHECK-SAME: (i8* nocapture [[P:%.*]], i32 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 (i8*, ...) @printf(i8* nocapture [[P]], i32 [[A]])
; CHECK-NEXT: ret void
;
entry:
%call = call i32 (i8*, ...) @printf(i8* %p, i32 %a)
ret void
@ -244,9 +351,13 @@ declare i32 @printf(i8* nocapture, ...)
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_0(i64* nofree nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" %a)
define i64* @not_captured_but_returned_0(i64* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@not_captured_but_returned_0
; CHECK-SAME: (i64* nofree nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: store i64 0, i64* [[A]], align 8
; CHECK-NEXT: ret i64* [[A]]
;
entry:
store i64 0, i64* %a, align 8
ret i64* %a
@ -260,8 +371,14 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" %a)
define i64* @not_captured_but_returned_1(i64* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@not_captured_but_returned_1
; CHECK-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i64, i64* [[A]], i64 1
; CHECK-NEXT: store i64 1, i64* [[ADD_PTR]], align 8
; CHECK-NEXT: ret i64* [[ADD_PTR]]
;
entry:
%add.ptr = getelementptr inbounds i64, i64* %a, i64 1
store i64 1, i64* %add.ptr, align 8
@ -275,8 +392,21 @@ entry:
; not_captured_but_returned_1(a);
; }
;
; CHECK: define void @test_not_captured_but_returned_calls(i64* nocapture nofree writeonly align 8 %a)
define void @test_not_captured_but_returned_calls(i64* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls
; IS__TUNIT____-SAME: (i64* nocapture nofree writeonly align 8 [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls
; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]])
; IS__CGSCC____-NEXT: ret void
;
entry:
%call = call i64* @not_captured_but_returned_0(i64* %a)
%call1 = call i64* @not_captured_but_returned_1(i64* %a)
@ -290,8 +420,19 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define align 8 i64* @negative_test_not_captured_but_returned_call_0a(i64* nofree returned writeonly align 8 "no-capture-maybe-returned" %a)
define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a
; IS__TUNIT____-SAME: (i64* nofree returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: ret i64* [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a
; IS__CGSCC____-SAME: (i64* nofree nonnull returned writeonly align 8 dereferenceable(8) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A]])
; IS__CGSCC____-NEXT: ret i64* [[CALL]]
;
entry:
%call = call i64* @not_captured_but_returned_0(i64* %a)
ret i64* %call
@ -304,8 +445,23 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define void @negative_test_not_captured_but_returned_call_0b(i64* nofree writeonly align 8 %a)
define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b
; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b
; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A]])
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8
; IS__CGSCC____-NEXT: ret void
;
entry:
%call = call i64* @not_captured_but_returned_0(i64* %a)
%0 = ptrtoint i64* %call to i64
@ -320,8 +476,19 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define nonnull align 8 dereferenceable(8) i64* @negative_test_not_captured_but_returned_call_1a(i64* nofree writeonly align 8 "no-capture-maybe-returned" %a)
define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a
; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: ret i64* [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a
; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]])
; IS__CGSCC____-NEXT: ret i64* [[CALL]]
;
entry:
%call = call i64* @not_captured_but_returned_1(i64* %a)
ret i64* %call
@ -334,8 +501,23 @@ entry:
; }
;
; There should *not* be a no-capture attribute on %a
; CHECK: define void @negative_test_not_captured_but_returned_call_1b(i64* nofree writeonly align 8 %a)
define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b
; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b
; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]])
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64
; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8
; IS__CGSCC____-NEXT: ret void
;
entry:
%call = call i64* @not_captured_but_returned_1(i64* %a)
%0 = ptrtoint i64* %call to i64
@ -353,12 +535,19 @@ entry:
;
; Verify we do *not* assume b is returned or not captured.
;
; CHECK: define i32* @ret_arg_or_unknown(i32* readnone %b)
; CHECK: define i32* @ret_arg_or_unknown_through_phi(i32* readnone %b)
declare i32* @unknown()
define i32* @ret_arg_or_unknown(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown
; CHECK-SAME: (i32* [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
; CHECK: ret_arg:
; CHECK-NEXT: ret i32* [[B]]
; CHECK: ret_unknown:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown()
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%cmp = icmp eq i32* %b, null
br i1 %cmp, label %ret_arg, label %ret_unknown
@ -372,6 +561,20 @@ ret_unknown:
}
define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
; CHECK-SAME: (i32* [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
; CHECK: ret_arg:
; CHECK-NEXT: br label [[R:%.*]]
; CHECK: ret_unknown:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown()
; CHECK-NEXT: br label [[R]]
; CHECK: r:
; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
; CHECK-NEXT: ret i32* [[PHI]]
;
entry:
%cmp = icmp eq i32* %b, null
br i1 %cmp, label %ret_arg, label %ret_unknown
@ -391,10 +594,15 @@ r:
; TEST not captured by readonly external function
;
; CHECK: define void @not_captured_by_readonly_call(i32* nocapture readonly %b)
declare i32* @readonly_unknown(i32*, i32*) readonly
define void @not_captured_by_readonly_call(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[B]])
; CHECK-NEXT: ret void
;
entry:
%call = call i32* @readonly_unknown(i32* %b, i32* %b)
ret void
@ -405,13 +613,13 @@ entry:
;
; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r.
;
; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either1(i32* nocapture readonly %b, i32* readonly returned %r)
;
; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either2(i32* nocapture readonly %b, i32* readonly returned %r)
; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either3(i32* nocapture readonly %b, i32* readonly returned %r)
;
; CHECK: define i32* @not_captured_by_readonly_call_not_returned_either4(i32* nocapture readonly %b, i32* readonly returned %r)
define i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) {
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either1
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[R]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @readonly_unknown(i32* %b, i32* %r) nounwind
ret i32* %call
@ -419,6 +627,12 @@ entry:
declare i32* @readonly_unknown_r1a(i32*, i32* returned) readonly
define i32* @not_captured_by_readonly_call_not_returned_either2(i32* %b, i32* %r) {
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either2
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) nounwind
ret i32* %call
@ -426,12 +640,24 @@ entry:
declare i32* @readonly_unknown_r1b(i32*, i32* returned) readonly nounwind
define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r) {
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either3
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @readonly_unknown_r1b(i32* %b, i32* %r)
ret i32* %call
}
define i32* @not_captured_by_readonly_call_not_returned_either4(i32* %b, i32* %r) nounwind {
; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either4
; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r)
ret i32* %call
@ -443,7 +669,7 @@ define void @nocapture_is_not_subsumed_1(i32* nocapture %b) {
; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_1
; CHECK-SAME: (i32* nocapture [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown_i32p(i32* [[B:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown_i32p(i32* [[B]])
; CHECK-NEXT: store i32 0, i32* [[CALL]]
; CHECK-NEXT: ret void
;
@ -456,9 +682,9 @@ entry:
declare i32* @readonly_i32p(i32*) readonly
define void @nocapture_is_not_subsumed_2(i32* nocapture %b) {
; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_2
; CHECK-SAME: (i32* nocapture nofree [[B:%.*]])
; CHECK-SAME: (i32* nocapture [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_i32p(i32* readonly [[B:%.*]])
; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_i32p(i32* readonly [[B]])
; CHECK-NEXT: store i32 0, i32* [[CALL]]
; CHECK-NEXT: ret void
;

View File

@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; Copied from Transforms/FunctoinAttrs/nofree-attributor.ll
; UTC_ARGS: --disable
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@ -16,10 +16,13 @@ declare void @_ZdaPv(i8*) local_unnamed_addr #2
; TEST 1 (positive case)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @only_return()
; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
define void @only_return() #0 {
ret void
; CHECK-LABEL: define {{[^@]+}}@only_return()
; CHECK-NEXT: ret void
;
ret void
}
@ -29,12 +32,16 @@ define void @only_return() #0 {
; free(p);
; }
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @only_free(i8* nocapture %0) local_unnamed_addr #1
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
tail call void @free(i8* %0) #1
ret void
; CHECK-LABEL: define {{[^@]+}}@only_free
; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: tail call void @free(i8* nocapture [[TMP0]])
; CHECK-NEXT: ret void
;
tail call void @free(i8* %0) #1
ret void
}
@ -49,19 +56,33 @@ define void @only_free(i8* nocapture %0) local_unnamed_addr #0 {
; }
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr
define void @free_in_scc1(i8* nocapture %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@free_in_scc1
; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: tail call void @free_in_scc2(i8* nocapture [[TMP0]])
; CHECK-NEXT: ret void
;
tail call void @free_in_scc2(i8* %0) #1
ret void
}
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR: define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define void @free_in_scc2(i8* nocapture %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@free_in_scc2
; CHECK-SAME: (i8* nocapture [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8* [[TMP0]], null
; CHECK-NEXT: br i1 [[CMP]], label [[REC:%.*]], label [[CALL:%.*]]
; CHECK: call:
; CHECK-NEXT: tail call void @free(i8* nocapture [[TMP0]])
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: rec:
; CHECK-NEXT: tail call void @free_in_scc1(i8* nocapture [[TMP0]])
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: ret void
;
%cmp = icmp eq i8* %0, null
br i1 %cmp, label %rec, label %call
call:
@ -85,16 +106,22 @@ end:
; }
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion1()
; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define void @mutual_recursion1() #0 {
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion1()
; CHECK-NEXT: unreachable
;
call void @mutual_recursion2()
ret void
}
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @mutual_recursion2()
; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define void @mutual_recursion2() #0 {
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion2()
; CHECK-NEXT: unreachable
;
call void @mutual_recursion1()
ret void
}
@ -106,10 +133,19 @@ define void @mutual_recursion2() #0 {
; delete [] p;
; }
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #1
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@_Z9delete_opPc
; CHECK-SAME: (i8* [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP4:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: tail call void @_ZdaPv(i8* nonnull [[TMP0]])
; CHECK-NEXT: br label [[TMP4]]
; CHECK: 4:
; CHECK-NEXT: ret void
;
%2 = icmp eq i8* %0, null
br i1 %2, label %4, label %3
@ -124,12 +160,16 @@ define void @_Z9delete_opPc(i8* %0) local_unnamed_addr #0 {
; TEST 6 (negative case)
; Call realloc
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0 {
%ret = tail call i8* @realloc(i8* %0, i64 %1) #2
ret i8* %ret
; CHECK-LABEL: define {{[^@]+}}@call_realloc
; CHECK-SAME: (i8* nocapture [[TMP0:%.*]], i64 [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[RET:%.*]] = tail call i8* @realloc(i8* nocapture [[TMP0]], i64 [[TMP1]])
; CHECK-NEXT: ret i8* [[RET]]
;
%ret = tail call i8* @realloc(i8* %0, i64 %1) #2
ret i8* %ret
}
@ -137,114 +177,152 @@ define noalias i8* @call_realloc(i8* nocapture %0, i64 %1) local_unnamed_addr #0
; Call function declaration with "nofree"
; ATTRIBUTOR: Function Attrs: nofree noinline nounwind readnone uwtable
; ATTRIBUTOR-NEXT: declare void @nofree_function()
; CHECK: Function Attrs: nofree noinline nounwind readnone uwtable
; CHECK-NEXT: declare void @nofree_function()
declare void @nofree_function() nofree readnone #0
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @call_nofree_function()
; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
define void @call_nofree_function() #0 {
tail call void @nofree_function()
ret void
; CHECK-LABEL: define {{[^@]+}}@call_nofree_function()
; CHECK-NEXT: ret void
;
tail call void @nofree_function()
ret void
}
; TEST 8 (negative case)
; Call function declaration without "nofree"
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @maybe_free()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NEXT: declare void @maybe_free()
declare void @maybe_free() #0
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @call_maybe_free()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define void @call_maybe_free() #0 {
tail call void @maybe_free()
ret void
; CHECK-LABEL: define {{[^@]+}}@call_maybe_free()
; CHECK-NEXT: tail call void @maybe_free()
; CHECK-NEXT: ret void
;
tail call void @maybe_free()
ret void
}
; TEST 9 (negative case)
; Call both of above functions
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nofree
; ATTRIBUTOR-NEXT: define void @call_both()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nofree
define void @call_both() #0 {
tail call void @maybe_free()
tail call void @nofree_function()
ret void
; CHECK-LABEL: define {{[^@]+}}@call_both()
; CHECK-NEXT: tail call void @maybe_free()
; CHECK-NEXT: ret void
;
tail call void @maybe_free()
tail call void @nofree_function()
ret void
}
; TEST 10 (positive case)
; Call intrinsic function
; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
; CHECK: Function Attrs: nounwind readnone speculatable
; CHECK-NEXT: declare float @llvm.floor.f32(float)
declare float @llvm.floor.f32(float)
; FIXME: missing nofree
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
define void @call_floor(float %a) #0 {
tail call float @llvm.floor.f32(float %a)
ret void
; CHECK-LABEL: define {{[^@]+}}@call_floor
; CHECK-SAME: (float [[A:%.*]])
; CHECK-NEXT: ret void
;
tail call float @llvm.floor.f32(float %a)
ret void
}
; FIXME: missing nofree
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define float @call_floor2(float %a)
; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable
define float @call_floor2(float %a) #0 {
%c = tail call float @llvm.floor.f32(float %a)
ret float %c
; CHECK-LABEL: define {{[^@]+}}@call_floor2
; CHECK-SAME: (float [[A:%.*]])
; CHECK-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]])
; CHECK-NEXT: ret float [[C]]
;
%c = tail call float @llvm.floor.f32(float %a)
ret float %c
}
; TEST 11 (positive case)
; Check propagation.
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @f1()
; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
define void @f1() #0 {
tail call void @nofree_function()
ret void
; CHECK-LABEL: define {{[^@]+}}@f1()
; CHECK-NEXT: ret void
;
tail call void @nofree_function()
ret void
}
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @f2()
; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
define void @f2() #0 {
tail call void @f1()
ret void
; CHECK-LABEL: define {{[^@]+}}@f2()
; CHECK-NEXT: ret void
;
tail call void @f1()
ret void
}
; TEST 12 NoFree argument - positive.
; ATTRIBUTOR: define double @test12(double* nocapture nofree nonnull readonly align 8 dereferenceable(8) %a)
define double @test12(double* nocapture readonly %a) {
; CHECK-LABEL: define {{[^@]+}}@test12
; CHECK-SAME: (double* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[A]], align 8
; CHECK-NEXT: [[CALL:%.*]] = tail call double @cos(double [[TMP0]])
; CHECK-NEXT: ret double [[CALL]]
;
entry:
%0 = load double, double* %a, align 8
%call = tail call double @cos(double %0) #2
ret double %call
%0 = load double, double* %a, align 8
%call = tail call double @cos(double %0) #2
ret double %call
}
declare double @cos(double) nobuiltin nounwind nofree
; FIXME: %a should be nofree.
; TEST 13 NoFree argument - positive.
; ATTRIBUTOR: define noalias i32* @test13(i64* nocapture nonnull readonly align 8 dereferenceable(8) %a)
define noalias i32* @test13(i64* nocapture readonly %a) {
; CHECK-LABEL: define {{[^@]+}}@test13
; CHECK-SAME: (i64* nocapture nonnull readonly align 8 dereferenceable(8) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[A]], align 8
; CHECK-NEXT: [[CALL:%.*]] = tail call noalias i8* @malloc(i64 [[TMP0]])
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[CALL]] to i32*
; CHECK-NEXT: ret i32* [[TMP1]]
;
entry:
%0 = load i64, i64* %a, align 8
%call = tail call noalias i8* @malloc(i64 %0) #2
%1 = bitcast i8* %call to i32*
ret i32* %1
%0 = load i64, i64* %a, align 8
%call = tail call noalias i8* @malloc(i64 %0) #2
%1 = bitcast i8* %call to i32*
ret i32* %1
}
; ATTRIBUTOR: define void @test14(i8* nocapture %0, i8* nocapture nofree readnone %1)
define void @test14(i8* nocapture %0, i8* nocapture %1) {
tail call void @free(i8* %0) #1
ret void
; CHECK-LABEL: define {{[^@]+}}@test14
; CHECK-SAME: (i8* nocapture [[TMP0:%.*]], i8* nocapture nofree readnone [[TMP1:%.*]])
; CHECK-NEXT: tail call void @free(i8* nocapture [[TMP0]])
; CHECK-NEXT: ret void
;
tail call void @free(i8* %0) #1
ret void
}
; UTC_ARGS: --enable
@ -255,6 +333,12 @@ define void @nonnull_assume_pos(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) #11 [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
; ATTRIBUTOR-NEXT: call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]])
; ATTRIBUTOR-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_pos
; CHECK-SAME: (i8* nofree [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* nofree [[ARG3:%.*]], i8* [[ARG4:%.*]])
; CHECK-NEXT: call void @llvm.assume(i1 true) #11 [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
; CHECK-NEXT: call void @unknown(i8* nofree [[ARG1]], i8* [[ARG2]], i8* nofree [[ARG3]], i8* [[ARG4]])
; CHECK-NEXT: ret void
;
call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg3)]
call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
@ -266,6 +350,12 @@ define void @nonnull_assume_neg(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
; ATTRIBUTOR-NEXT: call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
; ATTRIBUTOR-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
; CHECK-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
; CHECK-NEXT: call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
; CHECK-NEXT: ret void
;
call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
call void @llvm.assume(i1 true) ["nofree"(i8* %arg1), "nofree"(i8* %arg3)]
@ -286,6 +376,21 @@ define void @nonnull_assume_call(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG3]])
; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG4]])
; ATTRIBUTOR-NEXT: ret void
;
; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_call
; CHECK-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
; CHECK-NEXT: call void @unknown(i8* [[ARG1]], i8* [[ARG2]], i8* [[ARG3]], i8* [[ARG4]])
; CHECK-NEXT: call void @use_i8_ptr(i8* noalias readnone [[ARG1]])
; CHECK-NEXT: call void @use_i8_ptr(i8* noalias readnone [[ARG2]])
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG3]]) ]
; CHECK-NEXT: call void @use_i8_ptr(i8* noalias nofree readnone [[ARG3]])
; CHECK-NEXT: call void @use_i8_ptr(i8* noalias readnone [[ARG4]])
; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG1]])
; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias readnone [[ARG2]])
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nofree"(i8* [[ARG1]]), "nofree"(i8* [[ARG4]]) ]
; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG3]])
; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias nofree readnone [[ARG4]])
; CHECK-NEXT: ret void
;
call void @unknown(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4)
call void @use_i8_ptr(i8* %arg1)

File diff suppressed because it is too large Load Diff

View File

@ -1,100 +1,152 @@
; RUN: opt -attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
; RUN: opt -passes=attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_NPM
; Copied from Transforms/FunctoinAttrs/norecurse.ll
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; ATTRIBUTOR-NEXT: define i32 @leaf()
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__CGSSA____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
define i32 @leaf() {
; CHECK-LABEL: define {{[^@]+}}@leaf()
; CHECK-NEXT: ret i32 1
;
ret i32 1
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: readnone
; ATTRIBUTOR-NOT: norecurse
; ATTRIBUTOR-NEXT: define i32 @self_rec()
; CHECK: Function Attrs
; CHECK-SAME: readnone
; CHECK-NOT: norecurse
define i32 @self_rec() {
; CHECK-LABEL: define {{[^@]+}}@self_rec()
; CHECK-NEXT: unreachable
;
%a = call i32 @self_rec()
ret i32 4
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: readnone
; ATTRIBUTOR-NOT: norecurse
; ATTRIBUTOR-NEXT: define i32 @indirect_rec()
; CHECK: Function Attrs
; CHECK-SAME: readnone
; CHECK-NOT: norecurse
define i32 @indirect_rec() {
; CHECK-LABEL: define {{[^@]+}}@indirect_rec()
; CHECK-NEXT: unreachable
;
%a = call i32 @indirect_rec2()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: readnone
; ATTRIBUTOR-NOT: norecurse
; ATTRIBUTOR-NEXT: define i32 @indirect_rec2()
; CHECK: Function Attrs
; CHECK-SAME: readnone
; CHECK-NOT: norecurse
define i32 @indirect_rec2() {
; CHECK-LABEL: define {{[^@]+}}@indirect_rec2()
; CHECK-NEXT: unreachable
;
%a = call i32 @indirect_rec()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: readnone
; ATTRIBUTOR-NOT: norecurse
; ATTRIBUTOR-NEXT: define i32 @extern()
; CHECK: Function Attrs
; CHECK-SAME: readnone
; CHECK-NOT: norecurse
define i32 @extern() {
; CHECK-LABEL: define {{[^@]+}}@extern()
; CHECK-NEXT: [[A:%.*]] = call i32 @k()
; CHECK-NEXT: ret i32 [[A]]
;
%a = call i32 @k()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-NEXT: declare i32 @k()
; CHECK: Function Attrs
; CHECK-NEXT: declare i32 @k()
declare i32 @k() readnone
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-NOT: norecurse
; ATTRIBUTOR-NEXT: define void @intrinsic(i8* nocapture writeonly %dest, i8* nocapture readonly %src, i32 %len)
; CHECK: Function Attrs
; CHECK-NOT: norecurse
define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
; CHECK-LABEL: define {{[^@]+}}@intrinsic
; CHECK-SAME: (i8* nocapture writeonly [[DEST:%.*]], i8* nocapture readonly [[SRC:%.*]], i32 [[LEN:%.*]])
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly [[DEST]], i8* noalias nocapture readonly [[SRC]], i32 [[LEN]], i1 false)
; CHECK-NEXT: ret void
;
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
ret void
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32
; CHECK: Function Attrs
; CHECK-NEXT: declare void @llvm.memcpy.p0i8.p0i8.i32
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: norecurse nosync readnone
; IS__TUNIT____: Function Attrs
; IS__TUNIT____-SAME: nosync readnone
; IS__CGSSA____: Function Attrs
; IS__CGSSA____-SAME: norecurse nosync readnone
define internal i32 @called_by_norecurse() {
; CHECK-LABEL: define {{[^@]+}}@called_by_norecurse()
; CHECK-NEXT: [[A:%.*]] = call i32 @k()
; CHECK-NEXT: ret i32 undef
;
%a = call i32 @k()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-NEXT: define void @m()
; CHECK: Function Attrs
define void @m() norecurse {
; CHECK-LABEL: define {{[^@]+}}@m()
; CHECK-NEXT: [[A:%.*]] = call i32 @called_by_norecurse()
; CHECK-NEXT: ret void
;
%a = call i32 @called_by_norecurse()
ret void
}
; ATTRIBUTOR: Function Attrs
; CHECK: Function Attrs
; FIXME: norecurse missing
; ATTRIBUTOR-SAME: nosync readnone
; ATTRIBUTOR-NEXT: @called_by_norecurse_indirectly
; CHECK-SAME: nosync readnone
define internal i32 @called_by_norecurse_indirectly() {
; CHECK-LABEL: define {{[^@]+}}@called_by_norecurse_indirectly()
; CHECK-NEXT: [[A:%.*]] = call i32 @k()
; CHECK-NEXT: ret i32 [[A]]
;
%a = call i32 @k()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs
; ATTRIBUTOR-SAME: norecurse nosync readnone
; ATTRIBUTOR-NEXT: @o
; IS__TUNIT____: Function Attrs
; IS__TUNIT____-SAME: nosync readnone
; IS__CGSSA____: Function Attrs
; IS__CGSSA____-SAME: norecurse nosync readnone
define internal i32 @o() {
; CHECK-LABEL: define {{[^@]+}}@o()
; CHECK-NEXT: [[A:%.*]] = call i32 @called_by_norecurse_indirectly()
; CHECK-NEXT: ret i32 [[A]]
;
%a = call i32 @called_by_norecurse_indirectly()
ret i32 %a
}
define i32 @p() norecurse {
; CHECK-LABEL: define {{[^@]+}}@p()
; CHECK-NEXT: [[A:%.*]] = call i32 @o()
; CHECK-NEXT: ret i32 [[A]]
;
%a = call i32 @o()
ret i32 %a
}
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
; ATTRIBUTOR-NEXT: define void @f(i32 %x)
; CHECK: Function Attrs: nofree nosync nounwind
define void @f(i32 %x) {
; CHECK-LABEL: define {{[^@]+}}@f
; CHECK-SAME: (i32 [[X:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[X_ADDR]], align 4
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @g()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: ret void
;
entry:
%x.addr = alloca i32, align 4
store i32 %x, i32* %x.addr, align 4
@ -110,39 +162,57 @@ if.end:
ret void
}
; ATTRIBUTOR: define void @g()
define void @g() norecurse {
; CHECK-LABEL: define {{[^@]+}}@g()
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @f(i32 0)
; CHECK-NEXT: ret void
;
entry:
call void @f(i32 0)
ret void
}
; ATTRIBUTOR-NOT: Function Attrs
; ATTRIBUTOR: define linkonce_odr i32 @leaf_redefinable()
; CHECK-NOT: Function Attrs
define linkonce_odr i32 @leaf_redefinable() {
; CHECK-LABEL: define {{[^@]+}}@leaf_redefinable()
; CHECK-NEXT: ret i32 1
;
ret i32 1
}
; Call through a function pointer
; ATTRIBUTOR-NOT: Function Attrs
; ATTRIBUTOR: define i32 @eval_func1(i32 (i32)* nocapture nofree nonnull %0, i32 %1)
; CHECK-NOT: Function Attrs
define i32 @eval_func1(i32 (i32)* , i32) local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@eval_func1
; CHECK-SAME: (i32 (i32)* nocapture nofree nonnull [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
%3 = tail call i32 %0(i32 %1) #2
ret i32 %3
}
; ATTRIBUTOR-NOT: Function Attrs
; ATTRIBUTOR: define i32 @eval_func2(i32 (i32)* nocapture nofree %0, i32 %1)
; CHECK-NOT: Function Attrs
define i32 @eval_func2(i32 (i32)* , i32) local_unnamed_addr "null-pointer-is-valid"="true"{
; CHECK-LABEL: define {{[^@]+}}@eval_func2
; CHECK-SAME: (i32 (i32)* nocapture nofree [[TMP0:%.*]], i32 [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 [[TMP0]](i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
%3 = tail call i32 %0(i32 %1) #2
ret i32 %3
}
declare void @unknown()
; Call an unknown function in a dead block.
; ATTRIBUTOR_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; ATTRIBUTOR_NPM: define i32 @call_unknown_in_dead_block()
; CHECK_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
declare void @unknown()
define i32 @call_unknown_in_dead_block() local_unnamed_addr {
; CHECK-LABEL: define {{[^@]+}}@call_unknown_in_dead_block() local_unnamed_addr
; CHECK-NEXT: ret i32 0
; CHECK: Dead:
; CHECK-NEXT: unreachable
;
ret i32 0
Dead:
tail call void @unknown()

View File

@ -1,4 +1,8 @@
; RUN: opt -functionattrs -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; Test cases specifically designed for the "no-return" function attribute.
; We use FIXME's to indicate problems and missing attributes.
@ -12,10 +16,13 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; return srec0();
; }
;
; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define void @srec0()
;
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define void @srec0() #0 {
; CHECK-LABEL: define {{[^@]+}}@srec0()
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
call void @srec0()
ret void
@ -28,10 +35,16 @@ entry:
; return srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(srec16(a))))))))))))))));
; }
;
; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @srec16(i32 %a)
;
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define i32 @srec16(i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@srec16
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: unreachable
;
entry:
%call = call i32 @srec16(i32 %a)
%call1 = call i32 @srec16(i32 %call)
@ -62,10 +75,16 @@ exit:
; while (1);
; }
;
; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @endless_loop(i32 %a)
;
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define i32 @endless_loop(i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@endless_loop
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
@ -82,10 +101,18 @@ while.body: ; preds = %entry, %while.body
; }
;
; FIXME: no-return missing (D65243 should fix this)
; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @dead_return(i32 returned %a)
;
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define i32 @dead_return(i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@dead_return
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_BODY]]
; CHECK: return:
; CHECK-NEXT: unreachable
;
entry:
br label %while.body
@ -103,10 +130,21 @@ return: ; No predecessors!
; return a == 0 ? endless_loop(a) : srec16(a);
; }
;
; CHECK: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK: define i32 @multiple_noreturn_calls(i32 %a)
;
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define i32 @multiple_noreturn_calls(i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@multiple_noreturn_calls
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.true:
; CHECK-NEXT: unreachable
; CHECK: cond.false:
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: unreachable
;
entry:
%cmp = icmp eq i32 %a, 0
br i1 %cmp, label %cond.true, label %cond.false
@ -128,9 +166,15 @@ cond.end: ; preds = %cond.false, %cond.t
; TEST 6a: willreturn means *not* no-return or UB
; FIXME: we should derive "UB" as an argument and report it to the user on request.
; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
; CHECK-NEXT: define i32 @endless_loop_but_willreturn
; IS__TUNIT____: Function Attrs: nofree noreturn nosync nounwind readnone willreturn
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
define i32 @endless_loop_but_willreturn() willreturn {
; CHECK-LABEL: define {{[^@]+}}@endless_loop_but_willreturn()
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
@ -139,9 +183,13 @@ while.body: ; preds = %entry, %while.body
}
; TEST 6b: willreturn means *not* no-return or UB
; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
; CHECK-NEXT: define i32 @UB_and_willreturn
; IS__TUNIT____: Function Attrs: nofree noreturn nosync nounwind readnone willreturn
; IS__CGSCC____: Function Attrs: nofree norecurse noreturn nosync nounwind readnone willreturn
define i32 @UB_and_willreturn() willreturn {
; CHECK-LABEL: define {{[^@]+}}@UB_and_willreturn()
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
unreachable
}

View File

@ -1,4 +1,8 @@
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; Test cases designed for the nosync function attribute.
@ -24,9 +28,15 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
%struct.RT = type { i8, [10 x [20 x i32]], i8 }
%struct.ST = type { i32, double, %struct.RT }
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* nofree readnone "no-capture-maybe-returned" %s)
; IS__TUNIT____: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind optsize readnone ssp uwtable
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (%struct.ST* nofree readnone "no-capture-maybe-returned" [[S:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
; CHECK-NEXT: ret i32* [[ARRAYIDX]]
;
entry:
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
ret i32* %arrayidx
@ -39,9 +49,14 @@ entry:
; return n;
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@load_monotonic
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] monotonic, align 4
; CHECK-NEXT: ret i32 [[TMP2]]
;
%2 = load atomic i32, i32* %0 monotonic, align 4
ret i32 %2
}
@ -53,9 +68,14 @@ define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtabl
; atomic_load_explicit(num, memory_order_relaxed);
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable
define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@store_monotonic
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]])
; CHECK-NEXT: store atomic i32 10, i32* [[TMP0]] monotonic, align 4
; CHECK-NEXT: ret void
;
store atomic i32 10, i32* %0 monotonic, align 4
ret void
}
@ -67,10 +87,15 @@ define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
; return n;
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; CHECK-NOT: nosync
define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@load_acquire
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] acquire, align 4
; CHECK-NEXT: ret i32 [[TMP2]]
;
%2 = load atomic i32, i32* %0 acquire, align 4
ret i32 %2
}
@ -81,20 +106,30 @@ define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable
; atomic_store_explicit(num, 10, memory_order_release);
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture nofree writeonly align 4 %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; CHECK-NOT: nosync
define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@load_release
; CHECK-SAME: (i32* nocapture nofree writeonly align 4 [[TMP0:%.*]])
; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4
; CHECK-NEXT: ret void
;
store atomic volatile i32 10, i32* %0 release, align 4
ret void
}
; TEST 6 - negative volatile, relaxed atomic
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture nofree writeonly align 4 %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; CHECK-NOT: nosync
define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@load_volatile_release
; CHECK-SAME: (i32* nocapture nofree writeonly align 4 [[TMP0:%.*]])
; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4
; CHECK-NEXT: ret void
;
store atomic volatile i32 10, i32* %0 release, align 4
ret void
}
@ -105,10 +140,15 @@ define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable
; *num = 14;
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @volatile_store(i32* nofree align 4 %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; CHECK-NOT: nosync
define void @volatile_store(i32* %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@volatile_store
; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]])
; CHECK-NEXT: store volatile i32 14, i32* [[TMP0]], align 4
; CHECK-NEXT: ret void
;
store volatile i32 14, i32* %0, align 4
ret void
}
@ -120,37 +160,50 @@ define void @volatile_store(i32* %0) norecurse nounwind uwtable {
; return n;
; }
; ATTRIBUTOR: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* nofree align 4 %0)
; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable
; CHECK-NOT: nosync
define i32 @volatile_load(i32* %0) norecurse nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@volatile_load
; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4
; CHECK-NEXT: ret i32 [[TMP2]]
;
%2 = load volatile i32, i32* %0, align 4
ret i32 %2
}
; TEST 9
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @nosync_function()
; CHECK: Function Attrs: noinline nosync nounwind uwtable
; CHECK-NEXT: declare void @nosync_function()
declare void @nosync_function() noinline nounwind uwtable nosync
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
; ATTRIBUTOR-next: define void @call_nosync_function()
; IS__TUNIT____: Function Attrs: noinline nosync nounwind uwtable
; IS__CGSCC____: Function Attrs: noinline nosync nounwind uwtable
define void @call_nosync_function() nounwind uwtable noinline {
; CHECK-LABEL: define {{[^@]+}}@call_nosync_function()
; CHECK-NEXT: tail call void @nosync_function()
; CHECK-NEXT: ret void
;
tail call void @nosync_function() noinline nounwind uwtable
ret void
}
; TEST 10 - negative, should not deduce nosync
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NEXT: declare void @might_sync()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NEXT: declare void @might_sync()
declare void @might_sync() noinline nounwind uwtable
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @call_might_sync()
; IS__TUNIT____: Function Attrs: noinline nounwind uwtable
; IS__CGSCC____: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: nosync
define void @call_might_sync() nounwind uwtable noinline {
; CHECK-LABEL: define {{[^@]+}}@call_might_sync()
; CHECK-NEXT: tail call void @might_sync()
; CHECK-NEXT: ret void
;
tail call void @might_sync() noinline nounwind uwtable
ret void
}
@ -158,17 +211,27 @@ define void @call_might_sync() nounwind uwtable noinline {
; TEST 11 - positive, should deduce nosync
; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture nofree readnone %0)
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define i32 @scc1(i32* %0) noinline nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@scc1
; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]])
; CHECK-NEXT: unreachable
;
tail call void @scc2(i32* %0);
%val = tail call i32 @volatile_load(i32* %0);
ret i32 %val;
}
; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture nofree readnone %0)
; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
define void @scc2(i32* %0) noinline nounwind uwtable {
; CHECK-LABEL: define {{[^@]+}}@scc2
; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]])
; CHECK-NEXT: unreachable
;
tail call i32 @scc1(i32* %0);
ret void;
}
@ -192,10 +255,16 @@ define void @scc2(i32* %0) noinline nounwind uwtable {
%"struct.std::atomic" = type { %"struct.std::__atomic_base" }
%"struct.std::__atomic_base" = type { i8 }
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR: define void @foo1(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1)
; CHECK-NOT: nosync
define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
; CHECK-LABEL: define {{[^@]+}}@foo1
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]])
; CHECK-NEXT: store i32 100, i32* [[TMP0]], align 4
; CHECK-NEXT: fence release
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
; CHECK-NEXT: store atomic i8 1, i8* [[TMP3]] monotonic, align 1
; CHECK-NEXT: ret void
;
store i32 100, i32* %0, align 4
fence release
%3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
@ -203,9 +272,21 @@ define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
ret void
}
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR: define void @bar(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1)
; CHECK-NOT: nosync
define void @bar(i32* %0, %"struct.std::atomic"* %1) {
; CHECK-LABEL: define {{[^@]+}}@bar
; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]])
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
; CHECK-NEXT: br label [[TMP4:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
; CHECK-NEXT: br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
; CHECK: 8:
; CHECK-NEXT: fence acquire
; CHECK-NEXT: ret void
;
%3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
br label %4
@ -221,10 +302,17 @@ define void @bar(i32* %0, %"struct.std::atomic"* %1) {
}
; TEST 13 - Fence syncscope("singlethread") seq_cst
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn
; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) %0, %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) %1)
; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn
define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
; CHECK-LABEL: define {{[^@]+}}@foo1_singlethread
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]])
; CHECK-NEXT: store i32 100, i32* [[TMP0]], align 4
; CHECK-NEXT: fence syncscope("singlethread") release
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
; CHECK-NEXT: store atomic i8 1, i8* [[TMP3]] monotonic, align 1
; CHECK-NEXT: ret void
;
store i32 100, i32* %0, align 4
fence syncscope("singlethread") release
%3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
@ -232,9 +320,22 @@ define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
ret void
}
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture nofree readnone %0, %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) %1)
; IS__TUNIT____: Function Attrs: nofree nosync nounwind
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind
define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
; CHECK-LABEL: define {{[^@]+}}@bar_singlethread
; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]])
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
; CHECK-NEXT: br label [[TMP4:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
; CHECK-NEXT: br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
; CHECK: 8:
; CHECK-NEXT: fence syncscope("singlethread") acquire
; CHECK-NEXT: ret void
;
%3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
br label %4
@ -256,10 +357,15 @@ declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
; It is odd to add nocapture but a result of the llvm.memcpy nocapture.
;
; ATTRIBUTOR: Function Attrs: argmemonly nounwind
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture writeonly %ptr1, i8* nocapture readonly %ptr2)
; IS__TUNIT____: Function Attrs: argmemonly nounwind
; IS__CGSCC____: Function Attrs: argmemonly nounwind
; CHECK-NOT: nosync
define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
; CHECK-LABEL: define {{[^@]+}}@memcpy_volatile
; CHECK-SAME: (i8* nocapture writeonly [[PTR1:%.*]], i8* nocapture readonly [[PTR2:%.*]])
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly [[PTR1]], i8* noalias nocapture readonly [[PTR2]], i32 8, i1 true)
; CHECK-NEXT: ret i32 4
;
call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1)
ret i32 4
}
@ -268,41 +374,57 @@ define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
; It is odd to add nocapture but a result of the llvm.memset nocapture.
;
; ATTRIBUTOR: Function Attrs: argmemonly nosync
; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture writeonly %ptr1, i8 %val)
; IS__TUNIT____: Function Attrs: argmemonly nosync
; IS__CGSCC____: Function Attrs: argmemonly nosync
define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
; CHECK-LABEL: define {{[^@]+}}@memset_non_volatile
; CHECK-SAME: (i8* nocapture writeonly [[PTR1:%.*]], i8 [[VAL:%.*]])
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture writeonly [[PTR1]], i8 [[VAL]], i32 8, i1 false)
; CHECK-NEXT: ret i32 4
;
call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0)
ret i32 4
}
; TEST 16 - negative, inline assembly.
; ATTRIBUTOR: define i32 @inline_asm_test(i32 %x)
define i32 @inline_asm_test(i32 %x) {
; CHECK-LABEL: define {{[^@]+}}@inline_asm_test
; CHECK-SAME: (i32 [[X:%.*]])
; CHECK-NEXT: [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X]])
; CHECK-NEXT: ret i32 4
;
call i32 asm "bswap $0", "=r,r"(i32 %x)
ret i32 4
}
declare void @readnone_test() convergent readnone
; ATTRIBUTOR: define void @convergent_readnone()
; TEST 17 - negative. Convergent
define void @convergent_readnone(){
call void @readnone_test()
ret void
; CHECK-LABEL: define {{[^@]+}}@convergent_readnone()
; CHECK-NEXT: call void @readnone_test()
; CHECK-NEXT: ret void
;
call void @readnone_test()
ret void
}
; ATTRIBUTOR: Function Attrs: nounwind
; ATTRIBUTOR-NEXT: declare void @llvm.x86.sse2.clflush(i8*)
; CHECK: Function Attrs: nounwind
; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(i8*)
declare void @llvm.x86.sse2.clflush(i8*)
@a = common global i32 0, align 4
; TEST 18 - negative. Synchronizing intrinsic
; ATTRIBUTOR: Function Attrs: nounwind
; ATTRIBUTOR-NOT: nosync
; ATTRIBUTOR-NEXT: define void @i_totally_sync()
; IS__TUNIT____: Function Attrs: nounwind
; IS__CGSCC____: Function Attrs: nounwind
; CHECK-NOT: nosync
define void @i_totally_sync() {
; CHECK-LABEL: define {{[^@]+}}@i_totally_sync()
; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(i8* nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*))
; CHECK-NEXT: ret void
;
tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*))
ret void
}
@ -311,16 +433,25 @@ declare float @llvm.cos(float %val) readnone
; TEST 19 - positive, readnone & non-convergent intrinsic.
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind readnone willreturn
; ATTRIBUTOR-NEXT: define i32 @cos_test(float %x)
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
define i32 @cos_test(float %x) {
; CHECK-LABEL: define {{[^@]+}}@cos_test
; CHECK-SAME: (float [[X:%.*]])
; CHECK-NEXT: ret i32 4
;
call float @llvm.cos(float %x)
ret i32 4
}
; ATTRIBUTOR: Function Attrs: nosync nounwind
; ATTRIBUTOR-NEXT: define float @cos_test2(float %x)
; IS__TUNIT____: Function Attrs: nosync nounwind
; IS__CGSCC____: Function Attrs: nosync nounwind
define float @cos_test2(float %x) {
; CHECK-LABEL: define {{[^@]+}}@cos_test2
; CHECK-SAME: (float [[X:%.*]])
; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X]])
; CHECK-NEXT: ret float [[C]]
;
%c = call float @llvm.cos(float %x)
ret float %c
}

View File

@ -1,26 +1,40 @@
; RUN: opt < %s -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S | FileCheck %s --check-prefix=ATTRIBUTOR
; Copied from Transforms/FunctoinAttrs/nounwind.ll
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; TEST 1
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
; ATTRIBUTOR-NEXT: define i32 @foo1()
; IS__TUNIT____: Function Attrs: nofree nosync nounwind
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind
define i32 @foo1() {
; CHECK-LABEL: define {{[^@]+}}@foo1()
; CHECK-NEXT: ret i32 1
;
ret i32 1
}
; TEST 2
; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
; ATTRIBUTOR-NEXT: define i32 @scc1_foo()
; IS__TUNIT____: Function Attrs: nofree noreturn nosync nounwind
; IS__CGSCC_OPM: Function Attrs: nofree noreturn nosync nounwind
; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind
define i32 @scc1_foo() {
; CHECK-LABEL: define {{[^@]+}}@scc1_foo()
; CHECK-NEXT: unreachable
;
%1 = call i32 @scc1_bar()
ret i32 1
}
; TEST 3
; ATTRIBUTOR: Function Attrs: nofree noreturn nosync nounwind
; ATTRIBUTOR-NEXT: define i32 @scc1_bar()
; IS__TUNIT____: Function Attrs: nofree noreturn nosync nounwind
; IS__CGSCC_OPM: Function Attrs: nofree noreturn nosync nounwind
; IS__CGSCC_NPM: Function Attrs: nofree norecurse noreturn nosync nounwind
define i32 @scc1_bar() {
; CHECK-LABEL: define {{[^@]+}}@scc1_bar()
; CHECK-NEXT: unreachable
;
%1 = call i32 @scc1_foo()
ret i32 1
}
@ -28,10 +42,13 @@ define i32 @scc1_bar() {
declare i32 @non_nounwind()
; TEST 4
; ATTRIBUTOR: define void @call_non_nounwind() {
define void @call_non_nounwind(){
tail call i32 @non_nounwind()
ret void
; CHECK-LABEL: define {{[^@]+}}@call_non_nounwind()
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @non_nounwind()
; CHECK-NEXT: ret void
;
tail call i32 @non_nounwind()
ret void
}
; TEST 5 - throw
@ -42,8 +59,16 @@ define void @call_non_nounwind(){
; return -1;
; }
; ATTRIBUTOR: define i32 @maybe_throw(i1 zeroext %0)
define i32 @maybe_throw(i1 zeroext %0) {
; CHECK-LABEL: define {{[^@]+}}@maybe_throw
; CHECK-SAME: (i1 zeroext [[TMP0:%.*]])
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP2:%.*]], label [[TMP3:%.*]]
; CHECK: 2:
; CHECK-NEXT: tail call void @__cxa_rethrow()
; CHECK-NEXT: unreachable
; CHECK: 3:
; CHECK-NEXT: ret i32 -1
;
br i1 %0, label %2, label %3
2: ; preds = %1
@ -65,17 +90,29 @@ declare void @__cxa_rethrow()
; return 1;
; }
; ATTRIBUTOR: define i32 @catch_thing()
define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
; CHECK-LABEL: define {{[^@]+}}@catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
; CHECK-NEXT: invoke void @__cxa_rethrow()
; CHECK-NEXT: to label [[TMP1:%.*]] unwind label [[TMP2:%.*]]
; CHECK: 1:
; CHECK-NEXT: unreachable
; CHECK: 2:
; CHECK-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i8*, i32 } [[TMP3]], 0
; CHECK-NEXT: [[TMP5:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[TMP4]])
; CHECK-NEXT: tail call void @__cxa_end_catch()
; CHECK-NEXT: ret i32 -1
;
invoke void @__cxa_rethrow() #1
to label %1 unwind label %2
to label %1 unwind label %2
1: ; preds = %0
unreachable
2: ; preds = %0
%3 = landingpad { i8*, i32 }
catch i8* null
catch i8* null
%4 = extractvalue { i8*, i32 } %3, 0
%5 = tail call i8* @__cxa_begin_catch(i8* %4) #2
tail call void @__cxa_end_catch()
@ -83,9 +120,10 @@ define i32 @catch_thing() personality i8* bitcast (i32 (...)* @__gxx_personality
}
define i32 @catch_thing_user() {
; ATTRIBUTOR: define i32 @catch_thing_user
; ATTRIBUTOR-NEXT: %catch_thing_call = call
; ATTRIBUTOR-NEXT: ret i32 -1
; CHECK-LABEL: define {{[^@]+}}@catch_thing_user()
; CHECK-NEXT: [[CATCH_THING_CALL:%.*]] = call i32 @catch_thing()
; CHECK-NEXT: ret i32 -1
;
%catch_thing_call = call i32 @catch_thing()
ret i32 %catch_thing_call
}

View File

@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=CHECK,OLD_PM,MODULE_OLD_PM
; RUN: opt -passes=attributor -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=CHECK,NEW_PM,MODULE_NEW_PM
; RUN: opt -attributor-cgscc -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC_OLD_PM
; RUN: opt -passes=attributor-cgscc -attributor-disable=false -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC_NEW_PM
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=14 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; FIXME: CGSCC is not looking at callees and calleers even though it could be allowed.
@ -17,26 +17,15 @@ define i32 @test0(i32* %p) {
}
define i32 @test0-range-check(i32* %p) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@test0-range-check
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; IS__TUNIT____-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #4, !range !0
; IS__TUNIT____-NEXT: ret i32 [[A]]
;
; OLD_PM-LABEL: define {{[^@]+}}@test0-range-check
; OLD_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; OLD_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !0
; OLD_PM-NEXT: ret i32 [[A]]
;
; NEW_PM-LABEL: define {{[^@]+}}@test0-range-check
; NEW_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; NEW_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !0
; NEW_PM-NEXT: ret i32 [[A]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test0-range-check
; CGSCC_OLD_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_OLD_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_OLD_PM-NEXT: ret i32 [[A]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test0-range-check
; CGSCC_NEW_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_NEW_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_NEW_PM-NEXT: ret i32 [[A]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@test0-range-check
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; IS__CGSCC____-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: ret i32 [[A]]
;
%a = tail call i32 @test0(i32* %p)
ret i32 %a
@ -55,235 +44,121 @@ define void @use3(i1, i1, i1) {
; TEST0 icmp test
define void @test0-icmp-check(i32* %p){
; OLD_PM-LABEL: define {{[^@]+}}@test0-icmp-check
; OLD_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; OLD_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !0
; OLD_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; OLD_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; OLD_PM-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; OLD_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 false)
; OLD_PM-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; OLD_PM-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; OLD_PM-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; OLD_PM-NEXT: tail call void @use3(i1 true, i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 true)
; OLD_PM-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; OLD_PM-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; OLD_PM-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_UGT_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; OLD_PM-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; OLD_PM-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; OLD_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 false)
; OLD_PM-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; OLD_PM-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; OLD_PM-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_SGT_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 true)
; OLD_PM-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; OLD_PM-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; OLD_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 true, i1 true)
; OLD_PM-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; OLD_PM-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; OLD_PM-NEXT: tail call void @use3(i1 true, i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 false, i1 false)
; OLD_PM-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; OLD_PM-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; OLD_PM-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; OLD_PM-NEXT: tail call void @use3(i1 true, i1 true, i1 [[CMP_LTE_3]])
; OLD_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 false)
; OLD_PM-NEXT: ret void
;
; NEW_PM-LABEL: define {{[^@]+}}@test0-icmp-check
; NEW_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; NEW_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !0
; NEW_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; NEW_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; NEW_PM-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; NEW_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 false)
; NEW_PM-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; NEW_PM-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; NEW_PM-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; NEW_PM-NEXT: tail call void @use3(i1 true, i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 true)
; NEW_PM-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; NEW_PM-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; NEW_PM-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_UGT_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; NEW_PM-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; NEW_PM-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; NEW_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 false)
; NEW_PM-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; NEW_PM-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; NEW_PM-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_SGT_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 true)
; NEW_PM-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; NEW_PM-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; NEW_PM-NEXT: tail call void @use3(i1 false, i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 true, i1 true)
; NEW_PM-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; NEW_PM-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; NEW_PM-NEXT: tail call void @use3(i1 true, i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 false, i1 false)
; NEW_PM-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; NEW_PM-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; NEW_PM-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; NEW_PM-NEXT: tail call void @use3(i1 true, i1 true, i1 [[CMP_LTE_3]])
; NEW_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 false)
; NEW_PM-NEXT: ret void
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test0-icmp-check
; CGSCC_OLD_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_OLD_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_EQ_6:%.*]] = icmp eq i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_1]], i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 [[CMP_EQ_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_NE_1:%.*]] = icmp ne i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_NE_6:%.*]] = icmp ne i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_NE_1]], i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 [[CMP_NE_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_UGT_1:%.*]] = icmp ugt i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_UGT_2:%.*]] = icmp ugt i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_1]], i1 [[CMP_UGT_2]], i1 [[CMP_UGT_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; CGSCC_OLD_PM-NEXT: [[CMP_UGE_1:%.*]] = icmp uge i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_UGE_6:%.*]] = icmp uge i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_1]], i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 [[CMP_UGE_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_1:%.*]] = icmp sgt i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_2:%.*]] = icmp sgt i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_SGT_6:%.*]] = icmp sgt i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_1]], i1 [[CMP_SGT_2]], i1 [[CMP_SGT_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 [[CMP_SGT_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_1:%.*]] = icmp sge i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_5:%.*]] = icmp sge i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_GTE_6:%.*]] = icmp sge i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_1]], i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 [[CMP_GTE_5]], i1 [[CMP_GTE_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_1:%.*]] = icmp slt i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_5:%.*]] = icmp slt i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_SLT_6:%.*]] = icmp slt i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_1]], i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 [[CMP_SLT_5]], i1 [[CMP_SLT_6]])
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_1:%.*]] = icmp sle i32 [[RET]], 10
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_2:%.*]] = icmp sle i32 [[RET]], 9
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; CGSCC_OLD_PM-NEXT: [[CMP_LTE_6:%.*]] = icmp sle i32 [[RET]], -1
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_1]], i1 [[CMP_LTE_2]], i1 [[CMP_LTE_3]])
; CGSCC_OLD_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 [[CMP_LTE_6]])
; CGSCC_OLD_PM-NEXT: ret void
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test0-icmp-check
; CGSCC_NEW_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_NEW_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_EQ_6:%.*]] = icmp eq i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_1]], i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 [[CMP_EQ_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_NE_1:%.*]] = icmp ne i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_NE_6:%.*]] = icmp ne i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_NE_1]], i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 [[CMP_NE_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_UGT_1:%.*]] = icmp ugt i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_UGT_2:%.*]] = icmp ugt i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_1]], i1 [[CMP_UGT_2]], i1 [[CMP_UGT_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; CGSCC_NEW_PM-NEXT: [[CMP_UGE_1:%.*]] = icmp uge i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_UGE_6:%.*]] = icmp uge i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_1]], i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 [[CMP_UGE_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_1:%.*]] = icmp sgt i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_2:%.*]] = icmp sgt i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_SGT_6:%.*]] = icmp sgt i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_1]], i1 [[CMP_SGT_2]], i1 [[CMP_SGT_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 [[CMP_SGT_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_1:%.*]] = icmp sge i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_5:%.*]] = icmp sge i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_GTE_6:%.*]] = icmp sge i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_1]], i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 [[CMP_GTE_5]], i1 [[CMP_GTE_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_1:%.*]] = icmp slt i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_5:%.*]] = icmp slt i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_SLT_6:%.*]] = icmp slt i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_1]], i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 [[CMP_SLT_5]], i1 [[CMP_SLT_6]])
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_1:%.*]] = icmp sle i32 [[RET]], 10
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_2:%.*]] = icmp sle i32 [[RET]], 9
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; CGSCC_NEW_PM-NEXT: [[CMP_LTE_6:%.*]] = icmp sle i32 [[RET]], -1
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_1]], i1 [[CMP_LTE_2]], i1 [[CMP_LTE_3]])
; CGSCC_NEW_PM-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 [[CMP_LTE_6]])
; CGSCC_NEW_PM-NEXT: ret void
;
; ret = [0, 10)
; IS__TUNIT____-LABEL: define {{[^@]+}}@test0-icmp-check
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; IS__TUNIT____-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly align 4 [[P]]) #4, !range !0
; IS__TUNIT____-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; IS__TUNIT____-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; IS__TUNIT____-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; IS__TUNIT____-NEXT: tail call void @use3(i1 false, i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 false)
; IS__TUNIT____-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; IS__TUNIT____-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; IS__TUNIT____-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; IS__TUNIT____-NEXT: tail call void @use3(i1 true, i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 true)
; IS__TUNIT____-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; IS__TUNIT____-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; IS__TUNIT____-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_UGT_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; IS__TUNIT____-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; IS__TUNIT____-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; IS__TUNIT____-NEXT: tail call void @use3(i1 false, i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 false)
; IS__TUNIT____-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; IS__TUNIT____-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; IS__TUNIT____-NEXT: tail call void @use3(i1 false, i1 false, i1 [[CMP_SGT_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 true)
; IS__TUNIT____-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; IS__TUNIT____-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; IS__TUNIT____-NEXT: tail call void @use3(i1 false, i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 true, i1 true)
; IS__TUNIT____-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; IS__TUNIT____-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; IS__TUNIT____-NEXT: tail call void @use3(i1 true, i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 false, i1 false)
; IS__TUNIT____-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; IS__TUNIT____-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; IS__TUNIT____-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; IS__TUNIT____-NEXT: tail call void @use3(i1 true, i1 true, i1 [[CMP_LTE_3]])
; IS__TUNIT____-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 false)
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test0-icmp-check
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; IS__CGSCC____-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_EQ_5:%.*]] = icmp eq i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_EQ_6:%.*]] = icmp eq i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_EQ_1]], i1 [[CMP_EQ_2]], i1 [[CMP_EQ_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_EQ_4]], i1 [[CMP_EQ_5]], i1 [[CMP_EQ_6]])
; IS__CGSCC____-NEXT: [[CMP_NE_1:%.*]] = icmp ne i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_NE_2:%.*]] = icmp ne i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_NE_3:%.*]] = icmp ne i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_NE_4:%.*]] = icmp ne i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_NE_5:%.*]] = icmp ne i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_NE_6:%.*]] = icmp ne i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_NE_1]], i1 [[CMP_NE_2]], i1 [[CMP_NE_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_NE_4]], i1 [[CMP_NE_5]], i1 [[CMP_NE_6]])
; IS__CGSCC____-NEXT: [[CMP_UGT_1:%.*]] = icmp ugt i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_UGT_2:%.*]] = icmp ugt i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_UGT_3:%.*]] = icmp ugt i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_UGT_4:%.*]] = icmp ugt i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_UGT_5:%.*]] = icmp ugt i32 [[RET]], 0
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_UGT_1]], i1 [[CMP_UGT_2]], i1 [[CMP_UGT_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_UGT_4]], i1 [[CMP_UGT_5]], i1 false)
; IS__CGSCC____-NEXT: [[CMP_UGE_1:%.*]] = icmp uge i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_UGE_2:%.*]] = icmp uge i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_UGE_3:%.*]] = icmp uge i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_UGE_4:%.*]] = icmp uge i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_UGE_6:%.*]] = icmp uge i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_UGE_1]], i1 [[CMP_UGE_2]], i1 [[CMP_UGE_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_UGE_4]], i1 true, i1 [[CMP_UGE_6]])
; IS__CGSCC____-NEXT: [[CMP_SGT_1:%.*]] = icmp sgt i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_SGT_2:%.*]] = icmp sgt i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_SGT_3:%.*]] = icmp sgt i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_SGT_4:%.*]] = icmp sgt i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_SGT_5:%.*]] = icmp sgt i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_SGT_6:%.*]] = icmp sgt i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_SGT_1]], i1 [[CMP_SGT_2]], i1 [[CMP_SGT_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_SGT_4]], i1 [[CMP_SGT_5]], i1 [[CMP_SGT_6]])
; IS__CGSCC____-NEXT: [[CMP_GTE_1:%.*]] = icmp sge i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_GTE_2:%.*]] = icmp sge i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_GTE_3:%.*]] = icmp sge i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_GTE_4:%.*]] = icmp sge i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_GTE_5:%.*]] = icmp sge i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_GTE_6:%.*]] = icmp sge i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_GTE_1]], i1 [[CMP_GTE_2]], i1 [[CMP_GTE_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_GTE_4]], i1 [[CMP_GTE_5]], i1 [[CMP_GTE_6]])
; IS__CGSCC____-NEXT: [[CMP_SLT_1:%.*]] = icmp slt i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_SLT_2:%.*]] = icmp slt i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_SLT_3:%.*]] = icmp slt i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_SLT_4:%.*]] = icmp slt i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_SLT_5:%.*]] = icmp slt i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_SLT_6:%.*]] = icmp slt i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_SLT_1]], i1 [[CMP_SLT_2]], i1 [[CMP_SLT_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_SLT_4]], i1 [[CMP_SLT_5]], i1 [[CMP_SLT_6]])
; IS__CGSCC____-NEXT: [[CMP_LTE_1:%.*]] = icmp sle i32 [[RET]], 10
; IS__CGSCC____-NEXT: [[CMP_LTE_2:%.*]] = icmp sle i32 [[RET]], 9
; IS__CGSCC____-NEXT: [[CMP_LTE_3:%.*]] = icmp sle i32 [[RET]], 8
; IS__CGSCC____-NEXT: [[CMP_LTE_4:%.*]] = icmp sle i32 [[RET]], 1
; IS__CGSCC____-NEXT: [[CMP_LTE_5:%.*]] = icmp sle i32 [[RET]], 0
; IS__CGSCC____-NEXT: [[CMP_LTE_6:%.*]] = icmp sle i32 [[RET]], -1
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_LTE_1]], i1 [[CMP_LTE_2]], i1 [[CMP_LTE_3]])
; IS__CGSCC____-NEXT: tail call void @use3(i1 [[CMP_LTE_4]], i1 [[CMP_LTE_5]], i1 [[CMP_LTE_6]])
; IS__CGSCC____-NEXT: ret void
;
%ret = tail call i32 @test0(i32 *%p)
; ret = [0, 10), eq
@ -383,29 +258,18 @@ define i32 @test1(i32* %p) {
}
define i1 @test1-check(i32* %p) {
; OLD_PM-LABEL: define {{[^@]+}}@test1-check
; OLD_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; OLD_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !2
; OLD_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; OLD_PM-NEXT: ret i1 [[CMP]]
;
; NEW_PM-LABEL: define {{[^@]+}}@test1-check
; NEW_PM-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; NEW_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly align 4 [[P]]) #{{[0-9]+}}, !range !2
; NEW_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; NEW_PM-NEXT: ret i1 [[CMP]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@test1-check
; IS__TUNIT____-SAME: (i32* nocapture nofree readonly align 4 [[P:%.*]])
; IS__TUNIT____-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly align 4 [[P]]) #4, !range !2
; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; IS__TUNIT____-NEXT: ret i1 [[CMP]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test1-check
; CGSCC_OLD_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_OLD_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_OLD_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; CGSCC_OLD_PM-NEXT: ret i1 [[CMP]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test1-check
; CGSCC_NEW_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_NEW_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_NEW_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; CGSCC_NEW_PM-NEXT: ret i1 [[CMP]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@test1-check
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; IS__CGSCC____-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; IS__CGSCC____-NEXT: ret i1 [[CMP]]
;
%res = tail call i32 @test1(i32* %p)
%cmp = icmp eq i32 %res, 500
@ -441,55 +305,30 @@ entry:
}
define i32 @test2_check(i32* %p) {
; OLD_PM-LABEL: define {{[^@]+}}@test2_check
; OLD_PM-SAME: (i32* nocapture nofree readnone align 4 [[P:%.*]])
; OLD_PM-NEXT: entry:
; OLD_PM-NEXT: br label [[IF_THEN:%.*]]
; OLD_PM: if.then:
; OLD_PM-NEXT: br label [[RETURN:%.*]]
; OLD_PM: if.end:
; OLD_PM-NEXT: unreachable
; OLD_PM: return:
; OLD_PM-NEXT: ret i32 2
; IS__TUNIT____-LABEL: define {{[^@]+}}@test2_check
; IS__TUNIT____-SAME: (i32* nocapture nofree readnone align 4 [[P:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: br label [[IF_THEN:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: br label [[RETURN:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: unreachable
; IS__TUNIT____: return:
; IS__TUNIT____-NEXT: ret i32 2
;
; NEW_PM-LABEL: define {{[^@]+}}@test2_check
; NEW_PM-SAME: (i32* nocapture nofree readnone align 4 [[P:%.*]])
; NEW_PM-NEXT: entry:
; NEW_PM-NEXT: br label [[IF_THEN:%.*]]
; NEW_PM: if.then:
; NEW_PM-NEXT: br label [[RETURN:%.*]]
; NEW_PM: if.end:
; NEW_PM-NEXT: unreachable
; NEW_PM: return:
; NEW_PM-NEXT: ret i32 2
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test2_check
; CGSCC_OLD_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_OLD_PM-NEXT: entry:
; CGSCC_OLD_PM-NEXT: [[CALL:%.*]] = tail call i32 @test2(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_OLD_PM-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 5
; CGSCC_OLD_PM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CGSCC_OLD_PM: if.then:
; CGSCC_OLD_PM-NEXT: br label [[RETURN:%.*]]
; CGSCC_OLD_PM: if.end:
; CGSCC_OLD_PM-NEXT: br label [[RETURN]]
; CGSCC_OLD_PM: return:
; CGSCC_OLD_PM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 2, [[IF_THEN]] ], [ 3, [[IF_END]] ]
; CGSCC_OLD_PM-NEXT: ret i32 [[RETVAL_0]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test2_check
; CGSCC_NEW_PM-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; CGSCC_NEW_PM-NEXT: entry:
; CGSCC_NEW_PM-NEXT: [[CALL:%.*]] = tail call i32 @test2(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; CGSCC_NEW_PM-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 5
; CGSCC_NEW_PM-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CGSCC_NEW_PM: if.then:
; CGSCC_NEW_PM-NEXT: br label [[RETURN:%.*]]
; CGSCC_NEW_PM: if.end:
; CGSCC_NEW_PM-NEXT: br label [[RETURN]]
; CGSCC_NEW_PM: return:
; CGSCC_NEW_PM-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 2, [[IF_THEN]] ], [ 3, [[IF_END]] ]
; CGSCC_NEW_PM-NEXT: ret i32 [[RETVAL_0]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@test2_check
; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = tail call i32 @test2(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P]])
; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 5
; IS__CGSCC____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: return:
; IS__CGSCC____-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 2, [[IF_THEN]] ], [ 3, [[IF_END]] ]
; IS__CGSCC____-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%call = tail call i32 @test2(i32* %p)
@ -535,55 +374,38 @@ return: ; preds = %if.end, %if.then
declare dso_local void @unkown()
define internal i32 @r1(i32) local_unnamed_addr {
; OLD_PM-LABEL: define {{[^@]+}}@r1() local_unnamed_addr
; OLD_PM-NEXT: br label [[TMP4:%.*]]
; OLD_PM: 1:
; OLD_PM-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP7:%.*]], 10000
; OLD_PM-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[F:%.*]]
; OLD_PM: 3:
; OLD_PM-NEXT: ret i32 20
; OLD_PM: f:
; OLD_PM-NEXT: ret i32 10
; OLD_PM: 4:
; OLD_PM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP8:%.*]], [[TMP4]] ]
; OLD_PM-NEXT: [[TMP6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP7]], [[TMP4]] ]
; OLD_PM-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP5]], [[TMP6]]
; OLD_PM-NEXT: [[TMP8]] = add nuw nsw i32 [[TMP5]], 1
; OLD_PM-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 100
; OLD_PM-NEXT: br i1 [[TMP9]], label [[TMP1:%.*]], label [[TMP4]]
; IS________OPM-LABEL: define {{[^@]+}}@r1() local_unnamed_addr
; IS________OPM-NEXT: br label [[TMP4:%.*]]
; IS________OPM: 1:
; IS________OPM-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP7:%.*]], 10000
; IS________OPM-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[F:%.*]]
; IS________OPM: 3:
; IS________OPM-NEXT: ret i32 20
; IS________OPM: f:
; IS________OPM-NEXT: ret i32 10
; IS________OPM: 4:
; IS________OPM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP8:%.*]], [[TMP4]] ]
; IS________OPM-NEXT: [[TMP6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP7]], [[TMP4]] ]
; IS________OPM-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP5]], [[TMP6]]
; IS________OPM-NEXT: [[TMP8]] = add nuw nsw i32 [[TMP5]], 1
; IS________OPM-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 100
; IS________OPM-NEXT: br i1 [[TMP9]], label [[TMP1:%.*]], label [[TMP4]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@r1() local_unnamed_addr
; CGSCC_OLD_PM-NEXT: br label [[TMP4:%.*]]
; CGSCC_OLD_PM: 1:
; CGSCC_OLD_PM-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP7:%.*]], 10000
; CGSCC_OLD_PM-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[F:%.*]]
; CGSCC_OLD_PM: 3:
; CGSCC_OLD_PM-NEXT: ret i32 20
; CGSCC_OLD_PM: f:
; CGSCC_OLD_PM-NEXT: ret i32 10
; CGSCC_OLD_PM: 4:
; CGSCC_OLD_PM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP8:%.*]], [[TMP4]] ]
; CGSCC_OLD_PM-NEXT: [[TMP6:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP7]], [[TMP4]] ]
; CGSCC_OLD_PM-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP5]], [[TMP6]]
; CGSCC_OLD_PM-NEXT: [[TMP8]] = add nuw nsw i32 [[TMP5]], 1
; CGSCC_OLD_PM-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 100
; CGSCC_OLD_PM-NEXT: br i1 [[TMP9]], label [[TMP1:%.*]], label [[TMP4]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@r1() local_unnamed_addr
; CGSCC_NEW_PM-NEXT: br label [[TMP3:%.*]]
; CGSCC_NEW_PM: 1:
; CGSCC_NEW_PM-NEXT: br label [[F:%.*]]
; CGSCC_NEW_PM: 2:
; CGSCC_NEW_PM-NEXT: unreachable
; CGSCC_NEW_PM: f:
; CGSCC_NEW_PM-NEXT: ret i32 10
; CGSCC_NEW_PM: 3:
; CGSCC_NEW_PM-NEXT: [[TMP4:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP7:%.*]], [[TMP3]] ]
; CGSCC_NEW_PM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP6:%.*]], [[TMP3]] ]
; CGSCC_NEW_PM-NEXT: [[TMP6]] = add nuw nsw i32 [[TMP4]], [[TMP5]]
; CGSCC_NEW_PM-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP4]], 1
; CGSCC_NEW_PM-NEXT: [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 100
; CGSCC_NEW_PM-NEXT: br i1 [[TMP8]], label [[TMP1:%.*]], label [[TMP3]]
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@r1() local_unnamed_addr
; IS__CGSCC_NPM-NEXT: br label [[TMP3:%.*]]
; IS__CGSCC_NPM: 1:
; IS__CGSCC_NPM-NEXT: br label [[F:%.*]]
; IS__CGSCC_NPM: 2:
; IS__CGSCC_NPM-NEXT: unreachable
; IS__CGSCC_NPM: f:
; IS__CGSCC_NPM-NEXT: ret i32 10
; IS__CGSCC_NPM: 3:
; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = phi i32 [ 0, [[TMP0:%.*]] ], [ [[TMP7:%.*]], [[TMP3]] ]
; IS__CGSCC_NPM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP0]] ], [ [[TMP6:%.*]], [[TMP3]] ]
; IS__CGSCC_NPM-NEXT: [[TMP6]] = add nuw nsw i32 [[TMP4]], [[TMP5]]
; IS__CGSCC_NPM-NEXT: [[TMP7]] = add nuw nsw i32 [[TMP4]], 1
; IS__CGSCC_NPM-NEXT: [[TMP8:%.*]] = icmp eq i32 [[TMP7]], 100
; IS__CGSCC_NPM-NEXT: br i1 [[TMP8]], label [[TMP1:%.*]], label [[TMP3]]
;
br label %5
@ -604,43 +426,24 @@ f:
}
define void @f1(i32){
; OLD_PM-LABEL: define {{[^@]+}}@f1
; OLD_PM-SAME: (i32 [[TMP0:%.*]])
; OLD_PM-NEXT: [[TMP2:%.*]] = tail call i32 @r1()
; OLD_PM-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; OLD_PM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; OLD_PM: 4:
; OLD_PM-NEXT: tail call void @unkown()
; OLD_PM-NEXT: br label [[TMP5]]
; OLD_PM: 5:
; OLD_PM-NEXT: ret void
; IS________OPM-LABEL: define {{[^@]+}}@f1
; IS________OPM-SAME: (i32 [[TMP0:%.*]])
; IS________OPM-NEXT: [[TMP2:%.*]] = tail call i32 @r1()
; IS________OPM-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; IS________OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; IS________OPM: 4:
; IS________OPM-NEXT: tail call void @unkown()
; IS________OPM-NEXT: br label [[TMP5]]
; IS________OPM: 5:
; IS________OPM-NEXT: ret void
;
; NEW_PM-LABEL: define {{[^@]+}}@f1
; NEW_PM-SAME: (i32 [[TMP0:%.*]])
; NEW_PM-NEXT: br label [[TMP3:%.*]]
; NEW_PM: 2:
; NEW_PM-NEXT: unreachable
; NEW_PM: 3:
; NEW_PM-NEXT: ret void
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@f1
; CGSCC_OLD_PM-SAME: (i32 [[TMP0:%.*]])
; CGSCC_OLD_PM-NEXT: [[TMP2:%.*]] = tail call i32 @r1()
; CGSCC_OLD_PM-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP2]], 15
; CGSCC_OLD_PM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP5:%.*]]
; CGSCC_OLD_PM: 4:
; CGSCC_OLD_PM-NEXT: tail call void @unkown()
; CGSCC_OLD_PM-NEXT: br label [[TMP5]]
; CGSCC_OLD_PM: 5:
; CGSCC_OLD_PM-NEXT: ret void
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@f1
; CGSCC_NEW_PM-SAME: (i32 [[TMP0:%.*]])
; CGSCC_NEW_PM-NEXT: br label [[TMP3:%.*]]
; CGSCC_NEW_PM: 2:
; CGSCC_NEW_PM-NEXT: unreachable
; CGSCC_NEW_PM: 3:
; CGSCC_NEW_PM-NEXT: ret void
; IS________NPM-LABEL: define {{[^@]+}}@f1
; IS________NPM-SAME: (i32 [[TMP0:%.*]])
; IS________NPM-NEXT: br label [[TMP3:%.*]]
; IS________NPM: 2:
; IS________NPM-NEXT: unreachable
; IS________NPM: 3:
; IS________NPM-NEXT: ret void
;
%2 = tail call i32 @r1(i32 %0)
%3 = icmp sgt i32 %2, 15
@ -745,65 +548,39 @@ return: ; preds = %if.else, %if.then
define dso_local i32 @test4-g2(i32 %u) {
; OLD_PM-LABEL: define {{[^@]+}}@test4-g2
; OLD_PM-SAME: (i32 [[U:%.*]])
; OLD_PM-NEXT: entry:
; OLD_PM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]])
; OLD_PM-NEXT: ret i32 [[CALL]]
; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@test4-g2
; NOT_TUNIT_NPM-SAME: (i32 [[U:%.*]])
; NOT_TUNIT_NPM-NEXT: entry:
; NOT_TUNIT_NPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]])
; NOT_TUNIT_NPM-NEXT: ret i32 [[CALL]]
;
; NEW_PM-LABEL: define {{[^@]+}}@test4-g2
; NEW_PM-SAME: (i32 [[U:%.*]])
; NEW_PM-NEXT: entry:
; NEW_PM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #2, !range !3
; NEW_PM-NEXT: ret i32 [[CALL]]
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test4-g2
; IS__TUNIT_NPM-SAME: (i32 [[U:%.*]])
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #2, !range !3
; IS__TUNIT_NPM-NEXT: ret i32 [[CALL]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test4-g2
; CGSCC_OLD_PM-SAME: (i32 [[U:%.*]])
; CGSCC_OLD_PM-NEXT: entry:
; CGSCC_OLD_PM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]])
; CGSCC_OLD_PM-NEXT: ret i32 [[CALL]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test4-g2
; CGSCC_NEW_PM-SAME: (i32 [[U:%.*]])
; CGSCC_NEW_PM-NEXT: entry:
; CGSCC_NEW_PM-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]])
; CGSCC_NEW_PM-NEXT: ret i32 [[CALL]]
;
; CGSCC-LABEL: define {{[^@]+}}@test4-g2
; CGSCC-SAME: (i32 [[U:%.*]])
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]])
; CGSCC-NEXT: ret i32 [[CALL]]
entry:
%call = tail call i32 @test4-f2(i32 %u)
ret i32 %call
}
define dso_local i32 @test-5() {
; OLD_PM-LABEL: define {{[^@]+}}@test-5()
; OLD_PM-NEXT: entry:
; OLD_PM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0), !range !3
; OLD_PM-NEXT: ret i32 [[CALL]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test-5()
; IS__TUNIT_OPM-NEXT: entry:
; IS__TUNIT_OPM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0), !range !3
; IS__TUNIT_OPM-NEXT: ret i32 [[CALL]]
;
; NEW_PM-LABEL: define {{[^@]+}}@test-5()
; NEW_PM-NEXT: entry:
; NEW_PM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0), !range !4
; NEW_PM-NEXT: ret i32 [[CALL]]
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test-5()
; IS__TUNIT_NPM-NEXT: entry:
; IS__TUNIT_NPM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0), !range !4
; IS__TUNIT_NPM-NEXT: ret i32 [[CALL]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test-5()
; CGSCC_OLD_PM-NEXT: entry:
; CGSCC_OLD_PM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0)
; CGSCC_OLD_PM-NEXT: ret i32 [[CALL]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@test-5()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0)
; IS__CGSCC____-NEXT: ret i32 [[CALL]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@test-5()
; CGSCC_NEW_PM-NEXT: entry:
; CGSCC_NEW_PM-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0)
; CGSCC_NEW_PM-NEXT: ret i32 [[CALL]]
;
; CGSCC-LABEL: define {{[^@]+}}@test-5()
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CALL:%.*]] = call i32 @rec(i32 0)
; CGSCC-NEXT: ret i32 [[CALL]]
entry:
%call = call i32 @rec(i32 0)
ret i32 %call
@ -1087,23 +864,15 @@ define i8 @undef_collapse_2() {
}
define i8 @undef_collapse_caller() {
; OLD_PM-LABEL: define {{[^@]+}}@undef_collapse_caller()
; OLD_PM-NEXT: ret i8 0
;
; NEW_PM-LABEL: define {{[^@]+}}@undef_collapse_caller()
; NEW_PM-NEXT: ret i8 0
; IS__TUNIT____-LABEL: define {{[^@]+}}@undef_collapse_caller()
; IS__TUNIT____-NEXT: ret i8 0
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@undef_collapse_caller()
; CGSCC_OLD_PM-NEXT: [[C1:%.*]] = call i8 @undef_collapse_1()
; CGSCC_OLD_PM-NEXT: [[C2:%.*]] = call i8 @undef_collapse_2()
; CGSCC_OLD_PM-NEXT: [[A:%.*]] = add i8 [[C1]], [[C2]]
; CGSCC_OLD_PM-NEXT: ret i8 [[A]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@undef_collapse_caller()
; CGSCC_NEW_PM-NEXT: [[C1:%.*]] = call i8 @undef_collapse_1()
; CGSCC_NEW_PM-NEXT: [[C2:%.*]] = call i8 @undef_collapse_2()
; CGSCC_NEW_PM-NEXT: [[A:%.*]] = add i8 [[C1]], [[C2]]
; CGSCC_NEW_PM-NEXT: ret i8 [[A]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@undef_collapse_caller()
; IS__CGSCC____-NEXT: [[C1:%.*]] = call i8 @undef_collapse_1()
; IS__CGSCC____-NEXT: [[C2:%.*]] = call i8 @undef_collapse_2()
; IS__CGSCC____-NEXT: [[A:%.*]] = add i8 [[C1]], [[C2]]
; IS__CGSCC____-NEXT: ret i8 [[A]]
;
%c1 = call i8 @undef_collapse_1()
%c2 = call i8 @undef_collapse_2()
@ -1121,35 +890,21 @@ define i32 @ret1or2(i1 %c) {
ret i32 %s
}
define i1 @callee_range_1(i1 %c1, i1 %c2, i1 %c3) {
; OLD_PM-LABEL: define {{[^@]+}}@callee_range_1
; OLD_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; OLD_PM-NEXT: ret i1 true
;
; NEW_PM-LABEL: define {{[^@]+}}@callee_range_1
; NEW_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; NEW_PM-NEXT: ret i1 true
; IS__TUNIT____-LABEL: define {{[^@]+}}@callee_range_1
; IS__TUNIT____-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; IS__TUNIT____-NEXT: ret i1 true
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@callee_range_1
; CGSCC_OLD_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; CGSCC_OLD_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; CGSCC_OLD_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; CGSCC_OLD_PM-NEXT: [[INDIRECTION:%.*]] = select i1 [[C3]], i32 [[R1]], i32 [[R2]]
; CGSCC_OLD_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[INDIRECTION]]
; CGSCC_OLD_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 4
; CGSCC_OLD_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC_OLD_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC_OLD_PM-NEXT: ret i1 [[F]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@callee_range_1
; CGSCC_NEW_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; CGSCC_NEW_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; CGSCC_NEW_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; CGSCC_NEW_PM-NEXT: [[INDIRECTION:%.*]] = select i1 [[C3]], i32 [[R1]], i32 [[R2]]
; CGSCC_NEW_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[INDIRECTION]]
; CGSCC_NEW_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 4
; CGSCC_NEW_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC_NEW_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC_NEW_PM-NEXT: ret i1 [[F]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee_range_1
; IS__CGSCC____-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
; IS__CGSCC____-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; IS__CGSCC____-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; IS__CGSCC____-NEXT: [[INDIRECTION:%.*]] = select i1 [[C3]], i32 [[R1]], i32 [[R2]]
; IS__CGSCC____-NEXT: [[A:%.*]] = add i32 [[R1]], [[INDIRECTION]]
; IS__CGSCC____-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 4
; IS__CGSCC____-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; IS__CGSCC____-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; IS__CGSCC____-NEXT: ret i1 [[F]]
;
%r1 = call i32 @ret1or2(i1 %c1)
%r2 = call i32 @ret1or2(i1 %c2)
@ -1162,45 +917,36 @@ define i1 @callee_range_1(i1 %c1, i1 %c2, i1 %c3) {
}
define i1 @callee_range_2(i1 %c1, i1 %c2) {
; OLD_PM-LABEL: define {{[^@]+}}@callee_range_2
; OLD_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; OLD_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #2, !range !4
; OLD_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #3, !range !4
; OLD_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; OLD_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; OLD_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; OLD_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; OLD_PM-NEXT: ret i1 [[F]]
;
; NEW_PM-LABEL: define {{[^@]+}}@callee_range_2
; NEW_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; NEW_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #2, !range !5
; NEW_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #3, !range !5
; NEW_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; NEW_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; NEW_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; NEW_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; NEW_PM-NEXT: ret i1 [[F]]
; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@callee_range_2
; IS__TUNIT_OPM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; IS__TUNIT_OPM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #2, !range !4
; IS__TUNIT_OPM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #3, !range !4
; IS__TUNIT_OPM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; IS__TUNIT_OPM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; IS__TUNIT_OPM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; IS__TUNIT_OPM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; IS__TUNIT_OPM-NEXT: ret i1 [[F]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@callee_range_2
; CGSCC_OLD_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; CGSCC_OLD_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; CGSCC_OLD_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; CGSCC_OLD_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; CGSCC_OLD_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; CGSCC_OLD_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC_OLD_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC_OLD_PM-NEXT: ret i1 [[F]]
; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@callee_range_2
; IS__TUNIT_NPM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; IS__TUNIT_NPM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]]) #2, !range !5
; IS__TUNIT_NPM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]]) #3, !range !5
; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; IS__TUNIT_NPM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; IS__TUNIT_NPM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; IS__TUNIT_NPM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; IS__TUNIT_NPM-NEXT: ret i1 [[F]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@callee_range_2
; CGSCC_NEW_PM-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; CGSCC_NEW_PM-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; CGSCC_NEW_PM-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; CGSCC_NEW_PM-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; CGSCC_NEW_PM-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; CGSCC_NEW_PM-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; CGSCC_NEW_PM-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; CGSCC_NEW_PM-NEXT: ret i1 [[F]]
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee_range_2
; IS__CGSCC____-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]])
; IS__CGSCC____-NEXT: [[R1:%.*]] = call i32 @ret1or2(i1 [[C1]])
; IS__CGSCC____-NEXT: [[R2:%.*]] = call i32 @ret1or2(i1 [[C2]])
; IS__CGSCC____-NEXT: [[A:%.*]] = add i32 [[R1]], [[R2]]
; IS__CGSCC____-NEXT: [[I1:%.*]] = icmp sle i32 [[A]], 3
; IS__CGSCC____-NEXT: [[I2:%.*]] = icmp sge i32 [[A]], 2
; IS__CGSCC____-NEXT: [[F:%.*]] = and i1 [[I1]], [[I2]]
; IS__CGSCC____-NEXT: ret i1 [[F]]
;
%r1 = call i32 @ret1or2(i1 %c1)
%r2 = call i32 @ret1or2(i1 %c2)
@ -1220,53 +966,30 @@ define i32 @ret100() {
}
define i1 @ctx_adjustment(i32 %V) {
; OLD_PM-LABEL: define {{[^@]+}}@ctx_adjustment
; OLD_PM-SAME: (i32 [[V:%.*]])
; OLD_PM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; OLD_PM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; OLD_PM: if.true:
; OLD_PM-NEXT: br label [[END:%.*]]
; OLD_PM: if.false:
; OLD_PM-NEXT: br label [[END]]
; OLD_PM: end:
; OLD_PM-NEXT: [[PHI:%.*]] = phi i32 [ [[V]], [[IF_TRUE]] ], [ 100, [[IF_FALSE]] ]
; OLD_PM-NEXT: [[C2:%.*]] = icmp sge i32 [[PHI]], 100
; OLD_PM-NEXT: ret i1 [[C2]]
;
; NEW_PM-LABEL: define {{[^@]+}}@ctx_adjustment
; NEW_PM-SAME: (i32 [[V:%.*]])
; NEW_PM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; NEW_PM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; NEW_PM: if.true:
; NEW_PM-NEXT: br label [[END:%.*]]
; NEW_PM: if.false:
; NEW_PM-NEXT: br label [[END]]
; NEW_PM: end:
; NEW_PM-NEXT: ret i1 true
; IS________OPM-LABEL: define {{[^@]+}}@ctx_adjustment
; IS________OPM-SAME: (i32 [[V:%.*]])
; IS________OPM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; IS________OPM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; IS________OPM: if.true:
; IS________OPM-NEXT: br label [[END:%.*]]
; IS________OPM: if.false:
; IS________OPM-NEXT: br label [[END]]
; IS________OPM: end:
; IS________OPM-NEXT: [[PHI:%.*]] = phi i32 [ [[V]], [[IF_TRUE]] ], [ 100, [[IF_FALSE]] ]
; IS________OPM-NEXT: [[C2:%.*]] = icmp sge i32 [[PHI]], 100
; IS________OPM-NEXT: ret i1 [[C2]]
;
; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@ctx_adjustment
; CGSCC_OLD_PM-SAME: (i32 [[V:%.*]])
; CGSCC_OLD_PM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; CGSCC_OLD_PM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CGSCC_OLD_PM: if.true:
; CGSCC_OLD_PM-NEXT: br label [[END:%.*]]
; CGSCC_OLD_PM: if.false:
; CGSCC_OLD_PM-NEXT: br label [[END]]
; CGSCC_OLD_PM: end:
; CGSCC_OLD_PM-NEXT: [[PHI:%.*]] = phi i32 [ [[V]], [[IF_TRUE]] ], [ 100, [[IF_FALSE]] ]
; CGSCC_OLD_PM-NEXT: [[C2:%.*]] = icmp sge i32 [[PHI]], 100
; CGSCC_OLD_PM-NEXT: ret i1 [[C2]]
;
; CGSCC_NEW_PM-LABEL: define {{[^@]+}}@ctx_adjustment
; CGSCC_NEW_PM-SAME: (i32 [[V:%.*]])
; CGSCC_NEW_PM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; CGSCC_NEW_PM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CGSCC_NEW_PM: if.true:
; CGSCC_NEW_PM-NEXT: br label [[END:%.*]]
; CGSCC_NEW_PM: if.false:
; CGSCC_NEW_PM-NEXT: br label [[END]]
; CGSCC_NEW_PM: end:
; CGSCC_NEW_PM-NEXT: ret i1 true
; IS________NPM-LABEL: define {{[^@]+}}@ctx_adjustment
; IS________NPM-SAME: (i32 [[V:%.*]])
; IS________NPM-NEXT: [[C1:%.*]] = icmp sge i32 [[V]], 100
; IS________NPM-NEXT: br i1 [[C1]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; IS________NPM: if.true:
; IS________NPM-NEXT: br label [[END:%.*]]
; IS________NPM: if.false:
; IS________NPM-NEXT: br label [[END]]
; IS________NPM: end:
; IS________NPM-NEXT: ret i1 true
;
%c1 = icmp sge i32 %V, 100
br i1 %c1, label %if.true, label %if.false
@ -1284,9 +1007,22 @@ end:
!0 = !{i32 0, i32 10}
!1 = !{i32 10, i32 100}
; CHECK: !0 = !{i32 0, i32 10}
; CHECK-NEXT: !1 = !{i32 10, i32 100}
; NEW_PM: !2 = !{i32 200, i32 1091}
; OLD_PM: !3 = !{i32 0, i32 2}
; NEW_PM: !3 = !{i32 1, i32 -2147483648}
; NEW_PM: !4 = !{i32 0, i32 2}
; NOT_TUNIT____: !0 = !{i32 0, i32 10}
; NOT_TUNIT____: !1 = !{i32 10, i32 100}
; NOT_TUNIT____-NOT: !2
; IS__TUNIT_OPM: !0 = !{i32 0, i32 10}
; IS__TUNIT_OPM: !1 = !{i32 10, i32 100}
; IS__TUNIT_OPM: !2 = !{i32 200, i32 1091}
; IS__TUNIT_OPM: !3 = !{i32 0, i32 2}
; IS__TUNIT_OPM: !4 = !{i32 1, i32 3}
; IS__TUNIT_OPM-NOT: !5
; IS__TUNIT_NPM: !0 = !{i32 0, i32 10}
; IS__TUNIT_NPM: !1 = !{i32 10, i32 100}
; IS__TUNIT_NPM: !2 = !{i32 200, i32 1091}
; IS__TUNIT_NPM: !3 = !{i32 1, i32 -2147483648}
; IS__TUNIT_NPM: !4 = !{i32 0, i32 2}
; IS__TUNIT_NPM: !5 = !{i32 1, i32 3}
; IS__TUNIT_NPM-NOT: !6

View File

@ -1,4 +1,9 @@
; RUN: opt -functionattrs -enable-nonnull-arg-prop -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; This is an evolved example to stress test SCC parameter attribute propagation.
; The SCC in this test is made up of the following six function, three of which
@ -30,8 +35,16 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
; CHECK-NEXT: define i32* @external_ret2_nrw(i32* nofree %n0, i32* nofree %r0, i32* nofree returned %w0)
define i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
; CHECK-LABEL: define {{[^@]+}}@external_ret2_nrw
; CHECK-SAME: (i32* nofree [[N0:%.*]], i32* nofree [[R0:%.*]], i32* nofree returned [[W0:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @internal_ret0_nw(i32* nofree [[N0]], i32* nofree [[W0]])
; CHECK-NEXT: [[CALL1:%.*]] = call i32* @internal_ret1_rrw(i32* nofree align 4 [[R0]], i32* nofree [[R0]], i32* nofree [[W0]])
; CHECK-NEXT: [[CALL2:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree readonly align 4 [[R0]], i32* nofree writeonly [[W0]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32* @internal_ret1_rw(i32* nofree align 4 [[R0]], i32* nofree [[W0]])
; CHECK-NEXT: ret i32* [[CALL3]]
;
entry:
%call = call i32* @internal_ret0_nw(i32* %n0, i32* %w0)
%call1 = call i32* @internal_ret1_rrw(i32* %r0, i32* %r0, i32* %w0)
@ -41,8 +54,55 @@ entry:
}
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
; CHECK-NEXT: define internal i32* @internal_ret0_nw(i32* nofree returned %n0, i32* nofree %w0)
define internal i32* @internal_ret0_nw(i32* %n0, i32* %w0) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@internal_ret0_nw
; IS__TUNIT____-SAME: (i32* nofree returned [[N0:%.*]], i32* nofree [[W0:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[R0:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: [[R1:%.*]] = alloca i32, align 4
; IS__TUNIT____-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[N0]], null
; IS__TUNIT____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: br label [[RETURN:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: store i32 3, i32* [[R0]], align 4
; IS__TUNIT____-NEXT: store i32 5, i32* [[R1]], align 4
; IS__TUNIT____-NEXT: store i32 1, i32* [[W0]], align 4
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__TUNIT____-NEXT: [[CALL3:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R0]], i32* nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]])
; IS__TUNIT____-NEXT: [[CALL4:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R1]], i32* nofree nonnull writeonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[W0]])
; IS__TUNIT____-NEXT: [[CALL5:%.*]] = call i32* @internal_ret0_nw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__TUNIT____-NEXT: br label [[RETURN]]
; IS__TUNIT____: return:
; IS__TUNIT____-NEXT: [[RETVAL_0:%.*]] = phi i32* [ [[CALL5]], [[IF_END]] ], [ [[N0]], [[IF_THEN]] ]
; IS__TUNIT____-NEXT: ret i32* [[RETVAL_0]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@internal_ret0_nw
; IS__CGSCC____-SAME: (i32* nofree returned [[N0:%.*]], i32* nofree [[W0:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[R0:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: [[R1:%.*]] = alloca i32, align 4
; IS__CGSCC____-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[N0]], null
; IS__CGSCC____-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: store i32 3, i32* [[R0]], align 4
; IS__CGSCC____-NEXT: store i32 5, i32* [[R1]], align 4
; IS__CGSCC____-NEXT: store i32 1, i32* [[W0]], align 4
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: [[CALL2:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: [[CALL3:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R0]], i32* nofree nonnull writeonly align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: [[CALL4:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R1]], i32* nofree nonnull writeonly align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: [[CALL5:%.*]] = call i32* @internal_ret0_nw(i32* nofree [[N0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: return:
; IS__CGSCC____-NEXT: [[RETVAL_0:%.*]] = phi i32* [ [[CALL5]], [[IF_END]] ], [ [[N0]], [[IF_THEN]] ]
; IS__CGSCC____-NEXT: ret i32* [[RETVAL_0]]
;
entry:
%r0 = alloca i32, align 4
%r1 = alloca i32, align 4
@ -70,8 +130,34 @@ return: ; preds = %if.end, %if.then
}
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
; CHECK-NEXT: define internal i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %r1, i32* nofree %w0)
define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) {
; CHECK-LABEL: define {{[^@]+}}@internal_ret1_rrw
; CHECK-SAME: (i32* nofree nonnull align 4 dereferenceable(4) [[R0:%.*]], i32* nofree returned [[R1:%.*]], i32* nofree [[W0:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[R0]], align 4
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree [[W0]])
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[R0]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[R1]], align 4
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: store i32 [[ADD]], i32* [[W0]], align 4
; CHECK-NEXT: [[CALL1:%.*]] = call i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL2:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[W0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL4:%.*]] = call i32* @external_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL5:%.*]] = call i32* @external_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL6:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R1]], i32* nofree nonnull writeonly align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL7:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R0]], i32* nofree nonnull writeonly align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL8:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[R1]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32* [ [[CALL8]], [[IF_END]] ], [ [[R1]], [[IF_THEN]] ]
; CHECK-NEXT: ret i32* undef
;
entry:
%0 = load i32, i32* %r0, align 4
%tobool = icmp ne i32 %0, 0
@ -101,9 +187,23 @@ return: ; preds = %if.end, %if.then
ret i32* %retval.0
}
; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
; CHECK-NEXT: define i32* @external_sink_ret2_nrw(i32* nofree readnone %n0, i32* nocapture nofree readonly %r0, i32* nofree returned writeonly "no-capture-maybe-returned" %w0)
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
define i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
; CHECK-LABEL: define {{[^@]+}}@external_sink_ret2_nrw
; CHECK-SAME: (i32* nofree [[N0:%.*]], i32* nocapture nofree readonly [[R0:%.*]], i32* nofree returned writeonly "no-capture-maybe-returned" [[W0:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[N0]], null
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[R0]], align 4
; CHECK-NEXT: store i32 [[TMP0]], i32* [[W0]], align 4
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: ret i32* [[W0]]
;
entry:
%tobool = icmp ne i32* %n0, null
br i1 %tobool, label %if.end, label %if.then
@ -121,8 +221,28 @@ return: ; preds = %if.end, %if.then
}
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
; CHECK-NEXT: define internal i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) %r0, i32* nofree returned %w0)
define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) {
; CHECK-LABEL: define {{[^@]+}}@internal_ret1_rw
; CHECK-SAME: (i32* nofree nonnull align 4 dereferenceable(4) [[R0:%.*]], i32* nofree returned [[W0:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[R0]], align 4
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree [[W0]])
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[R0]], align 4
; CHECK-NEXT: store i32 [[TMP1]], i32* [[W0]], align 4
; CHECK-NEXT: [[CALL1:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL2:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[W0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL3:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull readonly align 4 dereferenceable(4) [[R0]], i32* nofree nonnull writeonly align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: [[CALL4:%.*]] = call i32* @external_ret2_nrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]])
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32* [ [[CALL4]], [[IF_END]] ], [ [[W0]], [[IF_THEN]] ]
; CHECK-NEXT: ret i32* [[RETVAL_0]]
;
entry:
%0 = load i32, i32* %r0, align 4
%tobool = icmp ne i32 %0, 0
@ -147,8 +267,21 @@ return: ; preds = %if.end, %if.then
}
; CHECK: Function Attrs: argmemonly nofree nosync nounwind
; CHECK-NEXT: define i32* @external_source_ret2_nrw(i32* nofree %n0, i32* nofree %r0, i32* nofree returned %w0)
define i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@external_source_ret2_nrw
; IS__TUNIT____-SAME: (i32* nofree [[N0:%.*]], i32* nofree [[R0:%.*]], i32* nofree returned [[W0:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nocapture nofree readonly [[R0]], i32* nofree writeonly "no-capture-maybe-returned" [[W0]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree [[R0]], i32* nofree [[W0]])
; IS__TUNIT____-NEXT: ret i32* [[CALL1]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@external_source_ret2_nrw
; IS__CGSCC____-SAME: (i32* nofree [[N0:%.*]], i32* nofree [[R0:%.*]], i32* nofree returned [[W0:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nofree readonly [[R0]], i32* nofree writeonly [[W0]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree [[R0]], i32* nofree [[W0]])
; IS__CGSCC____-NEXT: ret i32* [[CALL1]]
;
entry:
%call = call i32* @external_sink_ret2_nrw(i32* %n0, i32* %r0, i32* %w0)
%call1 = call i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0)
@ -158,9 +291,17 @@ entry:
; Verify that we see only expected attribute sets, the above lines only check
; for a subset relation.
;
; CHECK-NOT: attributes #
; CHECK: attributes #{{.*}} = { argmemonly nofree nosync nounwind }
; CHECK: attributes #{{.*}} = { argmemonly nofree norecurse nosync nounwind willreturn }
; CHECK: attributes #{{.*}} = { nosync nounwind }
; CHECK: attributes #{{.*}} = { norecurse nosync nounwind willreturn }
; CHECK-NOT: attributes #
; IS__CGSCC____-NOT: attributes #
; IS__CGSCC____: attributes #{{.*}} = { argmemonly nofree nosync nounwind }
; IS__CGSCC____: attributes #{{.*}} = { argmemonly nofree norecurse nosync nounwind willreturn }
; IS__CGSCC____: attributes #{{.*}} = { nofree nosync nounwind }
; IS__CGSCC____: attributes #{{.*}} = { nounwind }
; IS__CGSCC____: attributes #{{.*}} = { nounwind willreturn }
; IS__CGSCC____-NOT: attributes #
; IS__TUNIT____-NOT: attributes #
; IS__TUNIT____: attributes #{{.*}} = { argmemonly nofree nosync nounwind }
; IS__TUNIT____: attributes #{{.*}} = { argmemonly nofree nosync nounwind willreturn }
; IS__TUNIT____: attributes #{{.*}} = { nofree nosync nounwind }
; IS__TUNIT____: attributes #{{.*}} = { nofree nosync nounwind willreturn }
; IS__TUNIT____-NOT: attributes #

View File

@ -1,6 +1,9 @@
; RUN: opt < %s -attributor -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=ATTRIBUTOR
; RUN: opt < %s -aa-pipeline=basic-aa -passes='attributor' -attributor-disable=false -S -attributor-annotate-decl-cs | FileCheck %s --check-prefixes=ATTRIBUTOR
; Copied from Transforms/FunctionAttrs/readattrs.ll
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@x = global i32 0
@ -8,111 +11,175 @@ declare void @test1_1(i8* %x1_1, i8* readonly %y1_1, ...)
; NOTE: readonly for %y1_2 would be OK here but not for the similar situation in test13.
;
; ATTRIBUTOR: define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2)
define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
; CHECK-LABEL: define {{[^@]+}}@test1_2
; CHECK-SAME: (i8* [[X1_2:%.*]], i8* [[Y1_2:%.*]], i8* [[Z1_2:%.*]])
; CHECK-NEXT: call void (i8*, i8*, ...) @test1_1(i8* [[X1_2]], i8* readonly [[Y1_2]], i8* [[Z1_2]])
; CHECK-NEXT: store i32 0, i32* @x, align 4
; CHECK-NEXT: ret void
;
call void (i8*, i8*, ...) @test1_1(i8* %x1_2, i8* %y1_2, i8* %z1_2)
store i32 0, i32* @x
ret void
}
; ATTRIBUTOR: define i8* @test2(i8* nofree readnone returned %p)
define i8* @test2(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@test2
; CHECK-SAME: (i8* nofree readnone returned "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: store i32 0, i32* @x, align 4
; CHECK-NEXT: ret i8* [[P]]
;
store i32 0, i32* @x
ret i8* %p
}
; ATTRIBUTOR: define i1 @test3(i8* nofree readnone %p, i8* nofree readnone %q)
define i1 @test3(i8* %p, i8* %q) {
; CHECK-LABEL: define {{[^@]+}}@test3
; CHECK-SAME: (i8* nofree readnone [[P:%.*]], i8* nofree readnone [[Q:%.*]])
; CHECK-NEXT: [[A:%.*]] = icmp ult i8* [[P]], [[Q]]
; CHECK-NEXT: ret i1 [[A]]
;
%A = icmp ult i8* %p, %q
ret i1 %A
}
declare void @test4_1(i8* nocapture) readonly
; ATTRIBUTOR: define void @test4_2(i8* nocapture readonly %p)
define void @test4_2(i8* %p) {
; CHECK-LABEL: define {{[^@]+}}@test4_2
; CHECK-SAME: (i8* nocapture readonly [[P:%.*]])
; CHECK-NEXT: call void @test4_1(i8* nocapture readonly [[P]])
; CHECK-NEXT: ret void
;
call void @test4_1(i8* %p)
ret void
}
; ATTRIBUTOR: define void @test5(i8** nocapture nofree nonnull writeonly align 8 dereferenceable(8) %p, i8* nofree writeonly %q)
; Missed optz'n: we could make %q readnone, but don't break test6!
define void @test5(i8** %p, i8* %q) {
; CHECK-LABEL: define {{[^@]+}}@test5
; CHECK-SAME: (i8** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[P:%.*]], i8* nofree writeonly [[Q:%.*]])
; CHECK-NEXT: store i8* [[Q]], i8** [[P]], align 8
; CHECK-NEXT: ret void
;
store i8* %q, i8** %p
ret void
}
declare void @test6_1()
; ATTRIBUTOR: define void @test6_2(i8** nocapture nonnull writeonly align 8 dereferenceable(8) %p, i8* %q)
; This is not a missed optz'n.
define void @test6_2(i8** %p, i8* %q) {
; CHECK-LABEL: define {{[^@]+}}@test6_2
; CHECK-SAME: (i8** nocapture nonnull writeonly align 8 dereferenceable(8) [[P:%.*]], i8* [[Q:%.*]])
; CHECK-NEXT: store i8* [[Q]], i8** [[P]], align 8
; CHECK-NEXT: call void @test6_1()
; CHECK-NEXT: ret void
;
store i8* %q, i8** %p
call void @test6_1()
ret void
}
; ATTRIBUTOR: define void @test7_1(i32* inalloca nocapture nofree writeonly %a)
; inalloca parameters are always considered written
define void @test7_1(i32* inalloca %a) {
; CHECK-LABEL: define {{[^@]+}}@test7_1
; CHECK-SAME: (i32* inalloca nocapture nofree writeonly [[A:%.*]])
; CHECK-NEXT: ret void
;
ret void
}
; ATTRIBUTOR: define i32* @test8_1(i32* nofree readnone returned %p)
define i32* @test8_1(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@test8_1
; CHECK-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[P:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32* [[P]]
;
entry:
ret i32* %p
}
; ATTRIBUTOR: define void @test8_2(i32* nocapture nofree writeonly %p)
define void @test8_2(i32* %p) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@test8_2
; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @test8_1(i32* noalias nofree readnone "no-capture-maybe-returned" [[P]])
; IS__TUNIT____-NEXT: store i32 10, i32* [[CALL]], align 4
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test8_2
; IS__CGSCC____-SAME: (i32* nofree writeonly [[P:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call align 4 i32* @test8_1(i32* noalias nofree readnone [[P]])
; IS__CGSCC____-NEXT: store i32 10, i32* [[CALL]], align 4
; IS__CGSCC____-NEXT: ret void
;
entry:
%call = call i32* @test8_1(i32* %p)
store i32 10, i32* %call, align 4
ret void
}
; ATTRIBUTOR: declare void @llvm.masked.scatter
; CHECK: declare void @llvm.masked.scatter
declare void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*>, i32, <4 x i1>)
; ATTRIBUTOR-NOT: readnone
; ATTRIBUTOR-NOT: readonly
; ATTRIBUTOR: define void @test9
; CHECK-NOT: readnone
; CHECK-NOT: readonly
define void @test9(<4 x i32*> %ptrs, <4 x i32>%val) {
; CHECK-LABEL: define {{[^@]+}}@test9
; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]])
; CHECK-NEXT: call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32> [[VAL]], <4 x i32*> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>)
; CHECK-NEXT: ret void
;
call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
ret void
}
; ATTRIBUTOR: declare <4 x i32> @llvm.masked.gather
; CHECK: declare <4 x i32> @llvm.masked.gather
declare <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*>, i32, <4 x i1>, <4 x i32>)
; ATTRIBUTOR: readonly
; ATTRIBUTOR: define <4 x i32> @test10
; CHECK: readonly
define <4 x i32> @test10(<4 x i32*> %ptrs) {
; CHECK-LABEL: define {{[^@]+}}@test10
; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]])
; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef)
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
ret <4 x i32> %res
}
; ATTRIBUTOR: declare <4 x i32> @test11_1
; CHECK: declare <4 x i32> @test11_1
declare <4 x i32> @test11_1(<4 x i32*>) argmemonly nounwind readonly
; ATTRIBUTOR: readonly
; ATTRIBUTOR-NOT: readnone
; ATTRIBUTOR: define <4 x i32> @test11_2
; CHECK: readonly
; CHECK-NOT: readnone
define <4 x i32> @test11_2(<4 x i32*> %ptrs) {
; CHECK-LABEL: define {{[^@]+}}@test11_2
; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]])
; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test11_1(<4 x i32*> [[PTRS]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%res = call <4 x i32> @test11_1(<4 x i32*> %ptrs)
ret <4 x i32> %res
}
declare <4 x i32> @test12_1(<4 x i32*>) argmemonly nounwind
; ATTRIBUTOR-NOT: readnone
; ATTRIBUTOR: define <4 x i32> @test12_2
; CHECK-NOT: readnone
define <4 x i32> @test12_2(<4 x i32*> %ptrs) {
; CHECK-LABEL: define {{[^@]+}}@test12_2
; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]])
; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x i32*> [[PTRS]])
; CHECK-NEXT: ret <4 x i32> [[RES]]
;
%res = call <4 x i32> @test12_1(<4 x i32*> %ptrs)
ret <4 x i32> %res
}
; ATTRIBUTOR: define i32 @volatile_load(
; ATTRIBUTOR-NOT: readonly
; ATTRIBUTOR: ret
define i32 @volatile_load(i32* %p) {
; CHECK-LABEL: define {{[^@]+}}@volatile_load
; CHECK-SAME: (i32* nofree align 4 [[P:%.*]])
; CHECK-NEXT: [[LOAD:%.*]] = load volatile i32, i32* [[P]], align 4
; CHECK-NEXT: ret i32 [[LOAD]]
;
%load = load volatile i32, i32* %p
ret i32 %load
}
@ -125,10 +192,15 @@ declare void @escape_readonly_ptr(i8** %addr, i8* readonly %ptr)
; is marked as readnone/only. However, the functions can write the pointer into
; %addr, causing the store to write to %escaped_then_written.
;
;
; ATTRIBUTOR: define void @unsound_readnone(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
; ATTRIBUTOR: define void @unsound_readonly(i8* nocapture nofree readnone %ignored, i8* %escaped_then_written)
define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) {
; CHECK-LABEL: define {{[^@]+}}@unsound_readnone
; CHECK-SAME: (i8* nocapture nofree readnone [[IGNORED:%.*]], i8* [[ESCAPED_THEN_WRITTEN:%.*]])
; CHECK-NEXT: [[ADDR:%.*]] = alloca i8*
; CHECK-NEXT: call void @escape_readnone_ptr(i8** nonnull align 8 dereferenceable(8) [[ADDR]], i8* noalias readnone [[ESCAPED_THEN_WRITTEN]])
; CHECK-NEXT: [[ADDR_LD:%.*]] = load i8*, i8** [[ADDR]], align 8
; CHECK-NEXT: store i8 0, i8* [[ADDR_LD]]
; CHECK-NEXT: ret void
;
%addr = alloca i8*
call void @escape_readnone_ptr(i8** %addr, i8* %escaped_then_written)
%addr.ld = load i8*, i8** %addr
@ -137,6 +209,14 @@ define void @unsound_readnone(i8* %ignored, i8* %escaped_then_written) {
}
define void @unsound_readonly(i8* %ignored, i8* %escaped_then_written) {
; CHECK-LABEL: define {{[^@]+}}@unsound_readonly
; CHECK-SAME: (i8* nocapture nofree readnone [[IGNORED:%.*]], i8* [[ESCAPED_THEN_WRITTEN:%.*]])
; CHECK-NEXT: [[ADDR:%.*]] = alloca i8*
; CHECK-NEXT: call void @escape_readonly_ptr(i8** nonnull align 8 dereferenceable(8) [[ADDR]], i8* readonly [[ESCAPED_THEN_WRITTEN]])
; CHECK-NEXT: [[ADDR_LD:%.*]] = load i8*, i8** [[ADDR]], align 8
; CHECK-NEXT: store i8 0, i8* [[ADDR_LD]]
; CHECK-NEXT: ret void
;
%addr = alloca i8*
call void @escape_readonly_ptr(i8** %addr, i8* %escaped_then_written)
%addr.ld = load i8*, i8** %addr
@ -149,44 +229,69 @@ define void @unsound_readonly(i8* %ignored, i8* %escaped_then_written) {
;{
declare void @escape_i8(i8* %ptr)
; ATTRIBUTOR: @byval_not_readonly_1
; ATTRIBUTOR-SAME: i8* noalias byval %written
define void @byval_not_readonly_1(i8* byval %written) readonly {
; CHECK-LABEL: define {{[^@]+}}@byval_not_readonly_1
; CHECK-SAME: (i8* noalias byval [[WRITTEN:%.*]])
; CHECK-NEXT: call void @escape_i8(i8* [[WRITTEN]])
; CHECK-NEXT: ret void
;
call void @escape_i8(i8* %written)
ret void
}
; ATTRIBUTOR: @byval_not_readonly_2
; ATTRIBUTOR-SAME: i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) %written
define void @byval_not_readonly_2(i8* byval %written) readonly {
; CHECK-LABEL: define {{[^@]+}}@byval_not_readonly_2
; CHECK-SAME: (i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) [[WRITTEN:%.*]])
; CHECK-NEXT: store i8 0, i8* [[WRITTEN]]
; CHECK-NEXT: ret void
;
store i8 0, i8* %written
ret void
}
; ATTRIBUTOR: @byval_not_readnone_1
; ATTRIBUTOR-SAME: i8* noalias byval %written
define void @byval_not_readnone_1(i8* byval %written) readnone {
; CHECK-LABEL: define {{[^@]+}}@byval_not_readnone_1
; CHECK-SAME: (i8* noalias byval [[WRITTEN:%.*]])
; CHECK-NEXT: call void @escape_i8(i8* [[WRITTEN]])
; CHECK-NEXT: ret void
;
call void @escape_i8(i8* %written)
ret void
}
; ATTRIBUTOR: @byval_not_readnone_2
; ATTRIBUTOR-SAME: i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) %written
define void @byval_not_readnone_2(i8* byval %written) readnone {
; CHECK-LABEL: define {{[^@]+}}@byval_not_readnone_2
; CHECK-SAME: (i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) [[WRITTEN:%.*]])
; CHECK-NEXT: store i8 0, i8* [[WRITTEN]]
; CHECK-NEXT: ret void
;
store i8 0, i8* %written
ret void
}
; ATTRIBUTOR: @byval_no_fnarg
; ATTRIBUTOR-SAME: i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) %written
define void @byval_no_fnarg(i8* byval %written) {
; CHECK-LABEL: define {{[^@]+}}@byval_no_fnarg
; CHECK-SAME: (i8* noalias nocapture nofree nonnull writeonly byval dereferenceable(1) [[WRITTEN:%.*]])
; CHECK-NEXT: store i8 0, i8* [[WRITTEN]]
; CHECK-NEXT: ret void
;
store i8 0, i8* %written
ret void
}
; ATTRIBUTOR: @testbyval
; ATTRIBUTOR-SAME: i8* nocapture readonly %read_only
define void @testbyval(i8* %read_only) {
; IS__TUNIT____-LABEL: define {{[^@]+}}@testbyval
; IS__TUNIT____-SAME: (i8* nocapture readonly [[READ_ONLY:%.*]])
; IS__TUNIT____-NEXT: call void @byval_not_readonly_1(i8* nocapture readonly [[READ_ONLY]])
; IS__TUNIT____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture readnone [[READ_ONLY]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@testbyval
; IS__CGSCC____-SAME: (i8* nocapture readonly [[READ_ONLY:%.*]])
; IS__CGSCC____-NEXT: call void @byval_not_readonly_1(i8* noalias nocapture readonly [[READ_ONLY]])
; IS__CGSCC____-NEXT: call void @byval_not_readnone_1(i8* noalias nocapture nonnull readnone dereferenceable(1) [[READ_ONLY]])
; IS__CGSCC____-NEXT: ret void
;
call void @byval_not_readonly_1(i8* %read_only)
call void @byval_not_readonly_2(i8* %read_only)
call void @byval_not_readnone_1(i8* %read_only)
@ -201,7 +306,10 @@ declare i8 @maybe_returned_val(i8* %ptr) readonly nounwind
declare void @val_use(i8 %ptr) readonly nounwind
define void @ptr_uses(i8* %ptr) {
; ATTRIBUTOR: define void @ptr_uses(i8* nocapture readonly %ptr)
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
; CHECK-SAME: (i8* nocapture readonly [[PTR:%.*]])
; CHECK-NEXT: ret void
;
%call_ptr = call i8* @maybe_returned_ptr(i8* %ptr)
%call_val = call i8 @maybe_returned_val(i8* %call_ptr)
call void @val_use(i8 %call_val)

View File

@ -1,29 +1,15 @@
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -functionattrs -S < %s | FileCheck %s --check-prefix=BOTH
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
;
; Copied from Transforms/FunctoinAttrs/read_write_returned_arguments_scc.ll
;
; Test cases specifically designed for the "returned" argument attribute.
; We use FIXME's to indicate problems and missing attributes.
;
; TEST SCC test returning an integer value argument
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define i32 @sink_r0(i32 returned %r)
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; BOTH-NEXT: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; BOTH-NEXT: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; BOTH-NEXT: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
;
;
; ATTRIBUTOR: define i32 @sink_r0(i32 returned %r)
; ATTRIBUTOR: define i32 @scc_r1(i32 %a, i32 returned %r, i32 %b)
; ATTRIBUTOR: define i32 @scc_r2(i32 %a, i32 %b, i32 returned %r)
; ATTRIBUTOR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r)
;
; int scc_r1(int a, int b, int r);
; int scc_r2(int a, int b, int r);
;
@ -52,11 +38,23 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define i32 @sink_r0(i32 %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@sink_r0
; CHECK-SAME: (i32 returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[R]]
;
entry:
ret i32 %r
}
define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@scc_r1
; CHECK-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]])
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[CALL]])
; CHECK-NEXT: ret i32 [[CALL1]]
;
entry:
%call = call i32 @sink_r0(i32 %r)
%call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call)
@ -64,6 +62,42 @@ entry:
}
define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@scc_r2
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]])
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]])
; CHECK-NEXT: br label [[RETURN:%.*]]
; CHECK: if.end:
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
; CHECK: if.then3:
; CHECK-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]])
; CHECK-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef)
; CHECK-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]])
; CHECK-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef)
; CHECK-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]])
; CHECK-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]])
; CHECK-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef)
; CHECK-NEXT: br label [[RETURN]]
; CHECK: if.end12:
; CHECK-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
; CHECK-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.true:
; CHECK-NEXT: br label [[COND_END:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]])
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
; CHECK-NEXT: br label [[RETURN]]
; CHECK: return:
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ]
; CHECK-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%cmp = icmp sgt i32 %a, %b
br i1 %cmp, label %if.then, label %if.end
@ -109,6 +143,79 @@ return: ; preds = %cond.end, %if.then3
}
define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@scc_rX
; IS__TUNIT____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]])
; IS__TUNIT____-NEXT: br label [[RETURN:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
; IS__TUNIT____: if.then3:
; IS__TUNIT____-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]])
; IS__TUNIT____-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef)
; IS__TUNIT____-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]])
; IS__TUNIT____-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 undef)
; IS__TUNIT____-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef)
; IS__TUNIT____-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]])
; IS__TUNIT____-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 undef)
; IS__TUNIT____-NEXT: br label [[RETURN]]
; IS__TUNIT____: if.end12:
; IS__TUNIT____-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__TUNIT____: cond.true:
; IS__TUNIT____-NEXT: br label [[COND_END:%.*]]
; IS__TUNIT____: cond.false:
; IS__TUNIT____-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]])
; IS__TUNIT____-NEXT: br label [[COND_END]]
; IS__TUNIT____: cond.end:
; IS__TUNIT____-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
; IS__TUNIT____-NEXT: br label [[RETURN]]
; IS__TUNIT____: return:
; IS__TUNIT____-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ]
; IS__TUNIT____-NEXT: ret i32 [[RETVAL_0]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@scc_rX
; IS__CGSCC____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32 @sink_r0(i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[CALL]])
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
; IS__CGSCC____: if.then3:
; IS__CGSCC____-NEXT: [[CALL4:%.*]] = call i32 @sink_r0(i32 [[B]])
; IS__CGSCC____-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[CALL6]], i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[CALL5]], i32 [[CALL7]], i32 [[CALL8]])
; IS__CGSCC____-NEXT: [[CALL10:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]])
; IS__CGSCC____-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[CALL4]], i32 [[CALL9]], i32 [[CALL10]])
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: if.end12:
; IS__CGSCC____-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__CGSCC____: cond.true:
; IS__CGSCC____-NEXT: br label [[COND_END:%.*]]
; IS__CGSCC____: cond.false:
; IS__CGSCC____-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]])
; IS__CGSCC____-NEXT: br label [[COND_END]]
; IS__CGSCC____: cond.end:
; IS__CGSCC____-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: return:
; IS__CGSCC____-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ]
; IS__CGSCC____-NEXT: ret i32 [[RETVAL_0]]
;
entry:
%cmp = icmp sgt i32 %a, %b
br i1 %cmp, label %if.then, label %if.end
@ -156,14 +263,6 @@ return: ; preds = %cond.end, %if.then3
; TEST SCC test returning a pointer value argument
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_sink_r0(double* nofree readnone returned "no-capture-maybe-returned" %r)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_scc_r1(double* nofree readnone %a, double* nofree readnone returned %r, double* nocapture nofree readnone %b)
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @ptr_scc_r2(double* nofree readnone %a, double* nofree readnone %b, double* nofree readnone returned %r)
;
; double* ptr_scc_r1(double* a, double* b, double* r);
; double* ptr_scc_r2(double* a, double* b, double* r);
;
@ -183,11 +282,30 @@ return: ; preds = %cond.end, %if.then3
; return a == b ? r : ptr_scc_r2(a, b, r);
; }
define double* @ptr_sink_r0(double* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@ptr_sink_r0
; CHECK-SAME: (double* nofree readnone returned "no-capture-maybe-returned" [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret double* [[R]]
;
entry:
ret double* %r
}
define double* @ptr_scc_r1(double* %a, double* %r, double* %b) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@ptr_scc_r1
; IS__TUNIT____-SAME: (double* nofree readnone [[A:%.*]], double* nofree readnone returned [[R:%.*]], double* nocapture nofree readnone [[B:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone "no-capture-maybe-returned" [[R]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[R]], double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL]])
; IS__TUNIT____-NEXT: ret double* [[CALL1]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@ptr_scc_r1
; IS__CGSCC____-SAME: (double* nofree readnone [[A:%.*]], double* nofree readnone returned [[R:%.*]], double* nocapture nofree readnone [[B:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone [[R]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[R]], double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL]])
; IS__CGSCC____-NEXT: ret double* [[CALL1]]
;
entry:
%call = call double* @ptr_sink_r0(double* %r)
%call1 = call double* @ptr_scc_r2(double* %r, double* %a, double* %call)
@ -195,6 +313,78 @@ entry:
}
define double* @ptr_scc_r2(double* %a, double* %b, double* %r) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@ptr_scc_r2
; IS__TUNIT____-SAME: (double* nofree readnone [[A:%.*]], double* nofree readnone [[B:%.*]], double* nofree readnone returned [[R:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CMP:%.*]] = icmp ugt double* [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; IS__TUNIT____: if.then:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone "no-capture-maybe-returned" [[R]])
; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[B]], double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL]])
; IS__TUNIT____-NEXT: br label [[RETURN:%.*]]
; IS__TUNIT____: if.end:
; IS__TUNIT____-NEXT: [[CMP2:%.*]] = icmp ult double* [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
; IS__TUNIT____: if.then3:
; IS__TUNIT____-NEXT: [[CALL4:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone [[B]])
; IS__TUNIT____-NEXT: [[CALL5:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone undef)
; IS__TUNIT____-NEXT: [[CALL6:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[R]], double* noalias nofree readnone [[R]], double* noalias nofree readnone [[R]])
; IS__TUNIT____-NEXT: [[CALL7:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL6]], double* noalias nofree readnone undef)
; IS__TUNIT____-NEXT: [[CALL8:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone [[R]])
; IS__TUNIT____-NEXT: [[CALL9:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[CALL5]], double* noalias nofree readnone [[CALL7]], double* noalias nofree readnone [[CALL8]])
; IS__TUNIT____-NEXT: [[CALL11:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[CALL4]], double* noalias nofree readnone [[CALL9]], double* noalias nofree readnone undef)
; IS__TUNIT____-NEXT: br label [[RETURN]]
; IS__TUNIT____: if.end12:
; IS__TUNIT____-NEXT: [[CMP13:%.*]] = icmp eq double* [[A]], [[B]]
; IS__TUNIT____-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__TUNIT____: cond.true:
; IS__TUNIT____-NEXT: br label [[COND_END:%.*]]
; IS__TUNIT____: cond.false:
; IS__TUNIT____-NEXT: [[CALL14:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone [[R]])
; IS__TUNIT____-NEXT: br label [[COND_END]]
; IS__TUNIT____: cond.end:
; IS__TUNIT____-NEXT: [[COND:%.*]] = phi double* [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
; IS__TUNIT____-NEXT: br label [[RETURN]]
; IS__TUNIT____: return:
; IS__TUNIT____-NEXT: [[RETVAL_0:%.*]] = phi double* [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ]
; IS__TUNIT____-NEXT: ret double* [[RETVAL_0]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@ptr_scc_r2
; IS__CGSCC____-SAME: (double* nofree readnone [[A:%.*]], double* nofree readnone [[B:%.*]], double* nofree readnone returned [[R:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp ugt double* [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone [[R]])
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[B]], double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL]])
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
; IS__CGSCC____-NEXT: [[CMP2:%.*]] = icmp ult double* [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]]
; IS__CGSCC____: if.then3:
; IS__CGSCC____-NEXT: [[CALL4:%.*]] = call double* @ptr_sink_r0(double* noalias nofree readnone [[B]])
; IS__CGSCC____-NEXT: [[CALL5:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone undef)
; IS__CGSCC____-NEXT: [[CALL6:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[R]], double* noalias nofree readnone [[R]], double* noalias nofree readnone [[R]])
; IS__CGSCC____-NEXT: [[CALL7:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[CALL6]], double* noalias nofree readnone undef)
; IS__CGSCC____-NEXT: [[CALL8:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone [[R]])
; IS__CGSCC____-NEXT: [[CALL9:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[CALL5]], double* noalias nofree readnone [[CALL7]], double* noalias nofree readnone [[CALL8]])
; IS__CGSCC____-NEXT: [[CALL11:%.*]] = call double* @ptr_scc_r1(double* noalias nofree readnone [[CALL4]], double* noalias nofree readnone [[CALL9]], double* noalias nofree readnone undef)
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: if.end12:
; IS__CGSCC____-NEXT: [[CMP13:%.*]] = icmp eq double* [[A]], [[B]]
; IS__CGSCC____-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; IS__CGSCC____: cond.true:
; IS__CGSCC____-NEXT: br label [[COND_END:%.*]]
; IS__CGSCC____: cond.false:
; IS__CGSCC____-NEXT: [[CALL14:%.*]] = call double* @ptr_scc_r2(double* noalias nofree readnone [[A]], double* noalias nofree readnone [[B]], double* noalias nofree readnone [[R]])
; IS__CGSCC____-NEXT: br label [[COND_END]]
; IS__CGSCC____: cond.end:
; IS__CGSCC____-NEXT: [[COND:%.*]] = phi double* [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ]
; IS__CGSCC____-NEXT: br label [[RETURN]]
; IS__CGSCC____: return:
; IS__CGSCC____-NEXT: [[RETVAL_0:%.*]] = phi double* [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[COND]], [[COND_END]] ]
; IS__CGSCC____-NEXT: ret double* [[RETVAL_0]]
;
entry:
%cmp = icmp ugt double* %a, %b
br i1 %cmp, label %if.then, label %if.end
@ -246,9 +436,12 @@ return: ; preds = %cond.end, %if.then3
; return *a ? a : rt0(a);
; }
;
; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt0(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) %a)
define i32* @rt0(i32* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@rt0
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%v = load i32, i32* %a, align 4
%tobool = icmp ne i32 %v, 0
@ -263,9 +456,12 @@ entry:
; return *a ? undef : rt1(a);
; }
;
; BOTH: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
; BOTH-NEXT: define noalias nonnull align 536870912 dereferenceable(4294967295) i32* @rt1(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) %a)
define i32* @rt1(i32* %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@rt1
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%v = load i32, i32* %a, align 4
%tobool = icmp ne i32 %v, 0
@ -276,15 +472,37 @@ entry:
; TEST another SCC test
;
; BOTH: define i32* @rt2_helper(i32* nofree readnone returned %a)
; BOTH: define i32* @rt2(i32* nofree readnone %a, i32* nofree readnone "no-capture-maybe-returned" %b)
define i32* @rt2_helper(i32* %a) #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@rt2_helper
; IS__TUNIT____-SAME: (i32* nofree readnone returned [[A:%.*]])
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @rt2(i32* noalias nofree readnone [[A]], i32* noalias nofree readnone "no-capture-maybe-returned" [[A]])
; IS__TUNIT____-NEXT: ret i32* [[CALL]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@rt2_helper
; IS__CGSCC____-SAME: (i32* nofree readnone returned [[A:%.*]])
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @rt2(i32* noalias nofree readnone [[A]], i32* noalias nofree readnone [[A]])
; IS__CGSCC____-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @rt2(i32* %a, i32* %a)
ret i32* %call
}
define i32* @rt2(i32* %a, i32 *%b) #0 {
; CHECK-LABEL: define {{[^@]+}}@rt2
; CHECK-SAME: (i32* nofree readnone [[A:%.*]], i32* nofree readnone "no-capture-maybe-returned" [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[A]], null
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @rt2_helper(i32* noalias nofree readnone [[A]])
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[SEL:%.*]] = phi i32* [ [[B]], [[ENTRY:%.*]] ], [ [[CALL]], [[IF_THEN]] ]
; CHECK-NEXT: ret i32* [[SEL]]
;
entry:
%cmp = icmp eq i32* %a, null
br i1 %cmp, label %if.then, label %if.end
@ -300,15 +518,31 @@ if.end:
; TEST another SCC test
;
; BOTH: define i32* @rt3_helper(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
; BOTH: define i32* @rt3(i32* nofree readnone %a, i32* nofree readnone returned "no-capture-maybe-returned" %b)
define i32* @rt3_helper(i32* %a, i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@rt3_helper
; CHECK-SAME: (i32* nofree readnone [[A:%.*]], i32* nofree readnone returned "no-capture-maybe-returned" [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @rt3(i32* noalias nofree readnone [[A]], i32* noalias nofree readnone "no-capture-maybe-returned" [[B]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @rt3(i32* %a, i32* %b)
ret i32* %call
}
define i32* @rt3(i32* %a, i32 *%b) #0 {
; CHECK-LABEL: define {{[^@]+}}@rt3
; CHECK-SAME: (i32* nofree readnone [[A:%.*]], i32* nofree readnone returned "no-capture-maybe-returned" [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[A]], null
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @rt3_helper(i32* noalias nofree readnone [[A]], i32* noalias nofree readnone "no-capture-maybe-returned" [[B]])
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[SEL:%.*]] = phi i32* [ [[B]], [[ENTRY:%.*]] ], [ [[CALL]], [[IF_THEN]] ]
; CHECK-NEXT: ret i32* [[SEL]]
;
entry:
%cmp = icmp eq i32* %a, null
br i1 %cmp, label %if.then, label %if.end
@ -331,14 +565,14 @@ if.end:
; return r;
; }
;
; BOTH: declare void @unknown_fn(i32* (i32*)*)
;
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define i32* @calls_unknown_fn(i32* nofree readnone returned "no-capture-maybe-returned" %r)
; ATTRIBUTOR: define i32* @calls_unknown_fn(i32* nofree readnone returned "no-capture-maybe-returned" %r)
declare void @unknown_fn(i32* (i32*)*) #0
define i32* @calls_unknown_fn(i32* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@calls_unknown_fn
; CHECK-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[R:%.*]])
; CHECK-NEXT: tail call void @unknown_fn(i32* (i32*)* nonnull @calls_unknown_fn)
; CHECK-NEXT: ret i32* [[R]]
;
tail call void @unknown_fn(i32* (i32*)* nonnull @calls_unknown_fn)
ret i32* %r
}
@ -357,23 +591,23 @@ define i32* @calls_unknown_fn(i32* %r) #0 {
;
; Verify the maybe-redefined function is not annotated:
;
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
;
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn(i32* returned %r)
;
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn(i32* %r)
;
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define i32* @calls_maybe_redefined_fn(i32* returned %r)
define linkonce_odr i32* @maybe_redefined_fn(i32* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@maybe_redefined_fn
; CHECK-SAME: (i32* [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32* [[R]]
;
entry:
ret i32* %r
}
define i32* @calls_maybe_redefined_fn(i32* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn
; CHECK-SAME: (i32* returned [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @maybe_redefined_fn(i32* [[R]])
; CHECK-NEXT: ret i32* [[R]]
;
entry:
%call = call i32* @maybe_redefined_fn(i32* %r)
ret i32* %r
@ -391,18 +625,23 @@ entry:
;
; Verify the maybe-redefined function is not annotated:
;
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define linkonce_odr i32* @maybe_redefined_fn2(i32* %r)
; BOTH: Function Attrs: noinline nounwind uwtable
; BOTH-NEXT: define i32* @calls_maybe_redefined_fn2(i32* %r)
;
; ATTRIBUTOR: define i32* @calls_maybe_redefined_fn2(i32* %r)
define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@maybe_redefined_fn2
; CHECK-SAME: (i32* [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32* [[R]]
;
entry:
ret i32* %r
}
define i32* @calls_maybe_redefined_fn2(i32* %r) #0 {
; CHECK-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2
; CHECK-SAME: (i32* [[R:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @maybe_redefined_fn2(i32* [[R]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%call = call i32* @maybe_redefined_fn2(i32* %r)
ret i32* %call
@ -418,12 +657,20 @@ entry:
; return b == 0? b : x;
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double @select_and_phi(double returned %b)
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double @select_and_phi(double returned %b)
define double @select_and_phi(double %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@select_and_phi
; CHECK-SAME: (double returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[B]], 0.000000e+00
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = fcmp oeq double [[B]], 0.000000e+00
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], double [[B]], double [[PHI]]
; CHECK-NEXT: ret double [[SEL]]
;
entry:
%cmp = fcmp ogt double %b, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end
@ -448,13 +695,22 @@ if.end: ; preds = %if.then, %entry
; return b == 0? b : x;
; }
;
; BOTH: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; BOTH-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double @recursion_select_and_phi(i32 %a, double returned %b)
define double @recursion_select_and_phi(i32 %a, double %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@recursion_select_and_phi
; CHECK-SAME: (i32 [[A:%.*]], double returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DEC:%.*]] = add nsw i32 [[A]], -1
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]])
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[PHI:%.*]] = phi double [ [[CALL]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = fcmp oeq double [[B]], 0.000000e+00
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], double [[B]], double [[PHI]]
; CHECK-NEXT: ret double [[SEL]]
;
entry:
%dec = add nsw i32 %a, -1
%cmp = icmp sgt i32 %a, 0
@ -478,13 +734,13 @@ if.end: ; preds = %if.then, %entry
; return (double*)b;
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @bitcast(i32* nofree readnone returned "no-capture-maybe-returned" %b)
define double* @bitcast(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@bitcast
; CHECK-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC0:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: ret double* [[BC0]]
;
entry:
%bc0 = bitcast i32* %b to double*
ret double* %bc0
@ -500,13 +756,25 @@ entry:
; return b != 0 ? b : x;
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @bitcasts_select_and_phi(i32* nofree readnone returned %b)
define double* @bitcasts_select_and_phi(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@bitcasts_select_and_phi
; CHECK-SAME: (i32* nofree readnone returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC0:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: [[CMP:%.*]] = icmp eq double* [[BC0]], null
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[BC1:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[PHI:%.*]] = phi double* [ [[BC1]], [[IF_THEN]] ], [ [[BC0]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[BC2:%.*]] = bitcast double* [[PHI]] to i8*
; CHECK-NEXT: [[BC3:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne double* [[BC0]], null
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP2]], i8* [[BC2]], i8* [[BC3]]
; CHECK-NEXT: [[BC4:%.*]] = bitcast i8* [[SEL]] to double*
; CHECK-NEXT: ret double* [[BC4]]
;
entry:
%bc0 = bitcast i32* %b to double*
%cmp = icmp eq double* %bc0, null
@ -537,13 +805,23 @@ if.end: ; preds = %if.then, %entry
; /* return undef */
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @ret_arg_arg_undef(i32* nofree readnone returned %b)
define double* @ret_arg_arg_undef(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_arg_arg_undef
; CHECK-SAME: (i32* nofree readnone returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC0:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: [[CMP:%.*]] = icmp eq double* [[BC0]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[IF_END:%.*]]
; CHECK: ret_arg0:
; CHECK-NEXT: [[BC1:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: ret double* [[BC1]]
; CHECK: if.end:
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG1:%.*]], label [[RET_UNDEF:%.*]]
; CHECK: ret_arg1:
; CHECK-NEXT: ret double* [[BC0]]
; CHECK: ret_undef:
; CHECK-NEXT: ret double* undef
;
entry:
%bc0 = bitcast i32* %b to double*
%cmp = icmp eq double* %bc0, null
@ -574,13 +852,23 @@ ret_undef:
; /* return undef */
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
;
;
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define double* @ret_undef_arg_arg(i32* nofree readnone returned %b)
define double* @ret_undef_arg_arg(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_arg
; CHECK-SAME: (i32* nofree readnone returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC0:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: [[CMP:%.*]] = icmp eq double* [[BC0]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_UNDEF:%.*]], label [[IF_END:%.*]]
; CHECK: ret_undef:
; CHECK-NEXT: ret double* undef
; CHECK: if.end:
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[RET_ARG1:%.*]]
; CHECK: ret_arg0:
; CHECK-NEXT: ret double* [[BC0]]
; CHECK: ret_arg1:
; CHECK-NEXT: [[BC1:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: ret double* [[BC1]]
;
entry:
%bc0 = bitcast i32* %b to double*
%cmp = icmp eq double* %bc0, null
@ -611,11 +899,22 @@ ret_arg1:
; /* return undef */
; }
;
; BOTH: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; BOTH-NEXT: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
;
; ATTRIBUTOR: define double* @ret_undef_arg_undef(i32* nofree readnone returned %b)
define double* @ret_undef_arg_undef(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_undef
; CHECK-SAME: (i32* nofree readnone returned [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[BC0:%.*]] = bitcast i32* [[B]] to double*
; CHECK-NEXT: [[CMP:%.*]] = icmp eq double* [[BC0]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_UNDEF0:%.*]], label [[IF_END:%.*]]
; CHECK: ret_undef0:
; CHECK-NEXT: ret double* undef
; CHECK: if.end:
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNDEF1:%.*]]
; CHECK: ret_arg:
; CHECK-NEXT: ret double* [[BC0]]
; CHECK: ret_undef1:
; CHECK-NEXT: ret double* undef
;
entry:
%bc0 = bitcast i32* %b to double*
%cmp = icmp eq double* %bc0, null
@ -644,13 +943,20 @@ ret_undef1:
;
; Verify we do not assume b is returned
;
; ATTRIBUTOR: define i32* @ret_arg_or_unknown(i32* %b)
; ATTRIBUTOR: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
; BOTH: define i32* @ret_arg_or_unknown(i32* %b)
; BOTH: define i32* @ret_arg_or_unknown_through_phi(i32* %b)
declare i32* @unknown(i32*)
define i32* @ret_arg_or_unknown(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown
; CHECK-SAME: (i32* [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
; CHECK: ret_arg:
; CHECK-NEXT: ret i32* [[B]]
; CHECK: ret_unknown:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown(i32* [[B]])
; CHECK-NEXT: ret i32* [[CALL]]
;
entry:
%cmp = icmp eq i32* %b, null
br i1 %cmp, label %ret_arg, label %ret_unknown
@ -664,6 +970,20 @@ ret_unknown:
}
define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi
; CHECK-SAME: (i32* [[B:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null
; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]]
; CHECK: ret_arg:
; CHECK-NEXT: br label [[R:%.*]]
; CHECK: ret_unknown:
; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown(i32* [[B]])
; CHECK-NEXT: br label [[R]]
; CHECK: r:
; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ]
; CHECK-NEXT: ret i32* [[PHI]]
;
entry:
%cmp = icmp eq i32* %b, null
br i1 %cmp, label %ret_arg, label %ret_unknown
@ -682,15 +1002,14 @@ r:
; TEST inconsistent IR in dead code.
;
; ATTRIBUTOR: define i32 @deadblockcall1(i32 returned %A)
; ATTRIBUTOR: define i32 @deadblockcall2(i32 returned %A)
; ATTRIBUTOR: define i32 @deadblockphi1(i32 returned %A)
; ATTRIBUTOR: define i32 @deadblockphi2(i32 returned %A)
; BOTH: define i32 @deadblockcall1(i32 returned %A)
; BOTH: define i32 @deadblockcall2(i32 returned %A)
; BOTH: define i32 @deadblockphi1(i32 returned %A)
; BOTH: define i32 @deadblockphi2(i32 returned %A)
define i32 @deadblockcall1(i32 %A) #0 {
; CHECK-LABEL: define {{[^@]+}}@deadblockcall1
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[A]]
; CHECK: unreachableblock:
; CHECK-NEXT: unreachable
;
entry:
ret i32 %A
unreachableblock:
@ -701,6 +1020,15 @@ unreachableblock:
declare i32 @deadblockcall_helper(i32 returned %A);
define i32 @deadblockcall2(i32 %A) #0 {
; CHECK-LABEL: define {{[^@]+}}@deadblockcall2
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[A]]
; CHECK: unreachableblock1:
; CHECK-NEXT: unreachable
; CHECK: unreachableblock2:
; CHECK-NEXT: unreachable
;
entry:
ret i32 %A
unreachableblock1:
@ -712,6 +1040,17 @@ unreachableblock2:
}
define i32 @deadblockphi1(i32 %A) #0 {
; CHECK-LABEL: define {{[^@]+}}@deadblockphi1
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[R:%.*]]
; CHECK: unreachableblock1:
; CHECK-NEXT: unreachable
; CHECK: unreachableblock2:
; CHECK-NEXT: unreachable
; CHECK: r:
; CHECK-NEXT: ret i32 [[A]]
;
entry:
br label %r
unreachableblock1:
@ -726,6 +1065,19 @@ r:
}
define i32 @deadblockphi2(i32 %A) #0 {
; CHECK-LABEL: define {{[^@]+}}@deadblockphi2
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[R:%.*]]
; CHECK: unreachableblock1:
; CHECK-NEXT: unreachable
; CHECK: unreachableblock2:
; CHECK-NEXT: unreachable
; CHECK: unreachableblock3:
; CHECK-NEXT: unreachable
; CHECK: r:
; CHECK-NEXT: ret i32 [[A]]
;
entry:
br label %r
unreachableblock1:
@ -745,6 +1097,20 @@ r:
declare void @noreturn() noreturn;
define i32 @deadblockphi3(i32 %A, i1 %c) #0 {
; CHECK-LABEL: define {{[^@]+}}@deadblockphi3
; CHECK-SAME: (i32 returned [[A:%.*]], i1 [[C:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]]
; CHECK: unreachablecall:
; CHECK-NEXT: call void @noreturn()
; CHECK-NEXT: unreachable
; CHECK: unreachableblock2:
; CHECK-NEXT: unreachable
; CHECK: unreachableblock3:
; CHECK-NEXT: unreachable
; CHECK: r:
; CHECK-NEXT: ret i32 [[A]]
;
entry:
br i1 %c, label %r, label %unreachablecall
unreachablecall:
@ -763,38 +1129,109 @@ r:
}
define weak_odr i32 @non_exact_0() {
; CHECK-LABEL: define {{[^@]+}}@non_exact_0()
; CHECK-NEXT: ret i32 0
;
ret i32 0
}
define weak_odr i32 @non_exact_1(i32 %a) {
; CHECK-LABEL: define {{[^@]+}}@non_exact_1
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: ret i32 [[A]]
;
ret i32 %a
}
define weak_odr i32 @non_exact_2(i32 returned %a) {
; CHECK-LABEL: define {{[^@]+}}@non_exact_2
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: ret i32 [[A]]
;
ret i32 %a
}
define weak_odr align 16 i32* @non_exact_3(i32* align 32 returned %a) {
; CHECK-LABEL: define {{[^@]+}}@non_exact_3
; CHECK-SAME: (i32* returned align 32 [[A:%.*]])
; CHECK-NEXT: ret i32* [[A]]
;
ret i32* %a
}
define weak_odr align 16 i32* @non_exact_4(i32* align 32 %a) {
; CHECK-LABEL: define {{[^@]+}}@non_exact_4
; CHECK-SAME: (i32* align 32 [[A:%.*]])
; CHECK-NEXT: ret i32* [[A]]
;
ret i32* %a
}
; We can use the alignment information of the weak function non_exact_3 argument
; because it was given to us and not derived.
; We can use the return information of the weak function non_exact_4.
; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
define i32 @exact(i32* align 8 %a, i32* align 8 %b) {
; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@exact
; NOT_CGSCC_NPM-SAME: (i32* align 8 [[A:%.*]], i32* align 8 [[B:%.*]])
; NOT_CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @non_exact_0()
; NOT_CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @non_exact_1(i32 1)
; NOT_CGSCC_NPM-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 2)
; NOT_CGSCC_NPM-NEXT: [[C3:%.*]] = call align 32 i32* @non_exact_3(i32* align 32 [[A]])
; NOT_CGSCC_NPM-NEXT: [[C4:%.*]] = call align 16 i32* @non_exact_4(i32* align 32 [[B]])
; NOT_CGSCC_NPM-NEXT: [[C3L:%.*]] = load i32, i32* [[C3]], align 32
; NOT_CGSCC_NPM-NEXT: [[C4L:%.*]] = load i32, i32* [[C4]], align 16
; NOT_CGSCC_NPM-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
; NOT_CGSCC_NPM-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[C2]]
; NOT_CGSCC_NPM-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
; NOT_CGSCC_NPM-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
; NOT_CGSCC_NPM-NEXT: ret i32 [[ADD4]]
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@exact
; IS__CGSCC_NPM-SAME: (i32* align 8 [[A:%.*]], i32* align 8 [[B:%.*]])
; IS__CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @non_exact_0()
; IS__CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @non_exact_1(i32 1)
; IS__CGSCC_NPM-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 2)
; IS__CGSCC_NPM-NEXT: [[C3:%.*]] = call align 32 i32* @non_exact_3(i32* align 32 [[A]])
; IS__CGSCC_NPM-NEXT: [[C4:%.*]] = call align 16 i32* @non_exact_4(i32* align 32 [[B]])
; IS__CGSCC_NPM-NEXT: [[C3L:%.*]] = load i32, i32* [[C3]], align 32
; IS__CGSCC_NPM-NEXT: [[C4L:%.*]] = load i32, i32* [[C4]], align 16
; IS__CGSCC_NPM-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
; IS__CGSCC_NPM-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], 2
; IS__CGSCC_NPM-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
; IS__CGSCC_NPM-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
; IS__CGSCC_NPM-NEXT: ret i32 [[ADD4]]
;
; ____CGSCC_NPM-LABEL: define {{[^@]+}}@exact
; ____CGSCC_NPM-SAME: (i32* align 8 [[A:%.*]], i32* align 8 [[B:%.*]])
; ____CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @non_exact_0()
; ____CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @non_exact_1(i32 1)
; ____CGSCC_NPM-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 2)
; ____CGSCC_NPM-NEXT: [[C3:%.*]] = call align 32 i32* @non_exact_3(i32* align 32 [[A]])
; ____CGSCC_NPM-NEXT: [[C4:%.*]] = call align 16 i32* @non_exact_4(i32* align 32 [[B]])
; ____CGSCC_NPM-NEXT: [[C3L:%.*]] = load i32, i32* [[C3]], align 32
; ____CGSCC_NPM-NEXT: [[C4L:%.*]] = load i32, i32* [[C4]], align 16
; ____CGSCC_NPM-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
; ____CGSCC_NPM-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], 2
; ____CGSCC_NPM-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
; ____CGSCC_NPM-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
; ____CGSCC_NPM-NEXT: ret i32 [[ADD4]]
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-LABEL: define {{[^@]+}}@exact
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-SAME: (i32* align 8 [[A:%.*]], i32* align 8 [[B:%.*]])
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C0:%.*]] = call i32 @non_exact_0()
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C1:%.*]] = call i32 @non_exact_1(i32 1)
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 2)
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C3:%.*]] = call align 32 i32* @non_exact_3(i32* align 32 [[A]])
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C4:%.*]] = call align 16 i32* @non_exact_4(i32* align 32 [[B]])
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C3L:%.*]] = load i32, i32* [[C3]], align 32
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[C4L:%.*]] = load i32, i32* [[C4]], align 16
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]]
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], 2
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]]
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]]
; CGSCC_NPM,CHECK_MODULE,CHECK_CGSCC-NEXT: ret i32 [[ADD4]]
%c0 = call i32 @non_exact_0()
%c1 = call i32 @non_exact_1(i32 1)
%c2 = call i32 @non_exact_2(i32 2)
%c3 = call i32* @non_exact_3(i32* %a)
%c4 = call i32* @non_exact_4(i32* %b)
; We can use the alignment information of the weak function non_exact_3 argument
; because it was given to us and not derived.
; ATTRIBUTOR: %c3l = load i32, i32* %c3, align 32
%c3l = load i32, i32* %c3
; We can use the return information of the weak function non_exact_4.
; ATTRIBUTOR: %c4l = load i32, i32* %c4, align 16
%c4l = load i32, i32* %c4
; FIXME: %c2 and %c3 should be replaced but not %c0 or %c1!
; ATTRIBUTOR: %add1 = add i32 %c0, %c1
; ATTRIBUTOR: %add2 = add i32 %add1, %c2
; ATTRIBUTOR: %add3 = add i32 %add2, %c3l
; ATTRIBUTOR: %add4 = add i32 %add3, %c4l
%add1 = add i32 %c0, %c1
%add2 = add i32 %add1, %c2
%add3 = add i32 %add2, %c3l
@ -804,17 +1241,30 @@ define i32 @exact(i32* align 8 %a, i32* align 8 %b) {
@G = external global i8
define i32* @ret_const() #0 {
; CHECK-LABEL: define {{[^@]+}}@ret_const()
; CHECK-NEXT: [[BC:%.*]] = bitcast i8* @G to i32*
; CHECK-NEXT: ret i32* [[BC]]
;
%bc = bitcast i8* @G to i32*
ret i32* %bc
}
define i32* @use_const() #0 {
; CHECK-LABEL: define {{[^@]+}}@use_const()
; CHECK-NEXT: ret i32* bitcast (i8* @G to i32*)
;
%c = call i32* @ret_const()
; ATTRIBUTOR: ret i32* bitcast (i8* @G to i32*)
ret i32* %c
}
define i32* @dont_use_const() #0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@dont_use_const()
; IS__TUNIT____-NEXT: [[C:%.*]] = musttail call i32* @ret_const()
; IS__TUNIT____-NEXT: ret i32* [[C]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@dont_use_const()
; IS__CGSCC____-NEXT: [[C:%.*]] = musttail call nonnull dereferenceable(1) i32* @ret_const()
; IS__CGSCC____-NEXT: ret i32* [[C]]
;
%c = musttail call i32* @ret_const()
; ATTRIBUTOR: ret i32* %c
ret i32* %c
}

View File

@ -1,4 +1,8 @@
; RUN: opt --attributor --attributor-disable=false -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@ -9,16 +13,16 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; -- Load tests --
define void @load_wholly_unreachable() {
; ATTRIBUTOR-LABEL: @load_wholly_unreachable(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@load_wholly_unreachable()
; CHECK-NEXT: unreachable
;
%a = load i32, i32* null
ret void
}
define void @loads_wholly_unreachable() {
; ATTRIBUTOR-LABEL: @loads_wholly_unreachable(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@loads_wholly_unreachable()
; CHECK-NEXT: unreachable
;
%a = load i32, i32* null
%b = load i32, i32* null
@ -27,12 +31,13 @@ define void @loads_wholly_unreachable() {
define void @load_single_bb_unreachable(i1 %cond) {
; ATTRIBUTOR-LABEL: @load_single_bb_unreachable(
; ATTRIBUTOR-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[E:%.*]]
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@load_single_bb_unreachable
; CHECK-SAME: (i1 [[COND:%.*]])
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: ret void
;
br i1 %cond, label %t, label %e
t:
@ -45,20 +50,23 @@ e:
; Note that while the load is removed (because it's unused), the block
; is not changed to unreachable
define void @load_null_pointer_is_defined() "null-pointer-is-valid"="true" {
; ATTRIBUTOR-LABEL: @load_null_pointer_is_defined(
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@load_null_pointer_is_defined()
; CHECK-NEXT: ret void
;
%a = load i32, i32* null
ret void
}
define internal i32* @ret_null() {
; IS__CGSCC____-LABEL: define {{[^@]+}}@ret_null()
; IS__CGSCC____-NEXT: ret i32* null
;
ret i32* null
}
define void @load_null_propagated() {
; ATTRIBUTOR-LABEL: @load_null_propagated(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@load_null_propagated()
; CHECK-NEXT: unreachable
;
%ptr = call i32* @ret_null()
%a = load i32, i32* %ptr
@ -68,20 +76,21 @@ define void @load_null_propagated() {
; -- Store tests --
define void @store_wholly_unreachable() {
; ATTRIBUTOR-LABEL: @store_wholly_unreachable(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@store_wholly_unreachable()
; CHECK-NEXT: unreachable
;
store i32 5, i32* null
ret void
}
define void @store_single_bb_unreachable(i1 %cond) {
; ATTRIBUTOR-LABEL: @store_single_bb_unreachable(
; ATTRIBUTOR-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[E:%.*]]
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@store_single_bb_unreachable
; CHECK-SAME: (i1 [[COND:%.*]])
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: ret void
;
br i1 %cond, label %t, label %e
t:
@ -92,9 +101,9 @@ e:
}
define void @store_null_pointer_is_defined() "null-pointer-is-valid"="true" {
; ATTRIBUTOR-LABEL: @store_null_pointer_is_defined(
; ATTRIBUTOR-NEXT: store i32 5, i32* null
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@store_null_pointer_is_defined()
; CHECK-NEXT: store i32 5, i32* null, align 536870912
; CHECK-NEXT: ret void
;
store i32 5, i32* null
ret void
@ -103,6 +112,9 @@ define void @store_null_pointer_is_defined() "null-pointer-is-valid"="true" {
define void @store_null_propagated() {
; ATTRIBUTOR-LABEL: @store_null_propagated(
; ATTRIBUTOR-NEXT: unreachable
;
; CHECK-LABEL: define {{[^@]+}}@store_null_propagated()
; CHECK-NEXT: unreachable
;
%ptr = call i32* @ret_null()
store i32 5, i32* %ptr
@ -112,20 +124,21 @@ define void @store_null_propagated() {
; -- AtomicRMW tests --
define void @atomicrmw_wholly_unreachable() {
; ATTRIBUTOR-LABEL: @atomicrmw_wholly_unreachable(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@atomicrmw_wholly_unreachable()
; CHECK-NEXT: unreachable
;
%a = atomicrmw add i32* null, i32 1 acquire
ret void
}
define void @atomicrmw_single_bb_unreachable(i1 %cond) {
; ATTRIBUTOR-LABEL: @atomicrmw_single_bb_unreachable(
; ATTRIBUTOR-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[E:%.*]]
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@atomicrmw_single_bb_unreachable
; CHECK-SAME: (i1 [[COND:%.*]])
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: ret void
;
br i1 %cond, label %t, label %e
t:
@ -136,9 +149,9 @@ e:
}
define void @atomicrmw_null_pointer_is_defined() "null-pointer-is-valid"="true" {
; ATTRIBUTOR-LABEL: @atomicrmw_null_pointer_is_defined(
; ATTRIBUTOR-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@atomicrmw_null_pointer_is_defined()
; CHECK-NEXT: [[A:%.*]] = atomicrmw add i32* null, i32 1 acquire
; CHECK-NEXT: ret void
;
%a = atomicrmw add i32* null, i32 1 acquire
ret void
@ -147,6 +160,9 @@ define void @atomicrmw_null_pointer_is_defined() "null-pointer-is-valid"="true"
define void @atomicrmw_null_propagated() {
; ATTRIBUTOR-LABEL: @atomicrmw_null_propagated(
; ATTRIBUTOR-NEXT: unreachable
;
; CHECK-LABEL: define {{[^@]+}}@atomicrmw_null_propagated()
; CHECK-NEXT: unreachable
;
%ptr = call i32* @ret_null()
%a = atomicrmw add i32* %ptr, i32 1 acquire
@ -156,20 +172,21 @@ define void @atomicrmw_null_propagated() {
; -- AtomicCmpXchg tests --
define void @atomiccmpxchg_wholly_unreachable() {
; ATTRIBUTOR-LABEL: @atomiccmpxchg_wholly_unreachable(
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@atomiccmpxchg_wholly_unreachable()
; CHECK-NEXT: unreachable
;
%a = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
ret void
}
define void @atomiccmpxchg_single_bb_unreachable(i1 %cond) {
; ATTRIBUTOR-LABEL: @atomiccmpxchg_single_bb_unreachable(
; ATTRIBUTOR-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[E:%.*]]
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@atomiccmpxchg_single_bb_unreachable
; CHECK-SAME: (i1 [[COND:%.*]])
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: ret void
;
br i1 %cond, label %t, label %e
t:
@ -180,9 +197,9 @@ e:
}
define void @atomiccmpxchg_null_pointer_is_defined() "null-pointer-is-valid"="true" {
; ATTRIBUTOR-LABEL: @atomiccmpxchg_null_pointer_is_defined(
; ATTRIBUTOR-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
; ATTRIBUTOR-NEXT: ret void
; CHECK-LABEL: define {{[^@]+}}@atomiccmpxchg_null_pointer_is_defined()
; CHECK-NEXT: [[A:%.*]] = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
; CHECK-NEXT: ret void
;
%a = cmpxchg i32* null, i32 2, i32 3 acq_rel monotonic
ret void
@ -191,6 +208,9 @@ define void @atomiccmpxchg_null_pointer_is_defined() "null-pointer-is-valid"="tr
define void @atomiccmpxchg_null_propagated() {
; ATTRIBUTOR-LABEL: @atomiccmpxchg_null_propagated(
; ATTRIBUTOR-NEXT: unreachable
;
; CHECK-LABEL: define {{[^@]+}}@atomiccmpxchg_null_propagated()
; CHECK-NEXT: unreachable
;
%ptr = call i32* @ret_null()
%a = cmpxchg i32* %ptr, i32 2, i32 3 acq_rel monotonic
@ -202,14 +222,13 @@ define void @atomiccmpxchg_null_propagated() {
; Note: The unreachable on %t and %e is _not_ from AAUndefinedBehavior
define i32 @cond_br_on_undef() {
; ATTRIBUTOR-LABEL: @cond_br_on_undef(
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef()
; CHECK-NEXT: unreachable
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: unreachable
;
br i1 undef, label %t, label %e
t:
ret i32 1
@ -218,21 +237,21 @@ e:
}
; More complicated branching
define void @cond_br_on_undef2(i1 %cond) {
; ATTRIBUTOR-LABEL: @cond_br_on_undef2(
; ATTRIBUTOR-NEXT: br i1 [[COND:%.*]], label [[T1:%.*]], label [[E1:%.*]]
; ATTRIBUTOR: t1:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: t2:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e2:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e1:
; ATTRIBUTOR-NEXT: ret void
;
; Valid branch - verify that this is not converted
; to unreachable.
define void @cond_br_on_undef2(i1 %cond) {
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef2
; CHECK-SAME: (i1 [[COND:%.*]])
; CHECK-NEXT: br i1 [[COND]], label [[T1:%.*]], label [[E1:%.*]]
; CHECK: t1:
; CHECK-NEXT: unreachable
; CHECK: t2:
; CHECK-NEXT: unreachable
; CHECK: e2:
; CHECK-NEXT: unreachable
; CHECK: e1:
; CHECK-NEXT: ret void
;
br i1 %cond, label %t1, label %e1
t1:
br i1 undef, label %t2, label %e2
@ -245,17 +264,20 @@ e1:
}
define i1 @ret_undef() {
; CHECK-LABEL: define {{[^@]+}}@ret_undef()
; CHECK-NEXT: ret i1 undef
;
ret i1 undef
}
define void @cond_br_on_undef_interproc() {
; ATTRIBUTOR-LABEL: @cond_br_on_undef_interproc(
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef_interproc()
; CHECK-NEXT: unreachable
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: unreachable
;
%cond = call i1 @ret_undef()
br i1 %cond, label %t, label %e
t:
@ -265,6 +287,13 @@ e:
}
define i1 @ret_undef2() {
; CHECK-LABEL: define {{[^@]+}}@ret_undef2()
; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i1 undef
; CHECK: e:
; CHECK-NEXT: unreachable
;
br i1 true, label %t, label %e
t:
ret i1 undef
@ -274,12 +303,13 @@ e:
; More complicated interproc deduction of undef
define void @cond_br_on_undef_interproc2() {
; ATTRIBUTOR-LABEL: @cond_br_on_undef_interproc2(
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: unreachable
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef_interproc2()
; CHECK-NEXT: unreachable
; CHECK: t:
; CHECK-NEXT: unreachable
; CHECK: e:
; CHECK-NEXT: unreachable
;
%cond = call i1 @ret_undef2()
br i1 %cond, label %t, label %e
t:
@ -291,13 +321,13 @@ e:
; Branch on undef that depends on propagation of
; undef of a previous instruction.
define i32 @cond_br_on_undef3() {
; ATTRIBUTOR-LABEL: @cond_br_on_undef3(
; ATTRIBUTOR-NEXT: br label %t
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: ret i32 1
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: unreachable
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef3()
; CHECK-NEXT: br label [[T:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 1
; CHECK: e:
; CHECK-NEXT: unreachable
;
%cond = icmp ne i32 1, undef
br i1 %cond, label %t, label %e
t:
@ -309,15 +339,15 @@ e:
; Branch on undef because of uninitialized value.
; FIXME: Currently it doesn't propagate the undef.
define i32 @cond_br_on_undef_uninit() {
; ATTRIBUTOR-LABEL: @cond_br_on_undef_uninit(
; ATTRIBUTOR-NEXT: %alloc = alloca i1
; ATTRIBUTOR-NEXT: %cond = load i1, i1* %alloc
; ATTRIBUTOR-NEXT: br i1 %cond, label %t, label %e
; ATTRIBUTOR: t:
; ATTRIBUTOR-NEXT: ret i32 1
; ATTRIBUTOR: e:
; ATTRIBUTOR-NEXT: ret i32 2
; CHECK-LABEL: define {{[^@]+}}@cond_br_on_undef_uninit()
; CHECK-NEXT: [[ALLOC:%.*]] = alloca i1
; CHECK-NEXT: [[COND:%.*]] = load i1, i1* [[ALLOC]], align 1
; CHECK-NEXT: br i1 [[COND]], label [[T:%.*]], label [[E:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 1
; CHECK: e:
; CHECK-NEXT: ret i32 2
;
%alloc = alloca i1
%cond = load i1, i1* %alloc
br i1 %cond, label %t, label %e
@ -330,8 +360,16 @@ e:
; Note that the `load` has UB (so it will be changed to unreachable)
; and the branch is a terminator that can be constant-folded.
; We want to test that doing both won't cause a segfault.
; MODULE-NOT: @callee(
define internal i32 @callee(i1 %C, i32* %A) {
; ATTRIBUTOR-NOT: @callee(
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@callee()
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: T:
; IS__CGSCC____-NEXT: unreachable
; IS__CGSCC____: F:
; IS__CGSCC____-NEXT: ret i32 1
;
entry:
%A.0 = load i32, i32* null
@ -345,8 +383,9 @@ F:
}
define i32 @foo() {
; ATTRIBUTOR-LABEL: @foo()
; ATTRIBUTOR-NEXT: ret i32 1
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT: ret i32 1
;
%X = call i32 @callee(i1 false, i32* null)
ret i32 %X
}

View File

@ -1,38 +1,59 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s
; TODO: Add max-iteration check
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
; Disable update test checks and enable it where required.
; UTC_ARGS: --disable
; ModuleID = 'value-simplify.ll'
source_filename = "value-simplify.ll"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
declare void @f(i32)
; Test1: Replace argument with constant
define internal void @test1(i32 %a) {
; CHECK: tail call void @f(i32 1)
; CHECK-LABEL: define {{[^@]+}}@test1()
; CHECK-NEXT: tail call void @f(i32 1)
; CHECK-NEXT: ret void
;
tail call void @f(i32 %a)
ret void
}
define void @test1_helper() {
; CHECK-LABEL: define {{[^@]+}}@test1_helper()
; CHECK-NEXT: tail call void @test1()
; CHECK-NEXT: ret void
;
tail call void @test1(i32 1)
ret void
}
; TEST 2 : Simplify return value
define i32 @return0() {
; CHECK-LABEL: define {{[^@]+}}@return0()
; CHECK-NEXT: ret i32 0
;
ret i32 0
}
define i32 @return1() {
; CHECK-LABEL: define {{[^@]+}}@return1()
; CHECK-NEXT: ret i32 1
;
ret i32 1
}
; CHECK: define i32 @test2_1(i1 %c)
define i32 @test2_1(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test2_1
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: [[RET0:%.*]] = add i32 0, 1
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: if.false:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
; CHECK-NEXT: ret i32 1
;
br i1 %c, label %if.true, label %if.false
if.true:
%call = tail call i32 @return0()
@ -43,25 +64,36 @@ if.false:
br label %end
end:
; CHECK: %ret = phi i32 [ %ret0, %if.true ], [ 1, %if.false ]
%ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ]
; CHECK: ret i32 1
ret i32 1
}
; CHECK: define i32 @test2_2(i1 %c)
define i32 @test2_2(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test2_2
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: ret i32 1
;
%ret = tail call i32 @test2_1(i1 %c)
; CHECK: ret i32 1
ret i32 %ret
}
declare void @use(i32)
; CHECK: define void @test3(i1 %c)
define void @test3(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test3
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: if.false:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
; CHECK-NEXT: tail call void @use(i32 1)
; CHECK-NEXT: ret void
;
br i1 %c, label %if.true, label %if.false
if.true:
br label %end
@ -70,21 +102,40 @@ if.false:
br label %end
end:
; CHECK: %r = phi i32 [ 1, %if.true ], [ 1, %if.false ]
%r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ]
; CHECK: tail call void @use(i32 1)
tail call void @use(i32 %r)
ret void
}
define void @test-select-phi(i1 %c) {
; CHECK-LABEL: define {{[^@]+}}@test-select-phi
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: tail call void @use(i32 1)
; CHECK-NEXT: [[SELECT_NOT_SAME:%.*]] = select i1 [[C]], i32 1, i32 0
; CHECK-NEXT: tail call void @use(i32 [[SELECT_NOT_SAME]])
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if-true:
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: if-false:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[PHI_SAME:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
; CHECK-NEXT: [[PHI_NOT_SAME:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
; CHECK-NEXT: [[PHI_SAME_PROP:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
; CHECK-NEXT: [[PHI_SAME_UNDEF:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ undef, [[IF_FALSE]] ]
; CHECK-NEXT: [[SELECT_NOT_SAME_UNDEF:%.*]] = select i1 [[C]], i32 [[PHI_NOT_SAME]], i32 undef
; CHECK-NEXT: tail call void @use(i32 1)
; CHECK-NEXT: tail call void @use(i32 [[PHI_NOT_SAME]])
; CHECK-NEXT: tail call void @use(i32 1)
; CHECK-NEXT: tail call void @use(i32 1)
; CHECK-NEXT: tail call void @use(i32 [[SELECT_NOT_SAME_UNDEF]])
; CHECK-NEXT: ret void
;
%select-same = select i1 %c, i32 1, i32 1
; CHECK: tail call void @use(i32 1)
tail call void @use(i32 %select-same)
%select-not-same = select i1 %c, i32 1, i32 0
; CHECK: tail call void @use(i32 %select-not-same)
tail call void @use(i32 %select-not-same)
br i1 %c, label %if-true, label %if-false
if-true:
@ -99,19 +150,14 @@ end:
%select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef
; CHECK: tail call void @use(i32 1)
tail call void @use(i32 %phi-same)
; CHECK: tail call void @use(i32 %phi-not-same)
tail call void @use(i32 %phi-not-same)
; CHECK: tail call void @use(i32 1)
tail call void @use(i32 %phi-same-prop)
; CHECK: tail call void @use(i32 1)
tail call void @use(i32 %phi-same-undef)
; CHECK: tail call void @use(i32 %select-not-same-undef)
tail call void @use(i32 %select-not-same-undef)
ret void
@ -123,7 +169,7 @@ define i32 @ipccp1(i32 %a) {
; CHECK-SAME: (i32 returned [[A:%.*]])
; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 [[A:%.*]]
; CHECK-NEXT: ret i32 [[A]]
; CHECK: f:
; CHECK-NEXT: unreachable
;
@ -136,6 +182,13 @@ f:
}
define internal i1 @ipccp2i(i1 %a) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@ipccp2i()
; IS__CGSCC____-NEXT: br label [[T:%.*]]
; IS__CGSCC____: t:
; IS__CGSCC____-NEXT: ret i1 true
; IS__CGSCC____: f:
; IS__CGSCC____-NEXT: unreachable
;
br i1 %a, label %t, label %f
t:
ret i1 %a
@ -145,14 +198,25 @@ f:
}
define i1 @ipccp2() {
; CHECK-LABEL: define {{[^@]+}}@ipccp2()
; CHECK-NEXT: ret i1 true
; IS__TUNIT____-LABEL: define {{[^@]+}}@ipccp2()
; IS__TUNIT____-NEXT: ret i1 true
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@ipccp2()
; IS__CGSCC____-NEXT: [[R:%.*]] = call i1 @ipccp2i()
; IS__CGSCC____-NEXT: ret i1 [[R]]
;
%r = call i1 @ipccp2i(i1 true)
ret i1 %r
}
define internal i1 @ipccp2ib(i1 %a) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@ipccp2ib()
; IS__CGSCC____-NEXT: br label [[T:%.*]]
; IS__CGSCC____: t:
; IS__CGSCC____-NEXT: ret i1 true
; IS__CGSCC____: f:
; IS__CGSCC____-NEXT: unreachable
;
br i1 %a, label %t, label %f
t:
ret i1 true
@ -170,6 +234,13 @@ define i1 @ipccp2b() {
}
define internal i32 @ipccp3i(i32 %a) {
; IS__CGSCC____-LABEL: define {{[^@]+}}@ipccp3i()
; IS__CGSCC____-NEXT: br label [[T:%.*]]
; IS__CGSCC____: t:
; IS__CGSCC____-NEXT: ret i32 7
; IS__CGSCC____: f:
; IS__CGSCC____-NEXT: unreachable
;
%c = icmp eq i32 %a, 7
br i1 %c, label %t, label %f
t:
@ -180,20 +251,27 @@ f:
}
define i32 @ipccp3() {
; CHECK-LABEL: define {{[^@]+}}@ipccp3()
; CHECK-NEXT: ret i32 7
; IS__TUNIT____-LABEL: define {{[^@]+}}@ipccp3()
; IS__TUNIT____-NEXT: ret i32 7
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@ipccp3()
; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @ipccp3i()
; IS__CGSCC____-NEXT: ret i32 [[R]]
;
%r = call i32 @ipccp3i(i32 7)
ret i32 %r
}
; UTC_ARGS: --enable
; Do not touch complicated arguments (for now)
%struct.X = type { i8* }
define internal i32* @test_inalloca(i32* inalloca %a) {
; CHECK-LABEL: define {{[^@]+}}@test_inalloca
; CHECK-SAME: (i32* inalloca noalias nofree returned writeonly align 536870912 [[A:%.*]])
; CHECK-NEXT: ret i32* [[A]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_inalloca
; IS__TUNIT____-SAME: (i32* inalloca noalias nofree returned writeonly align 536870912 "no-capture-maybe-returned" [[A:%.*]])
; IS__TUNIT____-NEXT: ret i32* [[A]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inalloca
; IS__CGSCC____-SAME: (i32* inalloca noalias nofree returned writeonly "no-capture-maybe-returned" [[A:%.*]])
; IS__CGSCC____-NEXT: ret i32* [[A]]
;
ret i32* %a
}
@ -207,29 +285,45 @@ define i32* @complicated_args_inalloca() {
}
define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) {
; CHECK-LABEL: define {{[^@]+}}@test_sret
; CHECK-SAME: (%struct.X* noalias nofree sret writeonly align 536870912 [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]])
; CHECK-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
; CHECK-NEXT: ret void
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_sret
; IS__TUNIT____-SAME: (%struct.X* noalias nofree sret writeonly align 536870912 [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]])
; IS__TUNIT____-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_sret
; IS__CGSCC____-SAME: (%struct.X* noalias nofree sret writeonly [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]])
; IS__CGSCC____-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
; IS__CGSCC____-NEXT: ret void
;
store %struct.X* %a, %struct.X** %b
ret void
}
; FIXME: Alignment and dereferenceability are not propagated to the argument
define void @complicated_args_sret(%struct.X** %b) {
; CHECK-LABEL: define {{[^@]+}}@complicated_args_sret
; CHECK-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]])
; CHECK-NEXT: call void @test_sret(%struct.X* noalias nofree writeonly align 536870912 null, %struct.X** nocapture nofree writeonly align 8 [[B]])
; CHECK-NEXT: ret void
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@complicated_args_sret
; IS__TUNIT____-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]])
; IS__TUNIT____-NEXT: call void @test_sret(%struct.X* noalias nofree writeonly align 536870912 null, %struct.X** nocapture nofree writeonly align 8 [[B]])
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@complicated_args_sret
; IS__CGSCC____-SAME: (%struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B:%.*]])
; IS__CGSCC____-NEXT: call void @test_sret(%struct.X* noalias nofree writeonly align 536870912 null, %struct.X** nocapture nofree nonnull writeonly align 8 dereferenceable(8) [[B]])
; IS__CGSCC____-NEXT: ret void
;
call void @test_sret(%struct.X* null, %struct.X** %b)
ret void
}
define internal %struct.X* @test_nest(%struct.X* nest %a) {
; CHECK-LABEL: define {{[^@]+}}@test_nest
; CHECK-SAME: (%struct.X* nest noalias nofree readnone returned align 536870912 [[A:%.*]])
; CHECK-NEXT: ret %struct.X* [[A]]
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_nest
; IS__TUNIT____-SAME: (%struct.X* nest noalias nofree readnone returned align 536870912 "no-capture-maybe-returned" [[A:%.*]])
; IS__TUNIT____-NEXT: ret %struct.X* [[A]]
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_nest
; IS__CGSCC____-SAME: (%struct.X* nest noalias nofree readnone returned "no-capture-maybe-returned" [[A:%.*]])
; IS__CGSCC____-NEXT: ret %struct.X* [[A]]
;
ret %struct.X* %a
}
@ -244,6 +338,21 @@ define %struct.X* @complicated_args_nest() {
@S = external global %struct.X
define internal void @test_byval(%struct.X* byval %a) {
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test_byval
; IS__CGSCC_OPM-SAME: (%struct.X* noalias nocapture nofree nonnull writeonly byval align 8 dereferenceable(8) [[A:%.*]])
; IS__CGSCC_OPM-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X:%.*]], %struct.X* [[A]], i32 0, i32 0
; IS__CGSCC_OPM-NEXT: store i8* null, i8** [[G0]], align 8
; IS__CGSCC_OPM-NEXT: ret void
;
; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test_byval
; IS__CGSCC_NPM-SAME: (i8* nocapture nofree readnone [[TMP0:%.*]])
; IS__CGSCC_NPM-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]]
; IS__CGSCC_NPM-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.X* [[A_PRIV]] to i8**
; IS__CGSCC_NPM-NEXT: store i8* [[TMP0]], i8** [[A_PRIV_CAST]]
; IS__CGSCC_NPM-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X]], %struct.X* [[A_PRIV]], i32 0, i32 0
; IS__CGSCC_NPM-NEXT: store i8* null, i8** [[G0]], align 8
; IS__CGSCC_NPM-NEXT: ret void
;
%g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0
store i8* null, i8** %g0
ret void
@ -383,4 +492,3 @@ define internal i8 @callee(i8 %a) {
ret i8 %c
}
; UTC_ARGS: --disable

View File

@ -1,19 +1,23 @@
; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
; RUN: opt -passes=attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target datalayout = "e-m:e-i54:64-f80:128-n8:16:32:64-S128"
; Test cases specifically designed for the "willreturn" function attribute.
; We use FIXME's to indicate problems and missing attributes.
; TEST 1 (positive case)
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define void @only_return()
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
define void @only_return() #0 {
ret void
; CHECK-LABEL: define {{[^@]+}}@only_return()
; CHECK-NEXT: ret void
;
ret void
}
@ -25,9 +29,22 @@ define void @only_return() #0 {
; }
; FIXME: missing willreturn
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr
; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable
define i32 @fib(i32 %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@fib
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 2
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP9:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[TMP0]], -1
; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @fib(i32 [[TMP4]])
; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], -2
; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @fib(i32 [[TMP6]])
; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP7]], [[TMP5]]
; CHECK-NEXT: ret i32 [[TMP8]]
; CHECK: 9:
; CHECK-NEXT: ret i32 [[TMP0]]
;
%2 = icmp slt i32 %0, 2
br i1 %2, label %9, label %3
@ -53,11 +70,27 @@ define i32 @fib(i32 %0) local_unnamed_addr #0 {
; }
; fact_maybe_not(-1) doesn't stop.
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
; CHECK-NOT: willreturn
define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@fact_maybe_not_halt
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP11:%.*]], label [[TMP3:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP8:%.*]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
; CHECK-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP3]] ], [ 1, [[TMP1]] ]
; CHECK-NEXT: [[TMP6:%.*]] = icmp sgt i32 [[TMP4]], 0
; CHECK-NEXT: [[TMP7:%.*]] = sext i1 [[TMP6]] to i32
; CHECK-NEXT: [[TMP8]] = add nsw i32 [[TMP4]], [[TMP7]]
; CHECK-NEXT: [[TMP9]] = mul nsw i32 [[TMP4]], [[TMP5]]
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP8]], 0
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP11]], label [[TMP3]]
; CHECK: 11:
; CHECK-NEXT: [[TMP12:%.*]] = phi i32 [ 1, [[TMP1]] ], [ [[TMP9]], [[TMP3]] ]
; CHECK-NEXT: ret i32 [[TMP12]]
;
%2 = icmp eq i32 %0, 0
br i1 %2, label %11, label %3
@ -87,10 +120,24 @@ define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@fact_loop
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[TMP1:%.*]] ], [ [[TMP8:%.*]], [[TMP5]] ]
; CHECK-NEXT: ret i32 [[TMP4]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP5]] ], [ 1, [[TMP1]] ]
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 1, [[TMP1]] ]
; CHECK-NEXT: [[TMP8]] = mul nsw i32 [[TMP6]], [[TMP7]]
; CHECK-NEXT: [[TMP9]] = add nuw nsw i32 [[TMP6]], 1
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP6]], [[TMP0]]
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP3]], label [[TMP5]]
;
%2 = icmp slt i32 %0, 1
br i1 %2, label %3, label %5
@ -118,10 +165,19 @@ define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
declare void @sink() nounwind willreturn nosync nofree
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable
; CHECK-NOT: willreturn
define void @mutual_recursion1(i1 %c) #0 {
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion1
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
; CHECK: rec:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: call void @mutual_recursion2(i1 [[C]])
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: ret void
;
br i1 %c, label %rec, label %end
rec:
call void @sink()
@ -132,10 +188,14 @@ end:
}
; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable
; CHECK-NOT: willreturn
define void @mutual_recursion2(i1 %c) #0 {
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion2
; CHECK-SAME: (i1 [[C:%.*]])
; CHECK-NEXT: call void @mutual_recursion1(i1 [[C]])
; CHECK-NEXT: ret void
;
call void @mutual_recursion1(i1 %c)
ret void
}
@ -143,14 +203,17 @@ define void @mutual_recursion2(i1 %c) #0 {
; TEST 5 (negative case)
; call exit/abort (has noreturn attribute)
; ATTRIBUTOR: Function Attrs: noreturn
; ATTRIBUTOR-NEXT: declare void @exit(i32) local_unnamed_add
; CHECK: Function Attrs: noreturn
; CHECK-NEXT: declare void @exit(i32) local_unnamed_add
declare void @exit(i32 %0) local_unnamed_addr noreturn
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr
; CHECK: Function Attrs: noinline noreturn nounwind uwtable
; CHECK-NOT: willreturn
define void @only_exit() local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@only_exit() local_unnamed_addr
; CHECK-NEXT: tail call void @exit(i32 0)
; CHECK-NEXT: unreachable
;
tail call void @exit(i32 0)
unreachable
}
@ -165,10 +228,26 @@ define void @only_exit() local_unnamed_addr #0 {
; }
; return;
; }
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: willreturn
define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@conditional_exit
; CHECK-SAME: (i32 [[TMP0:%.*]], i32* nocapture readonly [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]]
; CHECK: 4:
; CHECK-NEXT: tail call void @exit(i32 0)
; CHECK-NEXT: unreachable
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[TMP1]], align 4
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 0
; CHECK-NEXT: br i1 [[TMP7]], label [[TMP9:%.*]], label [[TMP8:%.*]]
; CHECK: 8:
; CHECK-NEXT: tail call void @exit(i32 1)
; CHECK-NEXT: unreachable
; CHECK: 9:
; CHECK-NEXT: ret void
;
%3 = icmp eq i32 %0, 0
br i1 %3, label %5, label %4
@ -191,77 +270,100 @@ define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_
; TEST 6 (positive case)
; Call intrinsic function
; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable willreturn
; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
; CHECK: Function Attrs: nounwind readnone speculatable willreturn
; CHECK-NEXT: declare float @llvm.floor.f32(float)
declare float @llvm.floor.f32(float)
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
define void @call_floor(float %a) #0 {
tail call float @llvm.floor.f32(float %a)
ret void
; CHECK-LABEL: define {{[^@]+}}@call_floor
; CHECK-SAME: (float [[A:%.*]])
; CHECK-NEXT: ret void
;
tail call float @llvm.floor.f32(float %a)
ret void
}
; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define float @call_floor2(float %a)
; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable willreturn
define float @call_floor2(float %a) #0 {
%c = tail call float @llvm.floor.f32(float %a)
ret float %c
; CHECK-LABEL: define {{[^@]+}}@call_floor2
; CHECK-SAME: (float [[A:%.*]])
; CHECK-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]])
; CHECK-NEXT: ret float [[C]]
;
%c = tail call float @llvm.floor.f32(float %a)
ret float %c
}
; TEST 7 (negative case)
; Call function declaration without willreturn
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: declare void @maybe_noreturn()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: willreturn
; CHECK-NEXT: declare void @maybe_noreturn()
declare void @maybe_noreturn() #0
; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_maybe_noreturn()
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-NOT: willreturn
define void @call_maybe_noreturn() #0 {
tail call void @maybe_noreturn()
ret void
; CHECK-LABEL: define {{[^@]+}}@call_maybe_noreturn()
; CHECK-NEXT: tail call void @maybe_noreturn()
; CHECK-NEXT: ret void
;
tail call void @maybe_noreturn()
ret void
}
; TEST 8 (positive case)
; Check propagation.
; ATTRIBUTOR: Function Attrs: norecurse willreturn
; ATTRIBUTOR-NEXT: declare void @will_return()
; CHECK: Function Attrs: norecurse willreturn
; CHECK-NEXT: declare void @will_return()
declare void @will_return() willreturn norecurse
; ATTRIBUTOR_MODULE: Function Attrs: noinline nounwind uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @f1()
; CHECK_MODULE: Function Attrs: noinline nounwind uwtable willreturn
; CHECK_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
define void @f1() #0 {
tail call void @will_return()
ret void
; CHECK-LABEL: define {{[^@]+}}@f1()
; CHECK-NEXT: tail call void @will_return()
; CHECK-NEXT: ret void
;
tail call void @will_return()
ret void
}
; ATTRIBUTOR_MODULE: Function Attrs: noinline nounwind uwtable
; CHECK_MODULE: Function Attrs: noinline nounwind uwtable
; FIXME: Because we do not derive norecurse in the module run anymore, willreturn is missing as well.
; ATTRIBUTOR_MODULE-NOT: willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @f2()
; CHECK_MODULE-NOT: willreturn
; CHECK_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
define void @f2() #0 {
tail call void @f1()
ret void
; CHECK-LABEL: define {{[^@]+}}@f2()
; CHECK-NEXT: tail call void @f1()
; CHECK-NEXT: ret void
;
tail call void @f1()
ret void
}
; TEST 9 (negative case)
; call willreturn function in endless loop.
; ATTRIBUTOR_MODULE: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR_CGSCC: Function Attrs: noinline norecurse noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop()
; CHECK_MODULE: Function Attrs: noinline noreturn nounwind uwtable
; CHECK_CGSCC: Function Attrs: noinline norecurse noreturn nounwind uwtable
; CHECK-NOT: willreturn
define void @call_will_return_but_has_loop() #0 {
; CHECK-LABEL: define {{[^@]+}}@call_will_return_but_has_loop()
; CHECK-NEXT: br label [[LABEL1:%.*]]
; CHECK: label1:
; CHECK-NEXT: tail call void @will_return()
; CHECK-NEXT: br label [[LABEL2:%.*]]
; CHECK: label2:
; CHECK-NEXT: br label [[LABEL1]]
;
br label %label1
label1:
tail call void @will_return()
@ -274,21 +376,40 @@ label2:
; TEST 10 (positive case)
; invoke a function with willreturn
; ATTRIBUTOR: Function Attrs: noinline uwtable willreturn
; ATTRIBUTOR-NEXT: declare i1 @maybe_raise_exception()
; CHECK: Function Attrs: noinline uwtable willreturn
; CHECK-NEXT: declare i1 @maybe_raise_exception()
declare i1 @maybe_raise_exception() #1 willreturn
; ATTRIBUTOR: Function Attrs: nounwind willreturn
; ATTRIBUTOR-NEXT: define void @invoke_test()
; CHECK: Function Attrs: nounwind willreturn
define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 {
; IS__TUNIT____-LABEL: define {{[^@]+}}@invoke_test() #12 personality i32 (...)* @__gxx_personality_v0
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = invoke i1 @maybe_raise_exception()
; IS__TUNIT____-NEXT: to label [[N:%.*]] unwind label [[F:%.*]]
; IS__TUNIT____: N:
; IS__TUNIT____-NEXT: ret void
; IS__TUNIT____: F:
; IS__TUNIT____-NEXT: [[VAL:%.*]] = landingpad { i8*, i32 }
; IS__TUNIT____-NEXT: catch i8* null
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@invoke_test() #14 personality i32 (...)* @__gxx_personality_v0
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = invoke i1 @maybe_raise_exception()
; IS__CGSCC____-NEXT: to label [[N:%.*]] unwind label [[F:%.*]]
; IS__CGSCC____: N:
; IS__CGSCC____-NEXT: ret void
; IS__CGSCC____: F:
; IS__CGSCC____-NEXT: [[VAL:%.*]] = landingpad { i8*, i32 }
; IS__CGSCC____-NEXT: catch i8* null
; IS__CGSCC____-NEXT: ret void
;
invoke i1 @maybe_raise_exception()
to label %N unwind label %F
to label %N unwind label %F
N:
ret void
ret void
F:
%val = landingpad { i8*, i32 }
catch i8* null
ret void
%val = landingpad { i8*, i32 }
catch i8* null
ret void
}
declare i32 @__gxx_personality_v0(...)
@ -304,10 +425,24 @@ declare i32 @__gxx_personality_v0(...)
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture nofree readonly %0)
; CHECK_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable willreturn
; CHECK_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable willreturn
define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
; CHECK-LABEL: define {{[^@]+}}@loop_constant_trip_count
; CHECK-SAME: (i32* nocapture nofree readonly [[TMP0:%.*]])
; CHECK-NEXT: br label [[TMP3:%.*]]
; CHECK: 2:
; CHECK-NEXT: ret i32 [[TMP8:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = phi i64 [ 0, [[TMP1:%.*]] ], [ [[TMP9:%.*]], [[TMP3]] ]
; CHECK-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP1]] ], [ [[TMP8]], [[TMP3]] ]
; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP4]]
; CHECK-NEXT: [[TMP7:%.*]] = load i32, i32* [[TMP6]], align 4
; CHECK-NEXT: [[TMP8]] = add nsw i32 [[TMP7]], [[TMP5]]
; CHECK-NEXT: [[TMP9]] = add nuw nsw i64 [[TMP4]], 1
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 10
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP2:%.*]], label [[TMP3]]
;
br label %3
; <label>:2: ; preds = %3
@ -335,12 +470,28 @@ define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
; }
; return ans;
; }
; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
; ATTRIBUTOR_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable
; ATTRIBUTOR_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture nofree readonly %2, i32 %3) local_unnamed_addr
; CHECK_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable
; CHECK_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable
; CHECK-NOT: willreturn
define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@loop_trip_count_unbound
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32* nocapture nofree readonly [[TMP2:%.*]], i32 [[TMP3:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP8:%.*]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ 0, [[TMP4:%.*]] ], [ [[TMP14:%.*]], [[TMP8]] ]
; CHECK-NEXT: ret i32 [[TMP7]]
; CHECK: 8:
; CHECK-NEXT: [[TMP9:%.*]] = phi i32 [ [[TMP15:%.*]], [[TMP8]] ], [ [[TMP0]], [[TMP4]] ]
; CHECK-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP14]], [[TMP8]] ], [ 0, [[TMP4]] ]
; CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[TMP9]] to i64
; CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds i32, i32* [[TMP2]], i64 [[TMP11]]
; CHECK-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP12]], align 4
; CHECK-NEXT: [[TMP14]] = add nsw i32 [[TMP13]], [[TMP10]]
; CHECK-NEXT: [[TMP15]] = add i32 [[TMP9]], [[TMP3]]
; CHECK-NEXT: [[TMP16:%.*]] = icmp eq i32 [[TMP15]], [[TMP1]]
; CHECK-NEXT: br i1 [[TMP16]], label [[TMP6]], label [[TMP8]]
;
%5 = icmp eq i32 %0, %1
br i1 %5, label %6, label %8
@ -372,11 +523,30 @@ define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2,
; }
; ATTRIBUTOR_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture nofree readonly %1) local_unnamed_addr
; CHECK_MODULE: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable willreturn
; CHECK_CGSCC: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable willreturn
define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@loop_trip_dec
; CHECK-SAME: (i32 [[TMP0:%.*]], i32* nocapture nofree readonly [[TMP1:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], -1
; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP14:%.*]]
; CHECK: 4:
; CHECK-NEXT: [[TMP5:%.*]] = sext i32 [[TMP0]] to i64
; CHECK-NEXT: br label [[TMP6:%.*]]
; CHECK: 6:
; CHECK-NEXT: [[TMP7:%.*]] = phi i64 [ [[TMP5]], [[TMP4]] ], [ [[TMP12:%.*]], [[TMP6]] ]
; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ 0, [[TMP4]] ], [ [[TMP11:%.*]], [[TMP6]] ]
; CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 [[TMP7]]
; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP9]], align 4
; CHECK-NEXT: [[TMP11]] = add nsw i32 [[TMP10]], [[TMP8]]
; CHECK-NEXT: [[TMP12]] = add nsw i64 [[TMP7]], -1
; CHECK-NEXT: [[TMP13:%.*]] = icmp sgt i64 [[TMP7]], 0
; CHECK-NEXT: br i1 [[TMP13]], label [[TMP6]], label [[TMP14]]
; CHECK: 14:
; CHECK-NEXT: [[TMP15:%.*]] = phi i32 [ 0, [[TMP2:%.*]] ], [ [[TMP11]], [[TMP6]] ]
; CHECK-NEXT: ret i32 [[TMP15]]
;
%3 = icmp sgt i32 %0, -1
br i1 %3, label %4, label %14
@ -402,10 +572,18 @@ define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
; TEST 14 (positive case)
; multiple return
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a)
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
define i32 @multiple_return(i32 %a) #0 {
; CHECK-LABEL: define {{[^@]+}}@multiple_return
; CHECK-SAME: (i32 [[A:%.*]])
; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[A]], 0
; CHECK-NEXT: br i1 [[B]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 1
; CHECK: f:
; CHECK-NEXT: ret i32 0
;
%b = icmp eq i32 %a, 0
br i1 %b, label %t, label %f
@ -419,10 +597,15 @@ f:
; unreachable exit
; 15.1 (positive case)
; ATTRIBUTOR_MODULE: Function Attrs: noinline nounwind uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_positive1()
; CHECK_MODULE: Function Attrs: noinline nounwind uwtable willreturn
; CHECK_CGSCC: Function Attrs: noinline norecurse nounwind uwtable willreturn
define void @unreachable_exit_positive1() #0 {
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive1()
; CHECK-NEXT: tail call void @will_return()
; CHECK-NEXT: ret void
; CHECK: unreachable_label:
; CHECK-NEXT: unreachable
;
tail call void @will_return()
ret void
@ -431,10 +614,26 @@ unreachable_label:
unreachable
}
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
; CHECK_MODULE: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive2
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
; CHECK: 3:
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[TMP1:%.*]] ], [ [[TMP8:%.*]], [[TMP5]] ]
; CHECK-NEXT: ret i32 [[TMP4]]
; CHECK: 5:
; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP5]] ], [ 1, [[TMP1]] ]
; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 1, [[TMP1]] ]
; CHECK-NEXT: [[TMP8]] = mul nsw i32 [[TMP6]], [[TMP7]]
; CHECK-NEXT: [[TMP9]] = add nuw nsw i32 [[TMP6]], 1
; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP6]], [[TMP0]]
; CHECK-NEXT: br i1 [[TMP10]], label [[TMP3]], label [[TMP5]]
; CHECK: unreachable_label:
; CHECK-NEXT: unreachable
;
%2 = icmp slt i32 %0, 1
br i1 %2, label %3, label %5
@ -458,10 +657,15 @@ unreachable_label:
;15.2
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1()
; CHECK: Function Attrs: noinline noreturn nounwind uwtable
; CHECK-NOT: willreturn
define void @unreachable_exit_negative1() #0 {
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative1()
; CHECK-NEXT: tail call void @exit(i32 0)
; CHECK-NEXT: unreachable
; CHECK: unreachable_label:
; CHECK-NEXT: unreachable
;
tail call void @exit(i32 0)
ret void
@ -470,12 +674,19 @@ unreachable_label:
unreachable
}
; ATTRIBUTOR_MODULE: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR_CGSCC: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
; CHECK_MODULE: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
; CHECK_CGSCC: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
; CHECK-NOT: willreturn
define void @unreachable_exit_negative2() #0 {
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative2()
; CHECK-NEXT: br label [[L1:%.*]]
; CHECK: L1:
; CHECK-NEXT: br label [[L2:%.*]]
; CHECK: L2:
; CHECK-NEXT: br label [[L1]]
; CHECK: unreachable_label:
; CHECK-NEXT: unreachable
;
br label %L1
L1:
br label %L2
@ -487,20 +698,24 @@ unreachable_label:
unreachable
}
; ATTRIBUTOR: Function Attrs: noreturn nounwind
; ATTRIBUTOR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
; CHECK: Function Attrs: noreturn nounwind
; CHECK-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
declare void @llvm.eh.sjlj.longjmp(i8*)
; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr
; CHECK: Function Attrs: noinline noreturn nounwind uwtable
; CHECK-NOT: willreturn
define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 {
; CHECK-LABEL: define {{[^@]+}}@call_longjmp
; CHECK-SAME: (i8* nocapture readnone [[TMP0:%.*]]) local_unnamed_addr
; CHECK-NEXT: tail call void @llvm.eh.sjlj.longjmp(i8* noalias readnone [[TMP0]])
; CHECK-NEXT: unreachable
;
tail call void @llvm.eh.sjlj.longjmp(i8* %0)
ret void
}
; TEST 16 (negative case)
; TEST 16 (negative case)
; int infinite_loop_inside_bounded_loop(int n) {
; int ans = 0;
; for (int i = 0; i < n; i++) {
@ -510,11 +725,30 @@ define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 {
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree nosync nounwind readnone
; ATTRIBUTOR_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @infinite_loop_inside_bounded_loop(i32 %n)
; CHECK_MODULE: Function Attrs: nofree nosync nounwind readnone
; CHECK_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; CHECK-NOT: willreturn
define i32 @infinite_loop_inside_bounded_loop(i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@infinite_loop_inside_bounded_loop
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: br label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_COND]]
; CHECK: for.inc:
; CHECK-NEXT: unreachable
; CHECK: for.end:
; CHECK-NEXT: ret i32 0
;
entry:
br label %for.cond
@ -554,10 +788,37 @@ for.end: ; preds = %for.cond.cleanup
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree nosync nounwind readnone willreturn
; ATTRIBUTOR_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; ATTRIBUTOR-NEXT: define i32 @bounded_nested_loops(i32 %n)
; CHECK_MODULE: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
define i32 @bounded_nested_loops(i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@bounded_nested_loops
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC1:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[TMP:%.*]], [[FOR_INC]] ]
; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ -1, [[FOR_INC]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[N_ADDR_0]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[FOR_COND]] ]
; CHECK-NEXT: br label [[FOR_END:%.*]]
; CHECK: for.body:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: br i1 true, label [[WHILE_END:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: unreachable
; CHECK: while.end:
; CHECK-NEXT: [[TMP]] = add i32 [[N_ADDR_0]], [[ANS_0]]
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC1]] = add nuw nsw i32 [[I_0]], 1
; CHECK-NEXT: br label [[FOR_COND]]
; CHECK: for.end:
; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]]
;
entry:
br label %for.cond
@ -605,11 +866,40 @@ for.end: ; preds = %for.cond.cleanup
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree nosync nounwind readnone
; ATTRIBUTOR_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @bounded_loop_inside_unbounded_loop(i32 %n)
; CHECK_MODULE: Function Attrs: nofree nosync nounwind readnone
; CHECK_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; CHECK-NOT: willreturn
define i32 @bounded_loop_inside_unbounded_loop(i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@bounded_loop_inside_unbounded_loop
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2:%.*]], [[FOR_END:%.*]] ]
; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[INC:%.*]], [[FOR_END]] ]
; CHECK-NEXT: [[TMP:%.*]] = icmp sgt i32 [[N_ADDR_0]], -1
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP]], i32 [[N_ADDR_0]], i32 -1
; CHECK-NEXT: [[INC]] = add nsw i32 [[N_ADDR_0]], 1
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N_ADDR_0]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[ANS_0]], 1
; CHECK-NEXT: br label [[FOR_COND:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: br i1 true, label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: [[TMP2]] = add i32 [[TMP1]], [[SMAX]]
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.body:
; CHECK-NEXT: unreachable
; CHECK: for.inc:
; CHECK-NEXT: unreachable
; CHECK: for.end:
; CHECK-NEXT: br label [[WHILE_COND]]
; CHECK: while.end:
; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[WHILE_COND]] ]
; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]]
;
entry:
br label %while.cond
@ -662,11 +952,39 @@ while.end: ; preds = %while.cond
; return ans;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree nosync nounwind readnone
; ATTRIBUTOR_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define i32 @nested_unbounded_loops(i32 %n)
; CHECK_MODULE: Function Attrs: nofree nosync nounwind readnone
; CHECK_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; CHECK-NOT: willreturn
define i32 @nested_unbounded_loops(i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@nested_unbounded_loops
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_COND:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP1:%.*]], [[WHILE_END10:%.*]] ]
; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ -1, [[WHILE_END10]] ]
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N_ADDR_0]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_END11:%.*]], label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_COND1:%.*]]
; CHECK: while.cond1:
; CHECK-NEXT: br i1 true, label [[WHILE_END:%.*]], label [[WHILE_BODY4:%.*]]
; CHECK: while.body4:
; CHECK-NEXT: unreachable
; CHECK: while.end:
; CHECK-NEXT: [[TMP:%.*]] = add i32 [[N_ADDR_0]], -2
; CHECK-NEXT: br label [[WHILE_COND5:%.*]]
; CHECK: while.cond5:
; CHECK-NEXT: br i1 true, label [[WHILE_END10]], label [[WHILE_BODY8:%.*]]
; CHECK: while.body8:
; CHECK-NEXT: unreachable
; CHECK: while.end10:
; CHECK-NEXT: [[TMP1]] = add i32 [[TMP]], [[ANS_0]]
; CHECK-NEXT: br label [[WHILE_COND]]
; CHECK: while.end11:
; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[WHILE_COND]] ]
; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]]
;
entry:
br label %while.cond
@ -726,11 +1044,39 @@ while.end11: ; preds = %while.cond
; return;
; }
; ATTRIBUTOR_MODULE: Function Attrs: nofree nosync nounwind readnone
; ATTRIBUTOR_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; ATTRIBUTOR-NOT: willreturn
; ATTRIBUTOR-NEXT: define void @non_loop_cycle(i32 %n)
; CHECK_MODULE: Function Attrs: nofree nosync nounwind readnone
; CHECK_CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone
; CHECK-NOT: willreturn
define void @non_loop_cycle(i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@non_loop_cycle
; CHECK-SAME: (i32 [[N:%.*]])
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fact_loop(i32 [[N]])
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 5
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: br label [[ENTRY1:%.*]]
; CHECK: if.else:
; CHECK-NEXT: br label [[ENTRY2:%.*]]
; CHECK: entry1:
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @fact_loop(i32 [[N]])
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[CALL1]], 5
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]]
; CHECK: if.then3:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: if.else4:
; CHECK-NEXT: br label [[ENTRY2]]
; CHECK: entry2:
; CHECK-NEXT: [[CALL5:%.*]] = call i32 @fact_loop(i32 [[N]])
; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[CALL5]], 5
; CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]]
; CHECK: if.then7:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: if.else8:
; CHECK-NEXT: br label [[ENTRY1]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%call = call i32 @fact_loop(i32 %n)
%cmp = icmp sgt i32 %call, 5