diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -4745,6 +4745,15 @@ virtual bool forallInterferingAccesses( StoreInst &SI, function_ref CB) const = 0; + /// Call \p CB on all write accesses that might interfere with \p LI and + /// return true if all such accesses were known and the callback returned true + /// for all of them, false otherwise. In contrast to forallInterferingAccesses + /// this function will perform reasoning to exclude write accesses that cannot + /// affect the load even if they on the surface look as if they would. + virtual bool forallInterferingWrites( + Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI, + function_ref CB) const = 0; + /// This function should return true if the type of the \p AA is AAPointerInfo static bool classof(const AbstractAttribute *AA) { return (AA->getIdAddr() == &ID); diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/SetOperations.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -68,6 +69,12 @@ cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), cl::init(7)); +static cl::opt + MaxInterferingWrites("attributor-max-interfering-writes", cl::Hidden, + cl::desc("Maximum number of interfering writes to " + "check before assuming all might interfere."), + cl::init(6)); + STATISTIC(NumAAs, "Number of abstract attributes created"); // Some helper macros to deal with statistics tracking. @@ -1057,6 +1064,120 @@ const override { return State::forallInterferingAccesses(SI, CB); } + bool forallInterferingWrites( + Attributor &A, const AbstractAttribute &QueryingAA, LoadInst &LI, + function_ref UserCB) const override { + SmallPtrSet DominatingWrites; + SmallVector, 8> InterferingWrites; + + Function &Scope = *LI.getFunction(); + const auto &NoSyncAA = A.getAAFor( + QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL); + const auto *ExecDomainAA = A.lookupAAFor( + IRPosition::function(Scope), &QueryingAA, DepClassTy::OPTIONAL); + const bool NoSync = NoSyncAA.isAssumedNoSync(); + + // Helper to determine if we need to consider threading, which we cannot + // right now. However, if the function is (assumed) nosync or the thread + // executing all instructions is the main thread only we can ignore + // threading. + auto CanIgnoreThreading = [&](const Instruction &I) -> bool { + if (NoSync) + return true; + if (ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(I)) + return true; + return false; + }; + + // Helper to determine if the access is executed by the same thread as the + // load, for now it is sufficient to avoid any potential threading effects + // as we cannot deal with them anyway. + auto IsSameThreadAsLoad = [&](const Access &Acc) -> bool { + return CanIgnoreThreading(*Acc.getLocalInst()); + }; + + // TODO: Use inter-procedural reachability and dominance. + const auto &NoRecurseAA = A.getAAFor( + QueryingAA, IRPosition::function(*LI.getFunction()), + DepClassTy::OPTIONAL); + + // Helper to determine if the instruction may reach the load. + auto IsReachableFrom = [&](const Instruction &I) { + const auto &ReachabilityAA = A.getAAFor( + QueryingAA, IRPosition::function(*I.getFunction()), + DepClassTy::OPTIONAL); + return ReachabilityAA.isAssumedReachable(A, I, LI); + }; + + const bool CanUseCFGResoning = + NoRecurseAA.isKnownNoRecurse() && CanIgnoreThreading(LI); + InformationCache &InfoCache = A.getInfoCache(); + const DominatorTree *DT = + InfoCache.getAnalysisResultForFunction(Scope); + + auto AccessCB = [&](const Access &Acc, bool Exact) { + if (!Acc.isWrite()) + return true; + + // For now we only filter accesses based on CFG reasoning which does not + // work yet if we have threading effects, or the access is complicated. + if (CanUseCFGResoning) { + if (!IsReachableFrom(*Acc.getLocalInst())) + return true; + if (DT && Exact && + (Acc.getLocalInst()->getFunction() == LI.getFunction()) && + IsSameThreadAsLoad(Acc)) { + if (DT->dominates(Acc.getLocalInst(), &LI)) + DominatingWrites.insert(&Acc); + } + } + + InterferingWrites.push_back({&Acc, Exact}); + return true; + }; + if (!State::forallInterferingAccesses(LI, AccessCB)) + return false; + + // If we cannot use CFG reasoning we only filter the non-write accesses + // and are done here. + if (!CanUseCFGResoning) { + for (auto &It : InterferingWrites) + if (!UserCB(*It.first, It.second)) + return false; + return true; + } + + // Helper to determine if we can skip a specific write access. This is in + // the worst case quadratic as we are looking for another write that will + // hide the effect of this one. + auto CanSkipAccess = [&](const Access &Acc, bool Exact) { + if (!IsSameThreadAsLoad(Acc)) + return false; + if (!DominatingWrites.count(&Acc)) + return false; + for (const Access *DomAcc : DominatingWrites) { + assert(Acc.getLocalInst()->getFunction() == + DomAcc->getLocalInst()->getFunction() && + "Expected dominating writes to be in the same function!"); + + if (DomAcc != &Acc && + DT->dominates(Acc.getLocalInst(), DomAcc->getLocalInst())) { + return true; + } + } + return false; + }; + + // Run the user callback on all writes we cannot skip and return if that + // succeeded for all or not. + unsigned NumInterferingWrites = InterferingWrites.size(); + for (auto &It : InterferingWrites) + if (!DT || NumInterferingWrites > MaxInterferingWrites || + !CanSkipAccess(*It.first, It.second)) + if (!UserCB(*It.first, It.second)) + return false; + return true; + } ChangeStatus translateAndAddCalleeState(Attributor &A, const AAPointerInfo &CalleeAA, @@ -2878,6 +2999,10 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { + const auto &NoRecurseAA = A.getAAFor( + *this, IRPosition::function(*getAnchorScope()), DepClassTy::REQUIRED); + if (!NoRecurseAA.isAssumedNoRecurse()) + return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; } }; @@ -5238,8 +5363,6 @@ auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) { LLVM_DEBUG(dbgs() << " - visit access " << Acc << "\n"); - if (!Acc.isWrite()) - return true; if (Acc.isWrittenValueYetUndetermined()) return true; Value *Content = Acc.getWrittenValue(); @@ -5259,7 +5382,7 @@ auto &PI = A.getAAFor(AA, IRPosition::value(*Obj), DepClassTy::REQUIRED); - if (!PI.forallInterferingAccesses(L, CheckAccess)) + if (!PI.forallInterferingWrites(A, AA, L, CheckAccess)) return false; } return true; 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 @@ -213,5 +213,5 @@ ; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { argmemonly nofree nosync nounwind uwtable willreturn } ; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { argmemonly nofree nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { willreturn writeonly } -; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nosync nounwind willreturn } ;. 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 @@ -838,5 +838,5 @@ ; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { argmemonly inlinehint nofree norecurse nosync nounwind uwtable willreturn "min-legal-vector-width"="256" "prefer-vector-width"="256" "target-features"="+avx2" } ; IS__CGSCC____: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR6:[0-9]+]] = { willreturn writeonly } -; IS__CGSCC____: attributes #[[ATTR7:[0-9]+]] = { nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR7:[0-9]+]] = { nosync nounwind willreturn } ;. 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 @@ -60,19 +60,15 @@ ; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]], i64 [[TMP1:%.*]], i32 [[TMP2:%.*]]) #[[ATTR0:[0-9]+]] { ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32, align 4 -; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[X_PRIV]], align 4 ; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 8 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32* -; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 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 8 -; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 -; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8 -; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[X_PRIV]], align 4 +; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1 ; 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]] +; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 0, 2 +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: @@ -128,16 +124,14 @@ ; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull readonly byval([[STRUCT_SS]]) align 8 dereferenceable(12) [[S]], i32* noalias nocapture nofree noundef nonnull readonly byval(i32) align 4 dereferenceable(4) [[X]]) #[[ATTR1:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i32 [[C]] ; -; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test -; IS__CGSCC_NPM-SAME: (i32* nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR1:[0-9]+]] { +; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR0]] { ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]], align 8 ; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 ; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 -; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[X]], align 4 -; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @f(i32 undef, i64 undef, i32 [[TMP0]]) #[[ATTR2:[0-9]+]] -; IS__CGSCC_NPM-NEXT: ret i32 [[C]] +; IS__CGSCC_NPM-NEXT: ret i32 2 ; entry: %S = alloca %struct.ss @@ -158,6 +152,4 @@ ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nounwind readnone willreturn } ;. 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 @@ -54,12 +54,10 @@ ; IS__CGSCC_NPM-NEXT: [[X_PRIV:%.*]] = alloca i32, align 4 ; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 8 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32* -; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 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 8 -; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 -; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8 +; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1 ; IS__CGSCC_NPM-NEXT: ret void ; entry: 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 @@ -50,13 +50,11 @@ ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 4 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32* -; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 8 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 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 8 -; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 -; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8 -; IS__CGSCC_NPM-NEXT: ret i32 [[TMP1]] +; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1 +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: %tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0 @@ -109,13 +107,11 @@ ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: [[B_PRIV:%.*]] = alloca [[STRUCT_SS:%.*]], align 4 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_CAST:%.*]] = bitcast %struct.ss* [[B_PRIV]] to i32* -; IS__CGSCC_NPM-NEXT: store i32 1, i32* [[B_PRIV_CAST]], align 32 ; IS__CGSCC_NPM-NEXT: [[B_PRIV_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B_PRIV]], i64 0, i32 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 32 -; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 -; IS__CGSCC_NPM-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32 -; IS__CGSCC_NPM-NEXT: ret i32 [[TMP2]] +; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = add i32 1, 1 +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: %tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0 @@ -148,15 +144,15 @@ ; 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: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32* -; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 8 -; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_1]], align 8 -; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]]) #[[ATTR2:[0-9]+]] ; IS__TUNIT_NPM-NEXT: [[S_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32* -; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST1]], align 32 +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[S_CAST1]], align 8 ; IS__TUNIT_NPM-NEXT: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 32 +; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i64, i64* [[S_0_12]], align 8 +; IS__TUNIT_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 [[TMP0]], i64 [[TMP1]]) #[[ATTR2:[0-9]+]] +; IS__TUNIT_NPM-NEXT: [[S_CAST:%.*]] = bitcast %struct.ss* [[S]] to i32* +; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[S_CAST]], align 32 +; IS__TUNIT_NPM-NEXT: [[S_0_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i64 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_1]], align 32 ; IS__TUNIT_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]]) #[[ATTR2]] ; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]] ; IS__TUNIT_NPM-NEXT: ret i32 [[A]] @@ -181,10 +177,7 @@ ; IS__CGSCC_NPM-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]], align 4 ; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 ; IS__CGSCC_NPM-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 -; IS__CGSCC_NPM-NEXT: [[C0:%.*]] = call i32 @f(i32 undef, i64 undef) #[[ATTR1:[0-9]+]] -; IS__CGSCC_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 undef, i64 undef) #[[ATTR1]] -; IS__CGSCC_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]] -; IS__CGSCC_NPM-NEXT: ret i32 [[A]] +; IS__CGSCC_NPM-NEXT: ret i32 3 ; entry: %S = alloca %struct.ss @@ -209,5 +202,4 @@ ; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nounwind willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nounwind readnone willreturn } ;. 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 @@ -159,15 +159,15 @@ ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions ; IS__TUNIT_NPM-SAME: () #[[ATTR0]] { ; 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 8 -; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8 -; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]] ; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8* -; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8 -; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8 +; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 +; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]] +; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8* +; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8 +; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8 ; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP2]], i32 [[TMP3]]) #[[ATTR2:[0-9]+]] ; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]] ; @@ -252,16 +252,14 @@ ; IS__CGSCC_NPM-NEXT: [[U_PRIV:%.*]] = alloca [[STRUCT_MYSTR:%.*]], align 8 ; IS__CGSCC_NPM-NEXT: [[U_PRIV_CAST:%.*]] = bitcast %struct.MYstr* [[U_PRIV]] to i8* ; IS__CGSCC_NPM-NEXT: [[U_PRIV_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* [[U_PRIV]], i64 0, i32 1 -; IS__CGSCC_NPM-NEXT: store i32 0, i32* [[U_PRIV_0_1]], align 4 ; 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 8 ; IS__CGSCC_NPM-NEXT: [[TMP6:%.*]] = zext i8 0 to i32 -; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = add i32 0, [[TMP3]] -; IS__CGSCC_NPM-NEXT: ret i32 [[TMP7]] +; IS__CGSCC_NPM-NEXT: [[TMP7:%.*]] = add i32 0, 99 +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: %z = getelementptr %struct.MYstr, %struct.MYstr* %u, i32 0, i32 1 @@ -288,15 +286,15 @@ ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@unions_v2 ; IS__TUNIT_NPM-SAME: () #[[ATTR0]] { ; 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 8 -; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8 -; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]] ; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8* -; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8 -; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i8, i8* [[MYSTR_CAST1]], align 8 +; IS__TUNIT_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR:%.*]], %struct.MYstr* @mystr, i64 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP1:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 +; IS__TUNIT_NPM-NEXT: call void @vfu1(i8 [[TMP0]], i32 [[TMP1]]) #[[ATTR0]] +; IS__TUNIT_NPM-NEXT: [[MYSTR_CAST:%.*]] = bitcast %struct.MYstr* @mystr to i8* +; IS__TUNIT_NPM-NEXT: [[TMP2:%.*]] = load i8, i8* [[MYSTR_CAST]], align 8 +; IS__TUNIT_NPM-NEXT: [[MYSTR_0_1:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i64 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8 ; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 [[TMP2]], i32 [[TMP3]]) #[[ATTR2]] ; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]] ; @@ -313,8 +311,7 @@ ; IS__CGSCC_NPM-SAME: () #[[ATTR0]] { ; IS__CGSCC_NPM-NEXT: entry: ; IS__CGSCC_NPM-NEXT: call void @vfu1(i8 noundef 0, i32 undef) #[[ATTR0]] -; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 undef, i32 undef) #[[ATTR0]] -; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]] +; IS__CGSCC_NPM-NEXT: ret i32 99 ; entry: call void @vfu1(%struct.MYstr* byval(%struct.MYstr) align 4 @mystr) nounwind 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 @@ -382,7 +382,7 @@ define void @test8() { ; CHECK-LABEL: define {{[^@]+}}@test8() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) +; CHECK-NEXT: tail call void @no_sync_func(i8* 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* noundef align 4 [[TMP2]]) @@ -403,7 +403,7 @@ define void @test9() { ; IS________OPM-LABEL: define {{[^@]+}}@test9() { ; IS________OPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________OPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) +; IS________OPM-NEXT: tail call void @no_sync_func(i8* nocapture nofree [[TMP1]]) ; IS________OPM-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32* ; IS________OPM-NEXT: store i32 10, i32* [[TMP2]], align 4 ; IS________OPM-NEXT: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR5]] @@ -412,7 +412,7 @@ ; ; IS________NPM-LABEL: define {{[^@]+}}@test9() { ; IS________NPM-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; IS________NPM-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) +; IS________NPM-NEXT: tail call void @no_sync_func(i8* 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: tail call void @foo_nounw(i32* nofree noundef align 4 [[TMP2]]) #[[ATTR6]] diff --git a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll --- a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll @@ -280,7 +280,7 @@ define void @test8() { ; CHECK-LABEL: define {{[^@]+}}@test8() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) +; CHECK-NEXT: tail call void @no_sync_func(i8* 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* noundef align 4 [[TMP2]]) @@ -301,7 +301,7 @@ define void @test9() { ; CHECK-LABEL: define {{[^@]+}}@test9() { ; CHECK-NEXT: [[TMP1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: tail call void @no_sync_func(i8* noalias nocapture nofree [[TMP1]]) +; CHECK-NEXT: tail call void @no_sync_func(i8* 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 noundef align 4 [[TMP2]]) #[[ATTR5:[0-9]+]] 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 @@ -13,7 +13,7 @@ ; 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 noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]] +; IS__TUNIT____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]] ; IS__TUNIT____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo) ; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*)) @@ -26,8 +26,7 @@ ; IS__CGSCC____-SAME: (void (i8*)* noundef nonnull [[FP:%.*]]) { ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4 -; IS__CGSCC____-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]] +; IS__CGSCC____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]] ; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo) ; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*)) @@ -56,7 +55,7 @@ ; 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 noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]] +; IS__TUNIT____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]] ; IS__TUNIT____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo) ; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*)) ; IS__TUNIT____-NEXT: call void @callback2(void (i8*)* [[FP]]) @@ -70,7 +69,7 @@ ; 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 noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]] +; IS__CGSCC____-NEXT: call void @foo(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1]] ; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo) ; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* noundef bitcast (void (i32*)* @foo to void (i8*)*)) ; IS__CGSCC____-NEXT: call void @callback2(void (i8*)* [[FP]]) 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 @@ -385,8 +385,8 @@ define void @test12_2(){ ; CHECK-LABEL: define {{[^@]+}}@test12_2() { ; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 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_nocapture(i8* nocapture [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) ; CHECK-NEXT: tail call void @use(i8* [[A]]) ; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) ; CHECK-NEXT: ret void @@ -695,7 +695,7 @@ ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; NOT_CGSCC_NPM: if.then: -; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]] +; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[IF_END]] ; NOT_CGSCC_NPM: if.end: ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) #[[ATTR7]] @@ -752,7 +752,7 @@ ; NOT_CGSCC_NPM-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[C1]], 0 ; NOT_CGSCC_NPM-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; NOT_CGSCC_NPM: if.then: -; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]] +; NOT_CGSCC_NPM-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) #[[ATTR7]] ; NOT_CGSCC_NPM-NEXT: tail call void @make_alias(i32* nofree writeonly align 4 [[P]]) #[[ATTR7]] ; NOT_CGSCC_NPM-NEXT: br label [[IF_END]] ; NOT_CGSCC_NPM: if.end: diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll --- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll @@ -773,16 +773,23 @@ ; IS__TUNIT____-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4 ; IS__TUNIT____-NEXT: ret i32 [[L]] ; -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3 -; IS__CGSCC____-SAME: () #[[ATTR2:[0-9]+]] { -; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4 -; IS__CGSCC____-NEXT: store i32 1, i32* [[A]], align 4 -; IS__CGSCC____-NEXT: br label [[SPLIT:%.*]] -; IS__CGSCC____: split: -; IS__CGSCC____-NEXT: store i32 2, i32* [[A]], align 4 -; IS__CGSCC____-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4 -; IS__CGSCC____-NEXT: ret i32 [[L]] +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3 +; IS__CGSCC_OPM-SAME: () #[[ATTR2:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32, align 4 +; IS__CGSCC_OPM-NEXT: store i32 1, i32* [[A]], align 4 +; IS__CGSCC_OPM-NEXT: br label [[SPLIT:%.*]] +; IS__CGSCC_OPM: split: +; IS__CGSCC_OPM-NEXT: store i32 2, i32* [[A]], align 4 +; IS__CGSCC_OPM-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4 +; IS__CGSCC_OPM-NEXT: ret i32 [[L]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3 +; IS__CGSCC_NPM-SAME: () #[[ATTR2:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: br label [[SPLIT:%.*]] +; IS__CGSCC_NPM: split: +; IS__CGSCC_NPM-NEXT: ret i32 2 ; %A = alloca i32, align 4 store i32 1, i32* %A @@ -805,7 +812,7 @@ ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@local_alloca_simplifiable_4 -; IS__CGSCC____-SAME: () #[[ATTR2]] { +; IS__CGSCC____-SAME: () #[[ATTR2:[0-9]+]] { ; IS__CGSCC____-NEXT: ret i32 undef ; %A = alloca i32, align 4