[llvm] r347611 - [stack-safety] Inter-Procedural Analysis implementation
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 26 15:05:58 PST 2018
Author: vitalybuka
Date: Mon Nov 26 15:05:58 2018
New Revision: 347611
URL: http://llvm.org/viewvc/llvm-project?rev=347611&view=rev
Log:
[stack-safety] Inter-Procedural Analysis implementation
Summary:
IPA is implemented as module pass which produce map from Function or Alias to
StackSafetyInfo for a single function.
>From prototype by Evgenii Stepanov and Vlad Tsyrklevich.
Reviewers: eugenis, vlad.tsyrklevich, pcc, glider
Subscribers: hiraditya, mgrang, llvm-commits
Differential Revision: https://reviews.llvm.org/D54543
Added:
llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/
llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa-alias.ll
llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa.ll
llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa.ll
llvm/trunk/test/Analysis/StackSafetyAnalysis/scev-udiv.ll
Modified:
llvm/trunk/lib/Analysis/StackSafetyAnalysis.cpp
llvm/trunk/test/Analysis/StackSafetyAnalysis/local.ll
llvm/trunk/test/Analysis/StackSafetyAnalysis/memintrin.ll
Modified: llvm/trunk/lib/Analysis/StackSafetyAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/StackSafetyAnalysis.cpp?rev=347611&r1=347610&r2=347611&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/StackSafetyAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/StackSafetyAnalysis.cpp Mon Nov 26 15:05:58 2018
@@ -10,7 +10,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/StackSafetyAnalysis.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstIterator.h"
@@ -21,6 +20,9 @@ using namespace llvm;
#define DEBUG_TYPE "stack-safety"
+static cl::opt<int> StackSafetyMaxIterations("stack-safety-max-iterations",
+ cl::init(20), cl::Hidden);
+
namespace {
/// Rewrite an SCEV expression for a memory access address to an expression that
@@ -150,9 +152,14 @@ struct StackSafetyInfo::FunctionInfo {
SmallVector<ParamInfo, 4> Params;
// TODO: describe return value as depending on one or more of its arguments.
+ // StackSafetyDataFlowAnalysis counter stored here for faster access.
+ int UpdateCount = 0;
+
FunctionInfo(const StackSafetyInfo &SSI) : FunctionInfo(*SSI.Info) {}
explicit FunctionInfo(const Function *F) : GV(F){};
+ // Creates FunctionInfo that forwards all the parameters to the aliasee.
+ explicit FunctionInfo(const GlobalAlias *A);
FunctionInfo(FunctionInfo &&) = default;
@@ -163,6 +170,8 @@ struct StackSafetyInfo::FunctionInfo {
StringRef getName() const { return GV->getName(); }
void print(raw_ostream &O) const {
+ // TODO: Consider different printout format after
+ // StackSafetyDataFlowAnalysis. Calls and parameters are irrelevant then.
O << " @" << getName() << (IsDSOLocal() ? "" : " dso_preemptable")
<< (IsInterposable() ? " interposable" : "") << "\n";
O << " args uses:\n";
@@ -177,6 +186,18 @@ private:
FunctionInfo(const FunctionInfo &) = default;
};
+StackSafetyInfo::FunctionInfo::FunctionInfo(const GlobalAlias *A) : GV(A) {
+ unsigned PointerSize = A->getParent()->getDataLayout().getPointerSizeInBits();
+ const GlobalObject *Aliasee = A->getBaseObject();
+ const FunctionType *Type = cast<FunctionType>(Aliasee->getValueType());
+ // 'Forward' all parameters to this alias to the aliasee
+ for (unsigned ArgNo = 0; ArgNo < Type->getNumParams(); ArgNo++) {
+ Params.emplace_back(PointerSize, nullptr);
+ UseInfo &US = Params.back().Use;
+ US.Calls.emplace_back(Aliasee, ArgNo, ConstantRange(APInt(PointerSize, 0)));
+ }
+}
+
namespace {
class StackSafetyLocalAnalysis {
@@ -373,8 +394,172 @@ StackSafetyInfo StackSafetyLocalAnalysis
return StackSafetyInfo(std::move(Info));
}
+class StackSafetyDataFlowAnalysis {
+ using FunctionMap =
+ std::map<const GlobalValue *, StackSafetyInfo::FunctionInfo>;
+
+ FunctionMap Functions;
+ // Callee-to-Caller multimap.
+ DenseMap<const GlobalValue *, SmallVector<const GlobalValue *, 4>> Callers;
+ SetVector<const GlobalValue *> WorkList;
+
+ unsigned PointerSize = 0;
+ const ConstantRange UnknownRange;
+
+ ConstantRange getArgumentAccessRange(const GlobalValue *Callee,
+ unsigned ParamNo) const;
+ bool updateOneUse(UseInfo &US, bool UpdateToFullSet);
+ void updateOneNode(const GlobalValue *Callee,
+ StackSafetyInfo::FunctionInfo &FS);
+ void updateOneNode(const GlobalValue *Callee) {
+ updateOneNode(Callee, Functions.find(Callee)->second);
+ }
+ void updateAllNodes() {
+ for (auto &F : Functions)
+ updateOneNode(F.first, F.second);
+ }
+ void runDataFlow();
+ void verifyFixedPoint();
+
+public:
+ StackSafetyDataFlowAnalysis(
+ Module &M, std::function<const StackSafetyInfo &(Function &)> FI);
+ StackSafetyGlobalInfo run();
+};
+
+StackSafetyDataFlowAnalysis::StackSafetyDataFlowAnalysis(
+ Module &M, std::function<const StackSafetyInfo &(Function &)> FI)
+ : PointerSize(M.getDataLayout().getPointerSizeInBits()),
+ UnknownRange(PointerSize, true) {
+ // Without ThinLTO, run the local analysis for every function in the TU and
+ // then run the DFA and annotate allocas
+ for (auto &F : M.functions())
+ if (!F.isDeclaration())
+ Functions.emplace(&F, FI(F));
+ for (auto &A : M.aliases())
+ if (isa<Function>(A.getBaseObject()))
+ Functions.emplace(&A, &A);
+}
+
+ConstantRange
+StackSafetyDataFlowAnalysis::getArgumentAccessRange(const GlobalValue *Callee,
+ unsigned ParamNo) const {
+ auto IT = Functions.find(Callee);
+ // Unknown callee (outside of LTO domain or an indirect call).
+ if (IT == Functions.end())
+ return UnknownRange;
+ const StackSafetyInfo::FunctionInfo &FS = IT->second;
+ // The definition of this symbol may not be the definition in this linkage
+ // unit.
+ if (!FS.IsDSOLocal() || FS.IsInterposable())
+ return UnknownRange;
+ if (ParamNo >= FS.Params.size()) // possibly vararg
+ return UnknownRange;
+ return FS.Params[ParamNo].Use.Range;
+}
+
+bool StackSafetyDataFlowAnalysis::updateOneUse(UseInfo &US,
+ bool UpdateToFullSet) {
+ bool Changed = false;
+ for (auto &CS : US.Calls) {
+ assert(!CS.Range.isEmptySet() &&
+ "Param range can't be empty-set, invalid access range");
+
+ ConstantRange CalleeRange = getArgumentAccessRange(CS.Callee, CS.ParamNo);
+ CalleeRange = CalleeRange.add(CS.Offset);
+ if (!US.Range.contains(CalleeRange)) {
+ Changed = true;
+ if (UpdateToFullSet)
+ US.Range = UnknownRange;
+ else
+ US.Range = US.Range.unionWith(CalleeRange);
+ }
+ }
+ return Changed;
+}
+
+void StackSafetyDataFlowAnalysis::updateOneNode(
+ const GlobalValue *Callee, StackSafetyInfo::FunctionInfo &FS) {
+ bool UpdateToFullSet = FS.UpdateCount > StackSafetyMaxIterations;
+ bool Changed = false;
+ for (auto &AS : FS.Allocas)
+ Changed |= updateOneUse(AS.Use, UpdateToFullSet);
+ for (auto &PS : FS.Params)
+ Changed |= updateOneUse(PS.Use, UpdateToFullSet);
+
+ if (Changed) {
+ LLVM_DEBUG(dbgs() << "=== update [" << FS.UpdateCount
+ << (UpdateToFullSet ? ", full-set" : "") << "] "
+ << FS.getName() << "\n");
+ // Callers of this function may need updating.
+ for (auto &CallerID : Callers[Callee])
+ WorkList.insert(CallerID);
+
+ ++FS.UpdateCount;
+ }
+}
+
+void StackSafetyDataFlowAnalysis::runDataFlow() {
+ Callers.clear();
+ WorkList.clear();
+
+ SmallVector<const GlobalValue *, 16> Callees;
+ for (auto &F : Functions) {
+ Callees.clear();
+ StackSafetyInfo::FunctionInfo &FS = F.second;
+ for (auto &AS : FS.Allocas)
+ for (auto &CS : AS.Use.Calls)
+ Callees.push_back(CS.Callee);
+ for (auto &PS : FS.Params)
+ for (auto &CS : PS.Use.Calls)
+ Callees.push_back(CS.Callee);
+
+ llvm::sort(Callees);
+ Callees.erase(std::unique(Callees.begin(), Callees.end()), Callees.end());
+
+ for (auto &Callee : Callees)
+ Callers[Callee].push_back(F.first);
+ }
+
+ updateAllNodes();
+
+ while (!WorkList.empty()) {
+ const GlobalValue *Callee = WorkList.back();
+ WorkList.pop_back();
+ updateOneNode(Callee);
+ }
+}
+
+void StackSafetyDataFlowAnalysis::verifyFixedPoint() {
+ WorkList.clear();
+ updateAllNodes();
+ assert(WorkList.empty());
+}
+
+StackSafetyGlobalInfo StackSafetyDataFlowAnalysis::run() {
+ runDataFlow();
+ LLVM_DEBUG(verifyFixedPoint());
+
+ StackSafetyGlobalInfo SSI;
+ for (auto &F : Functions)
+ SSI.emplace(F.first, std::move(F.second));
+ return SSI;
+}
+
void print(const StackSafetyGlobalInfo &SSI, raw_ostream &O, const Module &M) {
- O << "Not Implemented\n";
+ size_t Count = 0;
+ for (auto &F : M.functions())
+ if (!F.isDeclaration()) {
+ SSI.find(&F)->second.print(O);
+ O << "\n";
+ ++Count;
+ }
+ for (auto &A : M.aliases()) {
+ SSI.find(&A)->second.print(O);
+ O << "\n";
+ ++Count;
+ }
+ assert(Count == SSI.size() && "Unexpected functions in the result");
}
} // end anonymous namespace
@@ -431,7 +616,14 @@ AnalysisKey StackSafetyGlobalAnalysis::K
StackSafetyGlobalInfo
StackSafetyGlobalAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
- return {};
+ FunctionAnalysisManager &FAM =
+ AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+
+ StackSafetyDataFlowAnalysis SSDFA(
+ M, [&FAM](Function &F) -> const StackSafetyInfo & {
+ return FAM.getResult<StackSafetyAnalysis>(F);
+ });
+ return SSDFA.run();
}
PreservedAnalyses StackSafetyGlobalPrinterPass::run(Module &M,
@@ -459,7 +651,14 @@ void StackSafetyGlobalInfoWrapperPass::g
AU.addRequired<StackSafetyInfoWrapperPass>();
}
-bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) { return false; }
+bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) {
+ StackSafetyDataFlowAnalysis SSDFA(
+ M, [this](Function &F) -> const StackSafetyInfo & {
+ return getAnalysis<StackSafetyInfoWrapperPass>(F).getResult();
+ });
+ SSI = SSDFA.run();
+ return false;
+}
static const char LocalPassArg[] = "stack-safety-local";
static const char LocalPassName[] = "Stack Safety Local Analysis";
Added: llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa-alias.ll?rev=347611&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa-alias.ll (added)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa-alias.ll Mon Nov 26 15:05:58 2018
@@ -0,0 +1,18 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at InterposableAliasWrite1 = linkonce dso_local alias void(i8*), void(i8*)* @Write1
+
+ at PreemptableAliasWrite1 = dso_preemptable alias void(i8*), void(i8*)* @Write1
+ at AliasToPreemptableAliasWrite1 = dso_local alias void(i8*), void(i8*)* @PreemptableAliasWrite1
+
+ at AliasWrite1 = dso_local alias void(i8*), void(i8*)* @Write1
+
+ at BitcastAliasWrite1 = dso_local alias void(i32*), bitcast (void(i8*)* @Write1 to void(i32*)*)
+ at AliasToBitcastAliasWrite1 = dso_local alias void(i8*), bitcast (void(i32*)* @BitcastAliasWrite1 to void(i8*)*)
+
+define dso_local void @Write1(i8* %p) {
+entry:
+ store i8 0, i8* %p, align 1
+ ret void
+}
Added: llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa.ll?rev=347611&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa.ll (added)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/Inputs/ipa.ll Mon Nov 26 15:05:58 2018
@@ -0,0 +1,118 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define dso_local void @Write1(i8* %p) {
+entry:
+ store i8 0, i8* %p, align 1
+ ret void
+}
+
+define dso_local void @Write4(i8* %p) {
+entry:
+ %0 = bitcast i8* %p to i32*
+ store i32 0, i32* %0, align 1
+ ret void
+}
+
+define dso_local void @Write4_2(i8* %p, i8* %q) {
+entry:
+ %0 = bitcast i8* %p to i32*
+ store i32 0, i32* %0, align 1
+ %1 = bitcast i8* %q to i32*
+ store i32 0, i32* %1, align 1
+ ret void
+}
+
+define dso_local void @Write8(i8* %p) {
+entry:
+ %0 = bitcast i8* %p to i64*
+ store i64 0, i64* %0, align 1
+ ret void
+}
+
+define dso_local i8* @WriteAndReturn8(i8* %p) {
+entry:
+ store i8 0, i8* %p, align 1
+ ret i8* %p
+}
+
+declare dso_local void @ExternalCall(i8* %p)
+
+define dso_preemptable void @PreemptableWrite1(i8* %p) {
+entry:
+ store i8 0, i8* %p, align 1
+ ret void
+}
+
+define linkonce dso_local void @InterposableWrite1(i8* %p) {
+entry:
+ store i8 0, i8* %p, align 1
+ ret void
+}
+
+define dso_local i8* @ReturnDependent(i8* %p) {
+entry:
+ %p2 = getelementptr i8, i8* %p, i64 2
+ ret i8* %p2
+}
+
+; access range [2, 6)
+define dso_local void @Rec0(i8* %p) {
+entry:
+ %p1 = getelementptr i8, i8* %p, i64 2
+ call void @Write4(i8* %p1)
+ ret void
+}
+
+; access range [3, 7)
+define dso_local void @Rec1(i8* %p) {
+entry:
+ %p1 = getelementptr i8, i8* %p, i64 1
+ call void @Rec0(i8* %p1)
+ ret void
+}
+
+; access range [-2, 2)
+define dso_local void @Rec2(i8* %p) {
+entry:
+ %p1 = getelementptr i8, i8* %p, i64 -5
+ call void @Rec1(i8* %p1)
+ ret void
+}
+
+; Recursive function that passes %acc unchanged => access range [0, 4).
+define dso_local void @RecursiveNoOffset(i32* %p, i32 %size, i32* %acc) {
+entry:
+ %cmp = icmp eq i32 %size, 0
+ br i1 %cmp, label %return, label %if.end
+
+if.end:
+ %0 = load i32, i32* %p, align 4
+ %1 = load i32, i32* %acc, align 4
+ %add = add nsw i32 %1, %0
+ store i32 %add, i32* %acc, align 4
+ %add.ptr = getelementptr inbounds i32, i32* %p, i64 1
+ %sub = add nsw i32 %size, -1
+ tail call void @RecursiveNoOffset(i32* %add.ptr, i32 %sub, i32* %acc)
+ ret void
+
+return:
+ ret void
+}
+
+; Recursive function that advances %acc on each iteration => access range unlimited.
+define dso_local void @RecursiveWithOffset(i32 %size, i32* %acc) {
+entry:
+ %cmp = icmp eq i32 %size, 0
+ br i1 %cmp, label %return, label %if.end
+
+if.end:
+ store i32 0, i32* %acc, align 4
+ %acc2 = getelementptr inbounds i32, i32* %acc, i64 1
+ %sub = add nsw i32 %size, -1
+ tail call void @RecursiveWithOffset(i32 %sub, i32* %acc2)
+ ret void
+
+return:
+ ret void
+}
Added: llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa-alias.ll?rev=347611&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa-alias.ll (added)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa-alias.ll Mon Nov 26 15:05:58 2018
@@ -0,0 +1,133 @@
+; Test IPA over a single combined file
+; RUN: llvm-as %s -o %t0.bc
+; RUN: llvm-as %S/Inputs/ipa-alias.ll -o %t1.bc
+; RUN: llvm-link %t0.bc %t1.bc -o %t.combined.bc
+; RUN: opt -S -analyze -stack-safety-local %t.combined.bc | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -passes="print<stack-safety-local>" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -analyze -stack-safety %t.combined.bc | FileCheck %s --check-prefixes=CHECK,GLOBAL
+; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @PreemptableAliasWrite1(i8* %p)
+declare void @AliasToPreemptableAliasWrite1(i8* %p)
+
+declare void @InterposableAliasWrite1(i8* %p)
+; Aliases to interposable aliases are not allowed
+
+declare void @AliasWrite1(i8* %p)
+
+declare void @BitcastAliasWrite1(i32* %p)
+declare void @AliasToBitcastAliasWrite1(i8* %p)
+
+; Call to dso_preemptable alias to a dso_local aliasee
+define void @PreemptableAliasCall() {
+; CHECK-LABEL: @PreemptableAliasCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x1[1]: empty-set, @PreemptableAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x1[1]: full-set, @PreemptableAliasWrite1(arg0, [0,1)){{$}}
+; LOCAL-NEXT: x2[1]: empty-set, @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x2[1]: [0,1), @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x1 = alloca i8
+ call void @PreemptableAliasWrite1(i8* %x1)
+
+ %x2 = alloca i8
+; Alias to a preemptable alias is not preemptable
+ call void @AliasToPreemptableAliasWrite1(i8* %x2)
+ ret void
+}
+
+; Call to an interposable alias to a non-interposable aliasee
+define void @InterposableAliasCall() {
+; CHECK-LABEL: @InterposableAliasCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[1]: empty-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[1]: full-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8
+; ThinLTO can resolve the prevailing implementation for interposable definitions.
+ call void @InterposableAliasWrite1(i8* %x)
+ ret void
+}
+
+; Call to a dso_local/non-interposable alias/aliasee
+define void @AliasCall() {
+; CHECK-LABEL: @AliasCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[1]: empty-set, @AliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[1]: [0,1), @AliasWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8
+ call void @AliasWrite1(i8* %x)
+ ret void
+}
+
+; Call to a bitcasted dso_local/non-interposable alias/aliasee
+define void @BitcastAliasCall() {
+; CHECK-LABEL: @BitcastAliasCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x1[4]: empty-set, @BitcastAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x1[4]: [0,1), @BitcastAliasWrite1(arg0, [0,1)){{$}}
+; LOCAL-NEXT: x2[1]: empty-set, @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x2[1]: [0,1), @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x1 = alloca i32
+ call void @BitcastAliasWrite1(i32* %x1)
+ %x2 = alloca i8
+ call void @AliasToBitcastAliasWrite1(i8* %x2)
+ ret void
+}
+
+; The rest is from Inputs/ipa-alias.ll
+
+; CHECK-LABEL: @Write1{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,1){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; GLOBAL-LABEL: @InterposableAliasWrite1 interposable{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
+
+; GLOBAL-LABEL: @PreemptableAliasWrite1 dso_preemptable{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
+
+; GLOBAL-LABEL: @AliasToPreemptableAliasWrite1{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
+
+; GLOBAL-LABEL: @AliasWrite1{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
+
+; GLOBAL-LABEL: @BitcastAliasWrite1{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
+
+; GLOBAL-LABEL: @AliasToBitcastAliasWrite1{{$}}
+; GLOBAL-NEXT: args uses:
+; GLOBAL-NEXT: <N/A>[]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: allocas uses:
+; GLOBAL-NOT: ]:
Added: llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa.ll?rev=347611&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa.ll (added)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/ipa.ll Mon Nov 26 15:05:58 2018
@@ -0,0 +1,448 @@
+; RUN: llvm-as %s -o %t0.bc
+; RUN: llvm-as %S/Inputs/ipa.ll -o %t1.bc
+; RUN: llvm-link -disable-lazy-loading %t0.bc %t1.bc -o %t.combined.bc
+; RUN: opt -S -analyze -stack-safety-local %t.combined.bc | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -passes="print<stack-safety-local>" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -analyze -stack-safety %t.combined.bc | FileCheck %s --check-prefixes=CHECK,GLOBAL
+; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @Write1(i8* %p)
+declare void @Write4(i8* %p)
+declare void @Write4_2(i8* %p, i8* %q)
+declare void @Write8(i8* %p)
+declare dso_local i8* @WriteAndReturn8(i8* %p)
+declare dso_local void @ExternalCall(i8* %p)
+declare void @PreemptableWrite1(i8* %p)
+declare void @InterposableWrite1(i8* %p)
+declare i8* @ReturnDependent(i8* %p)
+declare void @Rec2(i8* %p)
+declare void @RecursiveNoOffset(i32* %p, i32 %size, i32* %acc)
+declare void @RecursiveWithOffset(i32 %size, i32* %acc)
+
+; Basic out-of-bounds.
+define void @f1() {
+; CHECK-LABEL: @f1 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @Write8(i8* %x1)
+ ret void
+}
+
+; Basic in-bounds.
+define void @f2() {
+; CHECK-LABEL: @f2 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @Write1(i8* %x1)
+ ret void
+}
+
+; Another basic in-bounds.
+define void @f3() {
+; CHECK-LABEL: @f3 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @Write4(i8* %x1)
+ ret void
+}
+
+; In-bounds with offset.
+define void @f4() {
+; CHECK-LABEL: @f4 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 1
+ call void @Write1(i8* %x2)
+ ret void
+}
+
+; Out-of-bounds with offset.
+define void @f5() {
+; CHECK-LABEL: @f5 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 1
+ call void @Write4(i8* %x2)
+ ret void
+}
+
+; External call.
+define void @f6() {
+; CHECK-LABEL: @f6 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @ExternalCall(i8* %x1)
+ ret void
+}
+
+; Call to dso_preemptable function
+define void @PreemptableCall() {
+; CHECK-LABEL: @PreemptableCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @PreemptableWrite1(i8* %x1)
+ ret void
+}
+
+; Call to function with interposable linkage
+define void @InterposableCall() {
+; CHECK-LABEL: @InterposableCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @InterposableWrite1(i8* %x1)
+ ret void
+}
+
+; Call to function with private linkage
+define void @PrivateCall() {
+; CHECK-LABEL: @PrivateCall dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ call void @PrivateWrite1(i8* %x1)
+ ret void
+}
+
+define private void @PrivateWrite1(i8* %p) {
+; CHECK-LABEL: @PrivateWrite1{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,1){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+entry:
+ store i8 0, i8* %p, align 1
+ ret void
+}
+
+; Caller returns a dependent value.
+; FIXME: alloca considered unsafe even if the return value is unused.
+define void @f7() {
+; CHECK-LABEL: @f7 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i32, align 4
+ %x1 = bitcast i32* %x to i8*
+ %x2 = call i8* @ReturnDependent(i8* %x1)
+ ret void
+}
+
+define void @f8left() {
+; CHECK-LABEL: @f8left dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}}
+; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 2
+; 2 + [-2, 2) = [0, 4) => OK
+ call void @Rec2(i8* %x2)
+ ret void
+}
+
+define void @f8right() {
+; CHECK-LABEL: @f8right dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}}
+; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 6
+; 6 + [-2, 2) = [4, 8) => OK
+ call void @Rec2(i8* %x2)
+ ret void
+}
+
+define void @f8oobleft() {
+; CHECK-LABEL: @f8oobleft dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 1
+; 1 + [-2, 2) = [-1, 3) => NOT OK
+ call void @Rec2(i8* %x2)
+ ret void
+}
+
+define void @f8oobright() {
+; CHECK-LABEL: @f8oobright dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}}
+; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 7
+; 7 + [-2, 2) = [5, 9) => NOT OK
+ call void @Rec2(i8* %x2)
+ ret void
+}
+
+define void @TwoArguments() {
+; CHECK-LABEL: @TwoArguments dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [0,1)), @Write4_2(arg0, [4,5)){{$}}
+; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg1, [0,1)), @Write4_2(arg0, [4,5)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 4
+ call void @Write4_2(i8* %x2, i8* %x1)
+ ret void
+}
+
+define void @TwoArgumentsOOBOne() {
+; CHECK-LABEL: @TwoArgumentsOOBOne dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [0,1)), @Write4_2(arg0, [5,6)){{$}}
+; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg1, [0,1)), @Write4_2(arg0, [5,6)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x1 = bitcast i64* %x to i8*
+ %x2 = getelementptr i8, i8* %x1, i64 5
+ call void @Write4_2(i8* %x2, i8* %x1)
+ ret void
+}
+
+define void @TwoArgumentsOOBOther() {
+; CHECK-LABEL: @TwoArgumentsOOBOther dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [4,5)){{$}}
+; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [4,5)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x0 = bitcast i64* %x to i8*
+ %x1 = getelementptr i8, i8* %x0, i64 -1
+ %x2 = getelementptr i8, i8* %x0, i64 4
+ call void @Write4_2(i8* %x2, i8* %x1)
+ ret void
+}
+
+define void @TwoArgumentsOOBBoth() {
+; CHECK-LABEL: @TwoArgumentsOOBBoth dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [5,6)){{$}}
+; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [5,6)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i64, align 4
+ %x0 = bitcast i64* %x to i8*
+ %x1 = getelementptr i8, i8* %x0, i64 -1
+ %x2 = getelementptr i8, i8* %x0, i64 5
+ call void @Write4_2(i8* %x2, i8* %x1)
+ ret void
+}
+
+define i32 @TestRecursiveNoOffset(i32* %p, i32 %size) {
+; CHECK-LABEL: @TestRecursiveNoOffset dso_preemptable{{$}}
+; 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: ]:
+entry:
+ %sum = alloca i32, align 4
+ %0 = bitcast i32* %sum to i8*
+ store i32 0, i32* %sum, align 4
+ call void @RecursiveNoOffset(i32* %p, i32 %size, i32* %sum)
+ %1 = load i32, i32* %sum, align 4
+ ret i32 %1
+}
+
+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)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %sum = alloca i32, i64 16, align 4
+ call void @RecursiveWithOffset(i32 %size, i32* %sum)
+ ret void
+}
+
+; FIXME: IPA should detect that access is safe
+define void @TestUpdateArg() {
+; CHECK-LABEL: @TestUpdateArg dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8, i64 16, align 4
+ %0 = call i8* @WriteAndReturn8(i8* %x)
+ ret void
+}
+
+; The rest is from Inputs/ipa.ll
+
+; CHECK-LABEL: @Write1{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,1){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Write4{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,4){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Write4_2{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,4){{$}}
+; CHECK-NEXT: q[]: [0,4){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Write8{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,8){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @WriteAndReturn8{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: full-set{{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,1){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @InterposableWrite1 interposable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: [0,1){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @ReturnDependent{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: p[]: full-set{{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Rec0{{$}}
+; CHECK-NEXT: args uses:
+; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}}
+; GLOBAL-NEXT: p[]: [2,6), @Write4(arg0, [2,3)){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Rec1{{$}}
+; CHECK-NEXT: args uses:
+; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: p[]: [3,7), @Rec0(arg0, [1,2)){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @Rec2{{$}}
+; CHECK-NEXT: args uses:
+; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}}
+; GLOBAL-NEXT: p[]: [-2,2), @Rec1(arg0, [-5,-4)){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+
+; CHECK-LABEL: @RecursiveNoOffset{{$}}
+; 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, [4294967295,4294967296)){{$}}
+; 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, [4294967295,4294967296)){{$}}
+; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}}
+; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
Modified: llvm/trunk/test/Analysis/StackSafetyAnalysis/local.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/local.ll?rev=347611&r1=347610&r2=347611&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/local.ll (original)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/local.ll Mon Nov 26 15:05:58 2018
@@ -1,9 +1,7 @@
-; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s
-; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefix=GLOBAL
-; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefix=GLOBAL
-
-; GLOBAL: Not Implemented
+; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL
+; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@@ -147,7 +145,8 @@ define void @DirectCall() {
; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
-; CHECK-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
+; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
+; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
; CHECK-NOT: ]:
entry:
%x = alloca i64, align 4
Modified: llvm/trunk/test/Analysis/StackSafetyAnalysis/memintrin.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/memintrin.ll?rev=347611&r1=347610&r2=347611&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/memintrin.ll (original)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/memintrin.ll Mon Nov 26 15:05:58 2018
@@ -1,5 +1,7 @@
; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s
; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s
+; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
Added: llvm/trunk/test/Analysis/StackSafetyAnalysis/scev-udiv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/StackSafetyAnalysis/scev-udiv.ll?rev=347611&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/StackSafetyAnalysis/scev-udiv.ll (added)
+++ llvm/trunk/test/Analysis/StackSafetyAnalysis/scev-udiv.ll Mon Nov 26 15:05:58 2018
@@ -0,0 +1,65 @@
+; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
+; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL
+; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
+
+; Regression test that exercises a case when a AllocaOffsetRewritten SCEV
+; could return an empty-set range. This could occur with udiv SCEVs where the
+; RHS was re-written to 0.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @ExternalFn(i64)
+
+define void @Test1() {
+; CHECK-LABEL: @Test1 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[1]: empty-set, @Divide1(arg0, full-set){{$}}
+; GLOBAL-NEXT: x[1]: full-set, @Divide1(arg0, full-set){{$}}
+; CHECK-NOT: ]:
+ %x = alloca i8
+ %int = ptrtoint i8* %x to i64
+ call void @Divide1(i64 %int)
+ ret void
+}
+
+define dso_local void @Divide1(i64 %arg) {
+; CHECK-LABEL: @Divide1{{$}}
+; CHECK-NEXT: args uses:
+; LOCAL-NEXT: arg[]: empty-set, @ExternalFn(arg0, full-set){{$}}
+; GLOBAL-NEXT: arg[]: full-set, @ExternalFn(arg0, full-set){{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+ %quotient = udiv i64 undef, %arg
+ call void @ExternalFn(i64 %quotient)
+ unreachable
+}
+
+define void @Test2(i64 %arg) {
+; CHECK-LABEL: @Test2 dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: arg[]: empty-set{{$}}
+; CHECK-NEXT: allocas uses:
+; LOCAL-NEXT: x[1]: empty-set, @Divide2(arg0, full-set){{$}}
+; GLOBAL-NEXT: x[1]: full-set, @Divide2(arg0, full-set){{$}}
+; CHECK-NOT: ]:
+ %x = alloca i8
+ %int = ptrtoint i8* %x to i64
+ call void @Divide2(i64 %int)
+ ret void
+}
+
+define dso_local void @Divide2(i64 %arg) {
+; CHECK-LABEL: @Divide2{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: arg[]: full-set{{$}}
+; CHECK-NEXT: allocas uses:
+; CHECK-NOT: ]:
+ %x = inttoptr i64 %arg to i8*
+ %quotient = udiv i64 undef, %arg
+ %arrayidx = getelementptr i8, i8* %x, i64 %quotient
+ load i8, i8* %arrayidx
+ unreachable
+}
More information about the llvm-commits
mailing list