37#include "llvm/IR/IntrinsicsAArch64.h"
53#define DEBUG_TYPE "aarch64-stack-tagging"
57 cl::desc(
"merge stack variable initializers with tagging when possible"));
62 cl::desc(
"Use Stack Safety analysis results"));
74 cl::desc(
"How many lifetime ends to handle for a single alloca."),
89 "stack-tagging-record-stack-history",
90 cl::desc(
"Record stack frames with tagged allocations in a thread-local "
94 "storing into the stack ring buffer")),
101class InitializerBuilder {
117 std::map<uint64_t, Value *> Out;
124 SetTagZeroFn(SetTagZeroFn), StgpFn(StgpFn) {}
140 int64_t StoreSize =
DL->getTypeStoreSize(
SI->getOperand(0)->getType());
154 cast<ConstantInt>(MSI->
getValue()));
166 uint64_t Cst = 0x0101010101010101UL;
167 int LowBits =
Offset < Start ? (Start -
Offset) * 8 : 0;
169 Cst = (Cst >> LowBits) << LowBits;
172 Cst = (Cst << HighBits) >> HighBits;
174 ConstantInt::get(IRB.
getInt64Ty(), Cst *
V->getZExtValue());
201 Value *StoredValue) {
202 StoredValue = flatten(IRB, StoredValue);
204 Value *
V = sliceValue(IRB, StoredValue,
Offset - Start);
209 CurrentV = IRB.
CreateOr(CurrentV, V);
218 emitUndef(IRB, 0, Size);
228 auto I2 = Out.find(
Offset + 8);
229 if (I1 == Out.end() && I2 == Out.end())
233 emitZeroes(IRB, LastOffset,
Offset - LastOffset);
239 emitPair(IRB,
Offset, Store1, Store2);
245 if (LastOffset < Size)
246 emitZeroes(IRB, LastOffset, Size - LastOffset);
248 for (
const auto &R : Ranges) {
249 R.Inst->eraseFromParent();
282 if (
V->getType()->isIntegerTy())
285 if (
VectorType *VecTy = dyn_cast<VectorType>(
V->getType())) {
287 Type *EltTy = VecTy->getElementType();
289 uint32_t EltSize =
DL->getTypeSizeInBits(EltTy);
297 V, IRB.
getIntNTy(
DL->getTypeStoreSize(
V->getType()) * 8));
302 const bool MergeInit;
303 const bool UseStackSafety;
308 AArch64StackTagging(
bool IsOptNone =
false)
348char AArch64StackTagging::ID = 0;
359 return new AArch64StackTagging(IsOptNone);
365 InitializerBuilder &IB) {
371 for (; Count <
ClScanLimit && !BI->isTerminator(); ++BI) {
377 if (!isa<StoreInst>(BI) && !isa<MemSetInst>(BI)) {
381 if (BI->mayWriteToMemory() || BI->mayReadFromMemory())
386 if (
StoreInst *NextStore = dyn_cast<StoreInst>(BI)) {
387 if (!NextStore->isSimple())
391 std::optional<int64_t>
Offset =
392 NextStore->getPointerOperand()->getPointerOffsetFrom(StartPtr, *
DL);
398 LastInst = NextStore;
405 if (!isa<ConstantInt>(MSI->
getValue()))
409 std::optional<int64_t>
Offset =
425 F->getParent(), Intrinsic::aarch64_settag_zero);
427 Intrinsic::aarch64_stgp);
429 InitializerBuilder
IB(
Size,
DL,
Ptr, SetTagFunc, SetTagZeroFunc, StgpFunc);
432 if (MergeInit && !
F->hasOptNone() && LittleEndian &&
435 <<
", size = " <<
Size <<
"\n");
436 InsertBefore = collectInitializers(InsertBefore,
Ptr,
Size, IB);
450Instruction *AArch64StackTagging::insertBaseTaggedPointer(
456 for (
auto &
I : AllocasToInstrument) {
471 Base->setName(
"basetag");
472 const Triple &TargetTriple =
M.getTargetTriple();
478 !AllocasToInstrument.empty()) {
479 constexpr int StackMteSlot = -3;
480 constexpr uint64_t TagMask = 0xFULL << 56;
484 auto *ThreadLong = IRB.
CreateLoad(IntptrTy, SlotPtr);
499bool AArch64StackTagging::runOnFunction(
Function &Fn) {
504 SSI = &getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult();
508 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
510 getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
520 std::unique_ptr<DominatorTree> DeleteDT;
522 if (
auto *
P = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
523 DT = &
P->getDomTree();
526 DeleteDT = std::make_unique<DominatorTree>(*
F);
530 std::unique_ptr<PostDominatorTree> DeletePDT;
532 if (
auto *
P = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>())
533 PDT = &
P->getPostDomTree();
535 if (PDT ==
nullptr) {
536 DeletePDT = std::make_unique<PostDominatorTree>(*
F);
537 PDT = DeletePDT.get();
540 std::unique_ptr<LoopInfo> DeleteLI;
542 if (
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>()) {
543 LI = &LIWP->getLoopInfo();
545 DeleteLI = std::make_unique<LoopInfo>(*DT);
550 Intrinsic::aarch64_settag);
555 unsigned int NextTag = 0;
562 unsigned int Tag = NextTag;
563 NextTag = (NextTag + 1) % 16;
570 if (
Info.AI->hasName())
573 Info.AI->replaceUsesWithIf(TagPCall, [&](
const Use &U) {
574 return !isa<LifetimeIntrinsic>(
U.getUser());
582 bool StandardLifetime =
586 if (StandardLifetime) {
590 tagAlloca(AI, Start->getNextNode(), TagPCall,
Size);
596 for (
auto *
End :
Info.LifetimeEnd)
597 End->eraseFromParent();
603 for (
auto *RI : SInfo.
RetVec) {
604 untagAlloca(AI, RI,
Size);
608 for (
auto *
II :
Info.LifetimeStart)
609 II->eraseFromParent();
610 for (
auto *
II :
Info.LifetimeEnd)
611 II->eraseFromParent();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< bool > ClMergeInit("stack-tagging-merge-init", cl::Hidden, cl::init(true), cl::desc("merge stack variable initializers with tagging when possible"))
StackTaggingRecordStackHistoryMode
static cl::opt< unsigned > ClMergeInitSizeLimit("stack-tagging-merge-init-size-limit", cl::init(272), cl::Hidden)
static cl::opt< unsigned > ClScanLimit("stack-tagging-merge-init-scan-limit", cl::init(40), cl::Hidden)
static cl::opt< bool > ClUseStackSafety("stack-tagging-use-stack-safety", cl::Hidden, cl::init(true), cl::desc("Use Stack Safety analysis results"))
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 const Align kTagGranuleSize
static cl::opt< StackTaggingRecordStackHistoryMode > ClRecordStackHistory("stack-tagging-record-stack-history", cl::desc("Record stack frames with tagged allocations in a thread-local " "ring buffer"), cl::values(clEnumVal(none, "Do not record stack ring history"), clEnumVal(instr, "Insert instructions into the prologue for " "storing into the stack ring buffer")), cl::Hidden, cl::init(none))
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
#define clEnumVal(ENUMVAL, DESC)
This file contains constants used for implementing Dwarf debug support.
This header defines various interfaces for pass management in LLVM.
This file implements a map that provides insertion order iteration.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static unsigned getNumElements(Type *Ty)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
A private abstract base class describing the concept of an individual alias analysis implementation.
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.
an instruction to allocate memory on the stack
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
LLVM Basic Block Representation.
const Instruction & front() const
InstListType::iterator iterator
Instruction iterators...
This is the shared class of boolean and integer constants.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI 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...
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
const DataLayout & getDataLayout() const
Get the data layout of the module this function belongs to.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Module * getParent()
Get the module that this global value is contained inside of...
Value * CreateConstGEP1_64(Type *Ty, Value *Ptr, uint64_t Idx0, const Twine &Name="")
Value * CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Value * CreatePointerCast(Value *V, Type *DestTy, const Twine &Name="")
BasicBlock::iterator GetInsertPoint() const
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
IntegerType * getIntPtrTy(const DataLayout &DL, unsigned AddrSpace=0)
Fetch the type of an integer with size at least as big as that of a pointer in the given address spac...
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
LLVMContext & getContext() const
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
This class implements a map that also provides access to all stored values in a deterministic order.
Value * getLength() const
Value * getDest() const
This is just like getRawDest, but it strips off any cast instructions (including addrspacecast) that ...
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
Representation for a specific memory location.
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This pass performs the global (interprocedural) stack safety analysis (legacy pass manager).
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
bool isAndroidVersionLT(unsigned Major) const
bool isAndroid() const
Tests whether the target is Android.
LLVM_ABI bool isLittleEndian() const
Tests whether the target triple is little endian.
bool isAArch64() const
Tests whether the target is AArch64 (little and big endian).
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
A Use represents the edge between a Value definition and its users.
void setOperand(unsigned i, Value *Val)
LLVM Value Representation.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI std::optional< int64_t > getPointerOffsetFrom(const Value *Other, const DataLayout &DL) const
If this ptr is provably equal to Other plus a constant offset, return that offset in bytes.
const ParentTy * getParent() const
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
Value * getFP(IRBuilder<> &IRB)
bool isStandardLifetime(const SmallVectorImpl< IntrinsicInst * > &LifetimeStart, const SmallVectorImpl< IntrinsicInst * > &LifetimeEnd, const DominatorTree *DT, const LoopInfo *LI, size_t MaxLifetimes)
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)
Value * getAndroidSlotPtr(IRBuilder<> &IRB, int Slot)
Value * incrementThreadLong(IRBuilder<> &IRB, Value *ThreadLong, unsigned int Inc)
void annotateDebugRecords(AllocaInfo &Info, unsigned int Tag)
void alignAndPadAlloca(memtag::AllocaInfo &Info, llvm::Align Align)
Value * getPC(const Triple &TargetTriple, IRBuilder<> &IRB)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
FunctionPass * createAArch64StackTaggingPass(bool IsOptNone)
bool isNoModRef(const ModRefInfo MRI)
This struct is a compact representation of a valid (non-zero power of two) alignment.
MapVector< AllocaInst *, AllocaInfo > AllocasToInstrument
SmallVector< Instruction *, 8 > RetVec