LLVM 22.0.0git
DXILResourceAccess.cpp
Go to the documentation of this file.
1//===- DXILResourceAccess.cpp - Resource access via load/store ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "DirectX.h"
11#include "llvm/ADT/SetVector.h"
14#include "llvm/IR/BasicBlock.h"
15#include "llvm/IR/Dominators.h"
16#include "llvm/IR/IRBuilder.h"
17#include "llvm/IR/Instruction.h"
20#include "llvm/IR/Intrinsics.h"
21#include "llvm/IR/IntrinsicsDirectX.h"
22#include "llvm/IR/User.h"
26
27#define DEBUG_TYPE "dxil-resource-access"
28
29using namespace llvm;
30
33 assert(!PrevOffset && "Non-constant GEP chains not handled yet");
34
35 const DataLayout &DL = GEP->getDataLayout();
36
37 uint64_t ScalarSize = 1;
38 if (RTI.isTyped()) {
39 Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
40 // We need the size of an element in bytes so that we can calculate the
41 // offset in elements given a total offset in bytes.
42 Type *ScalarType = ContainedType->getScalarType();
43 ScalarSize = DL.getTypeSizeInBits(ScalarType) / 8;
44 }
45
46 APInt ConstantOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
47 if (GEP->accumulateConstantOffset(DL, ConstantOffset)) {
48 APInt Scaled = ConstantOffset.udiv(ScalarSize);
49 return ConstantInt::get(DL.getIndexType(GEP->getType()), Scaled);
50 }
51
52 unsigned NumIndices = GEP->getNumIndices();
53
54 // If we have a single index we're indexing into a top level array. This
55 // generally only happens with cbuffers.
56 if (NumIndices == 1)
57 return *GEP->idx_begin();
58
59 // If we have two indices, this should be a simple access through a pointer.
60 if (NumIndices == 2) {
61 auto IndexIt = GEP->idx_begin();
62 assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
63 "GEP is not indexing through pointer");
64 ++IndexIt;
65 Value *Offset = *IndexIt;
66 assert(++IndexIt == GEP->idx_end() && "Too many indices in GEP");
67 return Offset;
68 }
69
70 llvm_unreachable("Unhandled GEP structure for resource access");
71}
72
75 IRBuilder<> Builder(SI);
76 Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
77 Type *LoadType = StructType::get(ContainedType, Builder.getInt1Ty());
78
79 Value *V = SI->getValueOperand();
80 if (V->getType() == ContainedType) {
81 // V is already the right type.
82 assert(!Offset && "store of whole element has offset?");
83 } else if (V->getType() == ContainedType->getScalarType()) {
84 // We're storing a scalar, so we need to load the current value and only
85 // replace the relevant part.
86 auto *Load = Builder.CreateIntrinsic(
87 LoadType, Intrinsic::dx_resource_load_typedbuffer,
88 {II->getOperand(0), II->getOperand(1)});
89 auto *Struct = Builder.CreateExtractValue(Load, {0});
90
91 // If we have an offset from seeing a GEP earlier, use that. Otherwise, 0.
92 if (!Offset)
93 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);
94 V = Builder.CreateInsertElement(Struct, V, Offset);
95 } else {
96 llvm_unreachable("Store to typed resource has invalid type");
97 }
98
99 auto *Inst = Builder.CreateIntrinsic(
100 Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
101 {II->getOperand(0), II->getOperand(1), V});
102 SI->replaceAllUsesWith(Inst);
103}
104
106 IRBuilder<> Builder(SI);
107
108 if (!Offset)
109 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);
110 Value *V = SI->getValueOperand();
111 // TODO: break up larger types
112 auto *Inst = Builder.CreateIntrinsic(
113 Builder.getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
114 {II->getOperand(0), II->getOperand(1), Offset, V});
115 SI->replaceAllUsesWith(Inst);
116}
117
149
152 IRBuilder<> Builder(LI);
153 Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
154 Type *LoadType = StructType::get(ContainedType, Builder.getInt1Ty());
155
156 Value *V =
157 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
158 {II->getOperand(0), II->getOperand(1)});
159 V = Builder.CreateExtractValue(V, {0});
160
161 if (Offset)
162 V = Builder.CreateExtractElement(V, Offset);
163
164 // If we loaded a <1 x ...> instead of a scalar (presumably to feed a
165 // shufflevector), then make sure we're maintaining the resulting type.
166 if (auto *VT = dyn_cast<FixedVectorType>(LI->getType()))
167 if (VT->getNumElements() == 1 && !isa<FixedVectorType>(V->getType()))
168 V = Builder.CreateInsertElement(PoisonValue::get(VT), V,
169 Builder.getInt32(0));
170
171 LI->replaceAllUsesWith(V);
172}
173
175 IRBuilder<> Builder(LI);
176 // TODO: break up larger types
177 Type *LoadType = StructType::get(LI->getType(), Builder.getInt1Ty());
178 if (!Offset)
179 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);
180 Value *V =
181 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,
182 {II->getOperand(0), II->getOperand(1), Offset});
183 V = Builder.CreateExtractValue(V, {0});
184
185 LI->replaceAllUsesWith(V);
186}
187
188namespace {
189/// Helper for building a `load.cbufferrow` intrinsic given a simple type.
190struct CBufferRowIntrin {
191 Intrinsic::ID IID;
192 Type *RetTy;
193 unsigned int EltSize;
194 unsigned int NumElts;
195
196 CBufferRowIntrin(const DataLayout &DL, Type *Ty) {
197 assert(Ty == Ty->getScalarType() && "Expected scalar type");
198
199 switch (DL.getTypeSizeInBits(Ty)) {
200 case 16:
201 IID = Intrinsic::dx_resource_load_cbufferrow_8;
202 RetTy = StructType::get(Ty, Ty, Ty, Ty, Ty, Ty, Ty, Ty);
203 EltSize = 2;
204 NumElts = 8;
205 break;
206 case 32:
207 IID = Intrinsic::dx_resource_load_cbufferrow_4;
208 RetTy = StructType::get(Ty, Ty, Ty, Ty);
209 EltSize = 4;
210 NumElts = 4;
211 break;
212 case 64:
213 IID = Intrinsic::dx_resource_load_cbufferrow_2;
214 RetTy = StructType::get(Ty, Ty);
215 EltSize = 8;
216 NumElts = 2;
217 break;
218 default:
219 llvm_unreachable("Only 16, 32, and 64 bit types supported");
220 }
221 }
222};
223} // namespace
224
227 const DataLayout &DL = LI->getDataLayout();
228
229 Type *Ty = LI->getType();
230 assert(!isa<StructType>(Ty) && "Structs not handled yet");
231 CBufferRowIntrin Intrin(DL, Ty->getScalarType());
232
233 StringRef Name = LI->getName();
234 Value *Handle = II->getOperand(0);
235
236 IRBuilder<> Builder(LI);
237
238 ConstantInt *GlobalOffset = dyn_cast<ConstantInt>(II->getOperand(1));
239 assert(GlobalOffset && "CBuffer getpointer index must be constant");
240
241 unsigned int FixedOffset = GlobalOffset->getZExtValue();
242 // If we have a further constant offset we can just fold it in to the fixed
243 // offset.
244 if (auto *ConstOffset = dyn_cast_if_present<ConstantInt>(Offset)) {
245 FixedOffset += ConstOffset->getZExtValue();
246 Offset = nullptr;
247 }
248
249 Value *CurrentRow = ConstantInt::get(
250 Builder.getInt32Ty(), FixedOffset / hlsl::CBufferRowSizeInBytes);
251 unsigned int CurrentIndex =
252 (FixedOffset % hlsl::CBufferRowSizeInBytes) / Intrin.EltSize;
253
254 assert(!(CurrentIndex && Offset) &&
255 "Dynamic indexing into elements of cbuffer rows is not supported");
256 // At this point if we have a non-constant offset it has to be an array
257 // offset, so we can assume that it's a multiple of the row size.
258 if (Offset)
259 CurrentRow = FixedOffset ? Builder.CreateAdd(CurrentRow, Offset) : Offset;
260
261 auto *CBufLoad = Builder.CreateIntrinsic(
262 Intrin.RetTy, Intrin.IID, {Handle, CurrentRow}, nullptr, Name + ".load");
263 auto *Elt =
264 Builder.CreateExtractValue(CBufLoad, {CurrentIndex++}, Name + ".extract");
265
266 // At this point we've loaded the first scalar of our result, but our original
267 // type may have been a vector.
268 unsigned int Remaining =
269 ((DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;
270 if (Remaining == 0) {
271 // We only have a single element, so we're done.
272 Value *Result = Elt;
273
274 // However, if we loaded a <1 x T>, then we need to adjust the type.
275 if (auto *VT = dyn_cast<FixedVectorType>(Ty)) {
276 assert(VT->getNumElements() == 1 && "Can't have multiple elements here");
277 Result = Builder.CreateInsertElement(PoisonValue::get(VT), Result,
278 Builder.getInt32(0), Name);
279 }
280 LI->replaceAllUsesWith(Result);
281 return;
282 }
283
284 // Walk each element and extract it, wrapping to new rows as needed.
285 SmallVector<Value *> Extracts{Elt};
286 while (Remaining--) {
287 CurrentIndex %= Intrin.NumElts;
288
289 if (CurrentIndex == 0) {
290 CurrentRow = Builder.CreateAdd(CurrentRow,
291 ConstantInt::get(Builder.getInt32Ty(), 1));
292 CBufLoad = Builder.CreateIntrinsic(Intrin.RetTy, Intrin.IID,
293 {Handle, CurrentRow}, nullptr,
294 Name + ".load");
295 }
296
297 Extracts.push_back(Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},
298 Name + ".extract"));
299 }
300
301 // Finally, we build up the original loaded value.
302 Value *Result = PoisonValue::get(Ty);
303 for (int I = 0, E = Extracts.size(); I < E; ++I)
304 Result = Builder.CreateInsertElement(
305 Result, Extracts[I], Builder.getInt32(I), Name + formatv(".upto{}", I));
306 LI->replaceAllUsesWith(Result);
307}
308
341
346 auto *BB = Start->getParent();
347
348 // Seed with direct users in this block.
349 for (User *U : Start->users()) {
350 if (auto *I = dyn_cast<Instruction>(U)) {
351 if (I->getParent() == BB)
352 Worklist.push_back(I);
353 }
354 }
355
356 // BFS over transitive users, constrained to the same block.
357 while (!Worklist.empty()) {
358 Instruction *I = Worklist.pop_back_val();
359 if (!Visited.insert(I).second)
360 continue;
361 Out.push_back(I);
362
363 for (User *U : I->users()) {
364 if (auto *J = dyn_cast<Instruction>(U)) {
365 if (J->getParent() == BB)
366 Worklist.push_back(J);
367 }
368 }
369 for (Use &V : I->operands()) {
370 if (auto *J = dyn_cast<Instruction>(V)) {
371 if (J->getParent() == BB && V != Start)
372 Worklist.push_back(J);
373 }
374 }
375 }
376
377 // Order results in program order.
379 unsigned Idx = 0;
380 for (Instruction &I : *BB)
381 Ord[&I] = Idx++;
382
383 llvm::sort(Out, [&](Instruction *A, Instruction *B) {
384 return Ord.lookup(A) < Ord.lookup(B);
385 });
386
387 return Out;
388}
389
391 IRBuilder<> &Builder,
392 SmallVector<Instruction *> &UsesInBlock) {
393
395 Value *Val = Phi->getIncomingValueForBlock(BB);
396 VMap[Phi] = Val;
397 Builder.SetInsertPoint(&BB->back());
398 for (Instruction *I : UsesInBlock) {
399 // don't clone over the Phi just remap them
400 if (auto *PhiNested = dyn_cast<PHINode>(I)) {
401 VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB);
402 continue;
403 }
404 Instruction *Clone = I->clone();
405 RemapInstruction(Clone, VMap,
407 Builder.Insert(Clone);
408 VMap[I] = Clone;
409 }
410}
411
413 SmallVectorImpl<Instruction *> &PrevBBDeadInsts,
414 SetVector<BasicBlock *> &DeadBB) {
415 SmallVector<Instruction *> CurrBBDeadInsts;
416 for (User *U : II->users()) {
417 auto *Phi = dyn_cast<PHINode>(U);
418 if (!Phi)
419 continue;
420
421 IRBuilder<> Builder(Phi);
423 bool HasReturnUse = isa<ReturnInst>(UsesInBlock.back());
424
425 for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) {
426 auto *CurrIncomingBB = Phi->getIncomingBlock(I);
427 phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
428 if (HasReturnUse)
429 PrevBBDeadInsts.push_back(&CurrIncomingBB->back());
430 }
431
432 CurrBBDeadInsts.push_back(Phi);
433
434 for (Instruction *I : UsesInBlock) {
435 CurrBBDeadInsts.push_back(I);
436 }
437 if (HasReturnUse) {
438 BasicBlock *PhiBB = Phi->getParent();
439 DeadBB.insert(PhiBB);
440 }
441 }
442 // Traverse the now-dead instructions in RPO and remove them.
443 for (Instruction *Dead : llvm::reverse(CurrBBDeadInsts))
444 Dead->eraseFromParent();
445 CurrBBDeadInsts.clear();
446}
447
449 // Process users keeping track of indexing accumulated from GEPs.
450 struct AccessAndOffset {
451 User *Access;
452 Value *Offset;
453 };
455 for (User *U : II->users())
456 Worklist.push_back({U, nullptr});
457
459 while (!Worklist.empty()) {
460 AccessAndOffset Current = Worklist.back();
461 Worklist.pop_back();
462
463 if (auto *GEP = dyn_cast<GetElementPtrInst>(Current.Access)) {
464 IRBuilder<> Builder(GEP);
465
466 Value *Offset = calculateGEPOffset(GEP, Current.Offset, RTI);
467 for (User *U : GEP->users())
468 Worklist.push_back({U, Offset});
469 DeadInsts.push_back(GEP);
470
471 } else if (auto *SI = dyn_cast<StoreInst>(Current.Access)) {
472 assert(SI->getValueOperand() != II && "Pointer escaped!");
473 createStoreIntrinsic(II, SI, Current.Offset, RTI);
474 DeadInsts.push_back(SI);
475
476 } else if (auto *LI = dyn_cast<LoadInst>(Current.Access)) {
477 createLoadIntrinsic(II, LI, Current.Offset, RTI);
478 DeadInsts.push_back(LI);
479 } else
480 llvm_unreachable("Unhandled instruction - pointer escaped?");
481 }
482
483 // Traverse the now-dead instructions in RPO and remove them.
484 for (Instruction *Dead : llvm::reverse(DeadInsts))
485 Dead->eraseFromParent();
486 II->eraseFromParent();
487}
488
492 SmallVector<Instruction *> PrevBBDeadInsts;
493 for (BasicBlock &BB : make_early_inc_range(F)) {
495 if (auto *II = dyn_cast<IntrinsicInst>(&I))
496 if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer)
497 phiNodeReplacement(II, PrevBBDeadInsts, DeadBB);
498
499 for (Instruction &I : BB)
500 if (auto *II = dyn_cast<IntrinsicInst>(&I))
501 if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
502 auto *HandleTy = cast<TargetExtType>(II->getArgOperand(0)->getType());
503 Resources.emplace_back(II, DRTM[HandleTy]);
504 }
505 }
506 for (auto *Dead : PrevBBDeadInsts)
507 Dead->eraseFromParent();
508 PrevBBDeadInsts.clear();
509 for (auto *Dead : DeadBB)
510 Dead->eraseFromParent();
511 DeadBB.clear();
512
513 for (auto &[II, RI] : Resources)
514 replaceAccess(II, RI);
515
516 return !Resources.empty();
517}
518
521 auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
522 DXILResourceTypeMap *DRTM =
523 MAMProxy.getCachedResult<DXILResourceTypeAnalysis>(*F.getParent());
524 assert(DRTM && "DXILResourceTypeAnalysis must be available");
525
526 bool MadeChanges = transformResourcePointers(F, *DRTM);
527 if (!MadeChanges)
528 return PreservedAnalyses::all();
529
533 return PA;
534}
535
536namespace {
537class DXILResourceAccessLegacy : public FunctionPass {
538public:
539 bool runOnFunction(Function &F) override {
540 DXILResourceTypeMap &DRTM =
541 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
542 return transformResourcePointers(F, DRTM);
543 }
544 StringRef getPassName() const override { return "DXIL Resource Access"; }
545 DXILResourceAccessLegacy() : FunctionPass(ID) {}
546
547 static char ID; // Pass identification.
548 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
549 AU.addRequired<DXILResourceTypeWrapperPass>();
550 AU.addPreserved<DominatorTreeWrapperPass>();
551 }
552};
553char DXILResourceAccessLegacy::ID = 0;
554} // end anonymous namespace
555
556INITIALIZE_PASS_BEGIN(DXILResourceAccessLegacy, DEBUG_TYPE,
557 "DXIL Resource Access", false, false)
559INITIALIZE_PASS_END(DXILResourceAccessLegacy, DEBUG_TYPE,
560 "DXIL Resource Access", false, false)
561
563 return new DXILResourceAccessLegacy();
564}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
@ Scaled
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, IRBuilder<> &Builder, SmallVector< Instruction * > &UsesInBlock)
static Value * calculateGEPOffset(GetElementPtrInst *GEP, Value *PrevOffset, dxil::ResourceTypeInfo &RTI)
static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM)
static void createRawLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset)
static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static SmallVector< Instruction * > collectBlockUseDef(Instruction *Start)
DXIL Resource Access
static void phiNodeReplacement(IntrinsicInst *II, SmallVectorImpl< Instruction * > &PrevBBDeadInsts, SetVector< BasicBlock * > &DeadBB)
static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)
static void createRawStore(IntrinsicInst *II, StoreInst *SI, Value *Offset)
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
Hexagon Common GEP
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file implements a set that has insertion order iteration characteristics.
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt udiv(const APInt &RHS) const
Unsigned division operation.
Definition APInt.cpp:1573
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Instruction & back() const
Definition BasicBlock.h:484
This is the shared class of boolean and integer constants.
Definition Constants.h:87
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:163
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:63
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
Definition DenseMap.h:205
Analysis pass which computes a DominatorTree.
Definition Dominators.h:283
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2788
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
A vector that has set insertion semantics.
Definition SetVector.h:58
void clear()
Completely clear the SetVector.
Definition SetVector.h:265
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:149
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
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...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
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
Type * getTypeParameter(unsigned i) const
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:352
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:293
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:546
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
LLVM_ABI bool isTyped() const
TargetExtType * getHandleTy() const
dxil::ResourceKind getResourceKind() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
const unsigned CBufferRowSizeInBytes
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
Definition Casting.h:732
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:632
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
FunctionPass * createDXILResourceAccessLegacyPass()
Pass to update resource accesses to use load/store directly.
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1622
@ RF_IgnoreMissingLocals
If this flag is set, the remapper ignores missing function-local entries (Argument,...
Definition ValueMapper.h:98
@ RF_NoModuleLevelChanges
If this flag is set, the remapper knows that only local values within a function (such as an instruct...
Definition ValueMapper.h:80
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
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:180