1#ifndef PROTEUS_KERNELARGPTRDEFVISITOR_H
2#define PROTEUS_KERNELARGPTRDEFVISITOR_H
8#include <llvm/Analysis/PtrUseVisitor.h>
9#include <llvm/Analysis/ValueTracking.h>
11#include <llvm/ADT/DenseMap.h>
12#include <llvm/ADT/DenseSet.h>
13#include <llvm/ADT/Hashing.h>
14#include <llvm/ADT/SmallPtrSet.h>
15#include <llvm/ADT/SmallVector.h>
16#include <llvm/Analysis/AssumptionCache.h>
17#include <llvm/Analysis/BasicAliasAnalysis.h>
18#include <llvm/Analysis/MemoryLocation.h>
19#include <llvm/Analysis/MemorySSA.h>
20#include <llvm/Analysis/TargetLibraryInfo.h>
21#include <llvm/Analysis/ValueTracking.h>
22#include <llvm/IR/Constants.h>
23#include <llvm/IR/DataLayout.h>
24#include <llvm/IR/DebugInfo.h>
25#include <llvm/IR/Dominators.h>
26#include <llvm/IR/Function.h>
27#include <llvm/IR/InstrTypes.h>
28#include <llvm/IR/Instruction.h>
29#include <llvm/IR/Instructions.h>
30#include <llvm/IR/Metadata.h>
31#include <llvm/IR/Module.h>
32#include <llvm/IR/PassManager.h>
33#include <llvm/IR/Type.h>
34#include <llvm/IR/Value.h>
35#include <llvm/TargetParser/Triple.h>
44 return isa<AddrSpaceCastInst>(Val) || isa<AllocaInst>(Val) ||
45 isa<BitCastInst>(Val) || isa<IntToPtrInst>(Val);
51 <<
" [PTR use analysis]: Target Offset = " << TargetOffset <<
"\n");
53 <<
" [PTR use analysis]: Range Offset = " << RangeOffset <<
"\n");
55 <<
" [PTR use analysis]: Range Size = " << RangeSize <<
"\n");
56 return TargetOffset >= RangeOffset &&
57 static_cast<uint64_t
>(TargetOffset - RangeOffset) < RangeSize;
62 if (!Ty || !Ty->isSized())
64 return static_cast<uint64_t
>(DL.getTypeStoreSize(Ty));
87inline std::optional<MemoryLocation>
89 if (!Ptr || !Ptr->getType()->isPointerTy())
92 Type *PointeeTy =
nullptr;
93 if (
auto *AI = dyn_cast<AllocaInst>(Ptr))
94 PointeeTy = AI->getAllocatedType();
96 if (!PointeeTy || !PointeeTy->isSized())
97 return MemoryLocation::getBeforeOrAfter(Ptr);
99 return MemoryLocation(Ptr,
100 LocationSize::precise(DL.getTypeStoreSize(PointeeTy)));
108inline std::optional<LambdaPtrUseAnalysis>
110 int64_t TargetOffset) {
111 auto *PtrI = dyn_cast<Instruction>(Ptr);
112 auto *BoundaryI = dyn_cast<Instruction>(UseBoundary);
113 if (!PtrI || !BoundaryI || PtrI->getFunction() != BoundaryI->getFunction() ||
114 PtrI->getParent() != BoundaryI->getParent())
117 int64_t RootOffset = 0;
118 Value *RootBase = GetPointerBaseWithConstantOffset(Ptr, RootOffset, DL);
121 int64_t AbsoluteTarget = RootOffset + TargetOffset;
129 for (Instruction *I = BoundaryI->getNextNode(); I; I = I->getNextNode()) {
130 auto *CB = dyn_cast<CallBase>(I);
131 if (!CB || isa<DbgInfoIntrinsic>(CB) || CB->onlyReadsMemory())
133 for (Value *Arg : CB->args()) {
134 if (!Arg->getType()->isPointerTy())
136 int64_t ArgOffset = 0;
137 Value *ArgBase = GetPointerBaseWithConstantOffset(Arg, ArgOffset, DL);
138 if (ArgBase == RootBase)
143 for (Instruction *I = BoundaryI->getPrevNode(); I; I = I->getPrevNode()) {
144 if (
auto *SI = dyn_cast<StoreInst>(I)) {
145 int64_t StoreOffset = 0;
146 Value *StoreBase = GetPointerBaseWithConstantOffset(
147 SI->getPointerOperand(), StoreOffset, DL);
149 if (StoreBase == RootBase && StoreSize &&
152 .Offset = StoreOffset - RootOffset,
153 .ChangedRCLayout = std::nullopt};
159 if (
auto *CB = dyn_cast<CallBase>(I)) {
160 if (!isa<DbgInfoIntrinsic>(CB) && !CB->onlyReadsMemory())
180 DenseMap<Value *, int64_t> ValueOffsetMap;
181 Value *TrackedBase =
nullptr;
184 SmallVector<UseEdge> WorkList;
188 Value *Def =
nullptr;
189 SmallDenseSet<Value *> Seen;
190 bool AnalysisSuccess =
false;
191 bool AnalysisFailed =
false;
198 const DataLayout &Dl, int64_t TargetOff)
199 : TrackedBase(PtrBegin), DL(Dl) {
200 WorkList.push_back({PtrBegin,
nullptr});
204 if (!isa<GetElementPtrInst, BitCastInst, AddrSpaceCastInst>(SeenUse))
205 Seen.insert(SeenUse);
207 Seen.insert(LambdaCB);
208 ValueOffsetMap[PtrBegin] = TargetOff;
210 auto back() {
return WorkList.back(); }
212 auto Result = WorkList.back();
213 Def = Result.LastVal;
218 bool seen(Value *Val) {
return Seen.contains(Val); }
220 bool empty() {
return WorkList.empty(); }
228 WorkList.push_back(
UseEdge{NextVal, CurVal});
232 AnalysisFailed =
true;
233 AnalysisSuccess =
false;
235 <<
" [PTR use analysis]: Analysis failed due to absence of " << *V
236 <<
" in offset tracking map, this is an internal compiler bug\n");
244 SmallVector<User *, 4> PossibleWriters;
245 for (User *Usr : V->users()) {
246 if (Seen.contains(Usr))
248 auto *CB = dyn_cast<CallBase>(Usr);
249 if (CB && !isa<DbgInfoIntrinsic>(CB) && !CB->onlyReadsMemory()) {
250 PossibleWriters.push_back(Usr);
255 for (User *Usr : PossibleWriters)
260 Value *Stored = SI.getValueOperand();
261 Value *StoreBase = SI.getPointerOperand();
267 if (Stored == Def && Stored->getType()->isPointerTy()) {
268 if (!ValueOffsetMap.contains(Stored)) {
272 ValueOffsetMap[StoreBase] = ValueOffsetMap[Stored];
273 for (User *Usr : StoreBase->users())
274 if (Usr != &SI && !Seen.contains(Usr))
280 if (!ValueOffsetMap.contains(StoreBase)) {
289 <<
" Found PTRstore applicable to offset " << ValueOffsetMap[&SI]
290 <<
" Store size = " << *StoreSize <<
" ; " << SI <<
"\n");
291 AnalysisFailed =
false;
292 AnalysisSuccess =
true;
295 .ChangedRCLayout = std::nullopt};
299 if (!LI.getType()->isPointerTy()) {
301 <<
" [PTR use analysis]: Expected a pointer load, got " << LI
303 AnalysisFailed =
true;
304 AnalysisSuccess =
false;
307 if (!ValueOffsetMap.contains(LI.getPointerOperand())) {
311 ValueOffsetMap[&LI] = ValueOffsetMap[LI.getPointerOperand()];
319 if (
auto *II = dyn_cast<IntrinsicInst>(&CB)) {
320 if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
321 II->getIntrinsicID() == Intrinsic::lifetime_end)
325 Function *F = CB.getCalledFunction();
326 if (!F || F->isDeclaration()) {
328 <<
" [PTR use analysis]: Cannot trace indirect or declaration "
331 AnalysisFailed =
true;
332 AnalysisSuccess =
false;
337 if (!DefBeforeCB || !ValueOffsetMap.contains(DefBeforeCB)) {
342 bool FoundArg =
false;
343 for (
size_t ArgI = 0; ArgI < F->arg_size(); ++ArgI) {
345 << *CB.getArgOperand(ArgI) <<
"\n");
346 if (CB.getArgOperand(ArgI) != DefBeforeCB)
350 Argument *ArgToTrack = F->getArg(ArgI);
351 ValueOffsetMap[ArgToTrack] = ValueOffsetMap[DefBeforeCB];
353 <<
" Looking at uses of " << *ArgToTrack <<
"\n");
354 for (User *Usr : ArgToTrack->users())
358 <<
" Beginning analysis within " << *F <<
"\n");
361 <<
" [PTR use analysis]: Call does not pass the tracked "
362 "pointer on any callee argument: "
364 AnalysisFailed =
true;
365 AnalysisSuccess =
false;
376 APInt StepOffset(DL.getIndexTypeSizeInBits(GEP.getType()), 0);
377 if (!GEP.accumulateConstantOffset(DL, StepOffset)) {
378 AnalysisFailed =
true;
379 AnalysisSuccess =
false;
383 int64_t GEPOffset = StepOffset.getSExtValue();
385 <<
" " <<
"Computed GEP offset " << GEPOffset <<
"\n");
386 Value *GEPBase = GEP.getPointerOperand();
390 if (!ValueOffsetMap.contains(GEPBase)) {
397 <<
" GEP size = " << *ResultSize <<
"\n";)
402 <<
" Found GEP applicable to offset=" << ValueOffsetMap[GEPBase]
403 <<
" ; " << GEP <<
"\n");
406 ValueOffsetMap[&GEP] = ValueOffsetMap[GEPBase] - GEPOffset;
409 <<
" " <<
"Setting map K " << GEP <<
" : " << ValueOffsetMap[&GEP]
420 AnalysisFailed =
true;
421 AnalysisSuccess =
false;
423 <<
" Dominating use analysis somehow reached AllocaInst from "
427 if (!ValueOffsetMap.contains(&Alloca)) {
428 AnalysisFailed =
true;
429 AnalysisSuccess =
false;
431 <<
" Value offset map not correctly initialized with "
445 ValueOffsetMap[BC.getOperand(0)] =
Offset;
447 ValueOffsetMap[&BC] = ValueOffsetMap[BC.getOperand(0)];
454 if (!ValueOffsetMap.contains(&ASC)) {
455 if (!ValueOffsetMap.contains(ASC.getPointerOperand())) {
460 ValueOffsetMap[&ASC] = ValueOffsetMap[ASC.getPointerOperand()];
463 <<
" [PTR use analysis]: Setting offset " << ASC <<
" = "
464 << ValueOffsetMap[&ASC]);
470 if (
auto *MS = dyn_cast<MemSetInst>(&I)) {
471 if (Def != MS->getRawDest())
473 if (!ValueOffsetMap.contains(Def)) {
477 auto *Len = dyn_cast<ConstantInt>(MS->getLength());
484 <<
" [PTR use analysis]: Memset may overwrite the tracked "
487 AnalysisFailed =
true;
488 AnalysisSuccess =
false;
492 auto *MT = cast<MemTransferInst>(&I);
497 if (Def != MT->getRawDest())
500 if (!ValueOffsetMap.contains(Def)) {
505 auto *Len = dyn_cast<ConstantInt>(MT->getLength());
509 <<
" [PTR use analysis]: Dynamic-length transfer cannot prove "
510 "provenance for the tracked byte: "
512 AnalysisFailed =
true;
513 AnalysisSuccess =
false;
519 int64_t DstOff = 0, SrcOff = 0;
521 GetPointerBaseWithConstantOffset(MT->getRawDest(), DstOff, DL);
523 GetPointerBaseWithConstantOffset(MT->getRawSource(), SrcOff, DL);
524 if (!DstBase || !SrcBase) {
526 <<
" [PTR use analysis]: Failure due to nullptr dst/src " <<
"\n");
527 AnalysisFailed =
true;
532 <<
" [PTR use analysis]: Completed instrinsic analysis " <<
"\n");
539 int64_t OffsetCorrection = DstOff - SrcOff;
540 AnalysisSuccess =
true;
541 AnalysisFailed =
false;
543 .Offset = OffsetCorrection,
544 .ChangedRCLayout = std::nullopt};
549 <<
" [PTR use analysis]: Unhandled instruction "
550 << I.getOpcodeName() <<
": " << I <<
"\n");
551 AnalysisFailed =
true;
552 AnalysisSuccess =
false;
556inline std::optional<LambdaPtrUseAnalysis>
558 Value *SeenUse, int64_t TargetOffset,
559 CallBase *LambdaCB =
nullptr) {
561 <<
"Beginning PtrUse analysis with offset = " << TargetOffset <<
"\n");
571 auto *V = Visitor.
popBack().CurVal;
577 <<
" [PTR use analysis]: Visiting ptr use " << *V <<
"\n");
579 if (
auto *I = dyn_cast<Instruction>(V))
587 <<
" [PTR use analysis] [WARNING]: Dominating use analysis FAILED for "
588 << *ValueNeedingAnalysis <<
" <-- " << *SeenUse <<
"\n");
595 <<
" [PTR USE ANALYSIS]: Computed offset " << Info.
Offset <<
"\n");
uint32_t int32_t Type
Definition CompilerInterfaceDevice.cpp:98
uint64_t uint32_t uint32_t int64_t Offset
Definition CompilerInterfaceDevice.cpp:75
#define DEBUG(x)
Definition Helpers.h:14
Definition KernelArgPtrUseVisitor.h:169
LambdaInstUseVisitor(Value *PtrBegin, Value *SeenUse, CallBase *LambdaCB, const DataLayout &Dl, int64_t TargetOff)
Definition KernelArgPtrUseVisitor.h:197
void visitStoreInst(StoreInst &SI)
Definition KernelArgPtrUseVisitor.h:259
void visitInstruction(Instruction &I)
Definition KernelArgPtrUseVisitor.h:547
void visitGetElementPtrInst(GetElementPtrInst &GEP)
Definition KernelArgPtrUseVisitor.h:369
bool success()
Definition KernelArgPtrUseVisitor.h:221
void visitLoadInst(LoadInst &LI)
Definition KernelArgPtrUseVisitor.h:298
void markAsSeen(Value *Val)
Definition KernelArgPtrUseVisitor.h:219
auto popBack()
Definition KernelArgPtrUseVisitor.h:211
void offsetValueMapFailure(Value *V)
Definition KernelArgPtrUseVisitor.h:231
bool seen(Value *Val)
Definition KernelArgPtrUseVisitor.h:218
void visitBitCastInst(BitCastInst &BC)
Definition KernelArgPtrUseVisitor.h:441
bool failed()
Definition KernelArgPtrUseVisitor.h:222
auto getLastDef()
Definition KernelArgPtrUseVisitor.h:217
void visitCallBase(CallBase &CB)
Definition KernelArgPtrUseVisitor.h:315
auto back()
Definition KernelArgPtrUseVisitor.h:210
void pushBack(Value *NextVal, Value *CurVal)
Definition KernelArgPtrUseVisitor.h:227
bool empty()
Definition KernelArgPtrUseVisitor.h:220
void pushPointerUsers(Value *V)
Definition KernelArgPtrUseVisitor.h:243
void visitMemIntrinsic(MemIntrinsic &I)
Definition KernelArgPtrUseVisitor.h:469
void visitAllocaInst(AllocaInst &Alloca)
Definition KernelArgPtrUseVisitor.h:416
auto getAnalysisResult()
Definition KernelArgPtrUseVisitor.h:224
void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC)
Definition KernelArgPtrUseVisitor.h:451
static llvm::raw_ostream & logs(const std::string &Name)
Definition Logger.h:19
Definition CompiledLibrary.h:8
Definition MemoryCache.h:27
std::optional< LambdaPtrUseAnalysis > getDominatingUse(const DataLayout &DL, Value *ValueNeedingAnalysis, Value *SeenUse, int64_t TargetOffset, CallBase *LambdaCB=nullptr)
Definition KernelArgPtrUseVisitor.h:557
bool offsetCoveredByRange(int64_t TargetOffset, int64_t RangeOffset, uint64_t RangeSize)
Definition KernelArgPtrUseVisitor.h:48
std::optional< MemoryLocation > getTrackedPointerLocation(const DataLayout &DL, Value *Ptr)
Definition KernelArgPtrUseVisitor.h:88
bool needsDefUseAnalysis(Value *Val)
Definition KernelArgPtrUseVisitor.h:43
std::optional< LambdaPtrUseAnalysis > getPreviousCoveringStore(const DataLayout &DL, Value *Ptr, Value *UseBoundary, int64_t TargetOffset)
Definition KernelArgPtrUseVisitor.h:109
std::optional< uint64_t > getTypeStoreSize(const DataLayout &DL, Type *Ty)
Definition KernelArgPtrUseVisitor.h:60
Definition KernelArgPtrUseVisitor.h:75
Value * ValEnteringCallBase
Definition KernelArgPtrUseVisitor.h:76
CallBase * CallerCB
Definition KernelArgPtrUseVisitor.h:77
Function * Callee
Definition KernelArgPtrUseVisitor.h:78
Definition KernelArgPtrUseVisitor.h:67
Value * DominatingWrite
Definition KernelArgPtrUseVisitor.h:68
std::optional< RuntimeConstantType > ChangedRCLayout
Definition KernelArgPtrUseVisitor.h:72
int64_t Offset
Definition KernelArgPtrUseVisitor.h:69
Definition KernelArgPtrUseVisitor.h:82
Value * LastVal
Definition KernelArgPtrUseVisitor.h:84
Value * CurVal
Definition KernelArgPtrUseVisitor.h:83