Go to the documentation of this file.
47 #include "llvm/IR/IntrinsicsAArch64.h"
64 #define DEBUG_TYPE "aarch64-stack-tagging"
68 cl::desc(
"merge stack variable initializers with tagging when possible"));
73 cl::desc(
"Use Stack Safety analysis results"));
85 cl::desc(
"How many lifetime ends to handle for a single alloca."),
92 class InitializerBuilder {
108 std::map<uint64_t, Value *> Out;
115 SetTagZeroFn(SetTagZeroFn), StgpFn(StgpFn) {}
122 if (
I !=
Ranges.end() && End >
I->Start) {
126 Ranges.insert(
I, {Start, End, Inst});
131 int64_t StoreSize =
DL->getTypeStoreSize(
SI->getOperand(0)->getType());
145 cast<ConstantInt>(MSI->
getValue()));
149 void applyMemSet(
IRBuilder<> &IRB, int64_t Start, int64_t End,
157 uint64_t Cst = 0x0101010101010101UL;
158 int LowBits =
Offset < Start ? (Start -
Offset) * 8 : 0;
160 Cst = (Cst >> LowBits) << LowBits;
161 int HighBits = End -
Offset < 8 ? (8 - (End -
Offset)) * 8 : 0;
163 Cst = (Cst << HighBits) >> HighBits;
191 void applyStore(
IRBuilder<> &IRB, int64_t Start, int64_t End,
192 Value *StoredValue) {
193 StoredValue =
flatten(IRB, StoredValue);
195 Value *V = sliceValue(IRB, StoredValue,
Offset - Start);
200 CurrentV = IRB.
CreateOr(CurrentV, V);
209 emitUndef(IRB, 0, Size);
219 auto I2 = Out.find(
Offset + 8);
220 if (I1 == Out.end() && I2 == Out.end())
224 emitZeroes(IRB, LastOffset,
Offset - LastOffset);
230 emitPair(IRB,
Offset, Store1, Store2);
236 if (LastOffset < Size)
237 emitZeroes(IRB, LastOffset, Size - LastOffset);
239 for (
const auto &R : Ranges) {
240 R.Inst->eraseFromParent();
278 Type *EltTy = VecTy->getElementType();
280 uint32_t EltSize =
DL->getTypeSizeInBits(EltTy);
283 cast<FixedVectorType>(VecTy)->getNumElements());
293 const bool MergeInit;
294 const bool UseStackSafety;
299 AArch64StackTagging(
bool IsOptNone =
false)
319 StringRef getPassName()
const override {
return "AArch64 Stack Tagging"; }
349 return new AArch64StackTagging(IsOptNone);
355 InitializerBuilder &
IB) {
361 for (; Count <
ClScanLimit && !BI->isTerminator(); ++BI) {
362 if (!isa<DbgInfoIntrinsic>(*BI))
368 if (!isa<StoreInst>(BI) && !isa<MemSetInst>(BI)) {
372 if (BI->mayWriteToMemory() || BI->mayReadFromMemory())
377 if (
StoreInst *NextStore = dyn_cast<StoreInst>(BI)) {
378 if (!NextStore->isSimple())
382 std::optional<int64_t>
Offset =
389 LastInst = NextStore;
396 if (!isa<ConstantInt>(MSI->
getValue()))
400 std::optional<int64_t>
Offset =
415 auto SetTagZeroFunc =
420 InitializerBuilder
IB(Size,
DL,
Ptr, SetTagFunc, SetTagZeroFunc, StgpFunc);
424 if (MergeInit && !
F->hasOptNone() && LittleEndian &&
427 <<
", size = " << Size <<
"\n");
428 InsertBefore = collectInitializers(InsertBefore,
Ptr, Size,
IB);
442 Instruction *AArch64StackTagging::insertBaseTaggedPointer(
447 for (
auto &
I : AllocasToInstrument) {
463 Base->setName(
"basetag");
473 SSI = &getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult();
477 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
487 std::unique_ptr<DominatorTree> DeleteDT;
489 if (
auto *
P = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
490 DT = &
P->getDomTree();
493 DeleteDT = std::make_unique<DominatorTree>(*
F);
497 std::unique_ptr<PostDominatorTree> DeletePDT;
499 if (
auto *
P = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>())
500 PDT = &
P->getPostDomTree();
502 if (PDT ==
nullptr) {
503 DeletePDT = std::make_unique<PostDominatorTree>(*
F);
504 PDT = DeletePDT.get();
507 std::unique_ptr<LoopInfo> DeleteLI;
509 if (
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>()) {
510 LI = &LIWP->getLoopInfo();
512 DeleteLI = std::make_unique<LoopInfo>(*DT);
529 NextTag = (NextTag + 1) % 16;
533 F->getParent(), Intrinsic::aarch64_tagp, {Info.AI->getType()});
537 if (
Info.AI->hasName())
539 Info.AI->replaceAllUsesWith(TagPCall);
546 bool StandardLifetime =
551 if (StandardLifetime) {
554 cast<ConstantInt>(Start->getArgOperand(0))->getZExtValue();
556 tagAlloca(AI, Start->getNextNode(), Start->getArgOperand(1), Size);
558 auto TagEnd = [&](
Instruction *Node) { untagAlloca(AI, Node, Size); };
562 for (
auto *End :
Info.LifetimeEnd)
563 End->eraseFromParent();
569 for (
auto *RI : SInfo.
RetVec) {
570 untagAlloca(AI, RI, Size);
574 for (
auto *II :
Info.LifetimeStart)
575 II->eraseFromParent();
576 for (
auto *II :
Info.LifetimeEnd)
577 II->eraseFromParent();
581 for (
auto *DVI :
Info.DbgVariableIntrinsics)
582 DVI->replaceVariableLocationOp(OldAI,
Info.AI);
588 I->eraseFromParent();
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
This is an optimization pass for GlobalISel generic memory operations.
void initializeAArch64StackTaggingPass(PassRegistry &)
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
A parsed version of the target data layout string in and methods for querying it.
InstListType::iterator iterator
Instruction iterators...
bool isPointerTy() const
True if this is an instance of PointerType.
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Triple - Helper class for working with autoconf configuration names.
bool forAllReachableExits(const DominatorTree &DT, const PostDominatorTree &PDT, const LoopInfo &LI, const Instruction *Start, const SmallVectorImpl< IntrinsicInst * > &Ends, const SmallVectorImpl< Instruction * > &RetVec, llvm::function_ref< void(Instruction *)> Callback)
static cl::opt< bool > ClUseStackSafety("stack-tagging-use-stack-safety", cl::Hidden, cl::init(true), cl::desc("Use Stack Safety analysis results"))
The instances of the Type class are immutable: once they are created, they are never changed.
static cl::opt< bool > ClMergeInit("stack-tagging-merge-init", cl::Hidden, cl::init(true), cl::desc("merge stack variable initializers with tagging when possible"))
This class implements a map that also provides access to all stored values in a deterministic order.
static cl::opt< unsigned > ClScanLimit("stack-tagging-merge-init-scan-limit", cl::init(40), cl::Hidden)
LLVM Basic Block Representation.
SmallVector< Instruction *, 8 > RetVec
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isLittleEndian() const
Tests whether the target triple is little endian.
This is the shared class of boolean and integer constants.
static cl::opt< size_t > ClMaxLifetimes("stack-tagging-max-lifetimes-for-alloca", cl::Hidden, cl::init(3), cl::ReallyHidden, cl::desc("How many lifetime ends to handle for a single alloca."), cl::Optional)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
(vector float) vec_cmpeq(*A, *B) C
ModRefInfo getModRefInfo(const Instruction *I, const std::optional< MemoryLocation > &OptLoc)
Check whether or not an instruction may read or write the optionally specified memory location.
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Represent the analysis usage information of a pass.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static const Align kTagGranuleSize
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
LLVMContext & getContext() const
void setName(const Twine &Name)
Change the name of the value.
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
Analysis containing CSE Info
static FixedVectorType * get(Type *ElementType, unsigned NumElts)
This struct is a compact representation of a valid (non-zero power of two) alignment.
std::optional< int64_t > isPointerOffset(const Value *Ptr1, const Value *Ptr2, const DataLayout &DL)
If Ptr1 is provably equal to Ptr2 plus a constant offset, return that offset.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
Value * CreatePointerCast(Value *V, Type *DestTy, const Twine &Name="")
INITIALIZE_PASS_BEGIN(AArch64StackTagging, DEBUG_TYPE, "AArch64 Stack Tagging", false, false) INITIALIZE_PASS_END(AArch64StackTagging
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
bool isIntegerTy() const
True if this is an instance of IntegerType.
Base class of all SIMD vector types.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
static cl::opt< unsigned > ClMergeInitSizeLimit("stack-tagging-merge-init-size-limit", cl::init(272), cl::Hidden)
inst_range instructions(Function *F)
An instruction for storing to memory.
BasicBlock::iterator GetInsertPoint() const
Module * getParent()
Get the module that this global value is contained inside of...
SmallVector< Instruction *, 4 > UnrecognizedLifetimes
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
This is an important class for using LLVM in a threaded context.
PointerType * getInt8PtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer to an 8-bit integer value.
initializer< Ty > init(const Ty &Val)
Value handle that tracks a Value across RAUW.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void setOperand(unsigned i, Value *Val)
Value * getDest() const
This is just like getRawDest, but it strips off any cast instructions (including addrspacecast) that ...
void setPreservesCFG()
This function should be called by the pass, iff they do not:
StringRef - Represent a constant reference to a string, i.e.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
Type * getType() const
All values are typed, get the type of this value.
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Value * CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
const Instruction & front() const
bool isStandardLifetime(const SmallVectorImpl< IntrinsicInst * > &LifetimeStart, const SmallVectorImpl< IntrinsicInst * > &LifetimeEnd, const DominatorTree *DT, const LoopInfo *LI, size_t MaxLifetimes)
static bool runOnFunction(Function &F, bool PostInlining)
Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Value * getLength() const
void alignAndPadAlloca(memtag::AllocaInfo &Info, llvm::Align Align)
MapVector< AllocaInst *, AllocaInfo > AllocasToInstrument
Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
A wrapper class for inspecting calls to intrinsic functions.
This pass performs the global (interprocedural) stack safety analysis (legacy pass manager).
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=std::nullopt, const Twine &Name="", MDNode *FPMathTag=nullptr)
FunctionPass * createAArch64StackTaggingPass(bool IsOptNone)
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
const BasicBlock * getParent() const
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
bool isNoModRef(const ModRefInfo MRI)
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
FunctionPass class - This class is used to implement most global optimizations.
AnalysisUsage & addRequired()
an instruction to allocate memory on the stack
LLVM Value Representation.
Representation for a specific memory location.