LLVM 23.0.0git
MemoryTaggingSupport.cpp
Go to the documentation of this file.
1//== MemoryTaggingSupport.cpp - helpers for memory tagging implementations ===//
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7//
8// This file declares common infrastructure for HWAddressSanitizer and
9// Aarch64StackTagging.
10//
11//===----------------------------------------------------------------------===//
12
14
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/Analysis/CFG.h"
21#include "llvm/IR/BasicBlock.h"
22#include "llvm/IR/IRBuilder.h"
24#include "llvm/IR/Intrinsics.h"
27#include <utility>
28
29namespace llvm {
30namespace memtag {
31
33 const LoopInfo &LI, const AllocaInfo &AInfo,
35 llvm::function_ref<void(Instruction *)> Callback) {
36 if (AInfo.LifetimeEnd.size() == 1 && AInfo.LifetimeStart.size() == 1 &&
37 PDT.dominates(AInfo.LifetimeEnd[0], AInfo.LifetimeStart[0])) {
38 Callback(AInfo.LifetimeEnd[0]);
39 return true;
40 }
43 for (const auto &[BB, BBInfo] : AInfo.BBInfos) {
44 if (BBInfo.Last == Intrinsic::lifetime_end)
45 EndBlocks.insert(BB);
46 else
47 StartBlocks.push_back(BB);
48 }
49 bool UncoveredRets = false;
50
51 if (!StartBlocks.empty()) {
52 for (auto *RI : RetVec) {
53 auto WL = StartBlocks;
54 // If the block with the return is an EndBlock (i.e. a block where the
55 // last relevant lifetime intrinsic is an end), we don't have to run a
56 // complicated algorithm to know that the RetInst is never reachable
57 // without going through an end.
58 if (!EndBlocks.contains(RI->getParent()) &&
59 isPotentiallyReachableFromMany(WL, RI->getParent(), &EndBlocks, &DT,
60 &LI)) {
61 Callback(RI);
62 UncoveredRets = true;
63 }
64 }
65 }
66 for_each(AInfo.LifetimeEnd, Callback);
67 // We may have inserted untag outside of the lifetime interval.
68 // Signal the caller to remove the lifetime end call for this alloca.
69 return !UncoveredRets;
70}
71
72bool isSupportedLifetime(const AllocaInfo &AInfo, const DominatorTree *DT,
73 const LoopInfo *LI) {
74 if (AInfo.LifetimeStart.empty())
75 return false;
76 SmallVector<BasicBlock *, 2> LastEndBlocks;
79 if (any_of(AInfo.BBInfos, [&](const auto &It) {
80 const auto &[BB, BBI] = It;
81 if (BBI.Last == Intrinsic::lifetime_end)
82 LastEndBlocks.append(succ_begin(BB), succ_end(BB));
83 else
84 StartBlocks.insert(BB);
85 if (BBI.First == Intrinsic::lifetime_end)
86 FirstEndBlocks.insert(BB);
87 return BBI.DoubleEnd;
88 }))
89 return false;
90 if (LastEndBlocks.empty() || FirstEndBlocks.empty())
91 return true;
92 return !isManyPotentiallyReachableFromMany(LastEndBlocks, FirstEndBlocks,
93 &StartBlocks, DT, LI);
94}
95
97 if (isa<ReturnInst>(Inst)) {
98 if (CallInst *CI = Inst.getParent()->getTerminatingMustTailCall())
99 return CI;
100 return &Inst;
101 }
103 return &Inst;
104 }
105 return nullptr;
106}
107
109 Instruction &Inst) {
110 // Visit non-intrinsic debug-info records attached to Inst.
112 auto AddIfInteresting = [&](Value *V) {
113 if (auto *AI = dyn_cast_or_null<AllocaInst>(V)) {
114 if (getAllocaInterestingness(*AI) !=
116 return;
117 AllocaInfo &AInfo = Info.AllocasToInstrument[AI];
118 auto &DVRVec = AInfo.DbgVariableRecords;
119 if (DVRVec.empty() || DVRVec.back() != &DVR)
120 DVRVec.push_back(&DVR);
121 }
122 };
123
124 for_each(DVR.location_ops(), AddIfInteresting);
125 if (DVR.isDbgAssign())
126 AddIfInteresting(DVR.getAddress());
127 }
128
129 if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
130 if (CI->canReturnTwice()) {
131 Info.CallsReturnTwice = true;
132 }
133 }
134 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
135 switch (getAllocaInterestingness(*AI)) {
137 Info.AllocasToInstrument[AI].AI = AI;
138 ORE.emit([&]() {
139 return OptimizationRemarkMissed(DebugType, "safeAlloca", &Inst);
140 });
141 break;
143 ORE.emit(
144 [&]() { return OptimizationRemark(DebugType, "safeAlloca", &Inst); });
145 break;
147 break;
148 }
149 return;
150 }
151 if (auto *II = dyn_cast<LifetimeIntrinsic>(&Inst)) {
152 AllocaInst *AI = dyn_cast<AllocaInst>(II->getArgOperand(0));
153 if (!AI ||
155 return;
156 auto &AInfo = Info.AllocasToInstrument[AI];
157 auto &BBInfo = AInfo.BBInfos[II->getParent()];
158
159 if (II->getIntrinsicID() == Intrinsic::lifetime_start) {
160 AInfo.LifetimeStart.push_back(II);
161 } else {
162 AInfo.LifetimeEnd.push_back(II);
163 if (BBInfo.Last == Intrinsic::lifetime_end)
164 BBInfo.DoubleEnd = true;
165 }
166
167 BBInfo.Last = II->getIntrinsicID();
168 if (BBInfo.First == Intrinsic::not_intrinsic)
169 BBInfo.First = II->getIntrinsicID();
170
171 return;
172 }
173
175 if (ExitUntag)
176 Info.RetVec.push_back(ExitUntag);
177}
178
181 std::optional<TypeSize> Size = AI.getAllocationSize(AI.getDataLayout());
182 if (Size &&
183 // FIXME: support vscale.
184 !Size->isScalable() &&
185 // FIXME: instrument dynamic allocas, too
186 AI.isStaticAlloca() &&
187 // alloca() may be called with 0 size, ignore it.
188 !Size->isZero() &&
189 // We are only interested in allocas not promotable to registers.
190 // Promotable allocas are common under -O0.
191 !isAllocaPromotable(&AI) &&
192 // inalloca allocas are not treated as static, and we don't want
193 // dynamic alloca instrumentation for them as well.
194 !AI.isUsedWithInAlloca() &&
195 // swifterror allocas are register promoted by ISel
196 !AI.isSwiftError()) {
197 if (!(SSI && SSI->isSafe(AI))) {
199 }
200 // safe allocas are not interesting
202 }
204}
205
207 auto DL = AI.getDataLayout();
208 return *AI.getAllocationSize(DL);
209}
210
212 const Align NewAlignment = std::max(Info.AI->getAlign(), Alignment);
213 Info.AI->setAlignment(NewAlignment);
214 auto &Ctx = Info.AI->getFunction()->getContext();
215
217 uint64_t AlignedSize = alignTo(Size, Alignment);
218 if (Size == AlignedSize)
219 return;
220
221 // Add padding to the alloca.
222 Type *AllocatedType =
223 Info.AI->isArrayAllocation()
225 Info.AI->getAllocatedType(),
226 cast<ConstantInt>(Info.AI->getArraySize())->getZExtValue())
227 : Info.AI->getAllocatedType();
228 Type *PaddingType = ArrayType::get(Type::getInt8Ty(Ctx), AlignedSize - Size);
229 Type *TypeWithPadding = StructType::get(AllocatedType, PaddingType);
230 auto *NewAI = new AllocaInst(TypeWithPadding, Info.AI->getAddressSpace(),
231 nullptr, "", Info.AI->getIterator());
232 NewAI->takeName(Info.AI);
233 NewAI->setAlignment(Info.AI->getAlign());
234 NewAI->setUsedWithInAlloca(Info.AI->isUsedWithInAlloca());
235 NewAI->setSwiftError(Info.AI->isSwiftError());
236 NewAI->copyMetadata(*Info.AI);
237
238 Info.AI->replaceAllUsesWith(NewAI);
239 Info.AI->eraseFromParent();
240 Info.AI = NewAI;
241}
242
244 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
245 MDNode *MD =
246 MDNode::get(M->getContext(), {MDString::get(M->getContext(), Name)});
247 Value *Args[] = {MetadataAsValue::get(M->getContext(), MD)};
248 return IRB.CreateIntrinsic(Intrinsic::read_register,
249 IRB.getIntPtrTy(M->getDataLayout()), Args);
250}
251
252Value *getPC(const Triple &TargetTriple, IRBuilder<> &IRB) {
253 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
254 if (TargetTriple.getArch() == Triple::aarch64)
255 return memtag::readRegister(IRB, "pc");
256 return IRB.CreatePtrToInt(IRB.GetInsertBlock()->getParent(),
257 IRB.getIntPtrTy(M->getDataLayout()));
258}
259
262 Module *M = F->getParent();
263 return IRB.CreatePtrToInt(
264 IRB.CreateIntrinsic(Intrinsic::frameaddress,
265 IRB.getPtrTy(M->getDataLayout().getAllocaAddrSpace()),
266 {Constant::getNullValue(IRB.getInt32Ty())}),
267 IRB.getIntPtrTy(M->getDataLayout()));
268}
269
271 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
272 // FIXME: This should use the thread_pointer intrinsic. However, the
273 // intrinsic is not currently implemented on Darwin correctly. The
274 // TPIDRRO_EL0 register became part of the ABI to access TSD on recent
275 // versions of OS and so it is safe to use here
276 // Darwin provides a fixed slot for sanitizers at offset 231.
277 MDNode *MD = MDNode::get(M->getContext(),
278 {MDString::get(M->getContext(), "TPIDRRO_EL0")});
279 Value *Args[] = {MetadataAsValue::get(M->getContext(), MD)};
280 return IRB.CreateConstGEP1_32(
281 IRB.getInt8Ty(),
282 IRB.CreateIntToPtr(
283 IRB.CreateIntrinsic(Intrinsic::read_register,
284 {IRB.getIntPtrTy(M->getDataLayout())}, Args),
285 IRB.getPtrTy()),
286 8 * Slot);
287}
288
290 Module *M = IRB.GetInsertBlock()->getParent()->getParent();
291 // Android provides a fixed TLS slot for sanitizers. See TLS_SLOT_SANITIZER
292 // in Bionic's libc/private/bionic_tls.h.
293 Function *ThreadPointerFunc = Intrinsic::getOrInsertDeclaration(
294 M, Intrinsic::thread_pointer,
295 IRB.getPtrTy(M->getDataLayout().getDefaultGlobalsAddressSpace()));
296 return IRB.CreateConstGEP1_32(IRB.getInt8Ty(),
297 IRB.CreateCall(ThreadPointerFunc), 8 * Slot);
298}
299
301 return DVR->isDbgAssign() ? DVR : nullptr;
302}
303
304void annotateDebugRecords(AllocaInfo &Info, unsigned int Tag) {
305 auto AnnotateDbgRecord = [&](DbgVariableRecord *DPtr) {
306 // Prepend "tag_offset, N" to the dwarf expression.
307 // Tag offset logically applies to the alloca pointer, and it makes sense
308 // to put it at the beginning of the expression.
310 for (size_t LocNo = 0; LocNo < DPtr->getNumVariableLocationOps(); ++LocNo)
311 if (DPtr->getVariableLocationOp(LocNo) == Info.AI)
312 DPtr->setExpression(
313 DIExpression::appendOpsToArg(DPtr->getExpression(), NewOps, LocNo));
314 if (auto *DAI = DynCastToDbgAssign(DPtr)) {
315 if (DAI->getAddress() == Info.AI)
316 DAI->setAddressExpression(
317 DIExpression::prependOpcodes(DAI->getAddressExpression(), NewOps));
318 }
319 };
320
321 llvm::for_each(Info.DbgVariableRecords, AnnotateDbgRecord);
322}
323
325 unsigned int Inc, bool IsMemtagDarwin) {
326 // Update the ring buffer. Top byte of ThreadLong defines the size of the
327 // buffer in pages, it must be a power of two, and the start of the buffer
328 // must be aligned by twice that much. Therefore wrap around of the ring
329 // buffer is simply Addr &= ~((ThreadLong >> 56) << 12).
330 // The use of AShr instead of LShr is due to
331 // https://bugs.llvm.org/show_bug.cgi?id=39030
332 // Runtime library makes sure not to use the highest bit.
333 //
334 // Mechanical proof of this address calculation can be found at:
335 // https://github.com/google/sanitizers/blob/master/hwaddress-sanitizer/prove_hwasanwrap.smt2
336 //
337 // Example of the wrap case for N = 1
338 // Pointer: 0x01AAAAAAAAAAAFF8
339 // +
340 // 0x0000000000000008
341 // =
342 // 0x01AAAAAAAAAAB000
343 // &
344 // WrapMask: 0xFFFFFFFFFFFFF000
345 // =
346 // 0x01AAAAAAAAAAA000
347 //
348 // Then the WrapMask will be a no-op until the next wrap case.
349 //
350 // Darwin relies on bit 60-62 to store the size of the buffer in pages. This
351 // limits N to [0,2] while the rest of the proof remains unchanged. Bits
352 // 56-59 are avoided in order to prevent MTE Canonical Tag Faults while
353 // accessing the ring buffer. Bit 63 is avoided to prevent unintentional
354 // signed extension by AShr.
355 assert((4096 % Inc) == 0);
356 Value *WrapMask = IRB.CreateXor(
357 IRB.CreateShl(IRB.CreateAShr(ThreadLong, IsMemtagDarwin ? 60 : 56), 12,
358 "", true, true),
359 ConstantInt::get(ThreadLong->getType(), (uint64_t)-1));
360 return IRB.CreateAnd(
361 IRB.CreateAdd(ThreadLong, ConstantInt::get(ThreadLong->getType(), Inc)),
362 WrapMask);
363}
364
365} // namespace memtag
366} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains constants used for implementing Dwarf debug support.
#define F(x, y, z)
Definition MD5.cpp:54
uint64_t IntrinsicInst * II
This file contains some templates that are useful if you are working with the STL at all.
an instruction to allocate memory on the stack
bool isSwiftError() const
Return true if this alloca is used as a swifterror argument to a call.
LLVM_ABI bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size.
bool isUsedWithInAlloca() const
Return true if this alloca is used as an inalloca argument to a call.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI DIExpression * appendOpsToArg(const DIExpression *Expr, ArrayRef< uint64_t > Ops, unsigned ArgNo, bool StackValue=false)
Create a copy of Expr by appending the given list of Ops to each instance of the operand DW_OP_LLVM_a...
static LLVM_ABI DIExpression * prependOpcodes(const DIExpression *Expr, SmallVectorImpl< uint64_t > &Ops, bool StackValue=false, bool EntryValue=false)
Prepend DIExpr with the given opcodes and optionally turn it into a stack value.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:164
Module * getParent()
Get the module that this global value is contained inside of...
Value * CreateConstGEP1_32(Type *Ty, Value *Ptr, unsigned Idx0, const Twine &Name="")
Definition IRBuilder.h:1957
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2171
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...
Definition IRBuilder.h:610
BasicBlock * GetInsertBlock() const
Definition IRBuilder.h:201
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 * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1495
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1554
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1406
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2166
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2487
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:604
Value * CreateAShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1535
Value * CreateXor(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1602
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Definition IRBuilder.h:551
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2787
iterator_range< simple_ilist< DbgRecord >::iterator > getDbgRecordRange() const
Return a range over the DbgRecords attached to this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Metadata node.
Definition Metadata.h:1080
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1572
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:110
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
The optimization diagnostic interface.
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for missed-optimization remarks.
Diagnostic information for applied optimization remarks.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
LLVM_ABI bool dominates(const Instruction *I1, const Instruction *I2) const
Return true if I1 dominates I2.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:413
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
ArchType getArch() const
Get the parsed architecture type of this triple.
Definition Triple.h:420
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:294
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
void visit(OptimizationRemarkEmitter &ORE, Instruction &Inst)
AllocaInterestingness getAllocaInterestingness(const AllocaInst &AI)
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
@ DW_OP_LLVM_tag_offset
Only used in LLVM metadata.
Definition Dwarf.h:146
Value * getFP(IRBuilder<> &IRB)
bool isSupportedLifetime(const AllocaInfo &AInfo, const DominatorTree *DT, const LoopInfo *LI)
uint64_t getAllocaSizeInBytes(const AllocaInst &AI)
Value * getDarwinSlotPtr(IRBuilder<> &IRB, int Slot)
Value * getAndroidSlotPtr(IRBuilder<> &IRB, int Slot)
static DbgVariableRecord * DynCastToDbgAssign(DbgVariableRecord *DVR)
Value * readRegister(IRBuilder<> &IRB, StringRef Name)
void annotateDebugRecords(AllocaInfo &Info, unsigned int Tag)
Instruction * getUntagLocationIfFunctionExit(Instruction &Inst)
void alignAndPadAlloca(memtag::AllocaInfo &Info, llvm::Align Align)
Value * getPC(const Triple &TargetTriple, IRBuilder<> &IRB)
Value * incrementThreadLong(IRBuilder<> &IRB, Value *ThreadLong, unsigned int Inc, bool IsMemtagDarwin=false)
bool forAllReachableExits(const DominatorTree &DT, const PostDominatorTree &PDT, const LoopInfo &LI, const AllocaInfo &AInfo, const SmallVectorImpl< Instruction * > &RetVec, llvm::function_ref< void(Instruction *)> Callback)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1732
LLVM_ABI bool isPotentiallyReachableFromMany(SmallVectorImpl< BasicBlock * > &Worklist, const BasicBlock *StopBB, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT=nullptr, const LoopInfo *LI=nullptr)
Determine whether there is at least one path from a block in 'Worklist' to 'StopBB' without passing t...
Definition CFG.cpp:240
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI bool isAllocaPromotable(const AllocaInst *AI)
Return true if this alloca is legal for promotion.
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI bool isManyPotentiallyReachableFromMany(SmallVectorImpl< BasicBlock * > &Worklist, const SmallPtrSetImpl< const BasicBlock * > &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT=nullptr, const LoopInfo *LI=nullptr)
Determine whether there is a potentially a path from at least one block in 'Worklist' to at least one...
Definition CFG.cpp:249
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
SmallVector< DbgVariableRecord *, 2 > DbgVariableRecords
SmallVector< IntrinsicInst *, 2 > LifetimeEnd
SmallVector< IntrinsicInst *, 2 > LifetimeStart
MapVector< BasicBlock *, struct BBInfo > BBInfos