llvm.org GIT mirror llvm / 356397d
Only promote args when function attributes are compatible Summary: Check to make sure that the caller and the callee have compatible function arguments before promoting arguments. This uses the same TargetTransformInfo queries that are used to determine if attributes are compatible for inlining. The goal here is to avoid breaking ABI when a called function's ABI depends on a target feature that is not enabled in the caller. This is a very conservative fix for PR37358. Ideally we would have a more sophisticated check for ABI compatiblity rather than checking if the attributes are compatible for inlining. Reviewers: echristo, chandlerc, eli.friedman, craig.topper Reviewed By: echristo, chandlerc Subscribers: nikic, xbolva00, rkruppe, alexcrichton, llvm-commits Differential Revision: https://reviews.llvm.org/D53554 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351296 91177308-0d34-0410-b5e6-96231b3b80d8 Tom Stellard 8 months ago
5 changed file(s) with 114 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
932932 /// purposes.
933933 bool areInlineCompatible(const Function *Caller,
934934 const Function *Callee) const;
935
936 /// \returns True if the caller and callee agree on how \p Args will be passed
937 /// to the callee.
938 /// \param[out] Args The list of compatible arguments. The implementation may
939 /// filter out any incompatible args from this list.
940 bool areFunctionArgsABICompatible(const Function *Caller,
941 const Function *Callee,
942 SmallPtrSetImpl &Args) const;
935943
936944 /// The type of load/store indexing.
937945 enum MemIndexedMode {
11781186 unsigned RemainingBytes, unsigned SrcAlign, unsigned DestAlign) const = 0;
11791187 virtual bool areInlineCompatible(const Function *Caller,
11801188 const Function *Callee) const = 0;
1189 virtual bool
1190 areFunctionArgsABICompatible(const Function *Caller, const Function *Callee,
1191 SmallPtrSetImpl &Args) const = 0;
11811192 virtual bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const = 0;
11821193 virtual bool isIndexedStoreLegal(MemIndexedMode Mode,Type *Ty) const = 0;
11831194 virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const = 0;
15561567 const Function *Callee) const override {
15571568 return Impl.areInlineCompatible(Caller, Callee);
15581569 }
1570 bool areFunctionArgsABICompatible(
1571 const Function *Caller, const Function *Callee,
1572 SmallPtrSetImpl &Args) const override {
1573 return Impl.areFunctionArgsABICompatible(Caller, Callee, Args);
1574 }
15591575 bool isIndexedLoadLegal(MemIndexedMode Mode, Type *Ty) const override {
15601576 return Impl.isIndexedLoadLegal(Mode, Ty, getDataLayout());
15611577 }
525525 Callee->getFnAttribute("target-features"));
526526 }
527527
528 bool areFunctionArgsABICompatible(const Function *Caller, const Function *Callee,
529 SmallPtrSetImpl &Args) const {
530 return (Caller->getFnAttribute("target-cpu") ==
531 Callee->getFnAttribute("target-cpu")) &&
532 (Caller->getFnAttribute("target-features") ==
533 Callee->getFnAttribute("target-features"));
534 }
535
528536 bool isIndexedLoadLegal(TTI::MemIndexedMode Mode, Type *Ty,
529537 const DataLayout &DL) const {
530538 return false;
622622 bool TargetTransformInfo::areInlineCompatible(const Function *Caller,
623623 const Function *Callee) const {
624624 return TTIImpl->areInlineCompatible(Caller, Callee);
625 }
626
627 bool TargetTransformInfo::areFunctionArgsABICompatible(
628 const Function *Caller, const Function *Callee,
629 SmallPtrSetImpl &Args) const {
630 return TTIImpl->areFunctionArgsABICompatible(Caller, Callee, Args);
625631 }
626632
627633 bool TargetTransformInfo::isIndexedLoadLegal(MemIndexedMode Mode,
4848 #include "llvm/Analysis/Loads.h"
4949 #include "llvm/Analysis/MemoryLocation.h"
5050 #include "llvm/Analysis/TargetLibraryInfo.h"
51 #include "llvm/Analysis/TargetTransformInfo.h"
5152 #include "llvm/IR/Argument.h"
5253 #include "llvm/IR/Attributes.h"
5354 #include "llvm/IR/BasicBlock.h"
808809 return false;
809810 }
810811
812 static bool areFunctionArgsABICompatible(
813 const Function &F, const TargetTransformInfo &TTI,
814 SmallPtrSetImpl &ArgsToPromote,
815 SmallPtrSetImpl &ByValArgsToTransform) {
816 for (const Use &U : F.uses()) {
817 CallSite CS(U.getUser());
818 const Function *Caller = CS.getCaller();
819 const Function *Callee = CS.getCalledFunction();
820 if (!TTI.areFunctionArgsABICompatible(Caller, Callee, ArgsToPromote) ||
821 !TTI.areFunctionArgsABICompatible(Caller, Callee, ByValArgsToTransform))
822 return false;
823 }
824 return true;
825 }
826
811827 /// PromoteArguments - This method checks the specified function to see if there
812828 /// are any promotable arguments and if it is safe to promote the function (for
813829 /// example, all callers are direct). If safe to promote some arguments, it
816832 promoteArguments(Function *F, function_ref AARGetter,
817833 unsigned MaxElements,
818834 Optional>
819 ReplaceCallSite) {
835 ReplaceCallSite,
836 const TargetTransformInfo &TTI) {
820837 // Don't perform argument promotion for naked functions; otherwise we can end
821838 // up removing parameters that are seemingly 'not used' as they are referred
822839 // to in the assembly.
845862
846863 // Second check: make sure that all callers are direct callers. We can't
847864 // transform functions that have indirect callers. Also see if the function
848 // is self-recursive.
865 // is self-recursive and check that target features are compatible.
849866 bool isSelfRecursive = false;
850867 for (Use &U : F->uses()) {
851868 CallSite CS(U.getUser());
954971 if (ArgsToPromote.empty() && ByValArgsToTransform.empty())
955972 return nullptr;
956973
974 if (!areFunctionArgsABICompatible(*F, TTI, ArgsToPromote,
975 ByValArgsToTransform))
976 return nullptr;
977
957978 return doPromotion(F, ArgsToPromote, ByValArgsToTransform, ReplaceCallSite);
958979 }
959980
9791000 return FAM.getResult(F);
9801001 };
9811002
982 Function *NewF = promoteArguments(&OldF, AARGetter, MaxElements, None);
1003 const TargetTransformInfo &TTI = FAM.getResult(OldF);
1004 Function *NewF =
1005 promoteArguments(&OldF, AARGetter, MaxElements, None, TTI);
9831006 if (!NewF)
9841007 continue;
9851008 LocalChange = true;
10171040 void getAnalysisUsage(AnalysisUsage &AU) const override {
10181041 AU.addRequired();
10191042 AU.addRequired();
1043 AU.addRequired();
10201044 getAAResultsAnalysisUsage(AU);
10211045 CallGraphSCCPass::getAnalysisUsage(AU);
10221046 }
10421066 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
10431067 INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
10441068 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
1069 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
10451070 INITIALIZE_PASS_END(ArgPromotion, "argpromotion",
10461071 "Promote 'by reference' arguments to scalars", false, false)
10471072
10781103 CallerNode->replaceCallEdge(OldCS, NewCS, NewCalleeNode);
10791104 };
10801105
1106 const TargetTransformInfo &TTI =
1107 getAnalysis().getTTI(*OldF);
10811108 if (Function *NewF = promoteArguments(OldF, AARGetter, MaxElements,
1082 {ReplaceCallSite})) {
1109 {ReplaceCallSite}, TTI)) {
10831110 LocalChange = true;
10841111
10851112 // Update the call graph for the newly promoted function.
0 ; RUN: opt -S -argpromotion < %s | FileCheck %s
1 ; RUN: opt -S -passes=argpromotion < %s | FileCheck %s
2 ; Test that we only promote arguments when the caller/callee have compatible
3 ; function attrubtes.
4
5 target triple = "x86_64-unknown-linux-gnu"
6
7 ; CHECK-LABEL: @no_promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1)
8 define internal fastcc void @no_promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
9 bb:
10 %tmp = load <4 x i64>, <4 x i64>* %arg1
11 store <4 x i64> %tmp, <4 x i64>* %arg
12 ret void
13 }
14
15 define void @no_promote(<4 x i64>* %arg) #1 {
16 bb:
17 %tmp = alloca <4 x i64>, align 32
18 %tmp2 = alloca <4 x i64>, align 32
19 %tmp3 = bitcast <4 x i64>* %tmp to i8*
20 call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
21 call fastcc void @no_promote_avx2(<4 x i64>* %tmp2, <4 x i64>* %tmp)
22 %tmp4 = load <4 x i64>, <4 x i64>* %tmp2, align 32
23 store <4 x i64> %tmp4, <4 x i64>* %arg, align 2
24 ret void
25 }
26
27 ; CHECK-LABEL: @promote_avx2(<4 x i64>* %arg, <4 x i64> %
28 define internal fastcc void @promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
29 bb:
30 %tmp = load <4 x i64>, <4 x i64>* %arg1
31 store <4 x i64> %tmp, <4 x i64>* %arg
32 ret void
33 }
34
35 define void @promote(<4 x i64>* %arg) #0 {
36 bb:
37 %tmp = alloca <4 x i64>, align 32
38 %tmp2 = alloca <4 x i64>, align 32
39 %tmp3 = bitcast <4 x i64>* %tmp to i8*
40 call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
41 call fastcc void @promote_avx2(<4 x i64>* %tmp2, <4 x i64>* %tmp)
42 %tmp4 = load <4 x i64>, <4 x i64>* %tmp2, align 32
43 store <4 x i64> %tmp4, <4 x i64>* %arg, align 2
44 ret void
45 }
46
47 ; Function Attrs: argmemonly nounwind
48 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #2
49
50 attributes #0 = { inlinehint norecurse nounwind uwtable "target-features"="+avx2" }
51 attributes #1 = { nounwind uwtable }
52 attributes #2 = { argmemonly nounwind }