diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-02-01-ReturnAttrs.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-07-02-array-indexing.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-07-CGUpdate.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-07-CGUpdate.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-07-CGUpdate.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-07-CGUpdate.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-08-CGUpdateSelfEdge.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-08-CGUpdateSelfEdge.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-08-CGUpdateSelfEdge.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/2008-09-08-CGUpdateSelfEdge.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/attributes.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/attributes.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/attributes.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/attributes.ll @@ -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 @@ } 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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/min-legal-vector-width.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/min-legal-vector-width.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/min-legal-vector-width.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/min-legal-vector-width.ll @@ -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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 @@ ; 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll @@ -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 @@ %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 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll @@ -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 @@ 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: diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll @@ -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 @@ } 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) diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll @@ -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 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll @@ -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 @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 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll @@ -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 @@ 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 @@ 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_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32* +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = 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: [[TMP1:%.*]] = load i64, i64* [[S_0_12]], align 1 +; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]]) +; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32* +; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = 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: [[TMP3:%.*]] = load i64, i64* [[S_0_1]], 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll @@ -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) { diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/crash.ll @@ -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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll @@ -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 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll @@ -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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/inalloca.ll @@ -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 @@ ; 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 @@ } 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 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead.ll @@ -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 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll @@ -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 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 @@ } 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 -; -; 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__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 ; -; 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 +; 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_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 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 -; -; 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 +; 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 ; -; 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll @@ -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 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 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 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll @@ -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. diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll @@ -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*) { diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr3085.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr3085.ll deleted file mode 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr3085.ll +++ /dev/null @@ -1,1945 +0,0 @@ -; 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 -; PR 3085 - - %struct.Lit = type { i8 } - -define fastcc %struct.Lit* @import_lit(i32 %lit) nounwind { -entry: - br i1 false, label %bb, label %bb1 - -bb: ; preds = %entry - unreachable - -bb1: ; preds = %entry - br label %bb3 - -bb2: ; preds = %bb3 - br label %bb3 - -bb3: ; preds = %bb2, %bb1 - br i1 false, label %bb2, label %bb6 - -bb6: ; preds = %bb3 - br i1 false, label %bb.i.i, label %bb1.i.i - -bb.i.i: ; preds = %bb6 - br label %int2lit.exit - -bb1.i.i: ; preds = %bb6 - br label %int2lit.exit - -int2lit.exit: ; preds = %bb1.i.i, %bb.i.i - ret %struct.Lit* null -} - -define fastcc i32 @picosat_main(i32 %argc, i8** %argv) nounwind { -entry: - br i1 false, label %bb.i, label %picosat_time_stamp.exit - -bb.i: ; preds = %entry - br label %picosat_time_stamp.exit - -picosat_time_stamp.exit: ; preds = %bb.i, %entry - br label %bb108 - -bb: ; preds = %bb108 - br i1 false, label %bb1, label %bb2 - -bb1: ; preds = %bb - br label %bb106 - -bb2: ; preds = %bb - br i1 false, label %bb3, label %bb4 - -bb3: ; preds = %bb2 - br label %bb106 - -bb4: ; preds = %bb2 - br i1 false, label %bb5, label %bb6 - -bb5: ; preds = %bb4 - br label %bb106 - -bb6: ; preds = %bb4 - br i1 false, label %bb7, label %bb8 - -bb7: ; preds = %bb6 - br label %bb106 - -bb8: ; preds = %bb6 - br i1 false, label %bb106, label %bb10 - -bb10: ; preds = %bb8 - br i1 false, label %bb106, label %bb12 - -bb12: ; preds = %bb10 - br i1 false, label %bb106, label %bb14 - -bb14: ; preds = %bb12 - br i1 false, label %bb15, label %bb19 - -bb15: ; preds = %bb14 - br i1 false, label %bb16, label %bb17 - -bb16: ; preds = %bb15 - br label %bb106 - -bb17: ; preds = %bb15 - br label %bb106 - -bb19: ; preds = %bb14 - br i1 false, label %bb20, label %bb28 - -bb20: ; preds = %bb19 - br i1 false, label %bb21, label %bb22 - -bb21: ; preds = %bb20 - br label %bb106 - -bb22: ; preds = %bb20 - br i1 false, label %bb106, label %bb24 - -bb24: ; preds = %bb22 - br i1 false, label %bb106, label %bb26 - -bb26: ; preds = %bb24 - br label %bb106 - -bb28: ; preds = %bb19 - br i1 false, label %bb29, label %bb35 - -bb29: ; preds = %bb28 - br i1 false, label %bb30, label %bb31 - -bb30: ; preds = %bb29 - br label %bb106 - -bb31: ; preds = %bb29 - br i1 false, label %bb32, label %bb33 - -bb32: ; preds = %bb31 - br label %bb106 - -bb33: ; preds = %bb31 - br label %bb106 - -bb35: ; preds = %bb28 - br i1 false, label %bb36, label %bb40 - -bb36: ; preds = %bb35 - br i1 false, label %bb37, label %bb38 - -bb37: ; preds = %bb36 - br label %bb106 - -bb38: ; preds = %bb36 - br label %bb106 - -bb40: ; preds = %bb35 - br i1 false, label %bb41, label %bb49 - -bb41: ; preds = %bb40 - br i1 false, label %bb43, label %bb42 - -bb42: ; preds = %bb41 - br label %bb106 - -bb43: ; preds = %bb41 - br i1 false, label %bb44, label %bb45 - -bb44: ; preds = %bb43 - br label %bb106 - -bb45: ; preds = %bb43 - br i1 false, label %bb46, label %bb47 - -bb46: ; preds = %bb45 - br label %bb106 - -bb47: ; preds = %bb45 - br label %bb106 - -bb49: ; preds = %bb40 - br i1 false, label %bb50, label %bb56 - -bb50: ; preds = %bb49 - br i1 false, label %bb52, label %bb51 - -bb51: ; preds = %bb50 - br label %bb106 - -bb52: ; preds = %bb50 - br i1 false, label %bb53, label %bb54 - -bb53: ; preds = %bb52 - br label %bb106 - -bb54: ; preds = %bb52 - br label %bb106 - -bb56: ; preds = %bb49 - br i1 false, label %bb57, label %bb63 - -bb57: ; preds = %bb56 - br i1 false, label %bb59, label %bb58 - -bb58: ; preds = %bb57 - br label %bb106 - -bb59: ; preds = %bb57 - br i1 false, label %bb60, label %bb61 - -bb60: ; preds = %bb59 - br label %bb106 - -bb61: ; preds = %bb59 - br label %bb106 - -bb63: ; preds = %bb56 - br i1 false, label %bb64, label %bb70 - -bb64: ; preds = %bb63 - br i1 false, label %bb66, label %bb65 - -bb65: ; preds = %bb64 - br label %bb106 - -bb66: ; preds = %bb64 - br i1 false, label %bb67, label %bb68 - -bb67: ; preds = %bb66 - br label %bb106 - -bb68: ; preds = %bb66 - br label %bb106 - -bb70: ; preds = %bb63 - br i1 false, label %bb71, label %bb79 - -bb71: ; preds = %bb70 - br i1 false, label %bb73, label %bb72 - -bb72: ; preds = %bb71 - br label %bb106 - -bb73: ; preds = %bb71 - br i1 false, label %bb74, label %bb75 - -bb74: ; preds = %bb73 - br label %bb106 - -bb75: ; preds = %bb73 - br i1 false, label %bb76, label %bb77 - -bb76: ; preds = %bb75 - br label %bb106 - -bb77: ; preds = %bb75 - br label %bb106 - -bb79: ; preds = %bb70 - br i1 false, label %bb80, label %bb86 - -bb80: ; preds = %bb79 - br i1 false, label %bb82, label %bb81 - -bb81: ; preds = %bb80 - br label %bb106 - -bb82: ; preds = %bb80 - br i1 false, label %bb83, label %bb84 - -bb83: ; preds = %bb82 - br label %bb106 - -bb84: ; preds = %bb82 - br label %bb106 - -bb86: ; preds = %bb79 - br i1 false, label %bb87, label %bb93 - -bb87: ; preds = %bb86 - br i1 false, label %bb89, label %bb88 - -bb88: ; preds = %bb87 - br label %bb106 - -bb89: ; preds = %bb87 - br i1 false, label %bb90, label %bb91 - -bb90: ; preds = %bb89 - br label %bb106 - -bb91: ; preds = %bb89 - br label %bb106 - -bb93: ; preds = %bb86 - br i1 false, label %bb94, label %bb95 - -bb94: ; preds = %bb93 - br label %bb106 - -bb95: ; preds = %bb93 - br i1 false, label %bb98, label %bb97 - -bb97: ; preds = %bb95 - br label %bb106 - -bb98: ; preds = %bb95 - br i1 false, label %bb103, label %bb1.i24 - -bb1.i24: ; preds = %bb98 - br i1 false, label %bb99, label %bb103 - -bb99: ; preds = %bb1.i24 - br i1 false, label %bb101, label %bb100 - -bb100: ; preds = %bb99 - br label %bb102 - -bb101: ; preds = %bb99 - br label %bb102 - -bb102: ; preds = %bb101, %bb100 - br label %bb106 - -bb103: ; preds = %bb1.i24, %bb98 - br i1 false, label %bb104, label %bb105 - -bb104: ; preds = %bb103 - br label %bb106 - -bb105: ; preds = %bb103 - br label %bb106 - -bb106: ; preds = %bb105, %bb104, %bb102, %bb97, %bb94, %bb91, %bb90, %bb88, %bb84, %bb83, %bb81, %bb77, %bb76, %bb74, %bb72, %bb68, %bb67, %bb65, %bb61, %bb60, %bb58, %bb54, %bb53, %bb51, %bb47, %bb46, %bb44, %bb42, %bb38, %bb37, %bb33, %bb32, %bb30, %bb26, %bb24, %bb22, %bb21, %bb17, %bb16, %bb12, %bb10, %bb8, %bb7, %bb5, %bb3, %bb1 - br i1 false, label %bb108, label %bb110 - -bb108: ; preds = %bb106, %picosat_time_stamp.exit - br i1 false, label %bb, label %bb110 - -bb110: ; preds = %bb108, %bb106 - br i1 false, label %bb112, label %bb171 - -bb112: ; preds = %bb110 - br i1 false, label %bb114, label %bb113 - -bb113: ; preds = %bb112 - br label %bb114 - -bb114: ; preds = %bb113, %bb112 - br i1 false, label %bb.i.i35, label %bb1.i.i36 - -bb.i.i35: ; preds = %bb114 - unreachable - -bb1.i.i36: ; preds = %bb114 - br i1 false, label %bb5.i.i.i41, label %bb6.i.i.i42 - -bb5.i.i.i41: ; preds = %bb1.i.i36 - unreachable - -bb6.i.i.i42: ; preds = %bb1.i.i36 - br i1 false, label %bb7.i.i.i43, label %bb8.i.i.i44 - -bb7.i.i.i43: ; preds = %bb6.i.i.i42 - br label %bb8.i.i.i44 - -bb8.i.i.i44: ; preds = %bb7.i.i.i43, %bb6.i.i.i42 - br i1 false, label %picosat_init.exit, label %bb14.i.i - -bb14.i.i: ; preds = %bb8.i.i.i44 - br label %picosat_init.exit - -picosat_init.exit: ; preds = %bb14.i.i, %bb8.i.i.i44 - br i1 false, label %bb116, label %bb115 - -bb115: ; preds = %picosat_init.exit - br label %bb116 - -bb116: ; preds = %bb115, %picosat_init.exit - br i1 false, label %bb119, label %bb118 - -bb118: ; preds = %bb116 - br label %bb119 - -bb119: ; preds = %bb118, %bb116 - br i1 false, label %bb121, label %bb120 - -bb120: ; preds = %bb119 - br label %bb121 - -bb121: ; preds = %bb120, %bb119 - br i1 false, label %bb126, label %bb122 - -bb122: ; preds = %bb121 - br label %bb126 - -bb126: ; preds = %bb122, %bb121 - br i1 false, label %bb128, label %bb127 - -bb127: ; preds = %bb126 - br label %bb128 - -bb128: ; preds = %bb127, %bb126 - br label %SKIP_COMMENTS.i - -SKIP_COMMENTS.i.loopexit: ; preds = %bb.i149, %bb.i149 - br label %SKIP_COMMENTS.i.backedge - -SKIP_COMMENTS.i: ; preds = %SKIP_COMMENTS.i.backedge, %bb128 - br i1 false, label %bb.i149.preheader, label %bb3.i152 - -bb.i149.preheader: ; preds = %SKIP_COMMENTS.i - br label %bb.i149 - -bb.i149: ; preds = %bb.i149, %bb.i149.preheader - switch i32 0, label %bb.i149 [ - i32 -1, label %SKIP_COMMENTS.i.loopexit - i32 10, label %SKIP_COMMENTS.i.loopexit - ] - -bb3.i152: ; preds = %SKIP_COMMENTS.i - br i1 false, label %bb4.i153, label %SKIP_COMMENTS.i.backedge - -SKIP_COMMENTS.i.backedge: ; preds = %bb3.i152, %SKIP_COMMENTS.i.loopexit - br label %SKIP_COMMENTS.i - -bb4.i153: ; preds = %bb3.i152 - br i1 false, label %bb5.i154, label %bb129 - -bb5.i154: ; preds = %bb4.i153 - br i1 false, label %bb129, label %bb6.i155.preheader - -bb6.i155.preheader: ; preds = %bb5.i154 - br label %bb6.i155 - -bb6.i155: ; preds = %bb6.i155, %bb6.i155.preheader - br i1 false, label %bb7.i156, label %bb6.i155 - -bb7.i156: ; preds = %bb6.i155 - br i1 false, label %bb8.i157, label %bb129 - -bb8.i157: ; preds = %bb7.i156 - br i1 false, label %bb9.i158, label %bb129 - -bb9.i158: ; preds = %bb8.i157 - br i1 false, label %bb10.i159, label %bb129 - -bb10.i159: ; preds = %bb9.i158 - br i1 false, label %bb129, label %bb11.i160.preheader - -bb11.i160.preheader: ; preds = %bb10.i159 - br label %bb11.i160 - -bb11.i160: ; preds = %bb11.i160, %bb11.i160.preheader - br i1 false, label %bb12.i161, label %bb11.i160 - -bb12.i161: ; preds = %bb11.i160 - br i1 false, label %bb129, label %bb15.i165.preheader - -bb15.i165.preheader: ; preds = %bb12.i161 - br label %bb15.i165 - -bb14.i163: ; preds = %bb15.i165 - br label %bb15.i165 - -bb15.i165: ; preds = %bb14.i163, %bb15.i165.preheader - br i1 false, label %bb16.i166, label %bb14.i163 - -bb16.i166: ; preds = %bb15.i165 - br i1 false, label %bb129, label %bb17.i167.preheader - -bb17.i167.preheader: ; preds = %bb16.i166 - br label %bb17.i167 - -bb17.i167: ; preds = %bb17.i167, %bb17.i167.preheader - br i1 false, label %bb18.i168, label %bb17.i167 - -bb18.i168: ; preds = %bb17.i167 - br i1 false, label %bb129, label %bb21.i172.preheader - -bb21.i172.preheader: ; preds = %bb18.i168 - br label %bb21.i172 - -bb20.i170: ; preds = %bb21.i172 - br label %bb21.i172 - -bb21.i172: ; preds = %bb20.i170, %bb21.i172.preheader - br i1 false, label %bb22.i173, label %bb20.i170 - -bb22.i173: ; preds = %bb21.i172 - br i1 false, label %bb24.i175, label %bb129 - -bb24.i175: ; preds = %bb22.i173 - br i1 false, label %bb26.i180, label %bb25.i176 - -bb25.i176: ; preds = %bb24.i175 - br label %bb26.i180 - -bb26.i180: ; preds = %bb25.i176, %bb24.i175 - br i1 false, label %bb.i.i181, label %bb3.i.i184.preheader - -bb.i.i181: ; preds = %bb26.i180 - br label %bb3.i.i184.preheader - -bb3.i.i184.preheader: ; preds = %bb.i.i181, %bb26.i180 - br label %bb3.i.i184 - -bb2.i.i183: ; preds = %bb3.i.i184 - br label %bb3.i.i184 - -bb3.i.i184: ; preds = %bb2.i.i183, %bb3.i.i184.preheader - br i1 false, label %bb2.i.i183, label %bb4.i.i185 - -bb4.i.i185: ; preds = %bb3.i.i184 - br i1 false, label %bb.i.i.i186, label %picosat_adjust.exit.i - -bb.i.i.i186: ; preds = %bb4.i.i185 - br label %picosat_adjust.exit.i - -picosat_adjust.exit.i: ; preds = %bb.i.i.i186, %bb4.i.i185 - br i1 false, label %bb28.i188, label %bb27.i187 - -bb27.i187: ; preds = %picosat_adjust.exit.i - br label %bb28.i188 - -bb28.i188: ; preds = %bb27.i187, %picosat_adjust.exit.i - br label %READ_LITERAL.i.outer - -READ_LITERAL.i.outer: ; preds = %READ_LITERAL.i.outer.backedge, %bb28.i188 - br label %READ_LITERAL.i - -READ_LITERAL.i.loopexit: ; preds = %bb29.i189, %bb29.i189 - br label %READ_LITERAL.i.backedge - -READ_LITERAL.i: ; preds = %READ_LITERAL.i.backedge, %READ_LITERAL.i.outer - switch i32 0, label %bb39.i199 [ - i32 99, label %bb29.i189.preheader - i32 -1, label %bb33.i193 - ] - -bb29.i189.preheader: ; preds = %READ_LITERAL.i - br label %bb29.i189 - -bb29.i189: ; preds = %bb29.i189, %bb29.i189.preheader - switch i32 0, label %bb29.i189 [ - i32 -1, label %READ_LITERAL.i.loopexit - i32 10, label %READ_LITERAL.i.loopexit - ] - -bb33.i193: ; preds = %READ_LITERAL.i - br i1 false, label %bb35.i195, label %parse.exit - -bb35.i195: ; preds = %bb33.i193 - br i1 false, label %bb38.i198, label %parse.exit - -bb38.i198: ; preds = %bb35.i195 - br label %parse.exit - -bb39.i199: ; preds = %READ_LITERAL.i - br i1 false, label %bb40.i200, label %READ_LITERAL.i.backedge - -READ_LITERAL.i.backedge: ; preds = %bb39.i199, %READ_LITERAL.i.loopexit - br label %READ_LITERAL.i - -bb40.i200: ; preds = %bb39.i199 - br i1 false, label %bb41.i201, label %bb42.i202 - -bb41.i201: ; preds = %bb40.i200 - br label %bb42.i202 - -bb42.i202: ; preds = %bb41.i201, %bb40.i200 - br i1 false, label %parse.exit.loopexit, label %bb46.i.preheader - -bb46.i.preheader: ; preds = %bb42.i202 - br label %bb46.i - -bb45.i: ; preds = %bb46.i - br label %bb46.i - -bb46.i: ; preds = %bb45.i, %bb46.i.preheader - br i1 false, label %bb47.i, label %bb45.i - -bb47.i: ; preds = %bb46.i - br i1 false, label %parse.exit.loopexit, label %bb50.i - -bb50.i: ; preds = %bb47.i - br i1 false, label %bb55.i, label %bb51.i - -bb51.i: ; preds = %bb50.i - br i1 false, label %parse.exit.loopexit, label %bb54.i - -bb54.i: ; preds = %bb51.i - br label %bb56.i - -bb55.i: ; preds = %bb50.i - br label %bb56.i - -bb56.i: ; preds = %bb55.i, %bb54.i - br i1 false, label %bb3.i11.i, label %bb.i8.i - -bb.i8.i: ; preds = %bb56.i - br i1 false, label %bb1.i9.i, label %bb3.i11.i - -bb1.i9.i: ; preds = %bb.i8.i - br i1 false, label %bb3.i11.i, label %bb2.i10.i - -bb2.i10.i: ; preds = %bb1.i9.i - unreachable - -bb3.i11.i: ; preds = %bb1.i9.i, %bb.i8.i, %bb56.i - br i1 false, label %bb7.i.i208, label %bb6.i.i207 - -bb6.i.i207: ; preds = %bb3.i11.i - br label %READ_LITERAL.i.outer.backedge - -bb7.i.i208: ; preds = %bb3.i11.i - br i1 false, label %bb53.i.i.i.i.preheader, label %bb.i.i.i.i210.preheader - -bb.i.i.i.i210.preheader: ; preds = %bb7.i.i208 - br label %bb.i.i.i.i210 - -bb.i.i.i.i210: ; preds = %bb.i.i.i.i210.backedge, %bb.i.i.i.i210.preheader - br i1 false, label %bb17.i.i.i.i, label %bb18.i.i.i.i - -bb17.i.i.i.i: ; preds = %bb.i.i.i.i210 - br label %bb18.i.i.i.i - -bb18.i.i.i.i: ; preds = %bb17.i.i.i.i, %bb.i.i.i.i210 - br i1 false, label %bb19.i.i.i.i, label %bb20.i.i.i.i - -bb19.i.i.i.i: ; preds = %bb18.i.i.i.i - br label %bb20.i.i.i.i - -bb20.i.i.i.i: ; preds = %bb19.i.i.i.i, %bb18.i.i.i.i - br i1 false, label %bb21.i.i.i.i, label %bb22.i.i.i.i - -bb21.i.i.i.i: ; preds = %bb20.i.i.i.i - br label %bb22.i.i.i.i - -bb22.i.i.i.i: ; preds = %bb21.i.i.i.i, %bb20.i.i.i.i - br label %bb23.i.i.i.i.outer - -bb23.i.i.i.i.outer: ; preds = %bb28.i.i.i.i, %bb22.i.i.i.i - br label %bb23.i.i.i.i - -bb23.i.i.i.i: ; preds = %bb23.i.i.i.i, %bb23.i.i.i.i.outer - br i1 false, label %bb23.i.i.i.i, label %bb26.i.i.i.i.preheader - -bb26.i.i.i.i.preheader: ; preds = %bb23.i.i.i.i - br label %bb26.i.i.i.i - -bb26.i.i.i.i: ; preds = %bb26.i.i.i.i, %bb26.i.i.i.i.preheader - br i1 false, label %bb27.i.i.i.i, label %bb26.i.i.i.i - -bb27.i.i.i.i: ; preds = %bb26.i.i.i.i - br i1 false, label %bb28.i.i.i.i, label %bb29.i.i.i.i - -bb28.i.i.i.i: ; preds = %bb27.i.i.i.i - br label %bb23.i.i.i.i.outer - -bb29.i.i.i.i: ; preds = %bb27.i.i.i.i - br i1 false, label %bb33.i.i.i.i, label %bb44.i.i.i.i - -bb33.i.i.i.i: ; preds = %bb29.i.i.i.i - br i1 false, label %bb34.i.i.i.i, label %bb38.i.i.i.i - -bb34.i.i.i.i: ; preds = %bb33.i.i.i.i - br i1 false, label %bb37.i.i.i.i, label %bb35.i.i.i.i - -bb35.i.i.i.i: ; preds = %bb34.i.i.i.i - br label %bb37.i.i.i.i - -bb37.i.i.i.i: ; preds = %bb35.i.i.i.i, %bb34.i.i.i.i - br label %bb38.i.i.i.i - -bb38.i.i.i.i: ; preds = %bb37.i.i.i.i, %bb33.i.i.i.i - br i1 false, label %bb39.i.i.i.i, label %bb43.i.i.i.i - -bb39.i.i.i.i: ; preds = %bb38.i.i.i.i - br i1 false, label %bb42.i.i.i.i, label %bb40.i.i.i.i - -bb40.i.i.i.i: ; preds = %bb39.i.i.i.i - br label %bb42.i.i.i.i - -bb42.i.i.i.i: ; preds = %bb40.i.i.i.i, %bb39.i.i.i.i - br label %bb43.i.i.i.i - -bb43.i.i.i.i: ; preds = %bb42.i.i.i.i, %bb38.i.i.i.i - br label %bb.i.i.i.i210.backedge - -bb.i.i.i.i210.backedge: ; preds = %bb47.i.i.i.i, %bb44.i.i.i.i, %bb43.i.i.i.i - br label %bb.i.i.i.i210 - -bb44.i.i.i.i: ; preds = %bb29.i.i.i.i - br i1 false, label %bb.i.i.i.i210.backedge, label %bb46.i.i.i.i - -bb46.i.i.i.i: ; preds = %bb44.i.i.i.i - br i1 false, label %bb47.i.i.i.i, label %bb53.i.i.i.i.preheader.loopexit - -bb53.i.i.i.i.preheader.loopexit: ; preds = %bb46.i.i.i.i - br label %bb53.i.i.i.i.preheader - -bb53.i.i.i.i.preheader: ; preds = %bb53.i.i.i.i.preheader.loopexit, %bb7.i.i208 - br label %bb53.i.i.i.i - -bb47.i.i.i.i: ; preds = %bb46.i.i.i.i - br label %bb.i.i.i.i210.backedge - -bb50.i.i.i.i: ; preds = %bb53.i.i.i.i - br i1 false, label %bb51.i.i.i.i, label %bb52.i.i.i.i - -bb51.i.i.i.i: ; preds = %bb50.i.i.i.i - br label %bb52.i.i.i.i - -bb52.i.i.i.i: ; preds = %bb51.i.i.i.i, %bb50.i.i.i.i - br label %bb53.i.i.i.i - -bb53.i.i.i.i: ; preds = %bb52.i.i.i.i, %bb53.i.i.i.i.preheader - br i1 false, label %bb50.i.i.i.i, label %bb59.i.i.i.i.preheader - -bb59.i.i.i.i.preheader: ; preds = %bb53.i.i.i.i - br label %bb59.i.i.i.i - -bb55.i.i.i.i: ; preds = %bb59.i.i.i.i - br label %bb57.i.i.i.i - -bb56.i.i.i.i: ; preds = %bb57.i.i.i.i - br label %bb57.i.i.i.i - -bb57.i.i.i.i: ; preds = %bb56.i.i.i.i, %bb55.i.i.i.i - br i1 false, label %bb56.i.i.i.i, label %bb58.i.i.i.i - -bb58.i.i.i.i: ; preds = %bb57.i.i.i.i - br label %bb59.i.i.i.i - -bb59.i.i.i.i: ; preds = %bb58.i.i.i.i, %bb59.i.i.i.i.preheader - br i1 false, label %bb60.i.i.i.i, label %bb55.i.i.i.i - -bb60.i.i.i.i: ; preds = %bb59.i.i.i.i - br label %bb69.i.i.i.i - -bb61.i.i.i.i: ; preds = %bb69.i.i.i.i - br i1 false, label %bb68.i.i.i.i, label %bb62.i.i.i.i - -bb62.i.i.i.i: ; preds = %bb61.i.i.i.i - br i1 false, label %bb63.i.i.i.i, label %bb65.i.i.i.i - -bb63.i.i.i.i: ; preds = %bb62.i.i.i.i - br i1 false, label %bb.i.i12.i, label %bb65.i.i.i.i - -bb65.i.i.i.i: ; preds = %bb63.i.i.i.i, %bb62.i.i.i.i - br i1 false, label %bb.i.i12.i, label %bb67.i.i.i.i - -bb67.i.i.i.i: ; preds = %bb65.i.i.i.i - br label %bb68.i.i.i.i - -bb68.i.i.i.i: ; preds = %bb67.i.i.i.i, %bb61.i.i.i.i - br label %bb69.i.i.i.i - -bb69.i.i.i.i: ; preds = %bb68.i.i.i.i, %bb60.i.i.i.i - br i1 false, label %bb61.i.i.i.i, label %bb70.i.i.i.i - -bb70.i.i.i.i: ; preds = %bb69.i.i.i.i - br label %READ_LITERAL.i.outer.backedge - -bb.i.i12.i: ; preds = %bb65.i.i.i.i, %bb63.i.i.i.i - br i1 false, label %bb1.i.i.i213, label %bb5.i.i.i218 - -bb1.i.i.i213: ; preds = %bb.i.i12.i - br i1 false, label %bb4.i.i.i217, label %bb2.i.i.i214 - -bb2.i.i.i214: ; preds = %bb1.i.i.i213 - br label %bb4.i.i.i217 - -bb4.i.i.i217: ; preds = %bb2.i.i.i214, %bb1.i.i.i213 - br label %bb5.i.i.i218 - -bb5.i.i.i218: ; preds = %bb4.i.i.i217, %bb.i.i12.i - br label %READ_LITERAL.i.outer.backedge - -READ_LITERAL.i.outer.backedge: ; preds = %bb5.i.i.i218, %bb70.i.i.i.i, %bb6.i.i207 - br label %READ_LITERAL.i.outer - -parse.exit.loopexit: ; preds = %bb51.i, %bb47.i, %bb42.i202 - br label %parse.exit - -parse.exit: ; preds = %parse.exit.loopexit, %bb38.i198, %bb35.i195, %bb33.i193 - br i1 false, label %bb130, label %bb129 - -bb129: ; preds = %parse.exit, %bb22.i173, %bb18.i168, %bb16.i166, %bb12.i161, %bb10.i159, %bb9.i158, %bb8.i157, %bb7.i156, %bb5.i154, %bb4.i153 - br label %bb170 - -bb130: ; preds = %parse.exit - br i1 false, label %bb143, label %bb142.preheader - -bb142.preheader: ; preds = %bb130 - br label %bb142 - -bb132: ; preds = %bb142 - br i1 false, label %bb137, label %bb133 - -bb133: ; preds = %bb132 - br i1 false, label %bb137, label %bb134 - -bb134: ; preds = %bb133 - br i1 false, label %bb137, label %bb135 - -bb135: ; preds = %bb134 - br i1 false, label %bb137, label %bb136 - -bb136: ; preds = %bb135 - br i1 false, label %bb137, label %bb138 - -bb137: ; preds = %bb136, %bb135, %bb134, %bb133, %bb132 - br label %bb141 - -bb138: ; preds = %bb136 - br i1 false, label %bb139, label %bb141 - -bb139: ; preds = %bb138 - br i1 false, label %bb2.i126, label %picosat_assume.exit - -bb2.i126: ; preds = %bb139 - br i1 false, label %bb5.i130, label %bb3.i127 - -bb3.i127: ; preds = %bb2.i126 - br label %bb5.i130 - -bb5.i130: ; preds = %bb3.i127, %bb2.i126 - br label %picosat_assume.exit - -picosat_assume.exit: ; preds = %bb5.i130, %bb139 - br i1 false, label %bb141, label %bb140 - -bb140: ; preds = %picosat_assume.exit - br label %bb141 - -bb141: ; preds = %bb140, %picosat_assume.exit, %bb138, %bb137 - br label %bb142 - -bb142: ; preds = %bb141, %bb142.preheader - br i1 false, label %bb132, label %bb143.loopexit - -bb143.loopexit: ; preds = %bb142 - br label %bb143 - -bb143: ; preds = %bb143.loopexit, %bb130 - br i1 false, label %bb145, label %bb144 - -bb144: ; preds = %bb143 - br label %bb11.i - -bb5.i114: ; preds = %bb11.i - br label %bb11.i - -bb11.i: ; preds = %bb5.i114, %bb144 - br i1 false, label %bb12.i, label %bb5.i114 - -bb12.i: ; preds = %bb11.i - br i1 false, label %bb.i.i.i118, label %bb1.i.i.i119 - -bb.i.i.i118: ; preds = %bb12.i - br label %int2lit.exit.i - -bb1.i.i.i119: ; preds = %bb12.i - br label %int2lit.exit.i - -int2lit.exit.i: ; preds = %bb1.i.i.i119, %bb.i.i.i118 - br label %bb19.i - -bb13.i: ; preds = %bb19.i - br label %bb17.i - -bb14.i: ; preds = %bb17.i - br label %bb17.i - -bb17.i: ; preds = %bb14.i, %bb13.i - br i1 false, label %bb14.i, label %bb18.i - -bb18.i: ; preds = %bb17.i - br label %bb19.i - -bb19.i: ; preds = %bb18.i, %int2lit.exit.i - br i1 false, label %bb20.i, label %bb13.i - -bb20.i: ; preds = %bb19.i - br label %bb33.i - -bb24.i: ; preds = %bb33.i - br i1 false, label %bb29.i, label %bb25.i - -bb25.i: ; preds = %bb24.i - br label %bb27.i - -bb26.i: ; preds = %bb27.i - br label %bb27.i - -bb27.i: ; preds = %bb26.i, %bb25.i - br i1 false, label %bb26.i, label %bb28.i - -bb28.i: ; preds = %bb27.i - br label %bb29.i - -bb29.i: ; preds = %bb28.i, %bb24.i - br label %bb33.i - -bb33.i: ; preds = %bb29.i, %bb20.i - br i1 false, label %bb34.i, label %bb24.i - -bb34.i: ; preds = %bb33.i - br i1 false, label %bb.i.i58.i, label %bb1.i.i59.i - -bb.i.i58.i: ; preds = %bb34.i - br label %int2lit.exit63.i - -bb1.i.i59.i: ; preds = %bb34.i - br label %int2lit.exit63.i - -int2lit.exit63.i: ; preds = %bb1.i.i59.i, %bb.i.i58.i - br label %bb41.i - -bb35.i: ; preds = %bb41.i - br label %bb39.i - -bb36.i: ; preds = %bb39.i - br i1 false, label %bb38.i, label %bb37.i - -bb37.i: ; preds = %bb36.i - br label %bb38.i - -bb38.i: ; preds = %bb37.i, %bb36.i - br label %bb39.i - -bb39.i: ; preds = %bb38.i, %bb35.i - br i1 false, label %bb36.i, label %bb40.i - -bb40.i: ; preds = %bb39.i - br label %bb41.i - -bb41.i: ; preds = %bb40.i, %int2lit.exit63.i - br i1 false, label %bb42.i, label %bb35.i - -bb42.i: ; preds = %bb41.i - br label %bb44.i - -bb43.i: ; preds = %bb44.i - br label %bb44.i - -bb44.i: ; preds = %bb43.i, %bb42.i - br i1 false, label %bb43.i, label %picosat_print.exit - -picosat_print.exit: ; preds = %bb44.i - br label %bb167 - -bb145: ; preds = %bb143 - br i1 false, label %bb147, label %bb146 - -bb146: ; preds = %bb145 - br label %bb147 - -bb147: ; preds = %bb146, %bb145 - br i1 false, label %bb149, label %bb148 - -bb148: ; preds = %bb147 - br label %bb149 - -bb149: ; preds = %bb148, %bb147 - br i1 false, label %bb.i54, label %bb1.i55 - -bb.i54: ; preds = %bb149 - unreachable - -bb1.i55: ; preds = %bb149 - br i1 false, label %bb.i.i56, label %bb1.i.i57 - -bb.i.i56: ; preds = %bb1.i55 - br label %bb1.i.i57 - -bb1.i.i57: ; preds = %bb.i.i56, %bb1.i55 - br i1 false, label %bb3.i.i59, label %bb2.i.i58 - -bb2.i.i58: ; preds = %bb1.i.i57 - br label %bb3.i.i59 - -bb3.i.i59: ; preds = %bb2.i.i58, %bb1.i.i57 - br i1 false, label %bb5.i.i61, label %sat.exit.i - -bb5.i.i61: ; preds = %bb3.i.i59 - br i1 false, label %bb6.i.i65, label %bb1.i.i.i63 - -bb1.i.i.i63: ; preds = %bb5.i.i61 - br i1 false, label %sat.exit.i, label %bb6.i.i65 - -bb6.i.i65: ; preds = %bb1.i.i.i63, %bb5.i.i61 - br i1 false, label %bb8.i.i67, label %bb7.i.i66 - -bb7.i.i66: ; preds = %bb6.i.i65 - br label %bb8.i.i67 - -bb8.i.i67: ; preds = %bb7.i.i66, %bb6.i.i65 - br i1 false, label %bb10.i.i69, label %sat.exit.i - -bb10.i.i69: ; preds = %bb8.i.i67 - br i1 false, label %bb11.i.i70, label %bb1.i61.i.i - -bb1.i61.i.i: ; preds = %bb10.i.i69 - br i1 false, label %sat.exit.i, label %bb11.i.i70 - -bb11.i.i70: ; preds = %bb1.i61.i.i, %bb10.i.i69 - br label %bb13.i.i71.outer - -bb13.i.i71.outer: ; preds = %bb42.i.i, %bb11.i.i70 - br label %bb13.i.i71 - -bb13.i.i71: ; preds = %bb13.i.i71.backedge, %bb13.i.i71.outer - br i1 false, label %bb14.i.i72, label %bb15.i.i73 - -bb14.i.i72: ; preds = %bb13.i.i71 - br label %bb15.i.i73 - -bb15.i.i73: ; preds = %bb14.i.i72, %bb13.i.i71 - br i1 false, label %bb19.i.i, label %bb16.i.i - -bb16.i.i: ; preds = %bb15.i.i73 - br i1 false, label %bb.i.i79.i.i, label %incincs.exit.i.i - -bb.i.i79.i.i: ; preds = %bb16.i.i - br label %bb4.i.i.i85.i.i - -bb.i.i.i80.i.i: ; preds = %bb4.i.i.i85.i.i - br i1 false, label %bb3.i.i.i83.i.i, label %bb1.i.i.i81.i.i - -bb1.i.i.i81.i.i: ; preds = %bb.i.i.i80.i.i - br i1 false, label %bb2.i.i.i82.i.i, label %bb3.i.i.i83.i.i - -bb2.i.i.i82.i.i: ; preds = %bb1.i.i.i81.i.i - br label %bb3.i.i.i83.i.i - -bb3.i.i.i83.i.i: ; preds = %bb2.i.i.i82.i.i, %bb1.i.i.i81.i.i, %bb.i.i.i80.i.i - br label %bb4.i.i.i85.i.i - -bb4.i.i.i85.i.i: ; preds = %bb3.i.i.i83.i.i, %bb.i.i79.i.i - br i1 false, label %crescore.exit.i.i.i.i, label %bb.i.i.i80.i.i - -crescore.exit.i.i.i.i: ; preds = %bb4.i.i.i85.i.i - br label %incincs.exit.i.i - -incincs.exit.i.i: ; preds = %crescore.exit.i.i.i.i, %bb16.i.i - br i1 false, label %bb13.i.i71.backedge, label %sat.exit.i.loopexit.loopexit - -bb13.i.i71.backedge: ; preds = %bb1.i55.i.i, %bb28.i.i, %incincs.exit.i.i - br label %bb13.i.i71 - -bb19.i.i: ; preds = %bb15.i.i73 - br i1 false, label %bb20.i.i, label %bb1.i68.i.i - -bb1.i68.i.i: ; preds = %bb19.i.i - br i1 false, label %sat.exit.i.loopexit.loopexit, label %bb20.i.i - -bb20.i.i: ; preds = %bb1.i68.i.i, %bb19.i.i - br i1 false, label %bb24.i.i, label %bb21.i.i - -bb21.i.i: ; preds = %bb20.i.i - br i1 false, label %bb22.i.i, label %bb24.i.i - -bb22.i.i: ; preds = %bb21.i.i - br i1 false, label %bb23.i.i, label %bb24.i.i - -bb23.i.i: ; preds = %bb22.i.i - br label %bb24.i.i - -bb24.i.i: ; preds = %bb23.i.i, %bb22.i.i, %bb21.i.i, %bb20.i.i - br i1 false, label %bb26.i.i, label %sat.exit.i.loopexit.loopexit - -bb26.i.i: ; preds = %bb24.i.i - br i1 false, label %bb27.i.i, label %bb33.i.i.loopexit - -bb27.i.i: ; preds = %bb26.i.i - br i1 false, label %bb33.i.i.loopexit, label %bb28.i.i - -bb28.i.i: ; preds = %bb27.i.i - br i1 false, label %bb1.i55.i.i, label %bb13.i.i71.backedge - -bb1.i55.i.i: ; preds = %bb28.i.i - br i1 false, label %bb29.i.i, label %bb13.i.i71.backedge - -bb29.i.i: ; preds = %bb1.i55.i.i - br i1 false, label %bb31.i.i, label %sat.exit.i.loopexit.loopexit2 - -bb31.i.i: ; preds = %bb29.i.i - br i1 false, label %bb33.i.i, label %bb1.i48.i.i - -bb1.i48.i.i: ; preds = %bb31.i.i - br i1 false, label %sat.exit.i.loopexit.loopexit2, label %bb33.i.i - -bb33.i.i.loopexit: ; preds = %bb27.i.i, %bb26.i.i - br label %bb33.i.i - -bb33.i.i: ; preds = %bb33.i.i.loopexit, %bb1.i48.i.i, %bb31.i.i - br i1 false, label %bb34.i.i, label %bb35.i.i - -bb34.i.i: ; preds = %bb33.i.i - br i1 false, label %bb35.i.i, label %bb2.i44.i.i76 - -bb2.i44.i.i76: ; preds = %bb34.i.i - br label %bb35.i.i - -bb35.i.i: ; preds = %bb2.i44.i.i76, %bb34.i.i, %bb33.i.i - br i1 false, label %bb1.i37.i.i, label %bb.i35.i.i - -bb.i35.i.i: ; preds = %bb35.i.i - br label %bb36.i.i - -bb1.i37.i.i: ; preds = %bb35.i.i - br i1 false, label %bb37.i.i, label %bb36.i.i - -bb36.i.i: ; preds = %bb1.i37.i.i, %bb.i35.i.i - br label %bb25.i23.i.i - -bb.i18.i.i: ; preds = %bb25.i23.i.i - br i1 false, label %bb24.i22.i.i, label %bb22.i19.i.i - -bb22.i19.i.i: ; preds = %bb.i18.i.i - br label %bb24.i22.i.i - -bb24.i22.i.i: ; preds = %bb22.i19.i.i, %bb.i18.i.i - br label %bb25.i23.i.i - -bb25.i23.i.i: ; preds = %bb24.i22.i.i, %bb36.i.i - br i1 false, label %bb.i18.i.i, label %bb26.i24.i.i - -bb26.i24.i.i: ; preds = %bb25.i23.i.i - br i1 false, label %bb27.i25.i.i, label %bb32.i.i.i - -bb27.i25.i.i: ; preds = %bb26.i24.i.i - br label %bb32.i.i.i - -bb32.i.i.i: ; preds = %bb27.i25.i.i, %bb26.i24.i.i - br label %bb64.i.i.i - -bb33.i.i.i: ; preds = %bb64.i.i.i - br i1 false, label %bb60.i.i.i, label %bb34.i.i.i - -bb34.i.i.i: ; preds = %bb33.i.i.i - br i1 false, label %bb38.i.i.i, label %bb60.i.i.i - -bb38.i.i.i: ; preds = %bb34.i.i.i - br i1 false, label %bb39.i.i.i, label %bb48.i.i.i - -bb39.i.i.i: ; preds = %bb38.i.i.i - br i1 false, label %bb48.i.i.i, label %bb40.i.i.i - -bb40.i.i.i: ; preds = %bb39.i.i.i - br i1 false, label %bb60.i.i.i, label %bb45.i.i.i - -bb45.i.i.i: ; preds = %bb40.i.i.i - br label %bb60.i.i.i - -bb48.i.i.i: ; preds = %bb39.i.i.i, %bb38.i.i.i - br i1 false, label %bb53.i.i.i, label %bb60.i.i.i - -bb53.i.i.i: ; preds = %bb48.i.i.i - br i1 false, label %bb60.i.i.i, label %bb58.i.i.i - -bb58.i.i.i: ; preds = %bb53.i.i.i - br i1 false, label %bb59.i.i.i, label %bb60.i.i.i - -bb59.i.i.i: ; preds = %bb58.i.i.i - br label %bb60.i.i.i - -bb60.i.i.i: ; preds = %bb59.i.i.i, %bb58.i.i.i, %bb53.i.i.i, %bb48.i.i.i, %bb45.i.i.i, %bb40.i.i.i, %bb34.i.i.i, %bb33.i.i.i - %lcollect.i.i.i.1 = phi i32 [ %lcollect.i.i.i.2, %bb34.i.i.i ], [ %lcollect.i.i.i.2, %bb48.i.i.i ], [ %lcollect.i.i.i.2, %bb58.i.i.i ], [ %lcollect.i.i.i.2, %bb59.i.i.i ], [ %lcollect.i.i.i.2, %bb53.i.i.i ], [ %lcollect.i.i.i.2, %bb33.i.i.i ], [ %lcollect.i.i.i.2, %bb40.i.i.i ], [ 0, %bb45.i.i.i ] ; <i32> [#uses=1] - br label %bb64.i.i.i - -bb64.i.i.i: ; preds = %bb60.i.i.i, %bb32.i.i.i - %lcollect.i.i.i.2 = phi i32 [ 0, %bb32.i.i.i ], [ %lcollect.i.i.i.1, %bb60.i.i.i ] ; <i32> [#uses=8] - br i1 false, label %bb65.i.i.i, label %bb33.i.i.i - -bb65.i.i.i: ; preds = %bb64.i.i.i - br i1 false, label %bb103.i.i.i.preheader, label %bb66.i.i.i.preheader - -bb66.i.i.i.preheader: ; preds = %bb65.i.i.i - br label %bb66.i.i.i - -bb66.i.i.i: ; preds = %bb66.i.i.i.backedge, %bb66.i.i.i.preheader - br i1 false, label %bb67.i.i.i, label %bb68.i.i.i - -bb67.i.i.i: ; preds = %bb66.i.i.i - br label %bb68.i.i.i - -bb68.i.i.i: ; preds = %bb67.i.i.i, %bb66.i.i.i - br i1 false, label %bb69.i.i.i, label %bb70.i.i.i - -bb69.i.i.i: ; preds = %bb68.i.i.i - br label %bb70.i.i.i - -bb70.i.i.i: ; preds = %bb69.i.i.i, %bb68.i.i.i - br i1 false, label %bb71.i.i.i, label %bb72.i.i.i - -bb71.i.i.i: ; preds = %bb70.i.i.i - br label %bb72.i.i.i - -bb72.i.i.i: ; preds = %bb71.i.i.i, %bb70.i.i.i - br label %bb73.i.i.i.outer - -bb73.i.i.i.outer: ; preds = %bb78.i.i.i, %bb72.i.i.i - br label %bb73.i.i.i - -bb73.i.i.i: ; preds = %bb73.i.i.i, %bb73.i.i.i.outer - br i1 false, label %bb73.i.i.i, label %bb76.i.i.i.preheader - -bb76.i.i.i.preheader: ; preds = %bb73.i.i.i - br label %bb76.i.i.i - -bb76.i.i.i: ; preds = %bb76.i.i.i, %bb76.i.i.i.preheader - br i1 false, label %bb77.i.i.i, label %bb76.i.i.i - -bb77.i.i.i: ; preds = %bb76.i.i.i - br i1 false, label %bb78.i.i.i, label %bb79.i.i.i - -bb78.i.i.i: ; preds = %bb77.i.i.i - br label %bb73.i.i.i.outer - -bb79.i.i.i: ; preds = %bb77.i.i.i - br i1 false, label %bb83.i.i.i, label %bb94.i.i.i - -bb83.i.i.i: ; preds = %bb79.i.i.i - br i1 false, label %bb84.i.i.i, label %bb88.i.i.i - -bb84.i.i.i: ; preds = %bb83.i.i.i - br i1 false, label %bb87.i.i.i, label %bb85.i.i.i - -bb85.i.i.i: ; preds = %bb84.i.i.i - br label %bb87.i.i.i - -bb87.i.i.i: ; preds = %bb85.i.i.i, %bb84.i.i.i - br label %bb88.i.i.i - -bb88.i.i.i: ; preds = %bb87.i.i.i, %bb83.i.i.i - br i1 false, label %bb89.i.i.i, label %bb93.i.i.i - -bb89.i.i.i: ; preds = %bb88.i.i.i - br i1 false, label %bb92.i.i.i, label %bb90.i.i.i - -bb90.i.i.i: ; preds = %bb89.i.i.i - br label %bb92.i.i.i - -bb92.i.i.i: ; preds = %bb90.i.i.i, %bb89.i.i.i - br label %bb93.i.i.i - -bb93.i.i.i: ; preds = %bb92.i.i.i, %bb88.i.i.i - br label %bb66.i.i.i.backedge - -bb66.i.i.i.backedge: ; preds = %bb97.i.i.i, %bb94.i.i.i, %bb93.i.i.i - br label %bb66.i.i.i - -bb94.i.i.i: ; preds = %bb79.i.i.i - br i1 false, label %bb66.i.i.i.backedge, label %bb96.i.i.i - -bb96.i.i.i: ; preds = %bb94.i.i.i - br i1 false, label %bb97.i.i.i, label %bb103.i.i.i.preheader.loopexit - -bb103.i.i.i.preheader.loopexit: ; preds = %bb96.i.i.i - br label %bb103.i.i.i.preheader - -bb103.i.i.i.preheader: ; preds = %bb103.i.i.i.preheader.loopexit, %bb65.i.i.i - br label %bb103.i.i.i - -bb97.i.i.i: ; preds = %bb96.i.i.i - br label %bb66.i.i.i.backedge - -bb100.i.i.i: ; preds = %bb103.i.i.i - br i1 false, label %bb101.i.i.i, label %bb102.i.i.i - -bb101.i.i.i: ; preds = %bb100.i.i.i - br label %bb102.i.i.i - -bb102.i.i.i: ; preds = %bb101.i.i.i, %bb100.i.i.i - br label %bb103.i.i.i - -bb103.i.i.i: ; preds = %bb102.i.i.i, %bb103.i.i.i.preheader - br i1 false, label %bb100.i.i.i, label %bb109.i.i.i.preheader - -bb109.i.i.i.preheader: ; preds = %bb103.i.i.i - br label %bb109.i.i.i - -bb105.i.i.i: ; preds = %bb109.i.i.i - br label %bb107.i.i.i - -bb106.i.i.i: ; preds = %bb107.i.i.i - br label %bb107.i.i.i - -bb107.i.i.i: ; preds = %bb106.i.i.i, %bb105.i.i.i - br i1 false, label %bb106.i.i.i, label %bb108.i.i.i - -bb108.i.i.i: ; preds = %bb107.i.i.i - br label %bb109.i.i.i - -bb109.i.i.i: ; preds = %bb108.i.i.i, %bb109.i.i.i.preheader - br i1 false, label %bb110.i.i.i, label %bb105.i.i.i - -bb110.i.i.i: ; preds = %bb109.i.i.i - %0 = sub i32 0, %lcollect.i.i.i.2 ; <i32> [#uses=1] - %1 = add i32 %0, 1 ; <i32> [#uses=1] - br label %bb113.i.i.i - -bb111.i.i.i: ; preds = %bb113.i.i.i - br i1 false, label %bb114.i.i.i, label %bb113.i.i.i - -bb113.i.i.i: ; preds = %bb111.i.i.i, %bb110.i.i.i - br i1 false, label %bb111.i.i.i, label %bb114.i.i.i - -bb114.i.i.i: ; preds = %bb113.i.i.i, %bb111.i.i.i - %2 = lshr i32 %1, 1 ; <i32> [#uses=2] - br i1 false, label %bb116.i.i.i, label %bb124.i.i.i - -bb116.i.i.i: ; preds = %bb114.i.i.i - br i1 false, label %bb117.i.i.i.preheader, label %bb122.i.i.i.preheader - -bb122.i.i.i.preheader: ; preds = %bb116.i.i.i - br label %bb122.i.i.i - -bb117.i.i.i.preheader: ; preds = %bb116.i.i.i - br label %bb117.i.i.i - -bb117.i.i.i: ; preds = %bb118.i.i.i, %bb117.i.i.i.preheader - %target.i.i.i.1 = phi i32 [ %3, %bb118.i.i.i ], [ %2, %bb117.i.i.i.preheader ] ; <i32> [#uses=1] - %3 = add i32 %target.i.i.i.1, 1 ; <i32> [#uses=2] - br i1 false, label %bb118.i.i.i, label %bb124.i.i.i.loopexit - -bb118.i.i.i: ; preds = %bb117.i.i.i - br i1 false, label %bb117.i.i.i, label %bb124.i.i.i.loopexit - -bb122.i.i.i: ; preds = %bb123.i.i.i, %bb122.i.i.i.preheader - %target.i.i.i.2 = phi i32 [ %4, %bb123.i.i.i ], [ %2, %bb122.i.i.i.preheader ] ; <i32> [#uses=2] - br i1 false, label %bb124.i.i.i.loopexit1, label %bb123.i.i.i - -bb123.i.i.i: ; preds = %bb122.i.i.i - %4 = add i32 %target.i.i.i.2, -1 ; <i32> [#uses=1] - br i1 false, label %bb122.i.i.i, label %bb124.i.i.i.loopexit1 - -bb124.i.i.i.loopexit: ; preds = %bb118.i.i.i, %bb117.i.i.i - br label %bb124.i.i.i - -bb124.i.i.i.loopexit1: ; preds = %bb123.i.i.i, %bb122.i.i.i - br label %bb124.i.i.i - -bb124.i.i.i: ; preds = %bb124.i.i.i.loopexit1, %bb124.i.i.i.loopexit, %bb114.i.i.i - %target.i.i.i.0 = phi i32 [ 0, %bb114.i.i.i ], [ %3, %bb124.i.i.i.loopexit ], [ %target.i.i.i.2, %bb124.i.i.i.loopexit1 ] ; <i32> [#uses=0] - br label %bb132.i.i.i.outer - -bb125.i.i.i: ; preds = %bb132.i.i.i - br i1 false, label %bb132.i.i.i, label %bb130.i.i.i - -bb130.i.i.i: ; preds = %bb125.i.i.i - br label %bb132.i.i.i.outer - -bb132.i.i.i.outer: ; preds = %bb130.i.i.i, %bb124.i.i.i - br label %bb132.i.i.i - -bb132.i.i.i: ; preds = %bb132.i.i.i.outer, %bb125.i.i.i - br i1 false, label %bb125.i.i.i, label %bb133.i.i.i - -bb133.i.i.i: ; preds = %bb132.i.i.i - br i1 false, label %bb136.i.i.i, label %bb134.i.i.i - -bb134.i.i.i: ; preds = %bb133.i.i.i - br i1 false, label %bb136.i.i.i, label %bb135.i.i.i - -bb135.i.i.i: ; preds = %bb134.i.i.i - br label %bb136.i.i.i - -bb136.i.i.i: ; preds = %bb135.i.i.i, %bb134.i.i.i, %bb133.i.i.i - br i1 false, label %bb137.i.i.i, label %bb37.i.i - -bb137.i.i.i: ; preds = %bb136.i.i.i - br label %bb37.i.i - -bb37.i.i: ; preds = %bb137.i.i.i, %bb136.i.i.i, %bb1.i37.i.i - br i1 false, label %bb40.i.i, label %bb38.i.i - -bb38.i.i: ; preds = %bb37.i.i - br i1 false, label %bb39.i.i, label %bb40.i.i - -bb39.i.i: ; preds = %bb38.i.i - br i1 false, label %bb17.i.i.i, label %bb3.i12.i.i - -bb3.i12.i.i: ; preds = %bb39.i.i - br label %bb5.i14.i.i - -bb5.i14.i.i: ; preds = %bb8.i.i.i79, %bb3.i12.i.i - br i1 false, label %bb6.i15.i.i, label %bb9.i.i.i80 - -bb6.i15.i.i: ; preds = %bb5.i14.i.i - br i1 false, label %bb7.i.i.i78, label %bb9.i.i.i80 - -bb7.i.i.i78: ; preds = %bb6.i15.i.i - br i1 false, label %bb9.i.i.i80, label %bb8.i.i.i79 - -bb8.i.i.i79: ; preds = %bb7.i.i.i78 - br i1 false, label %bb9.i.i.i80, label %bb5.i14.i.i - -bb9.i.i.i80: ; preds = %bb8.i.i.i79, %bb7.i.i.i78, %bb6.i15.i.i, %bb5.i14.i.i - br i1 false, label %bb16.i.i.i, label %bb10.i.i.i81 - -bb10.i.i.i81: ; preds = %bb9.i.i.i80 - br i1 false, label %bb11.i.i.i, label %bb15.i.i.i - -bb11.i.i.i: ; preds = %bb10.i.i.i81 - br i1 false, label %bb16.i.i.i, label %bb15.i.i.i - -bb15.i.i.i: ; preds = %bb11.i.i.i, %bb10.i.i.i81 - br label %bb16.i.i.i - -bb16.i.i.i: ; preds = %bb15.i.i.i, %bb11.i.i.i, %bb9.i.i.i80 - br label %bb17.i.i.i - -bb17.i.i.i: ; preds = %bb16.i.i.i, %bb39.i.i - br i1 false, label %bb18.i.i.i, label %bb25.i.i.i - -bb18.i.i.i: ; preds = %bb17.i.i.i - br i1 false, label %bb24.i.i.i, label %bb23.i.i.i - -bb23.i.i.i: ; preds = %bb18.i.i.i - br label %bb24.i.i.i - -bb24.i.i.i: ; preds = %bb23.i.i.i, %bb18.i.i.i - br label %bb29.i.i.i - -bb25.i.i.i: ; preds = %bb17.i.i.i - br i1 false, label %bb29.i.i.i, label %bb27.i.i.i - -bb27.i.i.i: ; preds = %bb25.i.i.i - br i1 false, label %bb29.i.i.i, label %bb28.i.i.i - -bb28.i.i.i: ; preds = %bb27.i.i.i - br i1 false, label %bb29.i.i.i, label %bb.i4.i.i.i - -bb.i4.i.i.i: ; preds = %bb28.i.i.i - br i1 false, label %bb4.i.i16.i.i, label %bb29.i.i.i - -bb4.i.i16.i.i: ; preds = %bb.i4.i.i.i - br label %bb29.i.i.i - -bb29.i.i.i: ; preds = %bb4.i.i16.i.i, %bb.i4.i.i.i, %bb28.i.i.i, %bb27.i.i.i, %bb25.i.i.i, %bb24.i.i.i - br label %bb40.i.i - -bb40.i.i: ; preds = %bb29.i.i.i, %bb38.i.i, %bb37.i.i - br i1 false, label %bb9.i.i.i.i.preheader, label %bb2.i.i.i87 - -bb9.i.i.i.i.preheader: ; preds = %bb40.i.i - br label %bb9.i.i.i.i - -bb.i.i.i.i84: ; preds = %bb9.i.i.i.i - switch i8 0, label %bb8.i.i.i.i [ - i8 -1, label %bb1.i.i.i.i85 - i8 1, label %bb9.i.i.i.i - ] - -bb1.i.i.i.i85: ; preds = %bb.i.i.i.i84 - br i1 false, label %bb5.i.i.i.i, label %bb2.i.i.i87 - -bb5.i.i.i.i: ; preds = %bb1.i.i.i.i85 - br label %bb2.i.i.i87 - -bb8.i.i.i.i: ; preds = %bb.i.i.i.i84 - br i1 false, label %bb2.i.i.i87, label %bb6.i.i.i95 - -bb9.i.i.i.i: ; preds = %bb.i.i.i.i84, %bb9.i.i.i.i.preheader - br i1 false, label %bb.i.i.i.i84, label %bb10.i.i.i.i - -bb10.i.i.i.i: ; preds = %bb9.i.i.i.i - br label %bb2.i.i.i87 - -bb2.i.i.i87: ; preds = %bb10.i.i.i.i, %bb8.i.i.i.i, %bb5.i.i.i.i, %bb1.i.i.i.i85, %bb40.i.i - br i1 false, label %bb3.i.i.i88, label %decide.exit.i.i - -bb3.i.i.i88: ; preds = %bb2.i.i.i87 - br i1 false, label %bb4.i.i.i90, label %bb1.i23.i.i.i - -bb1.i23.i.i.i: ; preds = %bb3.i.i.i88 - br i1 false, label %decide.exit.i.i, label %bb4.i.i.i90 - -bb4.i.i.i90: ; preds = %bb1.i23.i.i.i, %bb3.i.i.i88 - br i1 false, label %bb1.i9.i.i.i, label %bb5.i.i.i94 - -bb1.i9.i.i.i: ; preds = %bb4.i.i.i90 - br i1 false, label %bb.i.i27.i.i.i.i, label %bb1.i.i28.i.i.i.i - -bb.i.i27.i.i.i.i: ; preds = %bb1.i9.i.i.i - br label %int2lit.exit32.i.i.i.i - -bb1.i.i28.i.i.i.i: ; preds = %bb1.i9.i.i.i - br label %int2lit.exit32.i.i.i.i - -int2lit.exit32.i.i.i.i: ; preds = %bb1.i.i28.i.i.i.i, %bb.i.i27.i.i.i.i - br i1 false, label %bb8.i19.i.i.i, label %bb2.i.i.i.i91 - -bb2.i.i.i.i91: ; preds = %int2lit.exit32.i.i.i.i - br label %bb4.i.i.i.i - -bb3.i.i.i.i92: ; preds = %gcd.exit.i.i.i.i - br label %bb4.i.i.i.i - -bb4.i.i.i.i: ; preds = %bb3.i.i.i.i92, %bb2.i.i.i.i91 - br label %bb3.i.i13.i.i.i - -bb2.i.i12.i.i.i: ; preds = %bb3.i.i13.i.i.i - br label %bb3.i.i13.i.i.i - -bb3.i.i13.i.i.i: ; preds = %bb2.i.i12.i.i.i, %bb4.i.i.i.i - br i1 false, label %gcd.exit.i.i.i.i, label %bb2.i.i12.i.i.i - -gcd.exit.i.i.i.i: ; preds = %bb3.i.i13.i.i.i - br i1 false, label %bb5.i14.i.i.i.preheader, label %bb3.i.i.i.i92 - -bb5.i14.i.i.i.preheader: ; preds = %gcd.exit.i.i.i.i - br label %bb5.i14.i.i.i - -bb5.i14.i.i.i: ; preds = %int2lit.exit.i.i.i.i, %bb5.i14.i.i.i.preheader - br i1 false, label %bb.i.i.i17.i.i.i, label %bb1.i.i.i18.i.i.i - -bb.i.i.i17.i.i.i: ; preds = %bb5.i14.i.i.i - br label %int2lit.exit.i.i.i.i - -bb1.i.i.i18.i.i.i: ; preds = %bb5.i14.i.i.i - br label %int2lit.exit.i.i.i.i - -int2lit.exit.i.i.i.i: ; preds = %bb1.i.i.i18.i.i.i, %bb.i.i.i17.i.i.i - br i1 false, label %bb8.i19.i.i.i.loopexit, label %bb5.i14.i.i.i - -bb8.i19.i.i.i.loopexit: ; preds = %int2lit.exit.i.i.i.i - br label %bb8.i19.i.i.i - -bb8.i19.i.i.i: ; preds = %bb8.i19.i.i.i.loopexit, %int2lit.exit32.i.i.i.i - br i1 false, label %bb5.i.i.i94, label %bb6.i.i.i95 - -bb5.i.i.i94: ; preds = %bb8.i19.i.i.i, %bb4.i.i.i90 - br label %bb.i2.i.i.i - -bb.i2.i.i.i: ; preds = %hpop.exit.i.i.i.i, %bb5.i.i.i94 - br i1 false, label %hpop.exit.i.i.i.i, label %bb1.i.i.i.i.i - -bb1.i.i.i.i.i: ; preds = %bb.i2.i.i.i - br label %bb2.i.i.i.i.i - -bb2.i.i.i.i.i: ; preds = %bb11.i.i.i.i.i, %bb1.i.i.i.i.i - br i1 false, label %bb3.i.i.i.i.i, label %bb12.i.i.i.i.i - -bb3.i.i.i.i.i: ; preds = %bb2.i.i.i.i.i - br i1 false, label %bb4.i.i.i.i.i, label %bb1.i.i.i.i.i.i - -bb1.i.i.i.i.i.i: ; preds = %bb3.i.i.i.i.i - br i1 false, label %bb8.i.i.i.i.i, label %bb3.i.i.i.i.i.i - -bb3.i.i.i.i.i.i: ; preds = %bb1.i.i.i.i.i.i - br i1 false, label %bb4.i.i.i.i.i, label %bb8.i.i.i.i.i - -bb4.i.i.i.i.i: ; preds = %bb3.i.i.i.i.i.i, %bb3.i.i.i.i.i - br i1 false, label %bb5.i.i.i.i.i, label %bb11.i.i.i.i.i - -bb5.i.i.i.i.i: ; preds = %bb4.i.i.i.i.i - br i1 false, label %bb6.i.i.i.i.i, label %bb1.i21.i.i.i.i.i - -bb1.i21.i.i.i.i.i: ; preds = %bb5.i.i.i.i.i - br i1 false, label %bb11.i.i.i.i.i, label %bb3.i24.i.i.i.i.i - -bb3.i24.i.i.i.i.i: ; preds = %bb1.i21.i.i.i.i.i - br i1 false, label %bb6.i.i.i.i.i, label %bb11.i.i.i.i.i - -bb6.i.i.i.i.i: ; preds = %bb3.i24.i.i.i.i.i, %bb5.i.i.i.i.i - br label %bb11.i.i.i.i.i - -bb8.i.i.i.i.i: ; preds = %bb3.i.i.i.i.i.i, %bb1.i.i.i.i.i.i - br i1 false, label %bb9.i.i.i.i.i, label %bb12.i.i.i.i.i - -bb9.i.i.i.i.i: ; preds = %bb8.i.i.i.i.i - br i1 false, label %bb11.i.i.i.i.i, label %bb1.i8.i.i.i.i.i - -bb1.i8.i.i.i.i.i: ; preds = %bb9.i.i.i.i.i - br i1 false, label %bb12.i.i.i.i.i, label %bb3.i11.i.i.i.i.i - -bb3.i11.i.i.i.i.i: ; preds = %bb1.i8.i.i.i.i.i - br i1 false, label %bb11.i.i.i.i.i, label %bb12.i.i.i.i.i - -bb11.i.i.i.i.i: ; preds = %bb3.i11.i.i.i.i.i, %bb9.i.i.i.i.i, %bb6.i.i.i.i.i, %bb3.i24.i.i.i.i.i, %bb1.i21.i.i.i.i.i, %bb4.i.i.i.i.i - br label %bb2.i.i.i.i.i - -bb12.i.i.i.i.i: ; preds = %bb3.i11.i.i.i.i.i, %bb1.i8.i.i.i.i.i, %bb8.i.i.i.i.i, %bb2.i.i.i.i.i - br label %hpop.exit.i.i.i.i - -hpop.exit.i.i.i.i: ; preds = %bb12.i.i.i.i.i, %bb.i2.i.i.i - br i1 false, label %sdecide.exit.i.i.i, label %bb.i2.i.i.i - -sdecide.exit.i.i.i: ; preds = %hpop.exit.i.i.i.i - br label %bb6.i.i.i95 - -bb6.i.i.i95: ; preds = %sdecide.exit.i.i.i, %bb8.i19.i.i.i, %bb8.i.i.i.i - br label %decide.exit.i.i - -decide.exit.i.i: ; preds = %bb6.i.i.i95, %bb1.i23.i.i.i, %bb2.i.i.i87 - br i1 false, label %bb42.i.i, label %sat.exit.i.loopexit.loopexit2 - -bb42.i.i: ; preds = %decide.exit.i.i - br label %bb13.i.i71.outer - -sat.exit.i.loopexit.loopexit: ; preds = %bb24.i.i, %bb1.i68.i.i, %incincs.exit.i.i - br label %sat.exit.i.loopexit - -sat.exit.i.loopexit.loopexit2: ; preds = %decide.exit.i.i, %bb1.i48.i.i, %bb29.i.i - br label %sat.exit.i.loopexit - -sat.exit.i.loopexit: ; preds = %sat.exit.i.loopexit.loopexit2, %sat.exit.i.loopexit.loopexit - br label %sat.exit.i - -sat.exit.i: ; preds = %sat.exit.i.loopexit, %bb1.i61.i.i, %bb8.i.i67, %bb1.i.i.i63, %bb3.i.i59 - br i1 false, label %bb7.i, label %bb2.i96 - -bb2.i96: ; preds = %sat.exit.i - switch i32 0, label %bb5.i99 [ - i32 10, label %bb4.i98 - i32 20, label %bb6.i100 - ] - -bb4.i98: ; preds = %bb2.i96 - br label %bb6.i100 - -bb5.i99: ; preds = %bb2.i96 - br label %bb6.i100 - -bb6.i100: ; preds = %bb5.i99, %bb4.i98, %bb2.i96 - br label %bb7.i - -bb7.i: ; preds = %bb6.i100, %sat.exit.i - br i1 false, label %bb.i1.i, label %picosat_sat.exit - -bb.i1.i: ; preds = %bb7.i - br label %picosat_sat.exit - -picosat_sat.exit: ; preds = %bb.i1.i, %bb7.i - switch i32 0, label %bb166 [ - i32 20, label %bb150 - i32 10, label %bb163 - ] - -bb150: ; preds = %picosat_sat.exit - br i1 false, label %bb152, label %bb151 - -bb151: ; preds = %bb150 - br label %bb152 - -bb152: ; preds = %bb151, %bb150 - br i1 false, label %bb154, label %bb153 - -bb153: ; preds = %bb152 - br label %bb154 - -bb154: ; preds = %bb153, %bb152 - br i1 false, label %bb157, label %bb156 - -bb156: ; preds = %bb154 - br label %bb157 - -bb157: ; preds = %bb156, %bb154 - br i1 false, label %bb159, label %bb158 - -bb158: ; preds = %bb157 - br label %bb159 - -bb159: ; preds = %bb158, %bb157 - br i1 false, label %bb167, label %bb160 - -bb160: ; preds = %bb159 - br label %bb167 - -bb163: ; preds = %picosat_sat.exit - br i1 false, label %bb167, label %bb164 - -bb164: ; preds = %bb163 - br label %bb4.i - -bb.i11: ; preds = %bb4.i - br i1 false, label %bb.i.i12, label %bb1.i.i14 - -bb.i.i12: ; preds = %bb.i11 - unreachable - -bb1.i.i14: ; preds = %bb.i11 - br i1 false, label %bb3.i.i16, label %bb2.i.i15 - -bb2.i.i15: ; preds = %bb1.i.i14 - unreachable - -bb3.i.i16: ; preds = %bb1.i.i14 - br i1 false, label %bb3.i, label %bb7.i.i - -bb7.i.i: ; preds = %bb3.i.i16 - br i1 false, label %bb.i.i.i.i17, label %bb1.i.i.i.i18 - -bb.i.i.i.i17: ; preds = %bb7.i.i - br label %int2lit.exit.i.i - -bb1.i.i.i.i18: ; preds = %bb7.i.i - br label %int2lit.exit.i.i - -int2lit.exit.i.i: ; preds = %bb1.i.i.i.i18, %bb.i.i.i.i17 - br i1 false, label %bb3.i, label %bb9.i.i - -bb9.i.i: ; preds = %int2lit.exit.i.i - br label %bb3.i - -bb3.i: ; preds = %bb9.i.i, %int2lit.exit.i.i, %bb3.i.i16 - br label %bb4.i - -bb4.i: ; preds = %bb3.i, %bb164 - br i1 false, label %bb5.i, label %bb.i11 - -bb5.i: ; preds = %bb4.i - br i1 false, label %bb6.i, label %bb167 - -bb6.i: ; preds = %bb5.i - br label %bb167 - -bb166: ; preds = %picosat_sat.exit - br label %bb167 - -bb167: ; preds = %bb166, %bb6.i, %bb5.i, %bb163, %bb160, %bb159, %picosat_print.exit - br i1 false, label %bb168, label %bb170 - -bb168: ; preds = %bb167 - br i1 false, label %bb170, label %bb169 - -bb169: ; preds = %bb168 - br i1 false, label %bb.i7, label %picosat_time_stamp.exit9 - -bb.i7: ; preds = %bb169 - br label %picosat_time_stamp.exit9 - -picosat_time_stamp.exit9: ; preds = %bb.i7, %bb169 - br label %bb170 - -bb170: ; preds = %picosat_time_stamp.exit9, %bb168, %bb167, %bb129 - br i1 false, label %bb.i.i3, label %picosat_leave.exit - -bb.i.i3: ; preds = %bb170 - br label %picosat_leave.exit - -picosat_leave.exit: ; preds = %bb.i.i3, %bb170 - br i1 false, label %bb1.i.i, label %bb.i.i - -bb.i.i: ; preds = %picosat_leave.exit - unreachable - -bb1.i.i: ; preds = %picosat_leave.exit - br label %bb9.i.i.i - -bb3.i.i.i: ; preds = %bb9.i.i.i - br i1 false, label %bb5.i.i.i, label %bb4.i.i.i - -bb4.i.i.i: ; preds = %bb3.i.i.i - br label %bb5.i.i.i - -bb5.i.i.i: ; preds = %bb4.i.i.i, %bb3.i.i.i - br label %bb9.i.i.i - -bb9.i.i.i: ; preds = %bb5.i.i.i, %bb1.i.i - br i1 false, label %bb10.i.i.i, label %bb3.i.i.i - -bb10.i.i.i: ; preds = %bb9.i.i.i - br i1 false, label %delete.exit.i.i.i, label %bb1.i.i.i.i - -bb1.i.i.i.i: ; preds = %bb10.i.i.i - br label %delete.exit.i.i.i - -delete.exit.i.i.i: ; preds = %bb1.i.i.i.i, %bb10.i.i.i - br i1 false, label %delete_clauses.exit.i.i, label %bb1.i7.i.i.i - -bb1.i7.i.i.i: ; preds = %delete.exit.i.i.i - br label %delete_clauses.exit.i.i - -delete_clauses.exit.i.i: ; preds = %bb1.i7.i.i.i, %delete.exit.i.i.i - br label %bb3.i.i - -bb2.i.i: ; preds = %bb3.i.i - br i1 false, label %lrelease.exit.i.i, label %bb1.i.i23.i.i - -bb1.i.i23.i.i: ; preds = %bb2.i.i - br label %lrelease.exit.i.i - -lrelease.exit.i.i: ; preds = %bb1.i.i23.i.i, %bb2.i.i - br label %bb3.i.i - -bb3.i.i: ; preds = %lrelease.exit.i.i, %delete_clauses.exit.i.i - br i1 false, label %bb4.i.i, label %bb2.i.i - -bb4.i.i: ; preds = %bb3.i.i - br i1 false, label %delete.exit214.i.i, label %bb1.i208.i.i - -bb1.i208.i.i: ; preds = %bb4.i.i - br label %delete.exit214.i.i - -delete.exit214.i.i: ; preds = %bb1.i208.i.i, %bb4.i.i - br i1 false, label %delete.exit203.i.i, label %bb1.i197.i.i - -bb1.i197.i.i: ; preds = %delete.exit214.i.i - br label %delete.exit203.i.i - -delete.exit203.i.i: ; preds = %bb1.i197.i.i, %delete.exit214.i.i - br i1 false, label %delete.exit192.i.i, label %bb1.i186.i.i - -bb1.i186.i.i: ; preds = %delete.exit203.i.i - br label %delete.exit192.i.i - -delete.exit192.i.i: ; preds = %bb1.i186.i.i, %delete.exit203.i.i - br i1 false, label %delete.exit181.i.i, label %bb1.i175.i.i - -bb1.i175.i.i: ; preds = %delete.exit192.i.i - br label %delete.exit181.i.i - -delete.exit181.i.i: ; preds = %bb1.i175.i.i, %delete.exit192.i.i - br i1 false, label %delete.exit170.i.i, label %bb1.i164.i.i - -bb1.i164.i.i: ; preds = %delete.exit181.i.i - br label %delete.exit170.i.i - -delete.exit170.i.i: ; preds = %bb1.i164.i.i, %delete.exit181.i.i - br i1 false, label %delete.exit159.i.i, label %bb1.i153.i.i - -bb1.i153.i.i: ; preds = %delete.exit170.i.i - br label %delete.exit159.i.i - -delete.exit159.i.i: ; preds = %bb1.i153.i.i, %delete.exit170.i.i - br i1 false, label %delete.exit148.i.i, label %bb1.i142.i.i - -bb1.i142.i.i: ; preds = %delete.exit159.i.i - br label %delete.exit148.i.i - -delete.exit148.i.i: ; preds = %bb1.i142.i.i, %delete.exit159.i.i - br i1 false, label %delete.exit137.i.i, label %bb1.i131.i.i - -bb1.i131.i.i: ; preds = %delete.exit148.i.i - br label %delete.exit137.i.i - -delete.exit137.i.i: ; preds = %bb1.i131.i.i, %delete.exit148.i.i - br i1 false, label %delete.exit126.i.i, label %bb1.i120.i.i - -bb1.i120.i.i: ; preds = %delete.exit137.i.i - br label %delete.exit126.i.i - -delete.exit126.i.i: ; preds = %bb1.i120.i.i, %delete.exit137.i.i - br i1 false, label %delete.exit115.i.i, label %bb1.i109.i.i - -bb1.i109.i.i: ; preds = %delete.exit126.i.i - br label %delete.exit115.i.i - -delete.exit115.i.i: ; preds = %bb1.i109.i.i, %delete.exit126.i.i - br i1 false, label %delete.exit104.i.i, label %bb1.i98.i.i - -bb1.i98.i.i: ; preds = %delete.exit115.i.i - br label %delete.exit104.i.i - -delete.exit104.i.i: ; preds = %bb1.i98.i.i, %delete.exit115.i.i - br i1 false, label %delete.exit93.i.i, label %bb1.i87.i.i - -bb1.i87.i.i: ; preds = %delete.exit104.i.i - br label %delete.exit93.i.i - -delete.exit93.i.i: ; preds = %bb1.i87.i.i, %delete.exit104.i.i - br i1 false, label %delete.exit82.i.i, label %bb1.i76.i.i - -bb1.i76.i.i: ; preds = %delete.exit93.i.i - br label %delete.exit82.i.i - -delete.exit82.i.i: ; preds = %bb1.i76.i.i, %delete.exit93.i.i - br i1 false, label %delete.exit71.i.i, label %bb1.i65.i.i - -bb1.i65.i.i: ; preds = %delete.exit82.i.i - br label %delete.exit71.i.i - -delete.exit71.i.i: ; preds = %bb1.i65.i.i, %delete.exit82.i.i - br i1 false, label %delete.exit60.i.i, label %bb1.i54.i.i - -bb1.i54.i.i: ; preds = %delete.exit71.i.i - br label %delete.exit60.i.i - -delete.exit60.i.i: ; preds = %bb1.i54.i.i, %delete.exit71.i.i - br i1 false, label %delete.exit38.i.i, label %bb1.i32.i.i - -bb1.i32.i.i: ; preds = %delete.exit60.i.i - br label %delete.exit38.i.i - -delete.exit38.i.i: ; preds = %bb1.i32.i.i, %delete.exit60.i.i - br i1 false, label %delete.exit18.i.i, label %bb1.i12.i.i - -bb1.i12.i.i: ; preds = %delete.exit38.i.i - br label %delete.exit18.i.i - -delete.exit18.i.i: ; preds = %bb1.i12.i.i, %delete.exit38.i.i - br i1 false, label %picosat_reset.exit, label %bb1.i2.i.i - -bb1.i2.i.i: ; preds = %delete.exit18.i.i - br label %picosat_reset.exit - -picosat_reset.exit: ; preds = %bb1.i2.i.i, %delete.exit18.i.i - br label %bb171 - -bb171: ; preds = %picosat_reset.exit, %bb110 - br i1 false, label %bb173, label %bb172 - -bb172: ; preds = %bb171 - br label %bb173 - -bb173: ; preds = %bb172, %bb171 - br i1 false, label %bb175, label %bb174 - -bb174: ; preds = %bb173 - br label %bb175 - -bb175: ; preds = %bb174, %bb173 - br i1 false, label %bb177, label %bb176 - -bb176: ; preds = %bb175 - br label %bb177 - -bb177: ; preds = %bb176, %bb175 - br i1 false, label %bb179, label %bb178 - -bb178: ; preds = %bb177 - ret i32 0 - -bb179: ; preds = %bb177 - ret i32 0 -} - -define i32 @main(i32 %argc, i8** %argv) nounwind { -entry: - br label %bb2 - -bb: ; preds = %bb2 - br i1 false, label %bb3, label %bb2 - -bb2: ; preds = %bb, %entry - br i1 false, label %bb5.loopexit, label %bb - -bb3: ; preds = %bb - br i1 false, label %bb5, label %bb4 - -bb4: ; preds = %bb3 - br label %bb5 - -bb5.loopexit: ; preds = %bb2 - br label %bb5 - -bb5: ; preds = %bb5.loopexit, %bb4, %bb3 - %0 = call fastcc i32 @picosat_main(i32 %argc, i8** %argv) nounwind ; <i32> [#uses=2] - br i1 false, label %bb7, label %bb6 - -bb6: ; preds = %bb5 - ret i32 %0 - -bb7: ; preds = %bb5 - ret i32 %0 -} diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr33641_remove_arg_dbgvalue.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr33641_remove_arg_dbgvalue.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr33641_remove_arg_dbgvalue.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr33641_remove_arg_dbgvalue.ll @@ -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. diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll @@ -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 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) diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll @@ -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 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} diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/tail.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/tail.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/tail.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/tail.ll @@ -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 @@ 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 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll @@ -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 @@ ; 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) diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/2008-06-09-WeakProp.ll b/llvm/test/Transforms/Attributor/IPConstantProp/2008-06-09-WeakProp.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/2008-06-09-WeakProp.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/2008-06-09-WeakProp.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll b/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/2009-09-24-byval-ptr.ll @@ -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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll @@ -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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR43857.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR43857.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR43857.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR43857.ll @@ -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 @@ } 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) diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-count-mismatch.ll @@ -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 @@ ; 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 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 } diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/arg-type-mismatch.ll @@ -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. diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/comdat-ipo.ll b/llvm/test/Transforms/Attributor/IPConstantProp/comdat-ipo.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/comdat-ipo.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/comdat-ipo.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll b/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll @@ -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 @@ } define i32 @main() nounwind readnone { +; CHECK-LABEL: define {{[^@]+}}@main() +; CHECK-NEXT: entry: +; CHECK-NEXT: ret i32 0 +; entry: ret i32 0 } diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/deadarg.ll b/llvm/test/Transforms/Attributor/IPConstantProp/deadarg.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/deadarg.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/deadarg.ll @@ -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 } diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/fp-bc-icmp-const-fold.ll b/llvm/test/Transforms/Attributor/IPConstantProp/fp-bc-icmp-const-fold.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/fp-bc-icmp-const-fold.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/fp-bc-icmp-const-fold.ll @@ -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" diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/global.ll b/llvm/test/Transforms/Attributor/IPConstantProp/global.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/global.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/global.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll b/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll @@ -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 ; ; ; /---------------------------------------| diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/musttail-call.ll b/llvm/test/Transforms/Attributor/IPConstantProp/musttail-call.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/musttail-call.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/musttail-call.ll @@ -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 @@ } 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* @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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll b/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll @@ -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" diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll @@ -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 @@ @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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll @@ -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 @@ ; 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 -; -; 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__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 +; +; 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 @@ 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]] +; +; 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]] ; -; CGSCC-LABEL: define {{[^@]+}}@baz -; CGSCC-SAME: (i8* nofree readnone returned [[ARG:%.*]]) -; CGSCC-NEXT: entry: -; CGSCC-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]] -; -; CGSCC-LABEL: define {{[^@]+}}@buz -; CGSCC-SAME: (i8* nofree readnone returned [[ARG:%.*]]) -; CGSCC-NEXT: entry: -; CGSCC-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]] +; +; 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/recursion.ll b/llvm/test/Transforms/Attributor/IPConstantProp/recursion.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/recursion.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/recursion.ll @@ -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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/remove-call-inst.ll b/llvm/test/Transforms/Attributor/IPConstantProp/remove-call-inst.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/remove-call-inst.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/remove-call-inst.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -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 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-constant.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-constants.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-constants.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-constants.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-constants.ll @@ -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. diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll b/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/solve-after-each-resolving-undefs-for-function.ll @@ -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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll b/llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll @@ -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 @@ } 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) diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll --- a/llvm/test/Transforms/Attributor/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll @@ -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 @@ ; 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 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; 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]] -; -; 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__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]] +; +; 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 @@ ; 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 @@ ; 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 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 @@ } 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 @@ ; 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 @@ } -; 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 @@ ; 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 @@ 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 @@ } ; 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 @@ 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 @@ 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 @@ 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 @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 @@ } 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 @@ } 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 @@ } 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 @@ ; 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_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 @@ ; 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 @@ exit: ret i32 0 } -; UTC_ARGS: --disable attributes #0 = { nounwind uwtable noinline } attributes #1 = { uwtable noinline } diff --git a/llvm/test/Transforms/Attributor/alwaysinline.ll b/llvm/test/Transforms/Attributor/alwaysinline.ll --- a/llvm/test/Transforms/Attributor/alwaysinline.ll +++ b/llvm/test/Transforms/Attributor/alwaysinline.ll @@ -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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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]] diff --git a/llvm/test/Transforms/Attributor/callbacks.ll b/llvm/test/Transforms/Attributor/callbacks.ll --- a/llvm/test/Transforms/Attributor/callbacks.ll +++ b/llvm/test/Transforms/Attributor/callbacks.ll @@ -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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; ; 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 @@ ; 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 @@ ; ; 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 diff --git a/llvm/test/Transforms/Attributor/dereferenceable-1.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll --- a/llvm/test/Transforms/Attributor/dereferenceable-1.ll +++ b/llvm/test/Transforms/Attributor/dereferenceable-1.ll @@ -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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; } ; } +; NOTE: %p should not be dereferenceable 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:%.*]] +; 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:%.*]] ; -; NOTE: %p should not be dereferenceable entry: %0 = add nsw i64 %start, 9 br label %for.body @@ -257,24 +339,25 @@ %cmp = icmp slt i64 %i.06, %0 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){ -; 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:%.*]] +; 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:%.*]] ; -; FIXME: %p should be dereferenceable(40) entry: %0 = add nsw i64 %start, 9 br label %for.body @@ -293,13 +376,13 @@ } 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 @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 @@ ; 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 @@ tail call void @use2(i8* dereferenceable(4) %a, i8* %b) ret void } + ; More complex test ; { ; fun1(dereferenceable(4) %a) @@ -341,9 +436,22 @@ ; 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 @@ ; } ; ; 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 @@ ; } ; } ; 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 @@ -463,6 +621,24 @@ ; 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() ret void @@ -474,6 +650,12 @@ ; 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)] ret void @@ -497,6 +679,24 @@ ; 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() call void @unknown_use32(i32* %p) diff --git a/llvm/test/Transforms/Attributor/dereferenceable-2.ll b/llvm/test/Transforms/Attributor/dereferenceable-2.ll --- a/llvm/test/Transforms/Attributor/dereferenceable-2.ll +++ b/llvm/test/Transforms/Attributor/dereferenceable-2.ll @@ -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 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_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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; 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 @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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @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_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 @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 @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 @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 @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_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 @@ ; ; 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: diff --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll --- a/llvm/test/Transforms/Attributor/heap_to_stack.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -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 @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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ 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 @@ ; 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @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 @@ 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 @@ ; 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 } diff --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll --- a/llvm/test/Transforms/Attributor/internal-noalias.ll +++ b/llvm/test/Transforms/Attributor/internal-noalias.ll @@ -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 @@ 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 @@ } -; 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 @@ } 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 @@ 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 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) diff --git a/llvm/test/Transforms/Attributor/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll --- a/llvm/test/Transforms/Attributor/liveness.ll +++ b/llvm/test/Transforms/Attributor/liveness.ll @@ -1,15 +1,11 @@ ; 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,MODULE_OLD -; RUN: opt -attributor-cgscc --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC,CGSCC_OLD -; 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,MODULE_NEW -; RUN: opt -passes='attributor-cgscc' --attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC,CGSCC_NEW -; XFAIL: * -; UTC_ARGS: --disable - -; MODULE_OLD: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)] -; MODULE_NEW: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)] -; CGSCC_OLD: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)] -; CGSCC_NEW: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)] +; 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 + +; NOT_CGSCC_OPM: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)] +; IS__CGSCC_OPM: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)] @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)] declare void @no_return_call() nofree noreturn nounwind nosync @@ -29,8 +25,19 @@ ; This internal function has no live call sites, so all its BBs are considered dead, ; and nothing should be deduced for it. -; MODULE-NOT: define internal i32 @dead_internal_func(i32 %0) define internal i32 @dead_internal_func(i32 %0) { +; IS__CGSCC____-LABEL: define {{[^@]+}}@dead_internal_func() +; IS__CGSCC____-NEXT: br label [[TMP2:%.*]] +; IS__CGSCC____: 1: +; IS__CGSCC____-NEXT: ret i32 undef +; IS__CGSCC____: 2: +; IS__CGSCC____-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP6:%.*]], [[TMP2]] ], [ 1, [[TMP0:%.*]] ] +; IS__CGSCC____-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP5:%.*]], [[TMP2]] ], [ 1, [[TMP0]] ] +; IS__CGSCC____-NEXT: [[TMP5]] = mul nsw i32 [[TMP3]], [[TMP4]] +; IS__CGSCC____-NEXT: [[TMP6]] = add nuw nsw i32 [[TMP3]], 1 +; IS__CGSCC____-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP3]], 10 +; IS__CGSCC____-NEXT: br i1 [[TMP7]], label [[TMP1:%.*]], label [[TMP2]] +; %2 = icmp slt i32 %0, 1 br i1 %2, label %3, label %5 @@ -49,26 +56,41 @@ ; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn define i32 @volatile_load(i32*) 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 } -; MODULE-NOT: internal_load define internal i32 @internal_load(i32*) norecurse nounwind uwtable { +; IS__CGSCC____-LABEL: define {{[^@]+}}@internal_load() +; IS__CGSCC____-NEXT: ret i32 undef +; %2 = load i32, i32* %0, align 4 ret i32 %2 } ; TEST 1: Only first block is live. ; CHECK: Function Attrs: nofree noreturn nosync nounwind -; MODULE-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nofree nonnull readnone %ptr1, i32* nocapture nofree readnone %ptr2) -; CGSCC-NEXT: define i32 @first_block_no_return(i32 %a, i32* nocapture nofree nonnull readnone %ptr1, i32* nocapture nofree readnone %ptr2) define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 { +; CHECK-LABEL: define {{[^@]+}}@first_block_no_return +; CHECK-SAME: (i32 [[A:%.*]], i32* nocapture nofree nonnull readnone [[PTR1:%.*]], i32* nocapture nofree readnone [[PTR2:%.*]]) +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @no_return_call() +; CHECK-NEXT: unreachable +; CHECK: cond.true: +; CHECK-NEXT: unreachable +; CHECK: cond.false: +; CHECK-NEXT: unreachable +; CHECK: cond.end: +; CHECK-NEXT: unreachable +; entry: call i32 @internal_load(i32* %ptr1) call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable call i32 @dead_internal_func(i32 10) %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false @@ -96,16 +118,28 @@ ; dead block and check if it is deduced. ; CHECK: Function Attrs: nosync -; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* nocapture nofree readnone %ptr1) define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 { +; CHECK-LABEL: define {{[^@]+}}@dead_block_present +; CHECK-SAME: (i32 [[A:%.*]], i32* nocapture nofree readnone [[PTR1:%.*]]) +; 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: call void @no_return_call() +; CHECK-NEXT: unreachable +; CHECK: cond.false: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 [[CALL1]] +; entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false cond.true: ; preds = %entry call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable %call = call i32 @volatile_load(i32* %ptr1) br label %cond.end @@ -115,8 +149,6 @@ br label %cond.end cond.end: ; preds = %cond.false, %cond.true -; CHECK: cond.end: -; CHECK-NEXT: ret i32 %call1 %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] ret i32 %cond } @@ -124,23 +156,32 @@ ; TEST 3: both cond.true and cond.false are dead, therfore cond.end is dead as well. define i32 @all_dead(i32 %a) #0 { +; CHECK-LABEL: define {{[^@]+}}@all_dead +; 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: call void @no_return_call() +; CHECK-NEXT: unreachable +; CHECK: cond.false: +; CHECK-NEXT: call void @no_return_call() +; 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 cond.true: ; preds = %entry call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable call i32 @dead_internal_func(i32 10) - ; CHECK-NOT: call %call = call i32 @foo() br label %cond.end cond.false: ; preds = %entry call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable call i32 @dead_internal_func(i32 10) %call1 = call i32 @bar() br label %cond.end @@ -154,8 +195,23 @@ ; TEST 4: All blocks are live. -; CHECK: define i32 @all_live(i32 %a) define i32 @all_live(i32 %a) #0 { +; CHECK-LABEL: define {{[^@]+}}@all_live +; 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: call void @normal_call() +; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_noreturn() +; CHECK-NEXT: unreachable +; CHECK: cond.false: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 [[CALL1]] +; entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false @@ -177,8 +233,29 @@ ; TEST 5.1 noreturn invoke instruction with a unreachable normal successor block. -; CHECK: define i32 @invoke_noreturn(i32 %a) define i32 @invoke_noreturn(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: define {{[^@]+}}@invoke_noreturn +; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +; 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: call void @normal_call() +; CHECK-NEXT: [[CALL:%.*]] = invoke i32 @foo_noreturn() +; CHECK-NEXT: to label [[CONTINUE:%.*]] unwind label [[CLEANUP:%.*]] +; CHECK: cond.false: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 [[CALL1]] +; CHECK: continue: +; CHECK-NEXT: unreachable +; CHECK: cleanup: +; CHECK-NEXT: [[RES:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: ret i32 0 +; entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false @@ -186,9 +263,7 @@ cond.true: ; preds = %entry call void @normal_call() %call = invoke i32 @foo_noreturn() to label %continue - unwind label %cleanup - ; CHECK: %call = invoke i32 @foo_noreturn() - ; CHECK-NEXT: to label %continue unwind label %cleanup + unwind label %cleanup cond.false: ; preds = %entry call void @normal_call() @@ -200,8 +275,6 @@ ret i32 %cond continue: - ; CHECK: continue: - ; CHECK-NEXT: unreachable br label %cond.end cleanup: @@ -213,8 +286,27 @@ ; TEST 5.2 noreturn invoke instruction replaced by a call and an unreachable instruction ; put after it. -; CHECK: define i32 @invoke_noreturn_nounwind(i32 %a) define i32 @invoke_noreturn_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: define {{[^@]+}}@invoke_noreturn_nounwind +; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +; 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: call void @normal_call() +; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_noreturn_nounwind() +; CHECK-NEXT: unreachable +; CHECK: cond.false: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.end: +; CHECK-NEXT: ret i32 [[CALL1]] +; CHECK: continue: +; CHECK-NEXT: unreachable +; CHECK: cleanup: +; CHECK-NEXT: unreachable +; entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false @@ -222,12 +314,8 @@ cond.true: ; preds = %entry call void @normal_call() %call = invoke i32 @foo_noreturn_nounwind() to label %continue - unwind label %cleanup - ; CHECK: call void @normal_call() - ; CHECK-NEXT: call i32 @foo_noreturn_nounwind() - ; CHECK-NEXT: unreachable + unwind label %cleanup - ; CHECK-NOT: @foo_noreturn_nounwind() cond.false: ; preds = %entry call void @normal_call() @@ -250,12 +338,25 @@ ; TEST 5.3 unounwind invoke instruction replaced by a call and a branch instruction put after it. define i32 @invoke_nounwind(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { ; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind +; CHECK-SAME: (i32 [[A:%.*]]) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +; 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: call void @normal_call() ; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo_nounwind() ; CHECK-NEXT: br label [[CONTINUE:%.*]] -; CHECK: continue: +; CHECK: cond.false: +; CHECK-NEXT: call void @normal_call() +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @bar() ; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[CALL]], [[CONTINUE]] ], [ [[CALL1]], [[COND_FALSE]] ] +; CHECK-NEXT: ret i32 [[COND]] +; CHECK: continue: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cleanup: +; CHECK-NEXT: unreachable ; entry: %cmp = icmp eq i32 %a, 0 @@ -284,8 +385,6 @@ ret i32 0 } -; UTC_ARGS: --enable - ; TEST 5.4 unounwind invoke instruction replaced by a call and a branch instruction put after it. define i32 @invoke_nounwind_phi(i32 %a) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { ; CHECK-LABEL: define {{[^@]+}}@invoke_nounwind_phi @@ -374,13 +473,18 @@ ret i32 0 } -; UTC_ARGS: --disable - ; TEST 6: Undefined behvior, taken from LangRef. ; FIXME: Should be able to detect undefined behavior. -; CHECK: define void @ub(i32* nocapture nofree writeonly %0) define void @ub(i32* %0) { +; CHECK-LABEL: define {{[^@]+}}@ub +; CHECK-SAME: (i32* nocapture nofree writeonly [[TMP0:%.*]]) +; CHECK-NEXT: [[POISON:%.*]] = sub nuw i32 0, 1 +; CHECK-NEXT: [[STILL_POISON:%.*]] = and i32 [[POISON]], 0 +; CHECK-NEXT: [[POISON_YET_AGAIN:%.*]] = getelementptr i32, i32* [[TMP0]], i32 [[STILL_POISON]] +; CHECK-NEXT: store i32 0, i32* [[POISON_YET_AGAIN]], align 4 +; CHECK-NEXT: ret void +; %poison = sub nuw i32 0, 1 ; Results in a poison value. %still_poison = and i32 %poison, 0 ; 0, but also poison. %poison_yet_again = getelementptr i32, i32* %0, i32 %still_poison @@ -389,6 +493,12 @@ } define void @inf_loop() #0 { +; CHECK-LABEL: define {{[^@]+}}@inf_loop() +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[WHILE_BODY:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br label [[WHILE_BODY]] +; entry: br label %while.body @@ -400,6 +510,20 @@ ; FIXME: Detect infloops, and mark affected blocks dead. define i32 @test5(i32, i32) #0 { +; CHECK-LABEL: define {{[^@]+}}@test5 +; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP1]] +; CHECK-NEXT: br i1 [[TMP3]], label [[COND_IF:%.*]], label [[COND_ELSEIF:%.*]] +; CHECK: cond.if: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.elseif: +; CHECK-NEXT: unreachable +; CHECK: cond.else: +; CHECK-NEXT: unreachable +; CHECK: cond.end: +; CHECK-NEXT: ret i32 0 +; %3 = icmp sgt i32 %0, %1 br i1 %3, label %cond.if, label %cond.elseif @@ -422,6 +546,10 @@ } define void @rec() #0 { +; CHECK-LABEL: define {{[^@]+}}@rec() +; CHECK-NEXT: entry: +; CHECK-NEXT: unreachable +; entry: call void @rec() ret void @@ -432,6 +560,18 @@ ; and unreachable should be put after call to @rec(). define i32 @test6(i32, i32) #0 { +; CHECK-LABEL: define {{[^@]+}}@test6 +; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK-NEXT: unreachable +; CHECK: cond.if: +; CHECK-NEXT: unreachable +; CHECK: cond.elseif: +; CHECK-NEXT: unreachable +; CHECK: cond.else: +; CHECK-NEXT: unreachable +; CHECK: cond.end: +; CHECK-NEXT: unreachable +; call void @rec() %3 = icmp sgt i32 %0, %1 br i1 %3, label %cond.if, label %cond.elseif @@ -457,6 +597,24 @@ ; FIXME: contains recursive call to itself in cond.elseif block define i32 @test7(i32, i32) #0 { +; CHECK-LABEL: define {{[^@]+}}@test7 +; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], [[TMP1]] +; CHECK-NEXT: br i1 [[TMP3]], label [[COND_IF:%.*]], label [[COND_ELSEIF:%.*]] +; CHECK: cond.if: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @bar() +; CHECK-NEXT: br label [[COND_END:%.*]] +; CHECK: cond.elseif: +; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @test7(i32 [[TMP0]], i32 [[TMP1]]) +; CHECK-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP0]], [[TMP1]] +; CHECK-NEXT: br i1 [[TMP6]], label [[COND_END]], label [[COND_ELSE:%.*]] +; CHECK: cond.else: +; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @foo() +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP1]], [[COND_ELSEIF]] ], [ 0, [[COND_ELSE]] ], [ 0, [[COND_IF]] ] +; CHECK-NEXT: ret i32 [[TMP8]] +; %3 = icmp sgt i32 %0, %1 br i1 %3, label %cond.if, label %cond.elseif @@ -498,12 +656,21 @@ @a2 = common global i8 0, align 16 define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f1(i8* readnone %0) +; CHECK-LABEL: define {{[^@]+}}@f1 +; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] +; CHECK: 3: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f2(i8* nonnull @a1) +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] +; CHECK-NEXT: ret i8* [[TMP6]] +; %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 8 @a1) %4 = tail call i8* @f2(i8* nonnull @a1) br label %5 @@ -513,18 +680,29 @@ } define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f2(i8* readnone %0) +; CHECK-LABEL: define {{[^@]+}}@f2 +; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]] +; CHECK: 3: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f1(i8* nonnull [[TMP0]]) +; CHECK-NEXT: br label [[TMP7:%.*]] +; CHECK: 5: +; CHECK-NEXT: [[TMP6:%.*]] = tail call i8* @f3(i8* nonnull @a2) +; CHECK-NEXT: br label [[TMP7]] +; CHECK: 7: +; CHECK-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ] +; CHECK-NEXT: ret i8* [[TMP8]] +; %2 = icmp eq i8* %0, null br i1 %2, label %5, label %3 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 8 %0) %4 = tail call i8* @f1(i8* nonnull %0) br label %7 ; <label>:5: ; preds = %1 -; ATTRIBUTOR: %6 = tail call i8* undef(i8* nonnull align 16 @a2) %6 = tail call i8* @f3(i8* nonnull @a2) br label %7 @@ -534,12 +712,21 @@ } define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 { -; ATTRIBUTOR: define internal i8* @f3(i8* readnone %0) +; CHECK-LABEL: define {{[^@]+}}@f3 +; CHECK-SAME: (i8* readnone [[TMP0:%.*]]) local_unnamed_addr +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] +; CHECK: 3: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @f1(i8* nonnull @a2) +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ] +; CHECK-NEXT: ret i8* [[TMP6]] +; %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 ; <label>:3: ; preds = %1 -; ATTRIBUTOR: %4 = tail call i8* undef(i8* nonnull align 16 @a2) %4 = tail call i8* @f1(i8* nonnull @a2) br label %5 @@ -550,17 +737,37 @@ declare void @sink() nofree nosync nounwind willreturn define void @test_unreachable() { -; CHECK: define void @test_unreachable() +; CHECK-LABEL: define {{[^@]+}}@test_unreachable() ; CHECK-NEXT: call void @sink() ; CHECK-NEXT: call void @test_unreachable() ; CHECK-NEXT: unreachable -; CHECK-NEXT: } +; call void @sink() call void @test_unreachable() unreachable } define linkonce_odr void @non_exact1() { +; CHECK-LABEL: define {{[^@]+}}@non_exact1() +; CHECK-NEXT: call void @non_dead_a0() +; CHECK-NEXT: call void @non_dead_a1() +; CHECK-NEXT: call void @non_dead_a2() +; CHECK-NEXT: call void @non_dead_a3() +; CHECK-NEXT: call void @non_dead_a4() +; CHECK-NEXT: call void @non_dead_a5() +; CHECK-NEXT: call void @non_dead_a6() +; CHECK-NEXT: call void @non_dead_a7() +; CHECK-NEXT: call void @non_dead_a8() +; CHECK-NEXT: call void @non_dead_a9() +; CHECK-NEXT: call void @non_dead_a10() +; CHECK-NEXT: call void @non_dead_a11() +; CHECK-NEXT: call void @non_dead_a12() +; CHECK-NEXT: call void @non_dead_a13() +; CHECK-NEXT: call void @non_dead_a14() +; CHECK-NEXT: call void @non_dead_a15() +; CHECK-NEXT: call void @middle() +; CHECK-NEXT: ret void +; call void @non_dead_a0() call void @non_dead_a1() call void @non_dead_a2() @@ -581,6 +788,35 @@ ret void } define internal void @middle() { +; CHECK-LABEL: define {{[^@]+}}@middle() +; CHECK-NEXT: bb0: +; CHECK-NEXT: call void @non_dead_b0() +; CHECK-NEXT: call void @non_dead_b1() +; CHECK-NEXT: call void @non_dead_b2() +; CHECK-NEXT: call void @non_dead_b3() +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @non_dead_b4() +; CHECK-NEXT: call void @non_dead_b5() +; CHECK-NEXT: call void @non_dead_b6() +; CHECK-NEXT: call void @non_dead_b7() +; CHECK-NEXT: br label [[BB2:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @non_dead_b8() +; CHECK-NEXT: call void @non_dead_b9() +; CHECK-NEXT: call void @non_dead_b10() +; CHECK-NEXT: call void @non_dead_b11() +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb3: +; CHECK-NEXT: call void @non_dead_b12() +; CHECK-NEXT: call void @non_dead_b13() +; CHECK-NEXT: call void @non_dead_b14() +; CHECK-NEXT: call void @non_dead_b15() +; CHECK-NEXT: br label [[BB4:%.*]] +; CHECK: bb4: +; CHECK-NEXT: call void @non_exact2() +; CHECK-NEXT: ret void +; bb0: call void @non_dead_b0() call void @non_dead_b1() @@ -610,6 +846,26 @@ ret void } define linkonce_odr void @non_exact2() { +; CHECK-LABEL: define {{[^@]+}}@non_exact2() +; CHECK-NEXT: call void @non_dead_c0() +; CHECK-NEXT: call void @non_dead_c1() +; CHECK-NEXT: call void @non_dead_c2() +; CHECK-NEXT: call void @non_dead_c3() +; CHECK-NEXT: call void @non_dead_c4() +; CHECK-NEXT: call void @non_dead_c5() +; CHECK-NEXT: call void @non_dead_c6() +; CHECK-NEXT: call void @non_dead_c7() +; CHECK-NEXT: call void @non_dead_c8() +; CHECK-NEXT: call void @non_dead_c9() +; CHECK-NEXT: call void @non_dead_c10() +; CHECK-NEXT: call void @non_dead_c11() +; CHECK-NEXT: call void @non_dead_c12() +; CHECK-NEXT: call void @non_dead_c13() +; CHECK-NEXT: call void @non_dead_c14() +; CHECK-NEXT: call void @non_dead_c15() +; CHECK-NEXT: call void @non_exact3() +; CHECK-NEXT: ret void +; call void @non_dead_c0() call void @non_dead_c1() call void @non_dead_c2() @@ -630,6 +886,26 @@ ret void } define linkonce_odr void @non_exact3() { +; CHECK-LABEL: define {{[^@]+}}@non_exact3() +; CHECK-NEXT: call void @non_dead_d0() +; CHECK-NEXT: call void @non_dead_d1() +; CHECK-NEXT: call void @non_dead_d2() +; CHECK-NEXT: call void @non_dead_d3() +; CHECK-NEXT: call void @non_dead_d4() +; CHECK-NEXT: call void @non_dead_d5() +; CHECK-NEXT: call void @non_dead_d6() +; CHECK-NEXT: call void @non_dead_d7() +; CHECK-NEXT: call void @non_dead_d8() +; CHECK-NEXT: call void @non_dead_d9() +; CHECK-NEXT: call void @non_dead_d10() +; CHECK-NEXT: call void @non_dead_d11() +; CHECK-NEXT: call void @non_dead_d12() +; CHECK-NEXT: call void @non_dead_d13() +; CHECK-NEXT: call void @non_dead_d14() +; CHECK-NEXT: call void @non_dead_d15() +; CHECK-NEXT: [[NR:%.*]] = call i32 @foo_noreturn() +; CHECK-NEXT: unreachable +; call void @non_dead_d0() call void @non_dead_d1() call void @non_dead_d2() @@ -650,370 +926,531 @@ call void @dead_e1() ret void } -; CHECK: define linkonce_odr void @non_exact3() { -; CHECK-NEXT: call void @non_dead_d0() -; CHECK-NEXT: call void @non_dead_d1() -; CHECK-NEXT: call void @non_dead_d2() -; CHECK-NEXT: call void @non_dead_d3() -; CHECK-NEXT: call void @non_dead_d4() -; CHECK-NEXT: call void @non_dead_d5() -; CHECK-NEXT: call void @non_dead_d6() -; CHECK-NEXT: call void @non_dead_d7() -; CHECK-NEXT: call void @non_dead_d8() -; CHECK-NEXT: call void @non_dead_d9() -; CHECK-NEXT: call void @non_dead_d10() -; CHECK-NEXT: call void @non_dead_d11() -; CHECK-NEXT: call void @non_dead_d12() -; CHECK-NEXT: call void @non_dead_d13() -; CHECK-NEXT: call void @non_dead_d14() -; CHECK-NEXT: call void @non_dead_d15() -; CHECK-NEXT: %nr = call i32 @foo_noreturn() -; CHECK-NEXT: unreachable define internal void @non_dead_a0() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a0() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a1() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a1() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a2() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a2() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a3() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a3() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a4() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a4() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a5() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a5() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a6() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a6() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a7() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a7() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a8() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a8() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a9() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a9() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a10() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a10() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a11() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a11() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a12() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a12() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a13() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a13() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a14() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a14() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_a15() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_a15() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b0() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b0() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b1() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b1() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b2() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b2() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b3() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b3() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b4() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b4() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b5() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b5() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b6() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b6() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b7() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b7() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b8() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b8() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b9() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b9() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b10() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b10() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b11() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b11() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b12() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b12() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b13() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b13() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b14() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b14() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_b15() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_b15() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c0() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c0() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c1() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c1() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c2() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c2() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c3() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c3() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c4() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c4() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c5() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c5() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c6() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c6() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c7() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c7() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c8() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c8() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c9() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c9() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c10() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c10() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c11() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c11() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c12() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c12() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c13() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c13() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c14() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c14() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_c15() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_c15() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d0() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d0() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d1() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d1() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d2() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d2() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d3() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d3() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d4() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d4() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d5() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d5() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d6() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d6() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d7() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d7() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d8() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d8() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d9() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d9() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d10() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d10() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d11() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d11() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d12() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d12() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d13() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d13() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d14() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d14() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @non_dead_d15() { +; CHECK-LABEL: define {{[^@]+}}@non_dead_d15() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } define internal void @dead_e0() { call void @dead_e1() ret void } +; IS__CGSCC____-LABEL: define {{[^@]+}}@dead_e0() +; IS__CGSCC____-NEXT: call void @dead_e1() +; IS__CGSCC____-NEXT: ret void +; define internal void @dead_e1() { call void @dead_e2() ret void } define internal void @dead_e2() { ret void } -; CHECK: define internal void @non_dead_a0() -; CHECK: define internal void @non_dead_a1() -; CHECK: define internal void @non_dead_a2() -; CHECK: define internal void @non_dead_a3() -; CHECK: define internal void @non_dead_a4() -; CHECK: define internal void @non_dead_a5() -; CHECK: define internal void @non_dead_a6() -; CHECK: define internal void @non_dead_a7() -; CHECK: define internal void @non_dead_a8() -; CHECK: define internal void @non_dead_a9() -; CHECK: define internal void @non_dead_a10() -; CHECK: define internal void @non_dead_a11() -; CHECK: define internal void @non_dead_a12() -; CHECK: define internal void @non_dead_a13() -; CHECK: define internal void @non_dead_a14() -; CHECK: define internal void @non_dead_a15() -; CHECK: define internal void @non_dead_b0() -; CHECK: define internal void @non_dead_b1() -; CHECK: define internal void @non_dead_b2() -; CHECK: define internal void @non_dead_b3() -; CHECK: define internal void @non_dead_b4() -; CHECK: define internal void @non_dead_b5() -; CHECK: define internal void @non_dead_b6() -; CHECK: define internal void @non_dead_b7() -; CHECK: define internal void @non_dead_b8() -; CHECK: define internal void @non_dead_b9() -; CHECK: define internal void @non_dead_b10() -; CHECK: define internal void @non_dead_b11() -; CHECK: define internal void @non_dead_b12() -; CHECK: define internal void @non_dead_b13() -; CHECK: define internal void @non_dead_b14() -; CHECK: define internal void @non_dead_b15() -; CHECK: define internal void @non_dead_c0() -; CHECK: define internal void @non_dead_c1() -; CHECK: define internal void @non_dead_c2() -; CHECK: define internal void @non_dead_c3() -; CHECK: define internal void @non_dead_c4() -; CHECK: define internal void @non_dead_c5() -; CHECK: define internal void @non_dead_c6() -; CHECK: define internal void @non_dead_c7() -; CHECK: define internal void @non_dead_c8() -; CHECK: define internal void @non_dead_c9() -; CHECK: define internal void @non_dead_c10() -; CHECK: define internal void @non_dead_c11() -; CHECK: define internal void @non_dead_c12() -; CHECK: define internal void @non_dead_c13() -; CHECK: define internal void @non_dead_c14() -; CHECK: define internal void @non_dead_c15() -; CHECK: define internal void @non_dead_d0() -; CHECK: define internal void @non_dead_d1() -; CHECK: define internal void @non_dead_d2() -; CHECK: define internal void @non_dead_d3() -; CHECK: define internal void @non_dead_d4() -; CHECK: define internal void @non_dead_d5() -; CHECK: define internal void @non_dead_d6() -; CHECK: define internal void @non_dead_d7() -; CHECK: define internal void @non_dead_d8() -; CHECK: define internal void @non_dead_d9() -; CHECK: define internal void @non_dead_d10() -; CHECK: define internal void @non_dead_d11() -; CHECK: define internal void @non_dead_d12() -; CHECK: define internal void @non_dead_d13() -; CHECK: define internal void @non_dead_d14() ; Verify we actually deduce information for these functions. -; MODULE: Function Attrs: nofree nosync nounwind willreturn -; MODULE-NEXT: define internal void @non_dead_d15() -; MODULE-NOT: define internal void @dead_e -; CGSCC: Function Attrs: nofree nosync nounwind willreturn -; CGSCC-NEXT: define internal void @non_dead_d15() declare void @blowup() noreturn define void @live_with_dead_entry() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK: define void @live_with_dead_entry( -; CHECK-NEXT: entry: -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %live_with_dead_entry.dead unwind label %lpad -; CHECK: lpad: ; preds = %entry -; CHECK-NEXT: %0 = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: br label %live_with_dead_entry -; CHECK: live_with_dead_entry.dead: ; preds = %entry -; CHECK-NEXT: unreachable -; CHECK: live_with_dead_entry: ; preds = %lpad -; CHECK-NEXT: ret void entry: invoke void @blowup() to label %live_with_dead_entry unwind label %lpad lpad: @@ -1024,25 +1461,26 @@ } define void @live_with_dead_entry_lp() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; CHECK: define void @live_with_dead_entry_lp( -; CHECK-NEXT: entry: -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %[[LIVE_WITH_DEAD_ENTRY_DEAD1:.*]] unwind label %[[LP1:.*]] -; CHECK: [[LP1]]: ; preds = %entry -; CHECK-NEXT: %lp = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: invoke void @blowup() -; CHECK-NEXT: to label %[[LIVE_WITH_DEAD_ENTRY_DEAD2:.*]] unwind label %[[LP2:.*]] -; CHECK: [[LP2]]: ; preds = %lp1 -; CHECK-NEXT: %0 = landingpad { i8*, i32 } -; CHECK-NEXT: catch i8* null -; CHECK-NEXT: br label %live_with_dead_entry -; CHECK: [[LIVE_WITH_DEAD_ENTRY_DEAD1]]: -; CHECK-NEXT: unreachable -; CHECK: [[LIVE_WITH_DEAD_ENTRY_DEAD2]]: -; CHECK-NEXT: unreachable -; CHECK: live_with_dead_entry: ; preds = %lp2 -; CHECK-NEXT: ret void +; CHECK-LABEL: define {{[^@]+}}@live_with_dead_entry_lp() #2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +; CHECK-NEXT: entry: +; CHECK-NEXT: invoke void @blowup() +; CHECK-NEXT: to label [[LIVE_WITH_DEAD_ENTRY_DEAD:%.*]] unwind label [[LP1:%.*]] +; CHECK: lp1: +; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: invoke void @blowup() +; CHECK-NEXT: to label [[LIVE_WITH_DEAD_ENTRY_DEAD1:%.*]] unwind label [[LP2:%.*]] +; CHECK: lp2: +; CHECK-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: catch i8* null +; CHECK-NEXT: br label [[LIVE_WITH_DEAD_ENTRY:%.*]] +; CHECK: live_with_dead_entry.dead: +; CHECK-NEXT: unreachable +; CHECK: live_with_dead_entry.dead1: +; CHECK-NEXT: unreachable +; CHECK: live_with_dead_entry: +; CHECK-NEXT: ret void +; entry: invoke void @blowup() to label %live_with_dead_entry unwind label %lp1 lp1: @@ -1055,68 +1493,81 @@ ret void } -; CHECK: define internal void @useless_arg_sink() define internal void @useless_arg_sink(i32* %a) { +; CHECK-LABEL: define {{[^@]+}}@useless_arg_sink() +; CHECK-NEXT: call void @sink() +; CHECK-NEXT: ret void +; call void @sink() ret void } -; CHECK: define internal void @useless_arg_almost_sink() define internal void @useless_arg_almost_sink(i32* %a) { -; CHECK: call void @useless_arg_sink() +; CHECK-LABEL: define {{[^@]+}}@useless_arg_almost_sink() +; CHECK-NEXT: call void @useless_arg_sink() +; CHECK-NEXT: ret void +; call void @useless_arg_sink(i32* %a) ret void } ; Check we do not annotate the function interface of this weak function. -; CHECK: define weak_odr void @useless_arg_ext(i32* %a) define weak_odr void @useless_arg_ext(i32* %a) { -; CHECK: call void @useless_arg_almost_sink() +; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext +; CHECK-SAME: (i32* [[A:%.*]]) +; CHECK-NEXT: call void @useless_arg_almost_sink() +; CHECK-NEXT: ret void +; call void @useless_arg_almost_sink(i32* %a) ret void } -; CHECK: define internal void @useless_arg_ext_int(i32* %a) define internal void @useless_arg_ext_int(i32* %a) { -; CHECK: call void @useless_arg_ext(i32* %a) +; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext_int +; CHECK-SAME: (i32* [[A:%.*]]) +; CHECK-NEXT: call void @useless_arg_ext(i32* [[A]]) +; CHECK-NEXT: ret void +; call void @useless_arg_ext(i32* %a) ret void } define void @useless_arg_ext_int_ext(i32* %a) { -; CHECK: call void @useless_arg_ext_int(i32* %a) +; CHECK-LABEL: define {{[^@]+}}@useless_arg_ext_int_ext +; CHECK-SAME: (i32* [[A:%.*]]) +; CHECK-NEXT: call void @useless_arg_ext_int(i32* [[A]]) +; CHECK-NEXT: ret void +; call void @useless_arg_ext_int(i32* %a) ret void } -; UTC_ARGS: --enable - ; FIXME: We should fold terminators. define internal i32 @switch_default(i64 %i) nounwind { -; MODULE-LABEL: define {{[^@]+}}@switch_default() -; MODULE-NEXT: entry: -; MODULE-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [ -; MODULE-NEXT: i64 3, label [[RETURN:%.*]] -; MODULE-NEXT: i64 10, label [[RETURN]] -; MODULE-NEXT: ] -; MODULE: sw.default: -; MODULE-NEXT: call void @sink() -; MODULE-NEXT: ret i32 undef -; MODULE: return: -; MODULE-NEXT: unreachable -; -; CGSCC-LABEL: define {{[^@]+}}@switch_default() -; CGSCC-NEXT: entry: -; CGSCC-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [ -; CGSCC-NEXT: i64 3, label [[RETURN:%.*]] -; CGSCC-NEXT: i64 10, label [[RETURN]] -; CGSCC-NEXT: ] -; CGSCC: sw.default: -; CGSCC-NEXT: call void @sink() -; CGSCC-NEXT: ret i32 123 -; CGSCC: return: -; CGSCC-NEXT: unreachable +; IS__TUNIT____-LABEL: define {{[^@]+}}@switch_default() +; IS__TUNIT____-NEXT: entry: +; IS__TUNIT____-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [ +; IS__TUNIT____-NEXT: i64 3, label [[RETURN:%.*]] +; IS__TUNIT____-NEXT: i64 10, label [[RETURN]] +; IS__TUNIT____-NEXT: ] +; IS__TUNIT____: sw.default: +; IS__TUNIT____-NEXT: call void @sink() +; IS__TUNIT____-NEXT: ret i32 undef +; IS__TUNIT____: return: +; IS__TUNIT____-NEXT: unreachable +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@switch_default() +; 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: call void @sink() +; IS__CGSCC____-NEXT: ret i32 123 +; IS__CGSCC____: return: +; IS__CGSCC____-NEXT: unreachable ; entry: switch i64 %i, label %sw.default [ @@ -1142,16 +1593,16 @@ } define internal i32 @switch_default_dead(i64 %i) nounwind { -; CGSCC-LABEL: define {{[^@]+}}@switch_default_dead() -; CGSCC-NEXT: entry: -; CGSCC-NEXT: switch i64 0, label [[SW_DEFAULT:%.*]] [ -; CGSCC-NEXT: i64 3, label [[RETURN:%.*]] -; CGSCC-NEXT: i64 10, label [[RETURN]] -; CGSCC-NEXT: ] -; CGSCC: sw.default: -; CGSCC-NEXT: ret i32 123 -; CGSCC: return: -; CGSCC-NEXT: unreachable +; IS__CGSCC____-LABEL: define {{[^@]+}}@switch_default_dead() +; 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 [ @@ -1185,79 +1636,45 @@ } ; FIXME: We have to prevent the propagation of %fp in the new pm CGSCC pass until the CallGraphUpdater can handle the new call edge. define internal void @call_via_pointer_with_dead_args_internal_a(i32* %a, i32* %b, void (i32*, i32*, i32*, i64, i32**)* %fp) { -; MODULE-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a -; MODULE-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) -; MODULE-NEXT: call void @called_via_pointer(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null) -; MODULE-NEXT: ret void +; IS__TUNIT____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a +; IS__TUNIT____-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) +; IS__TUNIT____-NEXT: call void @called_via_pointer(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null) +; IS__TUNIT____-NEXT: ret void ; -; CGSCC_OLD-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a -; CGSCC_OLD-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) -; CGSCC_OLD-NEXT: call void @called_via_pointer(i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null) -; CGSCC_OLD-NEXT: ret void -; -; CGSCC_NEW-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a -; CGSCC_NEW-SAME: (i32* [[A:%.*]], i32* [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) -; CGSCC_NEW-NEXT: call void [[FP]](i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null) -; CGSCC_NEW-NEXT: ret void +; IS__CGSCC____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_a +; IS__CGSCC____-SAME: (i32* [[A:%.*]], i32* [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) +; IS__CGSCC____-NEXT: call void [[FP]](i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null) +; IS__CGSCC____-NEXT: ret void ; call void %fp(i32* %a, i32* %b, i32* %a, i64 -1, i32** null) ret void } define internal void @call_via_pointer_with_dead_args_internal_b(i32* %a, i32* %b, void (i32*, i32*, i32*, i64, i32**)* %fp) { -; MODULE-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b -; MODULE-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) -; MODULE-NEXT: call void @called_via_pointer_internal_2(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null) -; MODULE-NEXT: ret void -; -; CGSCC_OLD-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b -; CGSCC_OLD-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) -; CGSCC_OLD-NEXT: call void @called_via_pointer_internal_2(i32* [[A]]) -; CGSCC_OLD-NEXT: ret void +; IS__TUNIT____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b +; IS__TUNIT____-SAME: (i32* [[A:%.*]], i32* nonnull align 128 dereferenceable(4) [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) +; IS__TUNIT____-NEXT: call void @called_via_pointer_internal_2(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[B]], i32* [[A]], i64 -1, i32** null) +; IS__TUNIT____-NEXT: ret void ; -; CGSCC_NEW-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b -; CGSCC_NEW-SAME: (i32* [[A:%.*]], i32* [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) -; CGSCC_NEW-NEXT: call void [[FP]](i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null) -; CGSCC_NEW-NEXT: ret void +; IS__CGSCC____-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_internal_b +; IS__CGSCC____-SAME: (i32* [[A:%.*]], i32* [[B:%.*]], void (i32*, i32*, i32*, i64, i32**)* nocapture nofree nonnull [[FP:%.*]]) +; IS__CGSCC____-NEXT: call void [[FP]](i32* [[A]], i32* [[B]], i32* [[A]], i64 -1, i32** null) +; IS__CGSCC____-NEXT: ret void ; call void %fp(i32* %a, i32* %b, i32* %a, i64 -1, i32** null) ret void } define void @call_via_pointer_with_dead_args_caller(i32* %a, i32* %b) { -; MODULE-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_caller -; MODULE-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) -; MODULE-NEXT: [[PTR1:%.*]] = alloca i32, align 128 -; MODULE-NEXT: [[PTR2:%.*]] = alloca i32, align 128 -; MODULE-NEXT: [[PTR3:%.*]] = alloca i32, align 128 -; MODULE-NEXT: [[PTR4:%.*]] = alloca i32, align 128 -; MODULE-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR1]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) -; MODULE-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR2]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_1) -; MODULE-NEXT: call void @call_via_pointer_with_dead_args_internal_a(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR3]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) -; MODULE-NEXT: call void @call_via_pointer_with_dead_args_internal_b(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR4]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_2) -; MODULE-NEXT: ret void -; -; CGSCC_OLD-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_caller -; CGSCC_OLD-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) -; CGSCC_OLD-NEXT: [[PTR1:%.*]] = alloca i32, align 128 -; CGSCC_OLD-NEXT: [[PTR2:%.*]] = alloca i32, align 128 -; CGSCC_OLD-NEXT: [[PTR3:%.*]] = alloca i32, align 128 -; CGSCC_OLD-NEXT: [[PTR4:%.*]] = alloca i32, align 128 -; CGSCC_OLD-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR1]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) -; CGSCC_OLD-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR2]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_1) -; CGSCC_OLD-NEXT: call void @call_via_pointer_with_dead_args_internal_a(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR3]]) -; CGSCC_OLD-NEXT: call void @call_via_pointer_with_dead_args_internal_b(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR4]]) -; CGSCC_OLD-NEXT: ret void -; -; CGSCC_NEW-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_caller -; CGSCC_NEW-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) -; CGSCC_NEW-NEXT: [[PTR1:%.*]] = alloca i32, align 128 -; CGSCC_NEW-NEXT: [[PTR2:%.*]] = alloca i32, align 128 -; CGSCC_NEW-NEXT: [[PTR3:%.*]] = alloca i32, align 128 -; CGSCC_NEW-NEXT: [[PTR4:%.*]] = alloca i32, align 128 -; CGSCC_NEW-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR1]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) -; CGSCC_NEW-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR2]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_1) -; CGSCC_NEW-NEXT: call void @call_via_pointer_with_dead_args_internal_a(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR3]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) -; CGSCC_NEW-NEXT: call void @call_via_pointer_with_dead_args_internal_b(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR4]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_2) -; CGSCC_NEW-NEXT: ret void +; CHECK-LABEL: define {{[^@]+}}@call_via_pointer_with_dead_args_caller +; CHECK-SAME: (i32* [[A:%.*]], i32* [[B:%.*]]) +; CHECK-NEXT: [[PTR1:%.*]] = alloca i32, align 128 +; CHECK-NEXT: [[PTR2:%.*]] = alloca i32, align 128 +; CHECK-NEXT: [[PTR3:%.*]] = alloca i32, align 128 +; CHECK-NEXT: [[PTR4:%.*]] = alloca i32, align 128 +; CHECK-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR1]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) +; CHECK-NEXT: call void @call_via_pointer_with_dead_args(i32* [[A]], i32* nonnull align 128 dereferenceable(4) [[PTR2]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_1) +; CHECK-NEXT: call void @call_via_pointer_with_dead_args_internal_a(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR3]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer) +; CHECK-NEXT: call void @call_via_pointer_with_dead_args_internal_b(i32* [[B]], i32* nonnull align 128 dereferenceable(4) [[PTR4]], void (i32*, i32*, i32*, i64, i32**)* nofree nonnull @called_via_pointer_internal_2) +; CHECK-NEXT: ret void ; %ptr1 = alloca i32, align 128 %ptr2 = alloca i32, align 128 @@ -1297,26 +1714,12 @@ } ; FIXME: Figure out why the MODULE has the unused arguments still define internal void @called_via_pointer_internal_2(i32* %a, i32* %b, i32* %c, i64 %d, i32** %e) { -; MODULE-LABEL: define {{[^@]+}}@called_via_pointer_internal_2 -; MODULE-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]]) -; MODULE-NEXT: entry: -; MODULE-NEXT: tail call void @use_i32p(i32* [[A]]) -; MODULE-NEXT: tail call void @use_i32p(i32* [[A]]) -; MODULE-NEXT: ret void -; -; CGSCC_OLD-LABEL: define {{[^@]+}}@called_via_pointer_internal_2 -; CGSCC_OLD-SAME: (i32* [[A:%.*]]) -; CGSCC_OLD-NEXT: entry: -; CGSCC_OLD-NEXT: tail call void @use_i32p(i32* [[A]]) -; CGSCC_OLD-NEXT: tail call void @use_i32p(i32* [[A]]) -; CGSCC_OLD-NEXT: ret void -; -; CGSCC_NEW-LABEL: define {{[^@]+}}@called_via_pointer_internal_2 -; CGSCC_NEW-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]]) -; CGSCC_NEW-NEXT: entry: -; CGSCC_NEW-NEXT: tail call void @use_i32p(i32* [[A]]) -; CGSCC_NEW-NEXT: tail call void @use_i32p(i32* [[A]]) -; CGSCC_NEW-NEXT: ret void +; CHECK-LABEL: define {{[^@]+}}@called_via_pointer_internal_2 +; CHECK-SAME: (i32* [[A:%.*]], i32* nocapture nofree readnone [[B:%.*]], i32* nocapture nofree readnone [[C:%.*]], i64 [[D:%.*]], i32** nocapture nofree readnone [[E:%.*]]) +; CHECK-NEXT: entry: +; CHECK-NEXT: tail call void @use_i32p(i32* [[A]]) +; CHECK-NEXT: tail call void @use_i32p(i32* [[A]]) +; CHECK-NEXT: ret void ; entry: tail call void @use_i32p(i32* %a) @@ -1325,13 +1728,26 @@ } declare void @use_i32p(i32*) -; UTC_ARGS: --disable - ; Allow blockaddress users -; MODULE-NOT: @dead_with_blockaddress_users -; CGSCC_NEW-NOT: @dead_with_blockaddress_users -; CGSCC_OLD: @dead_with_blockaddress_users +; NOT_CGSCC_OPM-NOT: @dead_with_blockaddress_users define internal void @dead_with_blockaddress_users(i32* nocapture %pc) nounwind readonly { +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@dead_with_blockaddress_users +; 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*]* @dead_with_blockaddress_users.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 diff --git a/llvm/test/Transforms/Attributor/liveness_chains.ll b/llvm/test/Transforms/Attributor/liveness_chains.ll --- a/llvm/test/Transforms/Attributor/liveness_chains.ll +++ b/llvm/test/Transforms/Attributor/liveness_chains.ll @@ -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. diff --git a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll --- a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll +++ b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll @@ -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 @@ ; 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 @@ ; 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 @@ } ; 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 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/lvi-for-ashr.ll b/llvm/test/Transforms/Attributor/lvi-for-ashr.ll --- a/llvm/test/Transforms/Attributor/lvi-for-ashr.ll +++ b/llvm/test/Transforms/Attributor/lvi-for-ashr.ll @@ -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 @@ ; 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 diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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* @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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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]]) diff --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll --- a/llvm/test/Transforms/Attributor/misc.ll +++ b/llvm/test/Transforms/Attributor/misc.ll @@ -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 @@ } 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 @@ } 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 diff --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll --- a/llvm/test/Transforms/Attributor/noalias.ll +++ b/llvm/test/Transforms/Attributor/noalias.ll @@ -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 @@ ; 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ 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 @@ 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_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 @@ 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 @@ ; 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 @@ 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 @@ %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 @@ ; 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,22 +639,54 @@ 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 %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 @@ -441,13 +719,47 @@ ; CHECK-LABEL define internal void @test16_sub(i32* noalias %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 %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: @@ -467,6 +779,11 @@ } 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 } diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll --- a/llvm/test/Transforms/Attributor/nocapture-1.ll +++ b/llvm/test/Transforms/Attributor/nocapture-1.ll @@ -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 @@ 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 @@ 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 @@ 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 @@ } @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 @@ } @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*) +; We know that 'null' in AS 0 does not alias anything and cannot be captured. Though the latter is not qurried -> derived atm. 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: -; 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) 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 @@ ; 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) diff --git a/llvm/test/Transforms/Attributor/nocapture-2.ll b/llvm/test/Transforms/Attributor/nocapture-2.ll --- a/llvm/test/Transforms/Attributor/nocapture-2.ll +++ b/llvm/test/Transforms/Attributor/nocapture-2.ll @@ -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 @@ ; 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 @@ ; 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 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 @@ ; ; 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 @@ ; 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 @@ ; 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 @@ } 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 @@ } 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 @@ ; 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 @@ ; 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 @@ ; } ; ; 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 @@ ; } ; ; 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 @@ ; 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 @@ ; } ; ; 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 @@ ; } ; ; 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 @@ ; } ; ; 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 @@ ; } ; ; 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 @@ ; ; 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 @@ } 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 @@ ; 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 @@ ; ; 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 @@ 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 @@ 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 @@ ; 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 @@ 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 ; diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll --- a/llvm/test/Transforms/Attributor/nofree.ll +++ b/llvm/test/Transforms/Attributor/nofree.ll @@ -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 @@ ; 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 @@ ; 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 @@ ; } -; 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 @@ ; } -; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ -256,6 +334,12 @@ ; 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) ret void @@ -267,6 +351,12 @@ ; 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)] ret void @@ -287,6 +377,21 @@ ; 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) call void @use_i8_ptr(i8* %arg2) diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll --- a/llvm/test/Transforms/Attributor/nonnull.ll +++ b/llvm/test/Transforms/Attributor/nonnull.ll @@ -1,9 +1,9 @@ ; 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=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_OPM -; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_NPM -; Copied from Transforms/FunctoinAttrs/nonnull.ll +; 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 -; UTC_ARGS: --disable target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -11,21 +11,35 @@ ; Return a pointer trivially nonnull (call return attribute) define i8* @test1() { -; ATTRIBUTOR: define nonnull i8* @test1 +; CHECK-LABEL: define {{[^@]+}}@test1() +; CHECK-NEXT: [[RET:%.*]] = call nonnull i8* @ret_nonnull() +; CHECK-NEXT: ret i8* [[RET]] +; %ret = call i8* @ret_nonnull() ret i8* %ret } ; Return a pointer trivially nonnull (argument attribute) define i8* @test2(i8* nonnull %p) { -; ATTRIBUTOR: define nonnull i8* @test2 +; CHECK-LABEL: define {{[^@]+}}@test2 +; CHECK-SAME: (i8* nofree nonnull readnone returned "no-capture-maybe-returned" [[P:%.*]]) +; CHECK-NEXT: ret i8* [[P]] +; ret i8* %p } ; Given an SCC where one of the functions can not be marked nonnull, ; can we still mark the other one which is trivially nonnull define i8* @scc_binder(i1 %c) { -; ATTRIBUTOR: define noalias align 536870912 i8* @scc_binder +; CHECK-LABEL: define {{[^@]+}}@scc_binder +; CHECK-SAME: (i1 [[C:%.*]]) +; CHECK-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] +; CHECK: rec: +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @test3(i1 [[C]]) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret i8* null +; br i1 %c, label %rec, label %end rec: call i8* @test3(i1 %c) @@ -35,7 +49,12 @@ } define i8* @test3(i1 %c) { -; ATTRIBUTOR: define nonnull i8* @test3 +; CHECK-LABEL: define {{[^@]+}}@test3 +; CHECK-SAME: (i1 [[C:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @scc_binder(i1 [[C]]) +; CHECK-NEXT: [[RET:%.*]] = call nonnull i8* @ret_nonnull() +; CHECK-NEXT: ret i8* [[RET]] +; call i8* @scc_binder(i1 %c) %ret = call i8* @ret_nonnull() ret i8* %ret @@ -45,13 +64,17 @@ ; nonnull if neither can ever return null. (In this case, they ; just never return period.) define i8* @test4_helper() { -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4_helper +; CHECK-LABEL: define {{[^@]+}}@test4_helper() +; CHECK-NEXT: unreachable +; %ret = call i8* @test4() ret i8* %ret } define i8* @test4() { -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test4 +; CHECK-LABEL: define {{[^@]+}}@test4() +; CHECK-NEXT: unreachable +; %ret = call i8* @test4_helper() ret i8* %ret } @@ -59,7 +82,14 @@ ; Given a mutual recursive set of functions which *can* return null ; make sure we haven't marked them as nonnull. define i8* @test5_helper(i1 %c) { -; ATTRIBUTOR: define noalias align 536870912 i8* @test5_helper +; CHECK-LABEL: define {{[^@]+}}@test5_helper +; CHECK-SAME: (i1 [[C:%.*]]) +; CHECK-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] +; CHECK: rec: +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: ret i8* null +; br i1 %c, label %rec, label %end rec: %ret = call i8* @test5(i1 %c) @@ -69,15 +99,26 @@ } define i8* @test5(i1 %c) { -; ATTRIBUTOR: define noalias align 536870912 i8* @test5 +; CHECK-LABEL: define {{[^@]+}}@test5 +; CHECK-SAME: (i1 [[C:%.*]]) +; CHECK-NEXT: ret i8* null +; %ret = call i8* @test5_helper(i1 %c) ret i8* %ret } ; Local analysis, but going through a self recursive phi -; ATTRIBUTOR: Function Attrs: noreturn -; ATTRIBUTOR: define noalias nonnull align 536870912 dereferenceable(4294967295) i8* @test6a() +; CHECK: Function Attrs: noreturn define i8* @test6a() { +; CHECK-LABEL: define {{[^@]+}}@test6a() +; CHECK-NEXT: entry: +; CHECK-NEXT: [[RET:%.*]] = call i8* @ret_nonnull() +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: unreachable +; CHECK: exit: +; CHECK-NEXT: unreachable +; entry: %ret = call i8* @ret_nonnull() br label %loop @@ -88,8 +129,18 @@ ret i8* %phi } -; ATTRIBUTOR: define nonnull i8* @test6b(i1 %c) define i8* @test6b(i1 %c) { +; CHECK-LABEL: define {{[^@]+}}@test6b +; CHECK-SAME: (i1 [[C:%.*]]) +; CHECK-NEXT: entry: +; CHECK-NEXT: [[RET:%.*]] = call nonnull i8* @ret_nonnull() +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[PHI:%.*]] = phi i8* [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ] +; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i8* [[PHI]] +; entry: %ret = call i8* @ret_nonnull() br label %loop @@ -100,28 +151,44 @@ ret i8* %phi } -; ATTRIBUTOR: define i8* @test7 define i8* @test7(i8* %a) { +; CHECK-LABEL: define {{[^@]+}}@test7 +; CHECK-SAME: (i8* nofree readnone returned "no-capture-maybe-returned" [[A:%.*]]) +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, i8* [[A]], i64 0 +; CHECK-NEXT: ret i8* [[B]] +; %b = getelementptr inbounds i8, i8* %a, i64 0 ret i8* %b } -; ATTRIBUTOR: define nonnull i8* @test8 define i8* @test8(i8* %a) { +; CHECK-LABEL: define {{[^@]+}}@test8 +; CHECK-SAME: (i8* nofree readnone "no-capture-maybe-returned" [[A:%.*]]) +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, i8* [[A]], i64 1 +; CHECK-NEXT: ret i8* [[B]] +; %b = getelementptr inbounds i8, i8* %a, i64 1 ret i8* %b } -; ATTRIBUTOR: define i8* @test9 define i8* @test9(i8* %a, i64 %n) { +; CHECK-LABEL: define {{[^@]+}}@test9 +; CHECK-SAME: (i8* nofree readnone "no-capture-maybe-returned" [[A:%.*]], i64 [[N:%.*]]) +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, i8* [[A]], i64 [[N]] +; CHECK-NEXT: ret i8* [[B]] +; %b = getelementptr inbounds i8, i8* %a, i64 %n ret i8* %b } declare void @llvm.assume(i1) -; ATTRIBUTOR_OPM: define i8* @test10 -; ATTRIBUTOR_NPM: define nonnull i8* @test10 define i8* @test10(i8* %a, i64 %n) { +; CHECK-LABEL: define {{[^@]+}}@test10 +; CHECK-SAME: (i8* nofree readnone "no-capture-maybe-returned" [[A:%.*]], i64 [[N:%.*]]) +; CHECK-NEXT: call void @llvm.assume(i1 undef) +; CHECK-NEXT: [[B:%.*]] = getelementptr inbounds i8, i8* [[A]], i64 [[N]] +; CHECK-NEXT: ret i8* [[B]] +; %cmp = icmp ne i64 %n, 0 call void @llvm.assume(i1 %cmp) %b = getelementptr inbounds i8, i8* %a, i64 %n @@ -133,8 +200,18 @@ ; return p? p: nonnull(); ; } ; FIXME: missing nonnull -; ATTRIBUTOR: define i8* @test11 define i8* @test11(i8*) local_unnamed_addr { +; CHECK-LABEL: define {{[^@]+}}@test11 +; CHECK-SAME: (i8* [[TMP0:%.*]]) local_unnamed_addr +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null +; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] +; CHECK: 3: +; CHECK-NEXT: [[TMP4:%.*]] = tail call i8* @ret_nonnull() +; CHECK-NEXT: br label [[TMP5]] +; CHECK: 5: +; CHECK-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] +; CHECK-NEXT: ret i8* [[TMP6]] +; %2 = icmp eq i8* %0, null br i1 %2, label %3, label %5 @@ -151,8 +228,11 @@ ; Simple CallSite Test declare void @test12_helper(i8*) define void @test12(i8* nonnull %a) { -; ATTRIBUTOR: define void @test12(i8* nonnull %a) -; ATTRIBUTOR-NEXT: tail call void @test12_helper(i8* nonnull %a) +; CHECK-LABEL: define {{[^@]+}}@test12 +; CHECK-SAME: (i8* nonnull [[A:%.*]]) +; CHECK-NEXT: tail call void @test12_helper(i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; tail call void @test12_helper(i8* %a) ret void } @@ -161,6 +241,13 @@ ; Simple Argument Tests declare i8* @unknown() define void @test13_helper() { +; CHECK-LABEL: define {{[^@]+}}@test13_helper() +; CHECK-NEXT: [[NONNULLPTR:%.*]] = tail call nonnull i8* @ret_nonnull() +; CHECK-NEXT: [[MAYBENULLPTR:%.*]] = tail call i8* @unknown() +; CHECK-NEXT: tail call void @test13(i8* noalias nofree nonnull readnone [[NONNULLPTR]], i8* noalias nofree nonnull readnone [[NONNULLPTR]], i8* noalias nofree readnone [[MAYBENULLPTR]]) +; CHECK-NEXT: tail call void @test13(i8* noalias nofree nonnull readnone [[NONNULLPTR]], i8* noalias nofree readnone [[MAYBENULLPTR]], i8* noalias nofree nonnull readnone [[NONNULLPTR]]) +; CHECK-NEXT: ret void +; %nonnullptr = tail call i8* @ret_nonnull() %maybenullptr = tail call i8* @unknown() tail call void @test13(i8* %nonnullptr, i8* %nonnullptr, i8* %maybenullptr) @@ -168,7 +255,20 @@ ret void } define internal void @test13(i8* %a, i8* %b, i8* %c) { -; ATTRIBUTOR: define internal void @test13(i8* noalias nocapture nofree nonnull readnone %a, i8* noalias nocapture nofree readnone %b, i8* noalias nocapture nofree readnone %c) +; IS__TUNIT____-LABEL: define {{[^@]+}}@test13 +; IS__TUNIT____-SAME: (i8* noalias nocapture nofree nonnull readnone [[A:%.*]], i8* noalias nocapture nofree readnone [[B:%.*]], i8* noalias nocapture nofree readnone [[C:%.*]]) +; IS__TUNIT____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree nonnull readnone [[A]]) +; IS__TUNIT____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[B]]) +; IS__TUNIT____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[C]]) +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@test13 +; IS__CGSCC____-SAME: (i8* nocapture nofree readnone [[A:%.*]], i8* nocapture nofree readnone [[B:%.*]], i8* nocapture nofree readnone [[C:%.*]]) +; IS__CGSCC____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[A]]) +; IS__CGSCC____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[B]]) +; IS__CGSCC____-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[C]]) +; IS__CGSCC____-NEXT: ret void +; call void @use_i8_ptr(i8* %a) call void @use_i8_ptr(i8* %b) call void @use_i8_ptr(i8* %c) @@ -191,7 +291,27 @@ define internal i32* @f1(i32* %arg) { ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: define internal nonnull i32* @f1(i32* nofree readonly %arg) +; CHECK-LABEL: define {{[^@]+}}@f1 +; CHECK-SAME: (i32* nofree readonly [[ARG:%.*]]) +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = icmp eq i32* [[ARG]], null +; CHECK-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARG]], align 4 +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0 +; CHECK-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]] +; CHECK: bb4: +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 1 +; CHECK-NEXT: [[TMP5B:%.*]] = tail call nonnull i32* @f3(i32* nofree nonnull readonly [[TMP5]]) +; CHECK-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, i32* [[TMP5B]], i64 -1 +; CHECK-NEXT: br label [[BB9]] +; CHECK: bb6: +; CHECK-NEXT: [[TMP7:%.*]] = tail call nonnull i32* @f2(i32* nofree nonnull readonly align 4 dereferenceable(4) [[ARG]]) +; CHECK-NEXT: ret i32* [[TMP7]] +; CHECK: bb9: +; CHECK-NEXT: [[TMP10:%.*]] = phi i32* [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to i32*), [[BB:%.*]] ] +; CHECK-NEXT: ret i32* [[TMP10]] +; bb: %tmp = icmp eq i32* %arg, null @@ -204,13 +324,11 @@ bb4: ; preds = %bb1 %tmp5 = getelementptr inbounds i32, i32* %arg, i64 1 -; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* nofree nonnull readonly %tmp5) %tmp5b = tail call i32* @f3(i32* %tmp5) %tmp5c = getelementptr inbounds i32, i32* %tmp5b, i64 -1 br label %bb9 bb6: ; preds = %bb1 -; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg) %tmp7 = tail call i32* @f2(i32* %arg) ret i32* %tmp7 @@ -220,26 +338,38 @@ } define internal i32* @f2(i32* %arg) { -; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg) +; CHECK-LABEL: define {{[^@]+}}@f2 +; CHECK-SAME: (i32* nofree nonnull readonly align 4 dereferenceable(4) [[ARG:%.*]]) +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = tail call nonnull i32* @f1(i32* nofree nonnull readonly align 4 dereferenceable(4) [[ARG]]) +; CHECK-NEXT: ret i32* [[TMP]] +; bb: -; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* nofree nonnull readonly align 4 dereferenceable(4) %arg) %tmp = tail call i32* @f1(i32* %arg) ret i32* %tmp } define dso_local noalias i32* @f3(i32* %arg) { ; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg) -; ATTRIBUTOR: define dso_local noalias nonnull i32* @f3(i32* nofree readonly %arg) +; CHECK-LABEL: define {{[^@]+}}@f3 +; CHECK-SAME: (i32* nofree readonly [[ARG:%.*]]) +; CHECK-NEXT: bb: +; CHECK-NEXT: [[TMP:%.*]] = call nonnull i32* @f1(i32* nofree readonly [[ARG]]) +; CHECK-NEXT: ret i32* [[TMP]] +; bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* nofree readonly %arg) %tmp = call i32* @f1(i32* %arg) ret i32* %tmp } ; TEST 15 define void @f15(i8* %arg) { -; ATTRIBUTOR: tail call void @use1(i8* nonnull dereferenceable(4) %arg) +; CHECK-LABEL: define {{[^@]+}}@f15 +; CHECK-SAME: (i8* nonnull dereferenceable(4) [[ARG:%.*]]) +; CHECK-NEXT: tail call void @use1(i8* nonnull dereferenceable(4) [[ARG]]) +; CHECK-NEXT: ret void +; tail call void @use1(i8* dereferenceable(4) %arg) ret void @@ -256,7 +386,17 @@ ; fun2(nonnull %a, %b) ; We can say that %a is nonnull but %b is not. define void @f16(i8* %a, i8 * %b, i8 %c) { -; ATTRIBUTOR: define void @f16(i8* nonnull %a, i8* %b, i8 %c) +; CHECK-LABEL: define {{[^@]+}}@f16 +; CHECK-SAME: (i8* nonnull [[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 @fun2(i8* nonnull [[A]], i8* nonnull [[B]]) +; CHECK-NEXT: ret void +; CHECK: if.else: +; CHECK-NEXT: tail call void @fun2(i8* nonnull [[A]], i8* [[B]]) +; CHECK-NEXT: ret void +; %cmp = icmp eq i8 %c, 0 br i1 %cmp, label %if.then, label %if.else if.then: @@ -274,7 +414,20 @@ ; fun1(nonnull %a) ; We can say that %a is nonnull define void @f17(i8* %a, i8 %c) { -; ATTRIBUTOR: define void @f17(i8* nonnull %a, i8 %c) +; CHECK-LABEL: define {{[^@]+}}@f17 +; CHECK-SAME: (i8* nonnull [[A:%.*]], 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 @fun0() +; CHECK-NEXT: br label [[CONT:%.*]] +; CHECK: if.else: +; CHECK-NEXT: tail call void @fun0() +; CHECK-NEXT: br label [[CONT]] +; CHECK: cont: +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; %cmp = icmp eq i8 %c, 0 br i1 %cmp, label %if.then, label %if.else if.then: @@ -299,7 +452,29 @@ ; fun1(nonnull %a) define void @f18(i8* %a, i8* %b, i8 %c) { -; ATTRIBUTOR: define void @f18(i8* nonnull %a, i8* %b, i8 %c) +; CHECK-LABEL: define {{[^@]+}}@f18 +; CHECK-SAME: (i8* nonnull [[A:%.*]], i8* [[B:%.*]], i8 [[C:%.*]]) +; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0 +; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: tail call void @fun0() +; CHECK-NEXT: br label [[CONT:%.*]] +; CHECK: if.else: +; CHECK-NEXT: tail call void @fun0() +; CHECK-NEXT: br label [[CONT]] +; CHECK: cont: +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1 +; CHECK-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]] +; CHECK: cont.then: +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[B]]) +; CHECK-NEXT: br label [[CONT2:%.*]] +; CHECK: cont.else: +; CHECK-NEXT: tail call void @fun0() +; CHECK-NEXT: br label [[CONT2]] +; CHECK: cont2: +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; %cmp1 = icmp eq i8 %c, 0 br i1 %cmp1, label %if.then, label %if.else if.then: @@ -325,7 +500,20 @@ ; TEST 19: Loop define void @f19(i8* %a, i8* %b, i8 %c) { -; ATTRIBUTOR: define void @f19(i8* %a, i8* nonnull %b, i8 %c) +; CHECK-LABEL: define {{[^@]+}}@f19 +; CHECK-SAME: (i8* [[A:%.*]], i8* nonnull [[B:%.*]], i8 [[C:%.*]]) +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 0 +; CHECK-NEXT: br i1 [[CMP2]], label [[LOOP_BODY:%.*]], label [[LOOP_EXIT:%.*]] +; CHECK: loop.body: +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[B]]) +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[A]]) +; CHECK-NEXT: br label [[LOOP_HEADER]] +; CHECK: loop.exit: +; CHECK-NEXT: tail call void @fun1(i8* nonnull [[B]]) +; CHECK-NEXT: ret void +; br label %loop.header loop.header: %cmp2 = icmp eq i8 %c, 0 @@ -354,10 +542,12 @@ ; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute. define void @parent1(i8* %a, i8* %b, i8* %c) { -; ATTRIBUTOR-LABEL: @parent1(i8* %a, i8* %b, i8* %c) -; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %a, i8* %b) -; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a) -; ATTRIBUTOR-NEXT: ret void +; CHECK-LABEL: define {{[^@]+}}@parent1 +; CHECK-SAME: (i8* [[A:%.*]], i8* [[B:%.*]], i8* [[C:%.*]]) +; CHECK-NEXT: call void @use3(i8* [[C]], i8* [[A]], i8* [[B]]) +; CHECK-NEXT: call void @use3nonnull(i8* nonnull [[B]], i8* nonnull [[C]], i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; call void @use3(i8* %c, i8* %a, i8* %b) call void @use3nonnull(i8* %b, i8* %c, i8* %a) ret void @@ -366,12 +556,13 @@ ; Extend non-null to parent for all arguments. define void @parent2(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: define {{[^@]+}}@parent2 +; CHECK-SAME: (i8* nonnull [[A:%.*]], i8* nonnull [[B:%.*]], i8* nonnull [[C:%.*]]) +; CHECK-NEXT: call void @use3nonnull(i8* nonnull [[B]], i8* nonnull [[C]], i8* nonnull [[A]]) +; CHECK-NEXT: call void @use3(i8* nonnull [[C]], i8* nonnull [[A]], i8* nonnull [[B]]) +; CHECK-NEXT: ret void +; -; ATTRIBUTOR-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use3nonnull(i8* nonnull %b, i8* nonnull %c, i8* nonnull %a) -; ATTRIBUTOR-NEXT: call void @use3(i8* nonnull %c, i8* nonnull %a, i8* nonnull %b) - -; ATTRIBUTOR-NEXT: ret void call void @use3nonnull(i8* %b, i8* %c, i8* %a) call void @use3(i8* %c, i8* %a, i8* %b) ret void @@ -380,12 +571,13 @@ ; Extend non-null to parent for 1st argument. define void @parent3(i8* %a, i8* %b, i8* %c) { +; CHECK-LABEL: define {{[^@]+}}@parent3 +; CHECK-SAME: (i8* nonnull [[A:%.*]], i8* [[B:%.*]], i8* [[C:%.*]]) +; CHECK-NEXT: call void @use1nonnull(i8* nonnull [[A]]) +; CHECK-NEXT: call void @use3(i8* [[C]], i8* [[B]], i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; -; ATTRIBUTOR-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; ATTRIBUTOR-NEXT: call void @use3(i8* %c, i8* %b, i8* nonnull %a) - -; ATTRIBUTOR-NEXT: ret void call void @use1nonnull(i8* %a) call void @use3(i8* %c, i8* %b, i8* %a) @@ -395,17 +587,15 @@ ; Extend non-null to parent for last 2 arguments. define void @parent4(i8* %a, i8* %b, i8* %c) { -; CHECK-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c) -; CHECK-NEXT: call void @use2nonnull(i8* %c, i8* %b) -; CHECK-NEXT: call void @use2(i8* %a, i8* %c) -; CHECK-NEXT: call void @use1(i8* %b) +; CHECK-LABEL: define {{[^@]+}}@parent4 +; CHECK-SAME: (i8* [[A:%.*]], i8* nonnull [[B:%.*]], i8* nonnull [[C:%.*]]) +; CHECK-NEXT: call void @use2nonnull(i8* nonnull [[C]], i8* nonnull [[B]]) +; CHECK-NEXT: call void @use2(i8* [[A]], i8* nonnull [[C]]) +; CHECK-NEXT: call void @use1(i8* nonnull [[B]]) +; CHECK-NEXT: ret void +; -; ATTRIBUTOR-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use2nonnull(i8* nonnull %c, i8* nonnull %b) -; ATTRIBUTOR-NEXT: call void @use2(i8* %a, i8* nonnull %c) -; ATTRIBUTOR-NEXT: call void @use1(i8* nonnull %b) -; ATTRIBUTOR: ret void call void @use2nonnull(i8* %c, i8* %b) call void @use2(i8* %a, i8* %c) @@ -418,13 +608,15 @@ ; because it would incorrectly propagate the wrong information to its callers. define void @parent5(i8* %a, i1 %a_is_notnull) { -; ATTRIBUTOR: @parent5(i8* %a, i1 %a_is_notnull) -; ATTRIBUTOR-NEXT: br i1 %a_is_notnull, label %t, label %f -; ATTRIBUTOR: t: -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; ATTRIBUTOR-NEXT: ret void -; ATTRIBUTOR: f: -; ATTRIBUTOR-NEXT: ret void +; CHECK-LABEL: define {{[^@]+}}@parent5 +; CHECK-SAME: (i8* [[A:%.*]], i1 [[A_IS_NOTNULL:%.*]]) +; CHECK-NEXT: br i1 [[A_IS_NOTNULL]], label [[T:%.*]], label [[F:%.*]] +; CHECK: t: +; CHECK-NEXT: call void @use1nonnull(i8* nonnull [[A]]) +; CHECK-NEXT: ret void +; CHECK: f: +; CHECK-NEXT: ret void +; br i1 %a_is_notnull, label %t, label %f t: @@ -438,10 +630,12 @@ ; The volatile load can't trap, so we can guarantee that we'll get to the call. define i8 @parent6(i8* %a, i8* %b) { -; ATTRIBUTOR-LABEL: @parent6(i8* nonnull %a, i8* %b) -; ATTRIBUTOR-NEXT: [[C:%.*]] = load volatile i8, i8* %b -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) -; ATTRIBUTOR-NEXT: ret i8 [[C]] +; CHECK-LABEL: define {{[^@]+}}@parent6 +; CHECK-SAME: (i8* nonnull [[A:%.*]], i8* [[B:%.*]]) +; CHECK-NEXT: [[C:%.*]] = load volatile i8, i8* [[B]] +; CHECK-NEXT: call void @use1nonnull(i8* nonnull [[A]]) +; CHECK-NEXT: ret i8 [[C]] +; %c = load volatile i8, i8* %b call void @use1nonnull(i8* %a) @@ -451,14 +645,14 @@ ; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent. define i8 @parent7(i8* %a) { +; CHECK-LABEL: define {{[^@]+}}@parent7 +; CHECK-SAME: (i8* nonnull [[A:%.*]]) +; CHECK-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* nonnull readonly [[A]]) +; CHECK-NEXT: call void @use1nonnull(i8* nonnull [[A]]) +; CHECK-NEXT: ret i8 [[RET]] +; -; ATTRIBUTOR-LABEL: @parent7(i8* nonnull %a) -; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* nonnull readonly %a) -; ATTRIBUTOR-NEXT: call void @use1nonnull(i8* nonnull %a) - -; ATTRIBUTOR-NEXT: ret i8 [[RET]] - %ret = call i8 @use1safecall(i8* %a) call void @use1nonnull(i8* %a) ret i8 %ret @@ -469,17 +663,32 @@ declare i32 @esfp(...) define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){ -; ATTRIBUTOR-LABEL: @parent8(i8* nonnull %a, i8* nocapture nofree readnone %bogus1, i8* nonnull %b) -; ATTRIBUTOR-NEXT: entry: -; ATTRIBUTOR-NEXT: invoke void @use2nonnull(i8* nonnull %a, i8* nonnull %b) -; ATTRIBUTOR-NEXT: to label %cont unwind label %exc -; ATTRIBUTOR: cont: -; ATTRIBUTOR-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null -; ATTRIBUTOR-NEXT: ret i1 [[NULL_CHECK]] -; ATTRIBUTOR: exc: -; ATTRIBUTOR-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } -; ATTRIBUTOR-NEXT: filter [0 x i8*] zeroinitializer -; ATTRIBUTOR-NEXT: unreachable +; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@parent8 +; NOT_CGSCC_OPM-SAME: (i8* nonnull [[A:%.*]], i8* nocapture nofree readnone [[BOGUS1:%.*]], i8* nonnull [[B:%.*]]) #4 personality i8* bitcast (i32 (...)* @esfp to i8*) +; NOT_CGSCC_OPM-NEXT: entry: +; NOT_CGSCC_OPM-NEXT: invoke void @use2nonnull(i8* nonnull [[A]], i8* nonnull [[B]]) +; NOT_CGSCC_OPM-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]] +; NOT_CGSCC_OPM: cont: +; NOT_CGSCC_OPM-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[B]], null +; NOT_CGSCC_OPM-NEXT: ret i1 [[NULL_CHECK]] +; NOT_CGSCC_OPM: exc: +; NOT_CGSCC_OPM-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } +; NOT_CGSCC_OPM-NEXT: filter [0 x i8*] zeroinitializer +; NOT_CGSCC_OPM-NEXT: unreachable +; +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@parent8 +; IS__CGSCC_OPM-SAME: (i8* nonnull [[A:%.*]], i8* nocapture nofree readnone [[BOGUS1:%.*]], i8* nonnull [[B:%.*]]) #5 personality i8* bitcast (i32 (...)* @esfp to i8*) +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: invoke void @use2nonnull(i8* nonnull [[A]], i8* nonnull [[B]]) +; IS__CGSCC_OPM-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]] +; IS__CGSCC_OPM: cont: +; IS__CGSCC_OPM-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[B]], null +; IS__CGSCC_OPM-NEXT: ret i1 [[NULL_CHECK]] +; IS__CGSCC_OPM: exc: +; IS__CGSCC_OPM-NEXT: [[LP:%.*]] = landingpad { i8*, i32 } +; IS__CGSCC_OPM-NEXT: filter [0 x i8*] zeroinitializer +; IS__CGSCC_OPM-NEXT: unreachable +; entry: invoke void @use2nonnull(i8* %a, i8* %b) @@ -495,83 +704,138 @@ unreachable } -; ATTRIBUTOR: define nonnull i32* @gep1( define i32* @gep1(i32* %p) { +; CHECK-LABEL: define {{[^@]+}}@gep1 +; CHECK-SAME: (i32* nofree readnone "no-capture-maybe-returned" [[P:%.*]]) +; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 1 +; CHECK-NEXT: ret i32* [[Q]] +; %q = getelementptr inbounds i32, i32* %p, i32 1 ret i32* %q } define i32* @gep1_no_null_opt(i32* %p) #0 { ; Should't be able to derive nonnull based on gep. -; ATTRIBUTOR: define i32* @gep1_no_null_opt( +; CHECK-LABEL: define {{[^@]+}}@gep1_no_null_opt +; CHECK-SAME: (i32* nofree readnone "no-capture-maybe-returned" [[P:%.*]]) +; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 1 +; CHECK-NEXT: ret i32* [[Q]] +; %q = getelementptr inbounds i32, i32* %p, i32 1 ret i32* %q } -; ATTRIBUTOR: define i32 addrspace(3)* @gep2( define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) { +; CHECK-LABEL: define {{[^@]+}}@gep2 +; CHECK-SAME: (i32 addrspace(3)* nofree readnone "no-capture-maybe-returned" [[P:%.*]]) +; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds i32, i32 addrspace(3)* [[P]], i32 1 +; CHECK-NEXT: ret i32 addrspace(3)* [[Q]] +; %q = getelementptr inbounds i32, i32 addrspace(3)* %p, i32 1 ret i32 addrspace(3)* %q } ; FIXME: We should propagate dereferenceable here but *not* nonnull -; ATTRIBUTOR: define dereferenceable_or_null(4) i32 addrspace(3)* @as(i32 addrspace(3)* nofree readnone returned dereferenceable(4) dereferenceable_or_null(4) %p) define i32 addrspace(3)* @as(i32 addrspace(3)* dereferenceable(4) %p) { +; CHECK-LABEL: define {{[^@]+}}@as +; CHECK-SAME: (i32 addrspace(3)* nofree readnone returned dereferenceable(4) dereferenceable_or_null(4) "no-capture-maybe-returned" [[P:%.*]]) +; CHECK-NEXT: ret i32 addrspace(3)* [[P]] +; ret i32 addrspace(3)* %p } -; ATTRIBUTOR-NOT: @g2() +; CHECK-NOT: @g2() define internal i32* @g2() { +; IS__CGSCC____-LABEL: define {{[^@]+}}@g2() +; IS__CGSCC____-NEXT: ret i32* inttoptr (i64 4 to i32*) +; ret i32* inttoptr (i64 4 to i32*) } -; ATTRIBUTOR: define nonnull align 4 i32* @g1() -; ATTRIBUTOR: ret i32* inttoptr (i64 4 to i32*) define i32* @g1() { - %c = call i32* @g2() +; CHECK-LABEL: define {{[^@]+}}@g1() +; CHECK-NEXT: ret i32* inttoptr (i64 4 to i32*) +; + %c = call i32* @g2() ret i32* %c } declare void @use_i32_ptr(i32* readnone nocapture) nounwind -; ATTRIBUTOR: define internal void @called_by_weak(i32* noalias nocapture nonnull readnone %a) define internal void @called_by_weak(i32* %a) { +; IS__TUNIT____-LABEL: define {{[^@]+}}@called_by_weak +; IS__TUNIT____-SAME: (i32* noalias nocapture nonnull readnone [[A:%.*]]) +; IS__TUNIT____-NEXT: call void @use_i32_ptr(i32* noalias nocapture nonnull readnone [[A]]) +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@called_by_weak +; IS__CGSCC____-SAME: (i32* nocapture nonnull readnone [[A:%.*]]) +; IS__CGSCC____-NEXT: call void @use_i32_ptr(i32* noalias nocapture nonnull readnone [[A]]) +; IS__CGSCC____-NEXT: ret void +; call void @use_i32_ptr(i32* %a) ret void } ; Check we do not annotate the function interface of this weak function. -; ATTRIBUTOR: define weak_odr void @weak_caller(i32* nonnull %a) define weak_odr void @weak_caller(i32* nonnull %a) { +; CHECK-LABEL: define {{[^@]+}}@weak_caller +; CHECK-SAME: (i32* nonnull [[A:%.*]]) +; CHECK-NEXT: call void @called_by_weak(i32* noalias nonnull readnone [[A]]) +; CHECK-NEXT: ret void +; call void @called_by_weak(i32* %a) ret void } ; Expect nonnull -; ATTRIBUTOR: define internal void @control(i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) %a) define internal void @control(i32* dereferenceable(4) %a) { +; IS__TUNIT____-LABEL: define {{[^@]+}}@control +; IS__TUNIT____-SAME: (i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) [[A:%.*]]) +; IS__TUNIT____-NEXT: call void @use_i32_ptr(i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) [[A]]) +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____-LABEL: define {{[^@]+}}@control +; IS__CGSCC____-SAME: (i32* nocapture nonnull readnone align 16 dereferenceable(8) [[A:%.*]]) +; IS__CGSCC____-NEXT: call void @use_i32_ptr(i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) [[A]]) +; IS__CGSCC____-NEXT: ret void +; call void @use_i32_ptr(i32* %a) ret void } ; Avoid nonnull as we do not touch naked functions -; ATTRIBUTOR: define internal void @naked(i32* dereferenceable(4) %a) define internal void @naked(i32* dereferenceable(4) %a) naked { +; CHECK-LABEL: define {{[^@]+}}@naked +; CHECK-SAME: (i32* dereferenceable(4) [[A:%.*]]) +; CHECK-NEXT: call void @use_i32_ptr(i32* [[A]]) +; CHECK-NEXT: ret void +; call void @use_i32_ptr(i32* %a) ret void } ; Avoid nonnull as we do not touch optnone -; ATTRIBUTOR: define internal void @optnone(i32* dereferenceable(4) %a) define internal void @optnone(i32* dereferenceable(4) %a) optnone noinline { +; CHECK-LABEL: define {{[^@]+}}@optnone +; CHECK-SAME: (i32* dereferenceable(4) [[A:%.*]]) +; CHECK-NEXT: call void @use_i32_ptr(i32* [[A]]) +; CHECK-NEXT: ret void +; call void @use_i32_ptr(i32* %a) ret void } define void @make_live(i32* nonnull dereferenceable(8) %a) { +; CHECK-LABEL: define {{[^@]+}}@make_live +; CHECK-SAME: (i32* nonnull align 16 dereferenceable(8) [[A:%.*]]) +; CHECK-NEXT: call void @naked(i32* nonnull align 16 dereferenceable(8) [[A]]) +; CHECK-NEXT: call void @control(i32* noalias nonnull readnone align 16 dereferenceable(8) [[A]]) +; CHECK-NEXT: call void @optnone(i32* nonnull align 16 dereferenceable(8) [[A]]) +; CHECK-NEXT: ret void +; call void @naked(i32* nonnull dereferenceable(8) align 16 %a) call void @control(i32* nonnull dereferenceable(8) align 16 %a) call void @optnone(i32* nonnull dereferenceable(8) align 16 %a) ret void } -; UTC_ARGS: --enable ;int f(int *u, int n){ ; for(int i = 0;i<n;i++){ @@ -583,20 +847,20 @@ declare i32 @g(i32*) willreturn nounwind define i32 @nonnull_exec_ctx_1(i32* %a, i32 %b) { ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1 -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]]) -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] +; CHECK-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1 +; CHECK-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) +; CHECK-NEXT: en: +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 +; CHECK-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] +; CHECK: ex: +; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) +; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK: hd: +; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] +; CHECK-NEXT: tail call void @h(i32* [[A]]) +; CHECK-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] +; CHECK-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -616,22 +880,22 @@ define i32 @nonnull_exec_ctx_1b(i32* %a, i32 %b) { ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b -; ATTRIBUTOR-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* [[A]]) -; ATTRIBUTOR-NEXT: br label [[HD2]] -; ATTRIBUTOR: hd2: -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] +; CHECK-LABEL: define {{[^@]+}}@nonnull_exec_ctx_1b +; CHECK-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) +; CHECK-NEXT: en: +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 +; CHECK-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] +; CHECK: ex: +; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) +; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK: hd: +; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] +; CHECK-NEXT: tail call void @h(i32* [[A]]) +; CHECK-NEXT: br label [[HD2]] +; CHECK: hd2: +; CHECK-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] +; CHECK-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -654,20 +918,20 @@ define i32 @nonnull_exec_ctx_2(i32* %a, i32 %b) willreturn nounwind { ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2 -; ATTRIBUTOR-SAME: (i32* nonnull [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] +; CHECK-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2 +; CHECK-SAME: (i32* nonnull [[A:%.*]], i32 [[B:%.*]]) +; CHECK-NEXT: en: +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 +; CHECK-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] +; CHECK: ex: +; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) +; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK: hd: +; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ] +; CHECK-NEXT: tail call void @h(i32* nonnull [[A]]) +; CHECK-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] +; CHECK-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -687,22 +951,22 @@ define i32 @nonnull_exec_ctx_2b(i32* %a, i32 %b) willreturn nounwind { ; -; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b -; ATTRIBUTOR-SAME: (i32* nonnull [[A:%.*]], i32 [[B:%.*]]) -; ATTRIBUTOR-NEXT: en: -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] -; ATTRIBUTOR: ex: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: ret i32 [[TMP5]] -; ATTRIBUTOR: hd: -; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] -; ATTRIBUTOR-NEXT: tail call void @h(i32* nonnull [[A]]) -; ATTRIBUTOR-NEXT: br label [[HD2]] -; ATTRIBUTOR: hd2: -; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] -; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] +; CHECK-LABEL: define {{[^@]+}}@nonnull_exec_ctx_2b +; CHECK-SAME: (i32* nonnull [[A:%.*]], i32 [[B:%.*]]) +; CHECK-NEXT: en: +; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0 +; CHECK-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]] +; CHECK: ex: +; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @g(i32* nonnull [[A]]) +; CHECK-NEXT: ret i32 [[TMP5]] +; CHECK: hd: +; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ] +; CHECK-NEXT: tail call void @h(i32* nonnull [[A]]) +; CHECK-NEXT: br label [[HD2]] +; CHECK: hd2: +; CHECK-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1 +; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]] +; CHECK-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]] ; en: %tmp3 = icmp eq i32 %b, 0 @@ -728,22 +992,22 @@ ; FIXME: the sink argument should be marked nonnull as in @PR43833_simple. define void @PR43833(i32* %0, i32 %1) { -; ATTRIBUTOR-LABEL: define {{[^@]+}}@PR43833 -; ATTRIBUTOR-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) -; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1]], 1 -; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; ATTRIBUTOR: 4: -; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] -; ATTRIBUTOR-NEXT: br label [[TMP8:%.*]] -; ATTRIBUTOR: 7: -; ATTRIBUTOR-NEXT: ret void -; ATTRIBUTOR: 8: -; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; ATTRIBUTOR-NEXT: tail call void @sink(i32* [[TMP6]]) -; ATTRIBUTOR-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; ATTRIBUTOR-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; ATTRIBUTOR-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; CHECK-LABEL: define {{[^@]+}}@PR43833 +; CHECK-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1]], 1 +; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; CHECK: 4: +; CHECK-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] +; CHECK-NEXT: br label [[TMP8:%.*]] +; CHECK: 7: +; CHECK-NEXT: ret void +; CHECK: 8: +; CHECK-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; CHECK-NEXT: tail call void @sink(i32* [[TMP6]]) +; CHECK-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; CHECK-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; CHECK-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] ; %3 = icmp sgt i32 %1, 1 br i1 %3, label %4, label %7 @@ -766,39 +1030,73 @@ ; Adjusted from PR43833 define void @PR43833_simple(i32* %0, i32 %1) { -; ATTRIBUTOR_OPM-LABEL: define {{[^@]+}}@PR43833_simple -; ATTRIBUTOR_OPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) -; ATTRIBUTOR_OPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 -; ATTRIBUTOR_OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; ATTRIBUTOR_OPM: 4: -; ATTRIBUTOR_OPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; ATTRIBUTOR_OPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] -; ATTRIBUTOR_OPM-NEXT: br label [[TMP8:%.*]] -; ATTRIBUTOR_OPM: 7: -; ATTRIBUTOR_OPM-NEXT: ret void -; ATTRIBUTOR_OPM: 8: -; ATTRIBUTOR_OPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; ATTRIBUTOR_OPM-NEXT: tail call void @sink(i32* [[TMP6]]) -; ATTRIBUTOR_OPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; ATTRIBUTOR_OPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; ATTRIBUTOR_OPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] -; -; ATTRIBUTOR_NPM-LABEL: define {{[^@]+}}@PR43833_simple -; ATTRIBUTOR_NPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) -; ATTRIBUTOR_NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 -; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] -; ATTRIBUTOR_NPM: 4: -; ATTRIBUTOR_NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 -; ATTRIBUTOR_NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] -; ATTRIBUTOR_NPM-NEXT: br label [[TMP8:%.*]] -; ATTRIBUTOR_NPM: 7: -; ATTRIBUTOR_NPM-NEXT: ret void -; ATTRIBUTOR_NPM: 8: -; ATTRIBUTOR_NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] -; ATTRIBUTOR_NPM-NEXT: tail call void @sink(i32* nonnull [[TMP6]]) -; ATTRIBUTOR_NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 -; ATTRIBUTOR_NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] -; ATTRIBUTOR_NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; CHECK_OPM-LABEL: define {{[^@]+}}@PR43833_simple +; CHECK_OPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK_OPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; CHECK_OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; CHECK_OPM: 4: +; CHECK_OPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; CHECK_OPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] +; CHECK_OPM-NEXT: br label [[TMP8:%.*]] +; CHECK_OPM: 7: +; CHECK_OPM-NEXT: ret void +; CHECK_OPM: 8: +; CHECK_OPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; CHECK_OPM-NEXT: tail call void @sink(i32* [[TMP6]]) +; CHECK_OPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; CHECK_OPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; CHECK_OPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; +; CHECK_NPM-LABEL: define {{[^@]+}}@PR43833_simple +; CHECK_NPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; CHECK_NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; CHECK_NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; CHECK_NPM: 4: +; CHECK_NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; CHECK_NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] +; CHECK_NPM-NEXT: br label [[TMP8:%.*]] +; CHECK_NPM: 7: +; CHECK_NPM-NEXT: ret void +; CHECK_NPM: 8: +; CHECK_NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; CHECK_NPM-NEXT: tail call void @sink(i32* nonnull [[TMP6]]) +; CHECK_NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; CHECK_NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; CHECK_NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; +; IS________OPM-LABEL: define {{[^@]+}}@PR43833_simple +; IS________OPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; IS________OPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; IS________OPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; IS________OPM: 4: +; IS________OPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; IS________OPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] +; IS________OPM-NEXT: br label [[TMP8:%.*]] +; IS________OPM: 7: +; IS________OPM-NEXT: ret void +; IS________OPM: 8: +; IS________OPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; IS________OPM-NEXT: tail call void @sink(i32* [[TMP6]]) +; IS________OPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; IS________OPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; IS________OPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] +; +; IS________NPM-LABEL: define {{[^@]+}}@PR43833_simple +; IS________NPM-SAME: (i32* [[TMP0:%.*]], i32 [[TMP1:%.*]]) +; IS________NPM-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0 +; IS________NPM-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]] +; IS________NPM: 4: +; IS________NPM-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64 +; IS________NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP5]] +; IS________NPM-NEXT: br label [[TMP8:%.*]] +; IS________NPM: 7: +; IS________NPM-NEXT: ret void +; IS________NPM: 8: +; IS________NPM-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ] +; IS________NPM-NEXT: tail call void @sink(i32* nonnull [[TMP6]]) +; IS________NPM-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1 +; IS________NPM-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]] +; IS________NPM-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]] ; %3 = icmp ne i32 %1, 0 br i1 %3, label %4, label %7 @@ -823,13 +1121,13 @@ ; We should not mark the return of @strrchr as `nonnull`, it may well be NULL! define i8* @mybasename(i8* nofree readonly %str) { -; ATTRIBUTOR-LABEL: define {{[^@]+}}@mybasename -; ATTRIBUTOR-SAME: (i8* nofree readonly [[STR:%.*]]) -; ATTRIBUTOR-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 47) -; ATTRIBUTOR-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[CALL]], null -; ATTRIBUTOR-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 1 -; ATTRIBUTOR-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i8* [[ADD_PTR]], i8* [[STR]] -; ATTRIBUTOR-NEXT: ret i8* [[COND]] +; CHECK-LABEL: define {{[^@]+}}@mybasename +; CHECK-SAME: (i8* nofree readonly [[STR:%.*]]) +; CHECK-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 47) +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[CALL]], null +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 1 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i8* [[ADD_PTR]], i8* [[STR]] +; CHECK-NEXT: ret i8* [[COND]] ; %call = call i8* @strrchr(i8* %str, i32 47) %tobool = icmp ne i8* %call, null @@ -846,6 +1144,20 @@ ; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call i8* @unknown() ; ATTRIBUTOR-NEXT: ret void ; +; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos +; NOT_CGSCC_OPM-SAME: (i8* nocapture nofree nonnull readnone [[ARG:%.*]]) +; NOT_CGSCC_OPM-NEXT: call void @llvm.assume(i1 true) #11 [ "nonnull"(i8* [[ARG]]) ] +; NOT_CGSCC_OPM-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree nonnull readnone [[ARG]]) +; NOT_CGSCC_OPM-NEXT: [[TMP1:%.*]] = call i8* @unknown() +; NOT_CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos +; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull readnone [[ARG:%.*]]) +; IS__CGSCC_OPM-NEXT: call void @llvm.assume(i1 true) #12 [ "nonnull"(i8* [[ARG]]) ] +; IS__CGSCC_OPM-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree nonnull readnone [[ARG]]) +; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = call i8* @unknown() +; IS__CGSCC_OPM-NEXT: ret void +; call void @llvm.assume(i1 true) ["nonnull"(i8* %arg)] call void @use_i8_ptr(i8* %arg) call i8* @unknown() @@ -864,6 +1176,18 @@ ; ATTRIBUTOR-NEXT: call void @use_i8_ptr_ret(i8* noalias nocapture nofree nonnull readnone [[ARG]]) ; ATTRIBUTOR-NEXT: ret void ; +; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg +; CHECK-SAME: (i8* nocapture nofree readnone [[ARG:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8* @unknown() +; CHECK-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree readnone [[ARG]]) +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i8* [[ARG]]) ] +; CHECK-NEXT: call void @use_i8_ptr(i8* noalias nocapture nofree nonnull readnone [[ARG]]) +; CHECK-NEXT: [[TMP2:%.*]] = call i8* @unknown() +; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias nocapture nofree nonnull readnone [[ARG]]) +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i8* [[ARG]]) ] +; CHECK-NEXT: call void @use_i8_ptr_ret(i8* noalias nocapture nofree nonnull readnone [[ARG]]) +; CHECK-NEXT: ret void +; call i8* @unknown() call void @use_i8_ptr(i8* %arg) call void @llvm.assume(i1 true) ["nonnull"(i8* %arg)] diff --git a/llvm/test/Transforms/Attributor/norecurse.ll b/llvm/test/Transforms/Attributor/norecurse.ll --- a/llvm/test/Transforms/Attributor/norecurse.ll +++ b/llvm/test/Transforms/Attributor/norecurse.ll @@ -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 - -; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; ATTRIBUTOR-NEXT: define i32 @leaf() +; 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 + +; 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 @@ 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() diff --git a/llvm/test/Transforms/Attributor/noreturn.ll b/llvm/test/Transforms/Attributor/noreturn.ll --- a/llvm/test/Transforms/Attributor/noreturn.ll +++ b/llvm/test/Transforms/Attributor/noreturn.ll @@ -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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; } ; ; 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 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 @@ ; 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 @@ } ; 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 } diff --git a/llvm/test/Transforms/Attributor/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll --- a/llvm/test/Transforms/Attributor/nosync.ll +++ b/llvm/test/Transforms/Attributor/nosync.ll @@ -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 @@ %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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; *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 @@ ; 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 @@ ; 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 @@ %"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 @@ 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 @@ } ; 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 } diff --git a/llvm/test/Transforms/Attributor/nounwind.ll b/llvm/test/Transforms/Attributor/nounwind.ll --- a/llvm/test/Transforms/Attributor/nounwind.ll +++ b/llvm/test/Transforms/Attributor/nounwind.ll @@ -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 @@ 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 @@ ; 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 @@ ; 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_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 } diff --git a/llvm/test/Transforms/Attributor/range.ll b/llvm/test/Transforms/Attributor/range.ll --- a/llvm/test/Transforms/Attributor/range.ll +++ b/llvm/test/Transforms/Attributor/range.ll @@ -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-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 @@ ; 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 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 @@ } 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 -; -; 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__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 +; +; 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 @@ 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]] -; -; 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________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]] +; +; 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 @@ } 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 -; -; 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________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 +; +; 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 @@ 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]] -; -; 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]] -; -; 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]] +; 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]] +; +; 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_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]] -; -; 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_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]] ; -; 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__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_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]] +; 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-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_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 ; -; 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]] +; IS__TUNIT____-LABEL: define {{[^@]+}}@undef_collapse_caller() +; IS__TUNIT____-NEXT: ret i8 0 ; -; 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 @@ 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 -; -; 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__TUNIT____-LABEL: define {{[^@]+}}@callee_range_1 +; IS__TUNIT____-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) +; IS__TUNIT____-NEXT: ret i1 true +; +; 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_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]] -; -; 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]] ; -; 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__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]] +; +; 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]] +; +; 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 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 -; -; 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________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]] +; +; 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 @@ !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 diff --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll --- a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll +++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll @@ -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 @@ } ; 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 @@ } ; 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 @@ 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 @@ } ; 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 @@ } ; 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 @@ ; 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 # diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll --- a/llvm/test/Transforms/Attributor/readattrs.ll +++ b/llvm/test/Transforms/Attributor/readattrs.ll @@ -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 @@ ; 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 @@ ; 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_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 @@ ;{ 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 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) diff --git a/llvm/test/Transforms/Attributor/returned.ll b/llvm/test/Transforms/Attributor/returned.ll --- a/llvm/test/Transforms/Attributor/returned.ll +++ b/llvm/test/Transforms/Attributor/returned.ll @@ -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 @@ } 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 @@ } 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 @@ ; 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 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 @@ } 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 *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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; ; 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 @@ ; ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; /* 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 @@ ; /* 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 @@ ; /* 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 @@ ; ; 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 @@ } 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 @@ ; 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 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ } 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 @@ @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 } diff --git a/llvm/test/Transforms/Attributor/undefined_behavior.ll b/llvm/test/Transforms/Attributor/undefined_behavior.ll --- a/llvm/test/Transforms/Attributor/undefined_behavior.ll +++ b/llvm/test/Transforms/Attributor/undefined_behavior.ll @@ -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 @@ ; -- 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 @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 @@ ; 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 @@ ; -- 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 @@ } 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 @@ -104,6 +113,9 @@ ; 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 ret void @@ -112,20 +124,21 @@ ; -- 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 @@ } 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 @@ -148,6 +161,9 @@ ; 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 ret void @@ -156,20 +172,21 @@ ; -- 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 @@ } 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 @@ -192,6 +209,9 @@ ; 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 ret void @@ -202,14 +222,13 @@ ; 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 @@ } ; 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 @@ } 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 @@ } 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ } 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 } diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -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 @@ 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 @@ 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 @@ %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 @@ ; 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 @@ } 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 @@ } 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 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 @@ } 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 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 @@ @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 @@ ret i8 %c } -; UTC_ARGS: --disable diff --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll --- a/llvm/test/Transforms/Attributor/willreturn.ll +++ b/llvm/test/Transforms/Attributor/willreturn.ll @@ -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 @@ ; } ; 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 @@ ; } ; 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 @@ ; 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 @@ 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 @@ } -; 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 @@ ; 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 @@ ; } ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; } ; 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 @@ ; } -; 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 @@ ; 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 @@ ; 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 } -; 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 @@ ;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 } -; 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 } -; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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