50#define DEBUG_TYPE "shadow-stack-gc-lowering"
54class ShadowStackGCLoweringImpl {
65 std::vector<std::pair<CallInst *, AllocaInst *>> Roots;
68 ShadowStackGCLoweringImpl() =
default;
70 bool doInitialization(
Module &M);
74 bool IsNullValue(
Value *V);
83 Type *Ty,
Value *BasePtr,
int Idx1,
int Idx2,
88 ShadowStackGCLoweringImpl Impl;
93 ShadowStackGCLowering();
100 std::optional<DomTreeUpdater> DTU;
101 if (
auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
102 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
103 return Impl.runOnFunction(
F, DTU ? &*DTU :
nullptr);
112 if (Map.StrategyMap.contains(
"shadow-stack"))
115 ShadowStackGCLoweringImpl Impl;
116 bool Changed = Impl.doInitialization(M);
122 Changed |= Impl.runOnFunction(
F, DT ? &DTU :
nullptr);
132char ShadowStackGCLowering::ID = 0;
136 "Shadow Stack GC Lowering",
false,
false)
144ShadowStackGCLowering::ShadowStackGCLowering() :
FunctionPass(
ID) {
150 Type *VoidPtr = PointerType::getUnqual(
F.getContext());
153 unsigned NumMeta = 0;
155 for (
unsigned I = 0;
I != Roots.size(); ++
I) {
156 Constant *
C = cast<Constant>(Roots[
I].first->getArgOperand(1));
157 if (!
C->isNullValue())
166 ConstantInt::get(Int32Ty, Roots.size(),
false),
167 ConstantInt::get(Int32Ty, NumMeta,
false),
193 GlobalVariable::InternalLinkage, FrameMap,
194 "__gc_" +
F.getName());
202Type *ShadowStackGCLoweringImpl::GetConcreteStackEntryType(
Function &
F) {
204 std::vector<Type *> EltTys;
205 EltTys.push_back(StackEntryTy);
206 for (
const std::pair<CallInst *, AllocaInst *> &Root : Roots)
207 EltTys.push_back(Root.second->getAllocatedType());
214bool ShadowStackGCLoweringImpl::doInitialization(
Module &M) {
217 if (
F.hasGC() &&
F.getGC() ==
"shadow-stack") {
230 std::vector<Type *> EltTys;
236 PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
244 PointerType *StackEntryPtrTy = PointerType::getUnqual(
M.getContext());
247 EltTys.push_back(StackEntryPtrTy);
248 EltTys.push_back(FrameMapPtrTy);
252 Head =
M.getGlobalVariable(
"llvm_gc_root_chain");
259 }
else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
267bool ShadowStackGCLoweringImpl::IsNullValue(
Value *V) {
269 return C->isNullValue();
273void ShadowStackGCLoweringImpl::CollectRoots(
Function &
F) {
278 assert(Roots.empty() &&
"Not cleaned up?");
285 if (
Function *
F = CI->getCalledFunction())
286 if (
F->getIntrinsicID() == Intrinsic::gcroot) {
287 std::pair<CallInst *, AllocaInst *> Pair = std::make_pair(
289 cast<AllocaInst>(CI->getArgOperand(0)->stripPointerCasts()));
290 if (IsNullValue(CI->getArgOperand(1)))
291 Roots.push_back(Pair);
298 Roots.insert(Roots.begin(), MetaRoots.
begin(), MetaRoots.
end());
304 int Idx2,
const char *
Name) {
308 Value *Val =
B.CreateGEP(Ty, BasePtr, Indices,
Name);
310 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
312 return dyn_cast<GetElementPtrInst>(Val);
322 Value *Val =
B.CreateGEP(Ty, BasePtr, Indices,
Name);
324 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
326 return dyn_cast<GetElementPtrInst>(Val);
330bool ShadowStackGCLoweringImpl::runOnFunction(
Function &
F,
333 if (!
F.hasGC() ||
F.getGC() !=
"shadow-stack")
347 Value *FrameMap = GetFrameMap(
F);
348 Type *ConcreteStackEntryTy = GetConcreteStackEntryType(
F);
355 AtEntry.CreateAlloca(ConcreteStackEntryTy,
nullptr,
"gc_frame");
357 AtEntry.SetInsertPointPastAllocas(&
F);
358 IP = AtEntry.GetInsertPoint();
362 AtEntry.CreateLoad(AtEntry.getPtrTy(), Head,
"gc_currhead");
363 Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
364 StackEntry, 0, 1,
"gc_frame.map");
365 AtEntry.CreateStore(FrameMap, EntryMapPtr);
368 for (
unsigned I = 0, E = Roots.size();
I != E; ++
I) {
370 Value *SlotPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
371 StackEntry, 1 +
I,
"gc_root");
383 while (isa<StoreInst>(IP))
385 AtEntry.SetInsertPoint(IP->getParent(), IP);
388 Instruction *EntryNextPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
389 StackEntry, 0, 0,
"gc_frame.next");
390 Instruction *NewHeadVal = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
391 StackEntry, 0,
"gc_newhead");
392 AtEntry.CreateStore(CurrentHead, EntryNextPtr);
393 AtEntry.CreateStore(NewHeadVal, Head);
401 CreateGEP(Context, *AtExit, ConcreteStackEntryTy, StackEntry, 0, 0,
404 AtExit->CreateLoad(AtExit->getPtrTy(), EntryNextPtr2,
"gc_savedhead");
405 AtExit->CreateStore(SavedHead, Head);
411 for (std::pair<CallInst *, AllocaInst *> &Root : Roots) {
412 Root.first->eraseFromParent();
413 Root.second->eraseFromParent();
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
an instruction to allocate memory on the stack
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
InstListType::iterator iterator
Instruction iterators...
static Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
static Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
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.
An analysis pass which caches information about the entire Module.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
@ LinkOnceAnyLinkage
Keep one copy of function when linking (inline)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserve()
Mark an analysis as preserved.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Class to represent struct types.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
char & ShadowStackGCLoweringID
ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.
void initializeShadowStackGCLoweringPass(PassRegistry &)
FunctionPass * createShadowStackGCLoweringPass()
ShadowStackGCLowering - Implements the custom lowering mechanism used by the shadow stack GC.