51#define DEBUG_TYPE "shadow-stack-gc-lowering"
55class ShadowStackGCLoweringImpl {
66 std::vector<std::pair<CallInst *, AllocaInst *>> Roots;
69 ShadowStackGCLoweringImpl() =
default;
71 bool doInitialization(
Module &M);
75 bool IsNullValue(
Value *V);
84 Type *Ty,
Value *BasePtr,
int Idx1,
int Idx2,
89 ShadowStackGCLoweringImpl Impl;
94 ShadowStackGCLowering();
101 std::optional<DomTreeUpdater> DTU;
102 if (
auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
103 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
104 return Impl.runOnFunction(
F, DTU ? &*DTU :
nullptr);
113 if (Map.StrategyMap.contains(
"shadow-stack"))
116 ShadowStackGCLoweringImpl Impl;
117 bool Changed = Impl.doInitialization(M);
123 Changed |= Impl.runOnFunction(
F, DT ? &DTU :
nullptr);
133char ShadowStackGCLowering::ID = 0;
137 "Shadow Stack GC Lowering",
false,
false)
145ShadowStackGCLowering::ShadowStackGCLowering() :
FunctionPass(
ID) {
151 Type *VoidPtr = PointerType::getUnqual(
F.getContext());
154 unsigned NumMeta = 0;
156 for (
unsigned I = 0;
I != Roots.size(); ++
I) {
157 Constant *
C = cast<Constant>(Roots[
I].first->getArgOperand(1));
158 if (!
C->isNullValue())
167 ConstantInt::get(Int32Ty, Roots.size(),
false),
168 ConstantInt::get(Int32Ty, NumMeta,
false),
194 GlobalVariable::InternalLinkage, FrameMap,
195 "__gc_" +
F.getName());
203Type *ShadowStackGCLoweringImpl::GetConcreteStackEntryType(
Function &
F) {
205 std::vector<Type *> EltTys;
206 EltTys.push_back(StackEntryTy);
207 for (
const std::pair<CallInst *, AllocaInst *> &Root : Roots)
208 EltTys.push_back(Root.second->getAllocatedType());
215bool ShadowStackGCLoweringImpl::doInitialization(
Module &M) {
218 if (
F.hasGC() &&
F.getGC() ==
"shadow-stack") {
231 std::vector<Type *> EltTys;
237 PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
248 EltTys.push_back(PointerType::getUnqual(StackEntryTy));
249 EltTys.push_back(FrameMapPtrTy);
250 StackEntryTy->setBody(EltTys);
251 PointerType *StackEntryPtrTy = PointerType::getUnqual(StackEntryTy);
254 Head =
M.getGlobalVariable(
"llvm_gc_root_chain");
261 }
else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
269bool ShadowStackGCLoweringImpl::IsNullValue(
Value *V) {
271 return C->isNullValue();
275void ShadowStackGCLoweringImpl::CollectRoots(
Function &
F) {
280 assert(Roots.empty() &&
"Not cleaned up?");
287 if (
Function *
F = CI->getCalledFunction())
288 if (
F->getIntrinsicID() == Intrinsic::gcroot) {
289 std::pair<CallInst *, AllocaInst *> Pair = std::make_pair(
291 cast<AllocaInst>(CI->getArgOperand(0)->stripPointerCasts()));
292 if (IsNullValue(CI->getArgOperand(1)))
293 Roots.push_back(Pair);
300 Roots.insert(Roots.begin(), MetaRoots.
begin(), MetaRoots.
end());
306 int Idx2,
const char *
Name) {
310 Value *Val =
B.CreateGEP(Ty, BasePtr, Indices,
Name);
312 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
314 return dyn_cast<GetElementPtrInst>(Val);
324 Value *Val =
B.CreateGEP(Ty, BasePtr, Indices,
Name);
326 assert(isa<GetElementPtrInst>(Val) &&
"Unexpected folded constant");
328 return dyn_cast<GetElementPtrInst>(Val);
332bool ShadowStackGCLoweringImpl::runOnFunction(
Function &
F,
335 if (!
F.hasGC() ||
F.getGC() !=
"shadow-stack")
349 Value *FrameMap = GetFrameMap(
F);
350 Type *ConcreteStackEntryTy = GetConcreteStackEntryType(
F);
357 AtEntry.CreateAlloca(ConcreteStackEntryTy,
nullptr,
"gc_frame");
359 AtEntry.SetInsertPointPastAllocas(&
F);
360 IP = AtEntry.GetInsertPoint();
364 AtEntry.CreateLoad(AtEntry.getPtrTy(), Head,
"gc_currhead");
365 Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
366 StackEntry, 0, 1,
"gc_frame.map");
367 AtEntry.CreateStore(FrameMap, EntryMapPtr);
370 for (
unsigned I = 0, E = Roots.size();
I != E; ++
I) {
372 Value *SlotPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
373 StackEntry, 1 +
I,
"gc_root");
385 while (isa<StoreInst>(IP))
387 AtEntry.SetInsertPoint(IP->getParent(), IP);
390 Instruction *EntryNextPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
391 StackEntry, 0, 0,
"gc_frame.next");
392 Instruction *NewHeadVal = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
393 StackEntry, 0,
"gc_newhead");
394 AtEntry.CreateStore(CurrentHead, EntryNextPtr);
395 AtEntry.CreateStore(NewHeadVal, Head);
403 CreateGEP(Context, *AtExit, ConcreteStackEntryTy, StackEntry, 0, 0,
406 AtExit->CreateLoad(AtExit->getPtrTy(), EntryNextPtr2,
"gc_savedhead");
407 AtExit->CreateStore(SavedHead, Head);
413 for (std::pair<CallInst *, AllocaInst *> &Root : Roots) {
414 Root.first->eraseFromParent();
415 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.