diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -21,6 +21,7 @@ #include "llvm/InitializePasses.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -141,7 +142,7 @@ struct FunctionInfo { std::map Allocas; - SmallVector Params; + std::map Params; // TODO: describe return value as depending on one or more of its arguments. // StackSafetyDataFlowAnalysis counter stored here for faster access. @@ -154,13 +155,13 @@ << ((F && F->isInterposable()) ? " interposable" : "") << "\n"; O << " args uses:\n"; - size_t Pos = 0; - for (auto &P : Params) { - StringRef Name = ""; + for (auto &KV : Params) { + O << " "; if (F) - Name = F->getArg(Pos)->getName(); - O << " " << Name << "[]: " << P << "\n"; - ++Pos; + O << F->getArg(KV.first)->getName(); + else + O << formatv("arg{0}", KV.first); + O << "[]: " << KV.second << "\n"; } O << " allocas uses:\n"; @@ -389,15 +390,16 @@ for (auto &I : instructions(F)) { if (auto *AI = dyn_cast(&I)) { - UseInfo &AS = Info.Allocas.emplace(AI, PointerSize).first->second; - analyzeAllUses(AI, AS); + auto &UI = Info.Allocas.emplace(AI, PointerSize).first->second; + analyzeAllUses(AI, UI); } } for (Argument &A : make_range(F.arg_begin(), F.arg_end())) { - Info.Params.emplace_back(PointerSize); - UseInfo &PS = Info.Params.back(); - analyzeAllUses(&A, PS); + if (A.getType()->isPointerTy()) { + auto &UI = Info.Params.emplace(A.getArgNo(), PointerSize).first->second; + analyzeAllUses(&A, UI); + } } LLVM_DEBUG(Info.print(dbgs(), F.getName(), &F)); @@ -415,7 +417,6 @@ DenseMap> Callers; SetVector WorkList; - bool updateOneUse(UseInfo &US, bool UpdateToFullSet); void updateOneNode(const GlobalValue *Callee, FunctionInfo &FS); void updateOneNode(const GlobalValue *Callee) { @@ -445,17 +446,18 @@ ConstantRange StackSafetyDataFlowAnalysis::getArgumentAccessRange( const GlobalValue *Callee, unsigned ParamNo, const ConstantRange &Offsets) const { - auto IT = Functions.find(Callee); + auto FnIt = Functions.find(Callee); // Unknown callee (outside of LTO domain or an indirect call). - if (IT == Functions.end()) + if (FnIt == Functions.end()) return UnknownRange; - const FunctionInfo &FS = IT->second; - if (ParamNo >= FS.Params.size()) // possibly vararg + auto &FS = FnIt->second; + auto ParamIt = FS.Params.find(ParamNo); + if (ParamIt == FS.Params.end()) return UnknownRange; - auto &Access = FS.Params[ParamNo].Range; + auto &Access = ParamIt->second.Range; if (Access.isEmptySet()) return Access; - if (Access.isFullSet() || Offsets.isFullSet()) + if (Access.isFullSet()) return UnknownRange; if (Offsets.signedAddMayOverflow(Access) != ConstantRange::OverflowResult::NeverOverflows) @@ -487,8 +489,8 @@ FunctionInfo &FS) { bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations; bool Changed = false; - for (auto &PS : FS.Params) - Changed |= updateOneUse(PS, UpdateToFullSet); + for (auto &KV : FS.Params) + Changed |= updateOneUse(KV.second, UpdateToFullSet); if (Changed) { LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount @@ -509,9 +511,8 @@ SmallVector Callees; for (auto &F : Functions) { Callees.clear(); - FunctionInfo &FS = F.second; - for (auto &PS : FS.Params) - for (auto &CS : PS.Calls) + for (auto &KV : F.second.Params) + for (auto &CS : KV.second.Calls) Callees.push_back(CS.Callee); llvm::sort(Callees); @@ -574,11 +575,6 @@ } } -void resolveAllCalls(SmallVectorImpl &Values) { - for (auto &V : Values) - resolveAllCalls(V); -} - GVToSSI createGlobalStackSafetyInfo( std::map Functions) { GVToSSI SSI; @@ -588,8 +584,9 @@ // FIXME: Simplify printing and remove copying here. auto Copy = Functions; - for (auto &FI : Copy) - resolveAllCalls(FI.second.Params); + for (auto &FnKV : Copy) + for (auto &KV : FnKV.second.Params) + resolveAllCalls(KV.second); uint32_t PointerSize = Copy.begin() ->first->getParent() @@ -610,10 +607,9 @@ // FIXME: This is needed only to preserve calls in print() results. A.Calls = SrcF.Allocas.find(KV.first)->second.Calls; } - size_t Pos = 0; - for (auto &P : FI.Params) { - P.Calls = SrcF.Params[Pos].Calls; - ++Pos; + for (auto &KV : FI.Params) { + auto &P = KV.second; + P.Calls = SrcF.Params.find(KV.first)->second.Calls; } SSI[F.first] = std::move(FI); } diff --git a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll @@ -317,7 +317,6 @@ ; CHECK-NEXT: args uses: ; LOCAL-NEXT: p[]: empty-set, @RecursiveNoOffset(arg0, [0,1)){{$}} ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}} -; CHECK-NEXT: size[]: empty-set, @RecursiveNoOffset(arg1, [0,1)){{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} ; CHECK-NOT: ]: @@ -333,7 +332,6 @@ define void @TestRecursiveWithOffset(i32 %size) { ; CHECK-LABEL: @TestRecursiveWithOffset dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: size[]: empty-set, @RecursiveWithOffset(arg0, [0,1)){{$}} ; CHECK-NEXT: allocas uses: ; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}} ; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}} @@ -434,14 +432,12 @@ ; CHECK-NEXT: args uses: ; LOCAL-NEXT: p[]: [0,4), @RecursiveNoOffset(arg0, [4,5)){{$}} ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}} -; CHECK-NEXT: size[]: empty-set, @RecursiveNoOffset(arg1, [-1,0)){{$}} ; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NOT: ]: ; CHECK-LABEL: @RecursiveWithOffset{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: size[]: empty-set, @RecursiveWithOffset(arg0, [-1,0)){{$}} ; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}} ; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}} ; CHECK-NEXT: allocas uses: diff --git a/llvm/test/Analysis/StackSafetyAnalysis/local.ll b/llvm/test/Analysis/StackSafetyAnalysis/local.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/local.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/local.ll @@ -175,7 +175,6 @@ define void @NonConstantOffset(i1 zeroext %z) { ; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: z[]: full-set{{$}} ; CHECK-NEXT: allocas uses: ; FIXME: SCEV can't look through selects. ; CHECK-NEXT: x[4]: [-4,4){{$}} @@ -205,7 +204,6 @@ define void @PossiblyNegativeOffset(i16 %z) { ; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: z[]: full-set ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[40]: [-131072,131072){{$}} ; CHECK-NOT: ]: @@ -219,7 +217,6 @@ define void @NonConstantOffsetOOB(i1 zeroext %z) { ; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: z[]: full-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [-8,8){{$}} ; CHECK-NOT: ]: @@ -265,7 +262,6 @@ define void @DynamicAllocaUnused(i64 %size) { ; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: size[]: empty-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: empty-set{{$}} ; CHECK-NOT: ]: @@ -278,7 +274,6 @@ define void @DynamicAlloca(i64 %size) { ; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: size[]: [-9223372036854775808,9223372036854775796){{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,4){{$}} ; CHECK-NOT: ]: @@ -293,7 +288,6 @@ define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) { ; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: z[]: [-9223372036854775808,9223372036854775796){{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,4){{$}} ; CHECK-NOT: ]: @@ -359,7 +353,6 @@ define dso_local void @SizeCheck(i32 %sz) { ; CHECK-LABEL: @SizeCheck{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: sz[]: empty-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x1[128]: [0,4294967295){{$}} ; CHECK-NOT: ]: @@ -384,7 +377,6 @@ ; CHECK-NEXT: args uses: ; CHECK-NEXT: p[]: full-set ; CHECK-NEXT: unused[]: empty-set -; CHECK-NEXT: v[]: full-set ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,1){{$}} ; CHECK-NOT: ]: diff --git a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll --- a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll @@ -53,7 +53,6 @@ define void @MemsetNonConst(i32 %size) { ; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: size[]: empty-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4294967295){{$}} ; CHECK-NOT: ]: @@ -69,7 +68,6 @@ define void @MemsetNonConstInBounds(i1 zeroext %z) { ; CHECK-LABEL: MemsetNonConstInBounds dso_preemptable{{$}} ; CHECK-NEXT: args uses: -; CHECK-NEXT: z[]: empty-set{{$}} ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[4]: [0,4294967295){{$}} ; CHECK-NOT: ]: