Go to the documentation of this file.
49 #include "llvm/IR/IntrinsicsAArch64.h"
66 #define DEBUG_TYPE "aarch64-stack-tagging"
70 cl::desc(
"merge stack variable initializers with tagging when possible"));
75 cl::desc(
"Use Stack Safety analysis results"));
87 cl::desc(
"How many lifetime ends to handle for a single alloca."),
94 class InitializerBuilder {
110 std::map<uint64_t, Value *> Out;
117 SetTagZeroFn(SetTagZeroFn), StgpFn(StgpFn) {}
124 if (
I != Ranges.end() && End >
I->Start) {
128 Ranges.
insert(
I, {Start, End, Inst});
133 int64_t StoreSize =
DL->getTypeStoreSize(
SI->getOperand(0)->getType());
134 if (!
addRange(Offset, Offset + StoreSize,
SI))
137 applyStore(IRB, Offset, Offset + StoreSize,
SI->getOperand(0));
143 if (!
addRange(Offset, Offset + StoreSize, MSI))
146 applyMemSet(IRB, Offset, Offset + StoreSize,
147 cast<ConstantInt>(MSI->
getValue()));
151 void applyMemSet(
IRBuilder<> &IRB, int64_t Start, int64_t End,
158 for (int64_t Offset = Start - Start % 8;
Offset < End;
Offset += 8) {
159 uint64_t Cst = 0x0101010101010101UL;
160 int LowBits =
Offset < Start ? (Start -
Offset) * 8 : 0;
162 Cst = (Cst >> LowBits) << LowBits;
163 int HighBits = End -
Offset < 8 ? (8 - (End -
Offset)) * 8 : 0;
165 Cst = (Cst << HighBits) >> HighBits;
184 }
else if (Offset < 0) {
193 void applyStore(
IRBuilder<> &IRB, int64_t Start, int64_t End,
194 Value *StoredValue) {
195 StoredValue =
flatten(IRB, StoredValue);
196 for (int64_t Offset = Start - Start % 8;
Offset < End;
Offset += 8) {
197 Value *V = sliceValue(IRB, StoredValue, Offset - Start);
202 CurrentV = IRB.
CreateOr(CurrentV, V);
210 if (Ranges.empty()) {
211 emitUndef(IRB, 0, Size);
220 auto I1 = Out.find(Offset);
221 auto I2 = Out.find(Offset + 8);
222 if (
I1 == Out.end() && I2 == Out.end())
225 if (Offset > LastOffset)
226 emitZeroes(IRB, LastOffset, Offset - LastOffset);
232 emitPair(IRB, Offset, Store1, Store2);
238 if (LastOffset < Size)
239 emitZeroes(IRB, LastOffset, Size - LastOffset);
241 for (
const auto &R : Ranges) {
242 R.Inst->eraseFromParent();
266 LLVM_DEBUG(
dbgs() <<
" [" << Offset <<
", " << Offset + 16 <<
"):\n");
280 Type *EltTy = VecTy->getElementType();
282 uint32_t EltSize =
DL->getTypeSizeInBits(EltTy);
285 cast<FixedVectorType>(VecTy)->getNumElements());
295 const bool MergeInit;
296 const bool UseStackSafety;
301 AArch64StackTagging(
bool IsOptNone =
false)
309 bool isInterestingAlloca(
const AllocaInst &AI);
316 uint64_t Size, InitializerBuilder &IB);
323 StringRef getPassName()
const override {
return "AArch64 Stack Tagging"; }
353 return new AArch64StackTagging(IsOptNone);
359 InitializerBuilder &IB) {
365 for (; Count <
ClScanLimit && !BI->isTerminator(); ++BI) {
366 if (!isa<DbgInfoIntrinsic>(*BI))
372 if (!isa<StoreInst>(BI) && !isa<MemSetInst>(BI)) {
376 if (BI->mayWriteToMemory() || BI->mayReadFromMemory())
381 if (
StoreInst *NextStore = dyn_cast<StoreInst>(BI)) {
382 if (!NextStore->isSimple())
391 if (!IB.addStore(*Offset, NextStore,
DL))
393 LastInst = NextStore;
400 if (!isa<ConstantInt>(MSI->
getValue()))
408 if (!IB.addMemSet(*Offset, MSI))
416 bool AArch64StackTagging::isInterestingAlloca(
const AllocaInst &AI) {
428 !(SSI && SSI->
isSafe(AI));
429 return IsInteresting;
434 auto SetTagZeroFunc =
439 InitializerBuilder IB(Size,
DL, Ptr, SetTagFunc, SetTagZeroFunc, StgpFunc);
443 if (MergeInit && !
F->hasOptNone() && LittleEndian &&
446 <<
", size = " << Size <<
"\n");
447 InsertBefore = collectInitializers(InsertBefore, Ptr, Size, IB);
461 Instruction *AArch64StackTagging::insertBaseTaggedPointer(
466 for (
auto &
I : AllocasToInstrument) {
482 Base->setName(
"basetag");
492 SSI = &getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult();
496 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
499 [
this](
const AllocaInst &AI) {
return isInterestingAlloca(AI); });
507 std::unique_ptr<DominatorTree> DeleteDT;
509 if (
auto *
P = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
510 DT = &
P->getDomTree();
513 DeleteDT = std::make_unique<DominatorTree>(*
F);
517 std::unique_ptr<PostDominatorTree> DeletePDT;
519 if (
auto *
P = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>())
520 PDT = &
P->getPostDomTree();
522 if (PDT ==
nullptr) {
523 DeletePDT = std::make_unique<PostDominatorTree>(*
F);
524 PDT = DeletePDT.get();
527 std::unique_ptr<LoopInfo> DeleteLI;
529 if (
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>()) {
530 LI = &LIWP->getLoopInfo();
532 DeleteLI = std::make_unique<LoopInfo>(*DT);
549 NextTag = (NextTag + 1) % 16;
553 F->getParent(), Intrinsic::aarch64_tagp, {Info.AI->getType()});
557 if (
Info.AI->hasName())
559 Info.AI->replaceAllUsesWith(TagPCall);
566 bool StandardLifetime =
571 if (StandardLifetime) {
574 cast<ConstantInt>(Start->getArgOperand(0))->getZExtValue();
576 tagAlloca(AI, Start->getNextNode(), Start->getArgOperand(1), Size);
578 auto TagEnd = [&](
Instruction *Node) { untagAlloca(AI, Node, Size); };
582 for (
auto *End :
Info.LifetimeEnd)
583 End->eraseFromParent();
589 for (
auto &RI : SInfo.
RetVec) {
590 untagAlloca(AI, RI, Size);
594 for (
auto &II :
Info.LifetimeStart)
595 II->eraseFromParent();
596 for (
auto &II :
Info.LifetimeEnd)
597 II->eraseFromParent();
601 for (
auto DVI :
Info.DbgVariableIntrinsics)
602 DVI->replaceVariableLocationOp(OldAI,
Info.AI);
608 I->eraseFromParent();
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
This is an optimization pass for GlobalISel generic memory operations.
NodeT * findNearestCommonDominator(NodeT *A, NodeT *B) const
Find nearest common dominator basic block for basic block A and B.
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.
bool isSafe(const AllocaInst &AI) const
A parsed version of the target data layout string in and methods for querying it.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return 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.
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.
bool isLittleEndian() const
Tests whether the target triple is little endian.
This is the shared class of boolean and integer constants.
bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size.
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...
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
(vector float) vec_cmpeq(*A, *B) C
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.
Optional< TypeSize > getAllocationSizeInBits(const DataLayout &DL) const
Get allocation size in bits.
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 isSwiftError() const
Return true if this alloca is used as a swifterror argument to a call.
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.
LLVM_NODISCARD bool isNoModRef(const ModRefInfo MRI)
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())
StandardInstrumentations SI(Debug, VerifyEach)
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
void visit(Instruction &Inst)
Value * CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
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
A wrapper class for inspecting calls to intrinsic functions.
This pass performs the global (interprocedural) stack safety analysis (legacy pass manager).
bool isUsedWithInAlloca() const
Return true if this alloca is used as an inalloca argument to a call.
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.
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.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
Representation for a specific memory location.
iterator insert(iterator I, T &&Elt)