21 #define DEBUG_TYPE "stack-safety" 31 const Value *AllocaPtr;
37 const SCEV *visit(
const SCEV *Expr) {
41 if (!isa<SCEVAddRecExpr>(Expr) && !isa<SCEVAddExpr>(Expr) &&
42 !isa<SCEVUnknown>(Expr))
52 return SE.getZero(Expr->
getType());
58 struct PassAsArgInfo {
69 : Callee(Callee), ParamNo(ParamNo), Offset(Offset) {}
75 return OS <<
"@" << P.getName() <<
"(arg" << P.ParamNo <<
", " << P.Offset
88 explicit UseInfo(
unsigned PointerSize) : Range{PointerSize,
false} {}
95 for (
auto &Call : U.Calls)
105 AllocaInfo(
unsigned PointerSize,
const AllocaInst *AI, uint64_t Size)
106 : AI(AI), Size(Size), Use(PointerSize) {}
112 return OS << A.getName() <<
"[" << A.Size <<
"]: " << A.Use;
119 explicit ParamInfo(
unsigned PointerSize,
const Argument *Arg)
120 : Arg(Arg), Use(PointerSize) {}
126 return OS << P.getName() <<
"[]: " << P.Use;
131 uint64_t getStaticAllocaAllocationSize(
const AllocaInst *AI) {
138 Size *=
C->getZExtValue();
175 O <<
" @" <<
getName() << (IsDSOLocal() ?
"" :
" dso_preemptable")
176 << (IsInterposable() ?
" interposable" :
"") <<
"\n";
177 O <<
" args uses:\n";
178 for (
auto &P : Params)
179 O <<
" " << P <<
"\n";
180 O <<
" allocas uses:\n";
181 for (
auto &AS : Allocas)
182 O <<
" " << AS <<
"\n";
194 for (
unsigned ArgNo = 0; ArgNo < Type->
getNumParams(); ArgNo++) {
203 class StackSafetyLocalAnalysis {
207 unsigned PointerSize = 0;
213 uint64_t AccessSize);
215 const Value *AllocaPtr);
217 bool analyzeAllUses(
const Value *Ptr, UseInfo &AS);
227 UnknownRange(PointerSize,
true) {}
234 StackSafetyLocalAnalysis::offsetFromAlloca(
Value *Addr,
235 const Value *AllocaPtr) {
236 if (!SE.isSCEVable(Addr->
getType()))
239 AllocaOffsetRewriter
Rewriter(SE, AllocaPtr);
240 const SCEV *Expr = Rewriter.visit(SE.getSCEV(Addr));
247 const Value *AllocaPtr,
248 uint64_t AccessSize) {
249 if (!SE.isSCEVable(Addr->
getType()))
252 AllocaOffsetRewriter
Rewriter(SE, AllocaPtr);
253 const SCEV *Expr = Rewriter.visit(SE.getSCEV(Addr));
256 SE.getUnsignedRange(Expr).
zextOrTrunc(PointerSize);
263 ConstantRange StackSafetyLocalAnalysis::getMemIntrinsicAccessRange(
265 if (
auto MTI = dyn_cast<MemTransferInst>(MI)) {
266 if (MTI->getRawSource() != U && MTI->getRawDest() != U)
267 return getRange(0, 1);
270 return getRange(0, 1);
276 ConstantRange AccessRange = getAccessRange(U, AllocaPtr, Len->getZExtValue());
282 bool StackSafetyLocalAnalysis::analyzeAllUses(
const Value *Ptr, UseInfo &US) {
288 while (!WorkList.
empty()) {
290 for (
const Use &UI : V->
uses()) {
291 auto I = cast<const Instruction>(UI.getUser());
294 switch (
I->getOpcode()) {
301 case Instruction::VAArg:
305 if (V ==
I->getOperand(0)) {
307 US.updateRange(UnknownRange);
310 US.updateRange(getAccessRange(
319 US.updateRange(UnknownRange);
323 case Instruction::Invoke: {
326 if (
I->isLifetimeStartOrEnd())
330 US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr));
340 US.updateRange(UnknownRange);
344 assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee));
350 US.Calls.emplace_back(Callee, A - B, Offset);
359 WorkList.
push_back(cast<const Instruction>(
I));
370 "Can't run StackSafety on a function declaration");
375 if (
auto AI = dyn_cast<AllocaInst>(&
I)) {
377 getStaticAllocaAllocationSize(AI));
379 analyzeAllUses(AI, AS.Use);
386 analyzeAllUses(&A, PS.Use);
394 class StackSafetyDataFlowAnalysis {
396 std::map<const GlobalValue *, StackSafetyInfo::FunctionInfo>;
398 FunctionMap Functions;
403 unsigned PointerSize = 0;
407 unsigned ParamNo)
const;
408 bool updateOneUse(UseInfo &US,
bool UpdateToFullSet);
412 updateOneNode(Callee, Functions.find(Callee)->second);
414 void updateAllNodes() {
415 for (
auto &
F : Functions)
416 updateOneNode(
F.first,
F.second);
419 void verifyFixedPoint();
422 StackSafetyDataFlowAnalysis(
427 StackSafetyDataFlowAnalysis::StackSafetyDataFlowAnalysis(
430 UnknownRange(PointerSize,
true) {
434 if (!
F.isDeclaration())
435 Functions.emplace(&
F, FI(
F));
437 if (isa<Function>(A.getBaseObject()))
442 StackSafetyDataFlowAnalysis::getArgumentAccessRange(
const GlobalValue *Callee,
443 unsigned ParamNo)
const {
444 auto IT = Functions.find(Callee);
446 if (
IT == Functions.end())
455 return FS.
Params[ParamNo].Use.Range;
458 bool StackSafetyDataFlowAnalysis::updateOneUse(UseInfo &US,
459 bool UpdateToFullSet) {
460 bool Changed =
false;
461 for (
auto &CS : US.Calls) {
462 assert(!CS.Offset.isEmptySet() &&
463 "Param range can't be empty-set, invalid offset range");
465 ConstantRange CalleeRange = getArgumentAccessRange(CS.Callee, CS.ParamNo);
466 CalleeRange = CalleeRange.add(CS.Offset);
467 if (!US.Range.contains(CalleeRange)) {
470 US.Range = UnknownRange;
472 US.Range = US.Range.unionWith(CalleeRange);
478 void StackSafetyDataFlowAnalysis::updateOneNode(
481 bool Changed =
false;
483 Changed |= updateOneUse(AS.Use, UpdateToFullSet);
484 for (
auto &PS : FS.
Params)
485 Changed |= updateOneUse(PS.Use, UpdateToFullSet);
489 << (UpdateToFullSet ?
", full-set" :
"") <<
"] " 492 for (
auto &CallerID : Callers[Callee])
493 WorkList.insert(CallerID);
499 void StackSafetyDataFlowAnalysis::runDataFlow() {
504 for (
auto &
F : Functions) {
508 for (
auto &CS : AS.Use.Calls)
510 for (
auto &PS : FS.
Params)
511 for (
auto &CS : PS.Use.Calls)
517 for (
auto &Callee : Callees)
518 Callers[
Callee].push_back(
F.first);
523 while (!WorkList.empty()) {
526 updateOneNode(Callee);
530 void StackSafetyDataFlowAnalysis::verifyFixedPoint() {
541 for (
auto &
F : Functions)
542 SSI.emplace(
F.first, std::move(
F.second));
549 if (!
F.isDeclaration()) {
550 SSI.find(&
F)->second.print(O);
555 SSI.find(&A)->second.print(O);
559 assert(Count == SSI.size() &&
"Unexpected functions in the result");
564 StackSafetyInfo::StackSafetyInfo() =
default;
585 OS <<
"'Stack Safety Local Analysis' for function '" << F.
getName() <<
"'\n";
606 StackSafetyLocalAnalysis SSLA(
607 F, getAnalysis<ScalarEvolutionWrapperPass>().getSE());
619 StackSafetyDataFlowAnalysis SSDFA(
628 OS <<
"'Stack Safety Analysis' for module '" << M.
getName() <<
"'\n";
652 StackSafetyDataFlowAnalysis SSDFA(
654 return getAnalysis<StackSafetyInfoWrapperPass>(
F).
getResult();
673 GlobalPassName, false, false)
A parsed version of the target data layout string in and methods for querying it. ...
Result run(Module &M, ModuleAnalysisManager &AM)
const GlobalObject * getBaseObject() const
iterator_range< use_iterator > uses()
FunctionInfo(const StackSafetyInfo &SSI)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This class represents an incoming formal argument to a Function.
ConstantRange unionWith(const ConstantRange &CR) const
Return the range that results from the union of this range with another range.
StringRef getName() const
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents lattice values for constants.
A Module instance is used to store all the information related to an LLVM module. ...
void print(raw_ostream &O, const Module *M) const override
print - Print out the internal state of the pass.
void push_back(const T &Elt)
The main scalar evolution driver.
StackSafetyGlobalInfoWrapperPass()
bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time...
unsigned getPointerSizeInBits(unsigned AS=0) const
Layout pointer size, in bits FIXME: The defaults need to be removed once all of the backends/clients ...
StringRef getName() const
Get a short "name" for the module.
block Block Frequency true
FunctionInfo(const Function *F)
Value * getLength() const
const SCEV * visit(const SCEV *S)
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass...
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
A Use represents the edge between a Value definition and its users.
static StringRef getName(Value *V)
void print(raw_ostream &O, const Module *M) const override
print - Print out the internal state of the pass.
ConstantRange zextOrTrunc(uint32_t BitWidth) const
Make this range have the bit width given by BitWidth.
static const char LocalPassArg[]
ValTy * getCalledValue() const
Return the pointer to function that is being called.
Class to represent function types.
Type * getType() const
All values are typed, get the type of this value.
Describes uses of allocas and parameters inside of a single function.
INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, false, true) INITIALIZE_PASS_END(StackSafetyInfoWrapperPass
void print(raw_ostream &O) const
This pass performs the global (interprocedural) stack safety analysis (legacy pass manager)...
amdgpu Simplify well known AMD library false Value * Callee
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
The operation itself must be expressed in terms of simpler actions on this target.
Analysis containing CSE Info
const StackSafetyGlobalInfo & getResult() const
StackSafetyInfo wrapper for the new pass manager.
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on...
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
initializer< Ty > init(const Ty &Val)
SmallVector< ParamInfo, 4 > Params
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
A set of analyses that are preserved following a run of a transformation pass.
iterator_range< iterator > functions()
StackSafetyInfo run(Function &F, FunctionAnalysisManager &AM)
The instances of the Type class are immutable: once they are created, they are never changed...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
Interface to access stack safety analysis results for single function.
unsigned getNumParams() const
Return the number of fixed parameters this function type requires.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Represent the analysis usage information of a pass.
Select target instructions out of generic instructions
FunctionPass class - This class is used to implement most global optimizations.
ConstantRange add(const ConstantRange &Other) const
Return a new range representing the possible values resulting from an addition of a value in this ran...
iterator erase(const_iterator CI)
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
This pass performs the global (interprocedural) stack safety analysis (new pass manager).
const Value * getArraySize() const
Get the number of elements allocated.
StackSafetyInfo wrapper for the legacy pass manager.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
static cl::opt< int > StackSafetyMaxIterations("stack-safety-max-iterations", cl::init(20), cl::Hidden)
void sort(IteratorTy Start, IteratorTy End)
bool isEmptySet() const
Return true if this set contains no members.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
This is the common base class for memset/memcpy/memmove.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
This is the shared class of boolean and integer constants.
static const char LocalPassName[]
void print(raw_ostream &O) const
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
std::map< const GlobalValue *, StackSafetyInfo > StackSafetyGlobalInfo
This class represents a range of values.
LLVM_NODISCARD T pop_back_val()
static true const char GlobalPassName[]
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Class for arbitrary precision integers.
void setPreservesAll()
Set by analyses that do not transform their input at all.
amdgpu Simplify well known AMD library false Value Value * Arg
Analysis pass that exposes the ScalarEvolution for a function.
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::ZeroOrMore, cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate IT block based on arch"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow deprecated IT based on ARMv8"), clEnumValN(NoRestrictedIT, "arm-no-restrict-it", "Allow IT blocks based on ARMv7")))
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
Virtual Register Rewriter
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
block Block Frequency Analysis
void emplace_back(ArgTypes &&... Args)
This class represents an analyzed expression in the program.
LLVM_NODISCARD bool empty() const
const Value * stripPointerCastsNoFollowAliases() const
Strip off pointer casts and all-zero GEPs.
StringRef getName() const
Return a constant reference to the value's name.
Establish a view to a call site for examination.
StackSafetyInfoWrapperPass()
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
void initializeStackSafetyGlobalInfoWrapperPassPass(PassRegistry &)
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Type * getValueType() const
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool isArrayAllocation() const
Return true if there is an allocation size parameter to the allocation instruction that is not 1...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void initializeStackSafetyInfoWrapperPassPass(PassRegistry &)
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
uint64_t getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type...
A vector that has set insertion semantics.
SmallVector< AllocaInfo, 4 > Allocas
This class implements an extremely fast bulk output stream that can only output to a stream...
print Print MemDeps of function
StringRef - Represent a constant reference to a string, i.e.
A container for analyses that lazily runs them and caches their results.
Value * getRawDest() const
A special type used by analysis passes to provide an address that identifies that particular analysis...
This visitor recursively visits a SCEV expression and re-writes it.
bool IsInterposable() const
an instruction to allocate memory on the stack
iterator_range< alias_iterator > aliases()
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...