llvm.org GIT mirror llvm / 1648cea
[PM] Port ArgumentPromotion to the new pass manager. Now that the call graph supports efficient replacement of a function and spurious reference edges, we can port ArgumentPromotion to the new pass manager very easily. The old PM-specific bits are sunk into callbacks that the new PM simply doesn't use. Unlike the old PM, the new PM simply does argument promotion and afterward does the update to LCG reflecting the promoted function. Differential Revision: https://reviews.llvm.org/D29580 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294667 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 2 years ago
20 changed file(s) with 135 addition(s) and 29 deletion(s). Raw diff Collapse all Expand all
0 //===- ArgumentPromotion.h - Promote by-reference arguments -----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H
10 #define LLVM_TRANSFORMS_IPO_ARGUMENTPROMOTION_H
11
12 #include "llvm/Analysis/CGSCCPassManager.h"
13 #include "llvm/Analysis/LazyCallGraph.h"
14
15 namespace llvm {
16
17 /// Argument promotion pass.
18 ///
19 /// This pass walks the functions in each SCC and for each one tries to
20 /// transform it and all of its callers to replace indirect arguments with
21 /// direct (by-value) arguments.
22 class ArgumentPromotionPass : public PassInfoMixin {
23 public:
24 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
25 LazyCallGraph &CG, CGSCCUpdateResult &UR);
26 };
27
28 }
29
30 #endif
6060 #include "llvm/Target/TargetMachine.h"
6161 #include "llvm/Transforms/GCOVProfiler.h"
6262 #include "llvm/Transforms/IPO/AlwaysInliner.h"
63 #include "llvm/Transforms/IPO/ArgumentPromotion.h"
6364 #include "llvm/Transforms/IPO/ConstantMerge.h"
6465 #include "llvm/Transforms/IPO/CrossDSOCFI.h"
6566 #include "llvm/Transforms/IPO/DeadArgumentElimination.h"
8484 #ifndef CGSCC_PASS
8585 #define CGSCC_PASS(NAME, CREATE_PASS)
8686 #endif
87 CGSCC_PASS("argpromotion", ArgumentPromotionPass())
8788 CGSCC_PASS("invalidate", InvalidateAllAnalysesPass())
8889 CGSCC_PASS("function-attrs", PostOrderFunctionAttrsPass())
8990 CGSCC_PASS("inline", InlinerPass())
2828 //
2929 //===----------------------------------------------------------------------===//
3030
31 #include "llvm/Transforms/IPO/ArgumentPromotion.h"
3132 #include "llvm/ADT/DepthFirstIterator.h"
33 #include "llvm/ADT/Optional.h"
3234 #include "llvm/ADT/Statistic.h"
3335 #include "llvm/ADT/StringExtras.h"
3436 #include "llvm/Analysis/AliasAnalysis.h"
3638 #include "llvm/Analysis/BasicAliasAnalysis.h"
3739 #include "llvm/Analysis/CallGraph.h"
3840 #include "llvm/Analysis/CallGraphSCCPass.h"
41 #include "llvm/Analysis/LazyCallGraph.h"
3942 #include "llvm/Analysis/Loads.h"
4043 #include "llvm/Analysis/TargetLibraryInfo.h"
4144 #include "llvm/IR/CFG.h"
6669 /// DoPromotion - This method actually performs the promotion of the specified
6770 /// arguments, and returns the new function. At this point, we know that it's
6871 /// safe to do so.
69 static CallGraphNode *
72 static Function *
7073 doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote,
71 SmallPtrSetImpl &ByValArgsToTransform, CallGraph &CG) {
74 SmallPtrSetImpl &ByValArgsToTransform,
75 Optional>
76 ReplaceCallSite) {
7277
7378 // Start by computing a new prototype for the function, which is the same as
7479 // the old function, but has modified arguments.
205210
206211 F->getParent()->getFunctionList().insert(F->getIterator(), NF);
207212 NF->takeName(F);
208
209 // Get a new callgraph node for NF.
210 CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF);
211213
212214 // Loop over all of the callers of the function, transforming the call sites
213215 // to pass in the loaded pointers.
333335 AttributesVec.clear();
334336
335337 // Update the callgraph to know that the callsite has been transformed.
336 CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()];
337 CalleeNode->replaceCallEdge(CS, CallSite(New), NF_CGN);
338 if (ReplaceCallSite)
339 (*ReplaceCallSite)(CS, CallSite(New));
338340
339341 if (!Call->use_empty()) {
340342 Call->replaceAllUsesWith(New);
462464 std::advance(I2, ArgIndices.size());
463465 }
464466
465 NF_CGN->stealCalledFunctionsFrom(CG[F]);
466
467 // Now that the old function is dead, delete it. If there is a dangling
468 // reference to the CallgraphNode, just leave the dead function around for
469 // someone else to nuke.
470 CallGraphNode *CGN = CG[F];
471 if (CGN->getNumReferences() == 0)
472 delete CG.removeFunctionFromModule(CGN);
473 else
474 F->setLinkage(Function::ExternalLinkage);
475
476 return NF_CGN;
467 return NF;
477468 }
478469
479470 /// AllCallersPassInValidPointerForArgument - Return true if we can prove that
817808 /// example, all callers are direct). If safe to promote some arguments, it
818809 /// calls the DoPromotion method.
819810 ///
820 static CallGraphNode *
821 promoteArguments(CallGraphNode *CGN, CallGraph &CG,
822 function_ref AARGetter,
823 unsigned MaxElements) {
824 Function *F = CGN->getFunction();
825
811 static Function *
812 promoteArguments(Function *F, function_ref AARGetter,
813 unsigned MaxElements,
814 Optional>
815 ReplaceCallSite) {
826816 // Make sure that it is local to this module.
827 if (!F || !F->hasLocalLinkage())
817 if (!F->hasLocalLinkage())
828818 return nullptr;
829819
830820 // Don't promote arguments for variadic functions. Adding, removing, or
949939 if (ArgsToPromote.empty() && ByValArgsToTransform.empty())
950940 return nullptr;
951941
952 return doPromotion(F, ArgsToPromote, ByValArgsToTransform, CG);
942 return doPromotion(F, ArgsToPromote, ByValArgsToTransform, ReplaceCallSite);
943 }
944
945 PreservedAnalyses ArgumentPromotionPass::run(LazyCallGraph::SCC &C,
946 CGSCCAnalysisManager &AM,
947 LazyCallGraph &CG,
948 CGSCCUpdateResult &UR) {
949 bool Changed = false, LocalChange;
950
951 // Iterate until we stop promoting from this SCC.
952 do {
953 LocalChange = false;
954
955 for (LazyCallGraph::Node &N : C) {
956 Function &OldF = N.getFunction();
957
958 FunctionAnalysisManager &FAM =
959 AM.getResult(C, CG).getManager();
960 // FIXME: This lambda must only be used with this function. We should
961 // skip the lambda and just get the AA results directly.
962 auto AARGetter = [&](Function &F) -> AAResults & {
963 assert(&F == &OldF && "Called with an unexpected function!");
964 return FAM.getResult(F);
965 };
966
967 Function *NewF = promoteArguments(&OldF, AARGetter, 3u, None);
968 if (!NewF)
969 continue;
970 LocalChange = true;
971
972 // Directly substitute the functions in the call graph. Note that this
973 // requires the old function to be completely dead and completely
974 // replaced by the new function. It does no call graph updates, it merely
975 // swaps out the particular function mapped to a particular node in the
976 // graph.
977 C.getOuterRefSCC().replaceNodeFunction(N, *NewF);
978 OldF.eraseFromParent();
979 }
980
981 Changed |= LocalChange;
982 } while (LocalChange);
983
984 if (!Changed)
985 return PreservedAnalyses::all();
986
987 return PreservedAnalyses::none();
953988 }
954989
955990 namespace {
10091044 LocalChange = false;
10101045 // Attempt to promote arguments from all functions in this SCC.
10111046 for (CallGraphNode *OldNode : SCC) {
1012 if (CallGraphNode *NewNode =
1013 promoteArguments(OldNode, CG, AARGetter, MaxElements)) {
1047 Function *OldF = OldNode->getFunction();
1048 if (!OldF)
1049 continue;
1050
1051 auto ReplaceCallSite = [&](CallSite OldCS, CallSite NewCS) {
1052 Function *Caller = OldCS.getInstruction()->getParent()->getParent();
1053 CallGraphNode *NewCalleeNode =
1054 CG.getOrInsertFunction(NewCS.getCalledFunction());
1055 CallGraphNode *CallerNode = CG[Caller];
1056 CallerNode->replaceCallEdge(OldCS, NewCS, NewCalleeNode);
1057 };
1058
1059 if (Function *NewF = promoteArguments(OldF, AARGetter, MaxElements,
1060 {ReplaceCallSite})) {
10141061 LocalChange = true;
1062
1063 // Update the call graph for the newly promoted function.
1064 CallGraphNode *NewNode = CG.getOrInsertFunction(NewF);
1065 NewNode->stealCalledFunctionsFrom(OldNode);
1066 if (OldNode->getNumReferences() == 0)
1067 delete CG.removeFunctionFromModule(OldNode);
1068 else
1069 OldF->setLinkage(Function::ExternalLinkage);
1070
1071 // And updat ethe SCC we're iterating as well.
10151072 SCC.ReplaceNode(OldNode, NewNode);
10161073 }
10171074 }
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 %T = type { i32, i32, i32, i32 }
34 @G = constant %T { i32 0, i32 0, i32 17, i32 25 }
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 %struct.ss = type { i32, i64 }
34
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 ; Arg promotion eliminates the struct argument.
34 ; FIXME: Should it eliminate the i32* argument?
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 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"
34
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 @G1 = constant i32 0
34 @G2 = constant i32* @G1
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 ; Don't promote around control flow.
34 define internal i32 @callee(i1 %C, i32* %P) {
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 ; CHECK: load i32, i32* %A
34 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"
0 ; RUN: opt -S < %s -inline -argpromotion | FileCheck %s
1 ; RUN: opt -S < %s -passes=inline,argpromotion | FileCheck %s
12
23 %S = type { %S* }
34
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 declare void @sink(i32)
34
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
34 target triple = "x86_64-unknown-linux-gnu"
0 ; RUN: opt %s -argpromotion -sroa -S | FileCheck %s
1 ; RUN: opt %s -passes='argpromotion,function(sroa)' -S | FileCheck %s
12
23 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"
34
0 ; RUN: opt -S -argpromotion < %s | FileCheck %s
1 ; RUN: opt -S -passes=argpromotion < %s | FileCheck %s
12 target triple = "x86_64-pc-windows-msvc"
23
34 define internal void @callee(i8*) {
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 ; PR17906
34 ; When we promote two arguments in a single function with different types,
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
34 target triple = "x86_64-pc-windows-msvc"
0 ; RUN: opt %s -argpromotion -S -o - | FileCheck %s
1 ; RUN: opt %s -passes=argpromotion -S -o - | FileCheck %s
12 ; PR14710
23
34 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
0 ; RUN: opt < %s -argpromotion -S | FileCheck %s
1 ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s
12
23 ; Unused arguments from variadic functions cannot be eliminated as that changes
34 ; their classiciation according to the SysV amd64 ABI. Clang and other frontends