Index: include/llvm/Transforms/IPO/DeadArgumentElimination.h =================================================================== --- include/llvm/Transforms/IPO/DeadArgumentElimination.h +++ include/llvm/Transforms/IPO/DeadArgumentElimination.h @@ -32,6 +32,7 @@ namespace llvm { class Module; +class TargetLibraryInfo; class Use; class Value; @@ -128,7 +129,7 @@ unsigned RetValNum = -1U); Liveness SurveyUses(const Value *V, UseVector &MaybeLiveUses); - void SurveyFunction(const Function &F); + void SurveyFunction(const Function &F, const TargetLibraryInfo &TLI); void MarkValue(const RetOrArg &RA, Liveness L, const UseVector &MaybeLiveUses); void MarkLive(const RetOrArg &RA); Index: lib/Transforms/IPO/ArgumentPromotion.cpp =================================================================== --- lib/Transforms/IPO/ArgumentPromotion.cpp +++ lib/Transforms/IPO/ArgumentPromotion.cpp @@ -816,7 +816,8 @@ promoteArguments(Function *F, function_ref AARGetter, unsigned MaxElements, Optional> - ReplaceCallSite) { + ReplaceCallSite, + const TargetLibraryInfo &TLI) { // Don't perform argument promotion for naked functions; otherwise we can end // up removing parameters that are seemingly 'not used' as they are referred // to in the assembly. @@ -827,6 +828,12 @@ if (!F->hasLocalLinkage()) return nullptr; + // Don't promote arguments for library functions. We can make assumptions + // about library function signatures in later passes. + LibFunc LF; + if (TLI.getLibFunc(*F, LF)) + return nullptr; + // Don't promote arguments for variadic functions. Adding, removing, or // changing non-pack parameters can change the classification of pack // parameters. Frontends encode that classification at the call site in the @@ -978,8 +985,10 @@ assert(&F == &OldF && "Called with an unexpected function!"); return FAM.getResult(F); }; + const TargetLibraryInfo *TLI = &FAM.getResult(OldF); - Function *NewF = promoteArguments(&OldF, AARGetter, MaxElements, None); + Function *NewF = promoteArguments(&OldF, AARGetter, MaxElements, None, + *TLI); if (!NewF) continue; LocalChange = true; @@ -1056,6 +1065,8 @@ // Get the callgraph information that we need to update to reflect our // changes. CallGraph &CG = getAnalysis().getCallGraph(); + TargetLibraryInfo const& TLI = + getAnalysis().getTLI(); LegacyAARGetter AARGetter(*this); @@ -1079,7 +1090,7 @@ }; if (Function *NewF = promoteArguments(OldF, AARGetter, MaxElements, - {ReplaceCallSite})) { + {ReplaceCallSite}, TLI)) { LocalChange = true; // Update the call graph for the newly promoted function. Index: lib/Transforms/IPO/DeadArgumentElimination.cpp =================================================================== --- lib/Transforms/IPO/DeadArgumentElimination.cpp +++ lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -20,6 +20,7 @@ #include "llvm/Transforms/IPO/DeadArgumentElimination.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -79,6 +80,7 @@ return false; DeadArgumentEliminationPass DAEP(ShouldHackArguments()); ModuleAnalysisManager DummyMAM; + DummyMAM.registerPass([&] { return TargetLibraryAnalysis(); }); PreservedAnalyses PA = DAEP.run(M, DummyMAM); return !PA.areAllPreserved(); } @@ -480,7 +482,8 @@ // // We consider arguments of non-internal functions to be intrinsically alive as // well as arguments to functions which have their "address taken". -void DeadArgumentEliminationPass::SurveyFunction(const Function &F) { +void DeadArgumentEliminationPass::SurveyFunction(const Function &F, + const TargetLibraryInfo &TLI) { // Functions with inalloca parameters are expecting args in a particular // register and memory layout. if (F.getAttributes().hasAttrSomewhere(Attribute::InAlloca)) { @@ -533,7 +536,10 @@ << " has musttail calls\n"); } - if (!F.hasLocalLinkage() && (!ShouldHackArguments || F.isIntrinsic())) { + bool CanTouchArguments = ShouldHackArguments && !F.isIntrinsic(); + LibFunc LF; + bool IsLibFunc = TLI.getLibFunc(F, LF); + if ((!F.hasLocalLinkage() && !CanTouchArguments) || IsLibFunc) { MarkLive(F); return; } @@ -1079,8 +1085,9 @@ } PreservedAnalyses DeadArgumentEliminationPass::run(Module &M, - ModuleAnalysisManager &) { + ModuleAnalysisManager &AM) { bool Changed = false; + const TargetLibraryInfo *TLI = &AM.getResult(M); // First pass: Do a simple check to see if any functions can have their "..." // removed. We can do this if they never call va_start. This loop cannot be @@ -1099,7 +1106,7 @@ // LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - Determining liveness\n"); for (auto &F : M) - SurveyFunction(F); + SurveyFunction(F, *TLI); // Now, remove all dead arguments and return values from each function in // turn. Index: test/Other/ipo-libfunc-signature.ll =================================================================== --- /dev/null +++ test/Other/ipo-libfunc-signature.ll @@ -0,0 +1,29 @@ +; RUN: opt %s -S -internalize -internalize-public-api-list=main -std-link-opts | FileCheck %s + +@Msg = hidden global [32 x i8] zeroinitializer, align 16 +@main.Parms = internal global [64 x i8] zeroinitializer, align 16 + +; Function Attrs: nounwind +define hidden void @main() local_unnamed_addr { +entry: + %call150 = call i8* @strcat( + i8* getelementptr inbounds ([64 x i8], [64 x i8]* @main.Parms, i32 0, i32 0), + i8* getelementptr inbounds ([32 x i8], [32 x i8]* @Msg, i32 0, i32 0)) + ret void +} + +declare hidden i8* @strcpy(i8* noalias returned, i8* noalias) local_unnamed_addr +declare hidden i32 @strlen(i8* %s) local_unnamed_addr + + +; CHECK: define{{.*}}i8* @strcat(i8*{{.*}}%dest, i8*{{.*}}%src) +; Function Attrs: noinline nounwind optsize +define hidden i8* @strcat(i8* noalias returned %dest, i8* noalias %src) local_unnamed_addr #0 { +entry: + %call = tail call i32 @strlen(i8* %dest) + %add.ptr = getelementptr inbounds i8, i8* %dest, i32 %call + %call1 = tail call i8* @strcpy(i8* %add.ptr, i8* %src) + ret i8* %dest +} + +attributes #0 = { noinline nounwind optsize }