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 @@ -9524,8 +9524,34 @@ bool CanReachUnknownCallee = false; }; -struct AAHotColdFunction : public AAHotCold { - AAHotColdFunction(const IRPosition &IRP, Attributor &A) : AAHotCold(IRP, A) {} +struct AAHotColdImpl : public AAHotCold { + AAHotColdImpl(const IRPosition &IRP, Attributor &A) : AAHotCold(IRP, A) {} + + const std::string getAsStr() const override { + std::string State; + + switch (getAssumed()) { + case HotColdState::UNKNOWN: + State = "Unknown"; + break; + case HotColdState::INVALID: + State = "Invalid"; + break; + case HotColdState::HOT: + State = "Hot"; + break; + case HotColdState::COLD: + State = "Cold"; + break; + } + + return "HotCold[" + State + "]"; + } +}; + +struct AAHotColdFunction : public AAHotColdImpl { + AAHotColdFunction(const IRPosition &IRP, Attributor &A) + : AAHotColdImpl(IRP, A) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { @@ -9548,12 +9574,12 @@ HotColdState OldState = getState(); // If all of the callers of a function are cold, we can assume that the - // function is cold too. But we can't assume it is hot. - // TODO: Propagate accross calls inside the same block. + // function is cold too. But we can't assume it is hot if all callers are + // hot. auto CallSiteCheck = [&](AbstractCallSite ACS) { - Function *Caller = ACS.getInstruction()->getFunction(); + CallBase *CB = ACS.getInstruction(); const AAHotCold &AA = A.getAAFor( - *this, IRPosition::function(*Caller), DepClassTy::REQUIRED); + *this, IRPosition::callsite_function(*CB), DepClassTy::REQUIRED); *this &= AA.getState(); return true; }; @@ -9564,8 +9590,60 @@ if (!A.checkForAllCallSites(CallSiteCheck, *this, true, AllCallSitesKnown)) indicatePessimisticFixpoint(); - return OldState == getState() ? ChangeStatus::UNCHANGED - : ChangeStatus::CHANGED; + ChangeStatus Change = OldState == getState() + ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED; + + // if there is a cold function being called from a basic block, + // we can assume that, any other call site inside that block is cold also. + // if all call sites are cold, we can assume that the function is cold. + // Here we collect information about call sites and get a hot/cold state + // for a basic block. + auto CheckCall = [&](Instruction &Inst) { + BasicBlock *ParentBlock = Inst.getParent(); + + CallBase &CB = static_cast(Inst); + Function *Fn = CB.getCalledFunction(); + HotColdState CallSiteInfo; + + if (Fn) { + // There is no need to use the call site info here. + const auto &AA = A.getAAFor(*this, IRPosition::function(*Fn), + DepClassTy::REQUIRED); + CallSiteInfo = AA.getState(); + } else { + CallSiteInfo.indicatePessimisticFixpoint(); + } + + // If this block contains a call with a unknown callee, assume that we + // can't know. We are being conservative here. + HotColdState &CurrentState = BlockStatus[ParentBlock]; + HotColdState OldState = CurrentState; + CurrentState &= CallSiteInfo; + + // Track changes. + Change |= CurrentState == OldState ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + + return true; + }; + + bool UsedAssumed = false; + if (!A.checkForAllCallLikeInstructions(CheckCall, *this, UsedAssumed)) { + // If we haven't looked at all instructions we can't trust this data. + BlockStatus.clear(); + } + + return Change; + } + + void trackStatistics() const override { + STATISTIC(NumFunctionsMarkedHot, "Number of functions marked hot"); + STATISTIC(NumFunctionsMarkedCold, "Number of functions marked cold"); + + if (isAssumedHot()) + NumFunctionsMarkedHot++; + else if (isAssumedCold()) + NumFunctionsMarkedCold++; } ChangeStatus manifest(Attributor &A) override { @@ -9580,28 +9658,64 @@ return IRAttributeManifest::manifestAttrs(A, this->getIRPosition(), Attrs); } - const std::string getAsStr() const override { - std::string State; + /// This represents the information we have about a basic block. + /// we use this information to determine if a callsite inside the + /// block is hot or cold. + /// A block not being in here means that we don't know if it is hot or cold. + /// A llvm::None value means that we now that we can't know for sure. + DenseMap BlockStatus; +}; - switch (getAssumed()) { - case HotColdState::UNKNOWN: - State = "Unknown"; - break; - case HotColdState::INVALID: - State = "Invalid"; - break; - case HotColdState::HOT: - State = "Hot"; - break; - case HotColdState::COLD: - State = "Cold"; - break; +struct AAHotColdCallSite : public AAHotColdImpl { + AAHotColdCallSite(const IRPosition &IRP, Attributor &A) + : AAHotColdImpl(IRP, A) {} + + ChangeStatus updateImpl(Attributor &A) override { + HotColdState OldState = this->getState(); + + auto CheckChange = [&]() { + return OldState == *this ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + }; + + + // Use the information from the function that this call is in. + Function *Anchor = getAnchorScope(); + auto &AnchorAA = A.getAAFor(*this, IRPosition::function(*Anchor), + DepClassTy::REQUIRED); + + // We can only propate cold this way. + if (AnchorAA.isAssumedCold()) { + *this &= AnchorAA; + return CheckChange(); } - return "HotCold[" + State + "]"; + auto &AnchorFunctionAA = static_cast(AnchorAA); + + // Use the information from the block this call is in. + BasicBlock *ParentBlock = getCtxI()->getParent(); + if (AnchorFunctionAA.BlockStatus.count(ParentBlock)) { + HotColdState BlockState = + AnchorFunctionAA.BlockStatus.find(ParentBlock)->second; + if (BlockState.getAssumed() != UNKNOWN && BlockState.isValidState()) { + *this &= BlockState; + return CheckChange(); + } + } + + // Use the information from the function called function. + Function *Called = getAssociatedFunction(); + if (!Called) + return CheckChange(); + + auto &CalledAA = A.getAAFor(*this, IRPosition::function(*Called), + DepClassTy::REQUIRED); + *this &= CalledAA; + return CheckChange(); } void trackStatistics() const override {} + }; } // namespace @@ -9741,6 +9855,7 @@ CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn) CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues) CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryLocation) +CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHotCold) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias) @@ -9762,7 +9877,6 @@ CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges) CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAFunctionReachability) -CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHotCold) CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior) 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 @@ -155,9 +155,9 @@ ; IS__TUNIT____: attributes #[[ATTR0:[0-9]+]] = { nofree nosync nounwind readnone willreturn } ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR1]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind readnone 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]] = { readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nounwind readnone willreturn } ;. 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 @@ -150,15 +150,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_CAST1:%.*]] = bitcast %struct.ss* [[S]] to i32* -; 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]], i32 0, i32 1 -; 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]]) #[[ATTR0]] ; 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: [[TMP0:%.*]] = load i32, i32* [[S_CAST]], align 8 ; 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 32 +; 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]]) #[[ATTR0]] +; 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: [[S_0_12:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i64, i64* [[S_0_12]], align 32 ; IS__TUNIT_NPM-NEXT: [[C1:%.*]] = call i32 @g(i32 [[TMP2]], i64 [[TMP3]]) #[[ATTR0]] ; IS__TUNIT_NPM-NEXT: [[A:%.*]] = add i32 [[C0]], [[C1]] ; IS__TUNIT_NPM-NEXT: ret 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 @@ -78,7 +78,7 @@ ; IS__CGSCC____-LABEL: define {{[^@]+}}@eggs ; IS__CGSCC____-SAME: (i8* [[ARG:%.*]]) { ; IS__CGSCC____-NEXT: bb: -; IS__CGSCC____-NEXT: [[TMP:%.*]] = call zeroext i1 @barney() +; IS__CGSCC____-NEXT: [[TMP:%.*]] = call zeroext i1 @barney() #[[ATTR3:[0-9]+]] ; IS__CGSCC____-NEXT: unreachable ; bb: @@ -145,4 +145,5 @@ ; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse noreturn nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR2]] = { noreturn nounwind readnone } +; IS__CGSCC____: attributes #[[ATTR3]] = { nounwind readnone } ;. 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 @@ -6,9 +6,13 @@ define internal void @dead() { -; IS__CGSCC____-LABEL: define {{[^@]+}}@dead() { -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @test(i32* noalias noundef align 536870912 null) -; IS__CGSCC____-NEXT: ret void +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@dead() { +; IS__CGSCC_OPM-NEXT: [[TMP1:%.*]] = call i32 @test(i32* noalias noundef align 536870912 null) #[[ATTR3:[0-9]+]] +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@dead() { +; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = call i32 @test(i32* noalias noundef align 536870912 null) #[[ATTR2:[0-9]+]] +; IS__CGSCC_NPM-NEXT: ret void ; call i32 @test(i32* null, i32* null) ret void @@ -50,14 +54,14 @@ ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller ; IS__CGSCC_OPM-SAME: () #[[ATTR1:[0-9]+]] { ; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32, align 4 -; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR3:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR4:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i32 undef ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller ; IS__CGSCC_NPM-SAME: () #[[ATTR1:[0-9]+]] { ; IS__CGSCC_NPM-NEXT: [[A:%.*]] = alloca i32, align 4 -; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR2:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR3:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i32 undef ; %A = alloca i32 @@ -97,9 +101,11 @@ ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nounwind writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn writeonly } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nounwind writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn writeonly } ;. 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 @@ -7,7 +7,7 @@ define internal void @dead() { ; IS__CGSCC____-LABEL: define {{[^@]+}}@dead() { -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @test(i32* noalias noundef align 536870912 null) +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @test(i32* noalias noundef align 536870912 null) #[[ATTR2:[0-9]+]] ; IS__CGSCC____-NEXT: ret void ; call i32 @test(i32* null, i32* null) @@ -46,18 +46,25 @@ } define internal i32 @caller(i32* %B) { -; NOT_CGSCC_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly -; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@caller -; NOT_CGSCC_NPM-SAME: (i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0]] { -; NOT_CGSCC_NPM-NEXT: [[A:%.*]] = alloca i32, align 4 -; NOT_CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR2:[0-9]+]] -; NOT_CGSCC_NPM-NEXT: ret i32 undef +; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly +; IS__TUNIT____-LABEL: define {{[^@]+}}@caller +; IS__TUNIT____-SAME: (i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0]] { +; IS__TUNIT____-NEXT: [[A:%.*]] = alloca i32, align 4 +; IS__TUNIT____-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR2:[0-9]+]] +; IS__TUNIT____-NEXT: ret i32 undef +; +; IS__CGSCC_OPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller +; IS__CGSCC_OPM-SAME: (i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0]] { +; IS__CGSCC_OPM-NEXT: [[A:%.*]] = alloca i32, align 4 +; IS__CGSCC_OPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR3:[0-9]+]] +; IS__CGSCC_OPM-NEXT: ret i32 undef ; ; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller ; IS__CGSCC_NPM-SAME: (i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0]] { ; IS__CGSCC_NPM-NEXT: [[A:%.*]] = alloca i32, align 4 -; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR2:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR3:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i32 undef ; %A = alloca i32 @@ -78,14 +85,14 @@ ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@callercaller ; IS__CGSCC_OPM-SAME: () #[[ATTR1:[0-9]+]] { ; IS__CGSCC_OPM-NEXT: [[B:%.*]] = alloca i32, align 4 -; IS__CGSCC_OPM-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR3:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR4:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i32 0 ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@callercaller ; IS__CGSCC_NPM-SAME: () #[[ATTR1:[0-9]+]] { ; IS__CGSCC_NPM-NEXT: [[B:%.*]] = alloca i32, align 4 -; IS__CGSCC_NPM-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR3:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR4:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i32 0 ; %B = alloca i32 @@ -101,11 +108,13 @@ ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind willreturn writeonly } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn writeonly } -; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nounwind willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nounwind writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn writeonly } +; IS__CGSCC_OPM: attributes #[[ATTR4]] = { nounwind willreturn writeonly } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn writeonly } -; IS__CGSCC_NPM: attributes #[[ATTR3]] = { nounwind willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nounwind writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn writeonly } +; IS__CGSCC_NPM: attributes #[[ATTR4]] = { nounwind willreturn writeonly } ;. 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_CAST1:%.*]] = bitcast %struct.MYstr* @mystr to i8* -; 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, i32 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, i32 0, i32 1 -; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_1]], align 8 +; 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, i32 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, i32 0, i32 1 +; IS__TUNIT_NPM-NEXT: [[TMP3:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 ; IS__TUNIT_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP2]], i32 [[TMP3]]) #[[ATTR2:[0-9]+]] ; IS__TUNIT_NPM-NEXT: ret i32 [[RESULT]] ; @@ -176,7 +176,7 @@ ; IS__CGSCC_OPM-SAME: () #[[ATTR0]] { ; IS__CGSCC_OPM-NEXT: entry: ; IS__CGSCC_OPM-NEXT: call void @vfu1(%struct.MYstr* noalias nocapture nofree noundef nonnull readonly byval([[STRUCT_MYSTR:%.*]]) align 8 dereferenceable(8) @mystr) #[[ATTR0]] -; IS__CGSCC_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* noalias nocapture nofree noundef nonnull readnone byval([[STRUCT_MYSTR]]) align 8 dereferenceable(8) @mystr) #[[ATTR0]] +; IS__CGSCC_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(%struct.MYstr* noalias nocapture nofree noundef nonnull readnone byval([[STRUCT_MYSTR]]) align 8 dereferenceable(8) @mystr) #[[ATTR2:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i32 [[RESULT]] ; ; IS__CGSCC_NPM: Function Attrs: nounwind @@ -188,7 +188,7 @@ ; IS__CGSCC_NPM-NEXT: [[TMP1:%.*]] = load i8, i8* getelementptr inbounds ([[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 0), align 8 ; IS__CGSCC_NPM-NEXT: [[MYSTR_0_12:%.*]] = getelementptr [[STRUCT_MYSTR]], %struct.MYstr* @mystr, i32 0, i32 1 ; IS__CGSCC_NPM-NEXT: [[TMP2:%.*]] = load i32, i32* [[MYSTR_0_12]], align 8 -; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP1]], i32 [[TMP2]]) #[[ATTR0]] +; IS__CGSCC_NPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2(i8 [[TMP1]], i32 [[TMP2]]) #[[ATTR2:[0-9]+]] ; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]] ; entry: @@ -306,7 +306,7 @@ ; IS__CGSCC_OPM-SAME: () #[[ATTR0]] { ; IS__CGSCC_OPM-NEXT: entry: ; IS__CGSCC_OPM-NEXT: call void @vfu1(%struct.MYstr* noalias nocapture nofree noundef nonnull readonly byval([[STRUCT_MYSTR:%.*]]) align 8 dereferenceable(8) @mystr) #[[ATTR0]] -; IS__CGSCC_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* noalias nocapture nofree noundef nonnull readnone byval([[STRUCT_MYSTR]]) align 8 dereferenceable(8) @mystr) #[[ATTR0]] +; IS__CGSCC_OPM-NEXT: [[RESULT:%.*]] = call i32 @vfu2_v2(%struct.MYstr* noalias nocapture nofree noundef nonnull readnone byval([[STRUCT_MYSTR]]) align 8 dereferenceable(8) @mystr) #[[ATTR2]] ; IS__CGSCC_OPM-NEXT: ret i32 [[RESULT]] ; ; IS__CGSCC_NPM: Function Attrs: nounwind @@ -314,7 +314,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: [[RESULT:%.*]] = call i32 @vfu2_v2(i8 undef, i32 undef) #[[ATTR2]] ; IS__CGSCC_NPM-NEXT: ret i32 [[RESULT]] ; entry: @@ -329,4 +329,5 @@ ;. ; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { nounwind } ; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nounwind readonly } ;. 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,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -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 -attributor -enable-new-pm=0 -attributor-manifest-internal -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-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 -enable-new-pm=0 -attributor-manifest-internal -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-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 @@ -80,18 +80,13 @@ ; IS__TUNIT____-NEXT: entry: ; IS__TUNIT____-NEXT: ret i64 42 ; -; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2c -; IS__CGSCC_OPM-SAME: () #[[ATTR0]] { -; IS__CGSCC_OPM-NEXT: entry: -; IS__CGSCC_OPM-NEXT: ret i64 42 -; -; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2c -; IS__CGSCC_NPM-SAME: () #[[ATTR0]] { -; IS__CGSCC_NPM-NEXT: entry: -; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = sext i32 undef to i64 -; IS__CGSCC_NPM-NEXT: ret i64 42 +; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2c +; IS__CGSCC____-SAME: () #[[ATTR0]] { +; IS__CGSCC____-NEXT: entry: +; IS__CGSCC____-NEXT: [[CONV:%.*]] = sext i32 undef to i64 +; IS__CGSCC____-NEXT: [[ADD:%.*]] = add i64 42, 0 +; IS__CGSCC____-NEXT: ret i64 42 ; entry: %conv = sext i32 undef to i64 @@ -128,7 +123,7 @@ ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn } ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_OPM: attributes #[[ATTR1]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind readnone willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } ;. 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 @@ -49,7 +49,7 @@ ; IS__CGSCC_OPM: if.end: ; IS__CGSCC_OPM-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] ; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 -; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]]) +; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]]) #[[ATTR3:[0-9]+]] ; IS__CGSCC_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 ; IS__CGSCC_OPM-NEXT: br label [[FOR_COND1]] ; IS__CGSCC_OPM: exit: @@ -154,7 +154,7 @@ ; 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 536870912 -; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) +; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) #[[ATTR3]] ; IS__CGSCC_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 ; IS__CGSCC_OPM-NEXT: br label [[FOR_COND1]] ; IS__CGSCC_OPM: exit: @@ -224,7 +224,12 @@ ; IS__TUNIT_NPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind } ; IS__TUNIT_NPM: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid } ;. -; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind } -; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nofree norecurse nosync nounwind null_pointer_is_valid } +; IS__CGSCC_OPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind } +; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind null_pointer_is_valid } +; IS__CGSCC_OPM: attributes #[[ATTR3]] = { nounwind readnone } +;. +; IS__CGSCC_NPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind } +; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind null_pointer_is_valid } ;. 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 @@ -133,7 +133,7 @@ ; IS__CGSCC_OPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] ; IS__CGSCC_OPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] ; IS__CGSCC_OPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 -; IS__CGSCC_OPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR3]] ; IS__CGSCC_OPM-NEXT: br label [[OK:%.*]] ; IS__CGSCC_OPM: OK: ; IS__CGSCC_OPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 @@ -152,7 +152,7 @@ ; IS__CGSCC_NPM-NEXT: [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] ; IS__CGSCC_NPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] ; IS__CGSCC_NPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 -; IS__CGSCC_NPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR3]] ; IS__CGSCC_NPM-NEXT: br label [[OK:%.*]] ; IS__CGSCC_NPM: OK: ; IS__CGSCC_NPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 @@ -199,6 +199,5 @@ ; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nounwind willreturn } -; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { nounwind readnone willreturn } ;. 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 @@ -96,6 +96,12 @@ ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller ; IS__CGSCC____-SAME: (i1 [[Q:%.*]]) #[[ATTR0]] { ; IS__CGSCC____-NEXT: [[X:%.*]] = call [[TMP0:%.*]] @foo(i1 [[Q]]) #[[ATTR1:[0-9]+]] +; IS__CGSCC____-NEXT: [[A:%.*]] = extractvalue [[TMP0]] [[X]], 0 +; IS__CGSCC____-NEXT: [[B:%.*]] = extractvalue [[TMP0]] [[X]], 1 +; IS__CGSCC____-NEXT: [[C:%.*]] = extractvalue [[TMP0]] undef, 0 +; IS__CGSCC____-NEXT: [[D:%.*]] = extractvalue [[TMP0]] undef, 1 +; IS__CGSCC____-NEXT: [[M:%.*]] = add i32 undef, undef +; IS__CGSCC____-NEXT: [[N:%.*]] = add i32 undef, undef ; IS__CGSCC____-NEXT: ret [[TMP0]] [[X]] ; %X = call %0 @foo(i1 %Q) @@ -155,5 +161,5 @@ ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn } ;. ; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR1]] = { readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR1]] = { nounwind readnone willreturn } ;. 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,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals -; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -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-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 -enable-new-pm=0 -attributor-manifest-internal -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-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 -enable-new-pm=0 -attributor-manifest-internal -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-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/hotcold.ll b/llvm/test/Transforms/Attributor/hotcold.ll --- a/llvm/test/Transforms/Attributor/hotcold.ll +++ b/llvm/test/Transforms/Attributor/hotcold.ll @@ -60,23 +60,72 @@ ret void } +; This function get's marked as cold because it is called from a function that contains +; calls to other cold functions. +define internal void @cold_block_test() { +; IS__TUNIT____: Function Attrs: cold nofree nosync nounwind willreturn writeonly +; IS__TUNIT____-LABEL: define {{[^@]+}}@cold_block_test +; IS__TUNIT____-SAME: () #[[ATTR0]] { +; IS__TUNIT____-NEXT: store i32 1, i32* @G, align 4 +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____: Function Attrs: cold nofree norecurse nosync nounwind willreturn writeonly +; IS__CGSCC____-LABEL: define {{[^@]+}}@cold_block_test +; IS__CGSCC____-SAME: () #[[ATTR0]] { +; IS__CGSCC____-NEXT: store i32 1, i32* @G, align 4 +; IS__CGSCC____-NEXT: ret void +; + store i32 1, i32* @G, align 4 + ret void +} + +; This function calls some cold functions, we expect that @cold_block_test will be marked as cold. +define internal void @block_call_test() { +; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn writeonly +; IS__TUNIT____-LABEL: define {{[^@]+}}@block_call_test +; IS__TUNIT____-SAME: () #[[ATTR1]] { +; IS__TUNIT____-NEXT: call void @cold_block_test() #[[ATTR1]] +; IS__TUNIT____-NEXT: call void @cold_caller2() #[[ATTR1]] +; IS__TUNIT____-NEXT: call void @cold_caller1() #[[ATTR1]] +; IS__TUNIT____-NEXT: ret void +; +; IS__CGSCC____: Function Attrs: cold nofree norecurse nosync nounwind willreturn writeonly +; IS__CGSCC____-LABEL: define {{[^@]+}}@block_call_test +; IS__CGSCC____-SAME: () #[[ATTR0]] { +; IS__CGSCC____-NEXT: call void @cold_block_test() #[[ATTR2]] +; IS__CGSCC____-NEXT: call void @cold_caller2() #[[ATTR2]] +; IS__CGSCC____-NEXT: call void @cold_caller1() #[[ATTR2]] +; IS__CGSCC____-NEXT: ret void +; + call void @cold_block_test() + call void @cold_caller2() + call void @cold_caller1() + ret void +} + define void @external() { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn writeonly ; IS__TUNIT____-LABEL: define {{[^@]+}}@external ; IS__TUNIT____-SAME: () #[[ATTR1]] { +; IS__TUNIT____-NEXT: call void @cold_block_test() #[[ATTR1]] ; IS__TUNIT____-NEXT: call void @cold_caller2() #[[ATTR1]] ; IS__TUNIT____-NEXT: call void @cold_caller1() #[[ATTR1]] +; IS__TUNIT____-NEXT: call void @block_call_test() #[[ATTR1]] ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@external ; IS__CGSCC____-SAME: () #[[ATTR1:[0-9]+]] { +; IS__CGSCC____-NEXT: call void @cold_block_test() #[[ATTR2]] ; IS__CGSCC____-NEXT: call void @cold_caller2() #[[ATTR2]] ; IS__CGSCC____-NEXT: call void @cold_caller1() #[[ATTR2]] +; IS__CGSCC____-NEXT: call void @block_call_test() #[[ATTR2]] ; IS__CGSCC____-NEXT: ret void ; + call void @cold_block_test() call void @cold_caller2() call void @cold_caller1() + call void @block_call_test() ret void } 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 @@ -2075,7 +2075,7 @@ } 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: call void @dead_e1() #[[ATTR18:[0-9]+]] ; IS__CGSCC____-NEXT: ret void ; define internal void @dead_e1() { call void @dead_e2() ret void } @@ -2581,7 +2581,7 @@ ; IS__CGSCC____-NEXT: entry: ; IS__CGSCC____-NEXT: [[N:%.*]] = alloca i8, align 1 ; IS__CGSCC____-NEXT: [[M:%.*]] = alloca i8, align 1 -; IS__CGSCC____-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 1, i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[N]]) #[[ATTR18:[0-9]+]] +; IS__CGSCC____-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 1, i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[N]]) #[[ATTR19:[0-9]+]] ; IS__CGSCC____-NEXT: br label [[EXIT:%.*]] ; IS__CGSCC____: while.body: ; IS__CGSCC____-NEXT: unreachable @@ -2590,7 +2590,7 @@ ; IS__CGSCC____: if.end: ; IS__CGSCC____-NEXT: unreachable ; IS__CGSCC____: exit: -; IS__CGSCC____-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 1, i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[N]]) #[[ATTR18]] +; IS__CGSCC____-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 1, i8* noalias nocapture nofree noundef nonnull dereferenceable(1) [[N]]) #[[ATTR19]] ; IS__CGSCC____-NEXT: ret void ; entry: @@ -2659,5 +2659,6 @@ ; IS__CGSCC____: attributes #[[ATTR15]] = { nofree nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR16:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR17]] = { nounwind willreturn } -; IS__CGSCC____: attributes #[[ATTR18]] = { willreturn } +; IS__CGSCC____: attributes #[[ATTR18]] = { nounwind readnone } +; IS__CGSCC____: attributes #[[ATTR19]] = { willreturn } ;. 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 @@ -974,8 +974,8 @@ ; IS__CGSCC____: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR8]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR9]] = { nofree norecurse noreturn nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR10]] = { readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR11]] = { readonly willreturn } +; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR11]] = { nounwind readonly willreturn } ; IS__CGSCC____: attributes #[[ATTR12]] = { willreturn } ; IS__CGSCC____: attributes #[[ATTR13]] = { nounwind willreturn writeonly } ;. diff --git a/llvm/test/Transforms/Attributor/potential.ll b/llvm/test/Transforms/Attributor/potential.ll --- a/llvm/test/Transforms/Attributor/potential.ll +++ b/llvm/test/Transforms/Attributor/potential.ll @@ -60,6 +60,7 @@ ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@call_with_two_values ; IS__CGSCC____-SAME: () #[[ATTR0]] { +; IS__CGSCC____-NEXT: [[RET:%.*]] = add i32 0, 0 ; IS__CGSCC____-NEXT: ret i32 undef ; %csret1 = call i32 @iszero2(i32 %c) @@ -113,9 +114,7 @@ define internal i32 @less_than_two(i32 %c) { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@less_than_two -; IS__CGSCC____-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { -; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp slt i32 undef, 2 -; IS__CGSCC____-NEXT: [[RET:%.*]] = zext i1 true to i32 +; IS__CGSCC____-SAME: () #[[ATTR0]] { ; IS__CGSCC____-NEXT: ret i32 undef ; %cmp = icmp slt i32 %c, 2 @@ -581,9 +580,9 @@ ; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@potential_test11 ; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { -; IS__CGSCC_OPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) #[[ATTR2]], !range [[RNG2:![0-9]+]] -; IS__CGSCC_OPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) #[[ATTR2]], !range [[RNG3:![0-9]+]] -; IS__CGSCC_OPM-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]]) #[[ATTR2]], !range [[RNG2]] +; IS__CGSCC_OPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) #[[ATTR3:[0-9]+]], !range [[RNG2:![0-9]+]] +; IS__CGSCC_OPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) #[[ATTR3]], !range [[RNG3:![0-9]+]] +; IS__CGSCC_OPM-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]]) #[[ATTR3]], !range [[RNG2]] ; IS__CGSCC_OPM-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]] ; IS__CGSCC_OPM-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]] ; IS__CGSCC_OPM-NEXT: ret i32 [[ACC2]] @@ -591,9 +590,9 @@ ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@potential_test11 ; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { -; IS__CGSCC_NPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) #[[ATTR1]], !range [[RNG2:![0-9]+]] -; IS__CGSCC_NPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) #[[ATTR1]], !range [[RNG3:![0-9]+]] -; IS__CGSCC_NPM-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]]) #[[ATTR1]], !range [[RNG2]] +; IS__CGSCC_NPM-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) #[[ATTR2:[0-9]+]], !range [[RNG2:![0-9]+]] +; IS__CGSCC_NPM-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) #[[ATTR2]], !range [[RNG3:![0-9]+]] +; IS__CGSCC_NPM-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]]) #[[ATTR2]], !range [[RNG2]] ; IS__CGSCC_NPM-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]] ; IS__CGSCC_NPM-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]] ; IS__CGSCC_NPM-NEXT: ret i32 [[ACC2]] @@ -667,7 +666,7 @@ ; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@potential_test12 ; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { -; IS__CGSCC_OPM-NEXT: [[ZERO:%.*]] = call noundef i32 @optimize_poison_1(i1 [[C]]) #[[ATTR2]], !range [[RNG3]] +; IS__CGSCC_OPM-NEXT: [[ZERO:%.*]] = call noundef i32 @optimize_poison_1(i1 [[C]]) #[[ATTR3]], !range [[RNG3]] ; IS__CGSCC_OPM-NEXT: ret i32 [[ZERO]] ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -841,10 +840,12 @@ ;. ; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone } -; IS__CGSCC_OPM: attributes #[[ATTR2]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nounwind readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR3]] = { readnone willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC_NPM: attributes #[[ATTR1]] = { readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nounwind readnone willreturn } +; IS__CGSCC_NPM: attributes #[[ATTR2]] = { readnone willreturn } ;. ; CHECK: [[META0:![0-9]+]] = !{i32 1, i32 4} ; CHECK: [[META1:![0-9]+]] = !{i32 3, i32 5} 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 @@ -1520,8 +1520,7 @@ define internal i1 @is_less_than_65536(i32 %arg) { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@is_less_than_65536 -; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] { -; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp ult i32 undef, 65536 +; IS__CGSCC____-SAME: () #[[ATTR1]] { ; IS__CGSCC____-NEXT: ret i1 undef ; %cmp = icmp ult i32 %arg, 65536 @@ -1728,8 +1727,7 @@ ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@is_less_than_100_2 -; IS__CGSCC____-SAME: (i32 [[C:%.*]]) #[[ATTR1]] { -; IS__CGSCC____-NEXT: [[CMP:%.*]] = icmp slt i32 undef, 100 +; IS__CGSCC____-SAME: () #[[ATTR1]] { ; IS__CGSCC____-NEXT: ret i1 undef ; %cmp = icmp slt i32 %c, 100 @@ -1809,7 +1807,7 @@ ; IS__CGSCC_OPM-NEXT: [[C:%.*]] = icmp slt i8 0, [[L]] ; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__CGSCC_OPM: t: -; IS__CGSCC_OPM-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) #[[ATTR5]] +; IS__CGSCC_OPM-NEXT: [[R:%.*]] = call i1 @non_zero(i8 [[L]]) #[[ATTR6:[0-9]+]] ; IS__CGSCC_OPM-NEXT: ret i1 [[R]] ; IS__CGSCC_OPM: f: ; IS__CGSCC_OPM-NEXT: ret i1 false @@ -1921,6 +1919,7 @@ ; IS__CGSCC_OPM: attributes #[[ATTR3]] = { readonly willreturn } ; IS__CGSCC_OPM: attributes #[[ATTR4]] = { nounwind readnone } ; IS__CGSCC_OPM: attributes #[[ATTR5]] = { readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR6]] = { nounwind readnone willreturn } ;. ; IS__CGSCC_NPM: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } ; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } 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 @@ -1634,4 +1634,5 @@ ; IS__CGSCC____: attributes #[[ATTR6:[0-9]+]] = { nofree norecurse nosync nounwind readnone willreturn } ; IS__CGSCC____: attributes #[[ATTR7]] = { nofree nosync nounwind readnone } ; IS__CGSCC____: attributes #[[ATTR8]] = { nounwind } +; IS__CGSCC____: attributes #[[ATTR9:[0-9]+]] = { nounwind readnone } ;. diff --git a/llvm/test/Transforms/Attributor/value-simplify-instances.ll b/llvm/test/Transforms/Attributor/value-simplify-instances.ll --- a/llvm/test/Transforms/Attributor/value-simplify-instances.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-instances.ll @@ -32,27 +32,16 @@ } define internal i1 @recursive_inst_generator(i1 %c, i1* %p) { -; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_inst_generator -; IS__TUNIT____-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) { -; IS__TUNIT____-NEXT: [[A:%.*]] = call i1* @geti1Ptr() -; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] -; IS__TUNIT____: t: -; IS__TUNIT____-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]]) #[[ATTR4:[0-9]+]] -; IS__TUNIT____-NEXT: ret i1 [[R1]] -; IS__TUNIT____: f: -; IS__TUNIT____-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]]) -; IS__TUNIT____-NEXT: ret i1 [[R2]] -; -; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_inst_generator -; IS__CGSCC____-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) { -; IS__CGSCC____-NEXT: [[A:%.*]] = call i1* @geti1Ptr() -; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] -; IS__CGSCC____: t: -; IS__CGSCC____-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]]) -; IS__CGSCC____-NEXT: ret i1 [[R1]] -; IS__CGSCC____: f: -; IS__CGSCC____-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]]) -; IS__CGSCC____-NEXT: ret i1 [[R2]] +; CHECK-LABEL: define {{[^@]+}}@recursive_inst_generator +; CHECK-SAME: (i1 [[C:%.*]], i1* nofree [[P:%.*]]) { +; CHECK-NEXT: [[A:%.*]] = call i1* @geti1Ptr() +; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; CHECK: t: +; CHECK-NEXT: [[R1:%.*]] = call i1 @recursive_inst_comparator(i1* noalias nofree readnone [[A]], i1* noalias nofree readnone [[P]]) #[[ATTR4:[0-9]+]] +; CHECK-NEXT: ret i1 [[R1]] +; CHECK: f: +; CHECK-NEXT: [[R2:%.*]] = call i1 @recursive_inst_generator(i1 noundef true, i1* nofree [[A]]) +; CHECK-NEXT: ret i1 [[R2]] ; %a = call i1* @geti1Ptr() br i1 %c, label %t, label %f @@ -144,7 +133,7 @@ ; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone ; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_alloca_compare_caller ; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] { -; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 [[C]], i1* undef) #[[ATTR4:[0-9]+]] +; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i1 @recursive_alloca_compare(i1 [[C]], i1* undef) #[[ATTR4]] ; IS__CGSCC____-NEXT: ret i1 [[CALL]] ; %call = call i1 @recursive_alloca_compare(i1 %c, i1* undef)