LLVM 22.0.0git
DXILOpLowering.cpp
Go to the documentation of this file.
1//===- DXILOpLowering.cpp - Lowering to DXIL operations -------------------===//
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
9#include "DXILOpLowering.h"
10#include "DXILConstants.h"
11#include "DXILOpBuilder.h"
12#include "DXILRootSignature.h"
13#include "DXILShaderFlags.h"
14#include "DirectX.h"
18#include "llvm/CodeGen/Passes.h"
19#include "llvm/IR/Constant.h"
21#include "llvm/IR/IRBuilder.h"
22#include "llvm/IR/Instruction.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/IntrinsicsDirectX.h"
26#include "llvm/IR/Module.h"
27#include "llvm/IR/PassManager.h"
28#include "llvm/IR/Use.h"
30#include "llvm/Pass.h"
33
34#define DEBUG_TYPE "dxil-op-lower"
35
36using namespace llvm;
37using namespace llvm::dxil;
38
39namespace {
40class OpLowerer {
41 Module &M;
42 DXILOpBuilder OpBuilder;
43 DXILResourceMap &DRM;
45 const ModuleMetadataInfo &MMDI;
46 SmallVector<CallInst *> CleanupCasts;
47 Function *CleanupNURI = nullptr;
48
49public:
50 OpLowerer(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM,
51 const ModuleMetadataInfo &MMDI)
52 : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
53
54 /// Replace every call to \c F using \c ReplaceCall, and then erase \c F. If
55 /// there is an error replacing a call, we emit a diagnostic and return true.
56 [[nodiscard]] bool
57 replaceFunction(Function &F,
58 llvm::function_ref<Error(CallInst *CI)> ReplaceCall) {
59 for (User *U : make_early_inc_range(F.users())) {
61 if (!CI)
62 continue;
63
64 if (Error E = ReplaceCall(CI)) {
65 std::string Message(toString(std::move(E)));
66 M.getContext().diagnose(DiagnosticInfoUnsupported(
67 *CI->getFunction(), Message, CI->getDebugLoc()));
68
69 return true;
70 }
71 }
72 if (F.user_empty())
73 F.eraseFromParent();
74 return false;
75 }
76
77 struct IntrinArgSelect {
78 enum class Type {
79#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
80#include "DXILOperation.inc"
81 };
82 Type Type;
83 int Value;
84 };
85
86 /// Replaces uses of a struct with uses of an equivalent named struct.
87 ///
88 /// DXIL operations that return structs give them well known names, so we need
89 /// to update uses when we switch from an LLVM intrinsic to an op.
90 Error replaceNamedStructUses(CallInst *Intrin, CallInst *DXILOp) {
91 auto *IntrinTy = cast<StructType>(Intrin->getType());
92 auto *DXILOpTy = cast<StructType>(DXILOp->getType());
93 if (!IntrinTy->isLayoutIdentical(DXILOpTy))
95 "Type mismatch between intrinsic and DXIL op",
97
98 for (Use &U : make_early_inc_range(Intrin->uses()))
99 if (auto *EVI = dyn_cast<ExtractValueInst>(U.getUser()))
100 EVI->setOperand(0, DXILOp);
101 else if (auto *IVI = dyn_cast<InsertValueInst>(U.getUser()))
102 IVI->setOperand(0, DXILOp);
103 else
104 return make_error<StringError>("DXIL ops that return structs may only "
105 "be used by insert- and extractvalue",
107 return Error::success();
108 }
109
110 [[nodiscard]] bool
111 replaceFunctionWithOp(Function &F, dxil::OpCode DXILOp,
112 ArrayRef<IntrinArgSelect> ArgSelects) {
113 return replaceFunction(F, [&](CallInst *CI) -> Error {
114 OpBuilder.getIRB().SetInsertPoint(CI);
116 if (ArgSelects.size()) {
117 for (const IntrinArgSelect &A : ArgSelects) {
118 switch (A.Type) {
119 case IntrinArgSelect::Type::Index:
120 Args.push_back(CI->getArgOperand(A.Value));
121 break;
122 case IntrinArgSelect::Type::I8:
123 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)A.Value));
124 break;
125 case IntrinArgSelect::Type::I32:
126 Args.push_back(OpBuilder.getIRB().getInt32(A.Value));
127 break;
128 }
129 }
130 } else {
131 Args.append(CI->arg_begin(), CI->arg_end());
132 }
133
134 Expected<CallInst *> OpCall =
135 OpBuilder.tryCreateOp(DXILOp, Args, CI->getName(), F.getReturnType());
136 if (Error E = OpCall.takeError())
137 return E;
138
139 if (isa<StructType>(CI->getType())) {
140 if (Error E = replaceNamedStructUses(CI, *OpCall))
141 return E;
142 } else
143 CI->replaceAllUsesWith(*OpCall);
144
145 CI->eraseFromParent();
146 return Error::success();
147 });
148 }
149
150 /// Create a cast between a `target("dx")` type and `dx.types.Handle`, which
151 /// is intended to be removed by the end of lowering. This is used to allow
152 /// lowering of ops which need to change their return or argument types in a
153 /// piecemeal way - we can add the casts in to avoid updating all of the uses
154 /// or defs, and by the end all of the casts will be redundant.
155 Value *createTmpHandleCast(Value *V, Type *Ty) {
156 CallInst *Cast = OpBuilder.getIRB().CreateIntrinsic(
157 Intrinsic::dx_resource_casthandle, {Ty, V->getType()}, {V});
158 CleanupCasts.push_back(Cast);
159 return Cast;
160 }
161
162 void cleanupHandleCasts() {
165
166 for (CallInst *Cast : CleanupCasts) {
167 // These casts were only put in to ease the move from `target("dx")` types
168 // to `dx.types.Handle in a piecemeal way. At this point, all of the
169 // non-cast uses should now be `dx.types.Handle`, and remaining casts
170 // should all form pairs to and from the now unused `target("dx")` type.
171 CastFns.push_back(Cast->getCalledFunction());
172
173 // If the cast is not to `dx.types.Handle`, it should be the first part of
174 // the pair. Keep track so we can remove it once it has no more uses.
175 if (Cast->getType() != OpBuilder.getHandleType()) {
176 ToRemove.push_back(Cast);
177 continue;
178 }
179 // Otherwise, we're the second handle in a pair. Forward the arguments and
180 // remove the (second) cast.
181 CallInst *Def = cast<CallInst>(Cast->getOperand(0));
182 assert(Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
183 "Unbalanced pair of temporary handle casts");
184 Cast->replaceAllUsesWith(Def->getOperand(0));
185 Cast->eraseFromParent();
186 }
187 for (CallInst *Cast : ToRemove) {
188 assert(Cast->user_empty() && "Temporary handle cast still has users");
189 Cast->eraseFromParent();
190 }
191
192 // Deduplicate the cast functions so that we only erase each one once.
193 llvm::sort(CastFns);
194 CastFns.erase(llvm::unique(CastFns), CastFns.end());
195 for (Function *F : CastFns)
196 F->eraseFromParent();
197
198 CleanupCasts.clear();
199 }
200
201 void cleanupNonUniformResourceIndexCalls() {
202 // Replace all NonUniformResourceIndex calls with their argument.
203 if (!CleanupNURI)
204 return;
205 for (User *U : make_early_inc_range(CleanupNURI->users())) {
206 CallInst *CI = dyn_cast<CallInst>(U);
207 if (!CI)
208 continue;
210 CI->eraseFromParent();
211 }
212 CleanupNURI->eraseFromParent();
213 CleanupNURI = nullptr;
214 }
215
216 // Remove the resource global associated with the handleFromBinding call
217 // instruction and their uses as they aren't needed anymore.
218 // TODO: We should verify that all the globals get removed.
219 // It's expected we'll need a custom pass in the future that will eliminate
220 // the need for this here.
221 void removeResourceGlobals(CallInst *CI) {
222 for (User *User : make_early_inc_range(CI->users())) {
223 if (StoreInst *Store = dyn_cast<StoreInst>(User)) {
224 Value *V = Store->getOperand(1);
225 Store->eraseFromParent();
226 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
227 if (GV->use_empty()) {
228 GV->removeDeadConstantUsers();
229 GV->eraseFromParent();
230 }
231 }
232 }
233 }
234
235 void replaceHandleFromBindingCall(CallInst *CI, Value *Replacement) {
237 Intrinsic::dx_resource_handlefrombinding);
238
239 removeResourceGlobals(CI);
240
241 auto *NameGlobal = dyn_cast<llvm::GlobalVariable>(CI->getArgOperand(4));
242
243 CI->replaceAllUsesWith(Replacement);
244 CI->eraseFromParent();
245
246 if (NameGlobal && NameGlobal->use_empty())
247 NameGlobal->removeFromParent();
248 }
249
250 bool hasNonUniformIndex(Value *IndexOp) {
251 if (isa<llvm::Constant>(IndexOp))
252 return false;
253
254 SmallVector<Value *> WorkList;
255 WorkList.push_back(IndexOp);
256
257 while (!WorkList.empty()) {
258 Value *V = WorkList.pop_back_val();
259 if (auto *CI = dyn_cast<CallInst>(V)) {
260 if (CI->getCalledFunction()->getIntrinsicID() ==
261 Intrinsic::dx_resource_nonuniformindex)
262 return true;
263 }
264 if (auto *U = llvm::dyn_cast<llvm::User>(V)) {
265 for (llvm::Value *Op : U->operands()) {
267 continue;
268 WorkList.push_back(Op);
269 }
270 }
271 }
272 return false;
273 }
274
275 Error validateRawBufferElementIndex(Value *Resource, Value *ElementIndex) {
276 bool IsStructured =
277 cast<RawBufferExtType>(Resource->getType())->isStructured();
278 bool IsPoison = isa<PoisonValue>(ElementIndex);
279
280 if (IsStructured && IsPoison)
282 "Element index of structured buffer may not be poison",
284
285 if (!IsStructured && !IsPoison)
287 "Element index of raw buffer must be poison",
289
290 return Error::success();
291 }
292
293 [[nodiscard]] bool lowerToCreateHandle(Function &F) {
294 IRBuilder<> &IRB = OpBuilder.getIRB();
295 Type *Int8Ty = IRB.getInt8Ty();
296 Type *Int32Ty = IRB.getInt32Ty();
297 Type *Int1Ty = IRB.getInt1Ty();
298
299 return replaceFunction(F, [&](CallInst *CI) -> Error {
300 IRB.SetInsertPoint(CI);
301
302 auto *It = DRM.find(CI);
303 assert(It != DRM.end() && "Resource not in map?");
304 dxil::ResourceInfo &RI = *It;
305
306 const auto &Binding = RI.getBinding();
307 dxil::ResourceClass RC = DRTM[RI.getHandleTy()].getResourceClass();
308
309 Value *IndexOp = CI->getArgOperand(3);
310 if (Binding.LowerBound != 0)
311 IndexOp = IRB.CreateAdd(IndexOp,
312 ConstantInt::get(Int32Ty, Binding.LowerBound));
313
314 bool HasNonUniformIndex =
315 (Binding.Size == 1) ? false : hasNonUniformIndex(IndexOp);
316 std::array<Value *, 4> Args{
317 ConstantInt::get(Int8Ty, llvm::to_underlying(RC)),
318 ConstantInt::get(Int32Ty, Binding.RecordID), IndexOp,
319 ConstantInt::get(Int1Ty, HasNonUniformIndex)};
320 Expected<CallInst *> OpCall =
321 OpBuilder.tryCreateOp(OpCode::CreateHandle, Args, CI->getName());
322 if (Error E = OpCall.takeError())
323 return E;
324
325 Value *Cast = createTmpHandleCast(*OpCall, CI->getType());
326 replaceHandleFromBindingCall(CI, Cast);
327 return Error::success();
328 });
329 }
330
331 [[nodiscard]] bool lowerToBindAndAnnotateHandle(Function &F) {
332 IRBuilder<> &IRB = OpBuilder.getIRB();
333 Type *Int32Ty = IRB.getInt32Ty();
334 Type *Int1Ty = IRB.getInt1Ty();
335
336 return replaceFunction(F, [&](CallInst *CI) -> Error {
337 IRB.SetInsertPoint(CI);
338
339 auto *It = DRM.find(CI);
340 assert(It != DRM.end() && "Resource not in map?");
341 dxil::ResourceInfo &RI = *It;
342
343 const auto &Binding = RI.getBinding();
344 dxil::ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
346
347 Value *IndexOp = CI->getArgOperand(3);
348 if (Binding.LowerBound != 0)
349 IndexOp = IRB.CreateAdd(IndexOp,
350 ConstantInt::get(Int32Ty, Binding.LowerBound));
351
352 std::pair<uint32_t, uint32_t> Props =
353 RI.getAnnotateProps(*F.getParent(), RTI);
354
355 // For `CreateHandleFromBinding` we need the upper bound rather than the
356 // size, so we need to be careful about the difference for "unbounded".
357 uint32_t Unbounded = std::numeric_limits<uint32_t>::max();
358 uint32_t UpperBound = Binding.Size == Unbounded
359 ? Unbounded
360 : Binding.LowerBound + Binding.Size - 1;
361 Constant *ResBind = OpBuilder.getResBind(Binding.LowerBound, UpperBound,
362 Binding.Space, RC);
363 bool NonUniformIndex =
364 (Binding.Size == 1) ? false : hasNonUniformIndex(IndexOp);
365 Constant *NonUniformOp = ConstantInt::get(Int1Ty, NonUniformIndex);
366 std::array<Value *, 3> BindArgs{ResBind, IndexOp, NonUniformOp};
367 Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
368 OpCode::CreateHandleFromBinding, BindArgs, CI->getName());
369 if (Error E = OpBind.takeError())
370 return E;
371
372 std::array<Value *, 2> AnnotateArgs{
373 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
374 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
375 OpCode::AnnotateHandle, AnnotateArgs,
376 CI->hasName() ? CI->getName() + "_annot" : Twine());
377 if (Error E = OpAnnotate.takeError())
378 return E;
379
380 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->getType());
381 replaceHandleFromBindingCall(CI, Cast);
382 return Error::success();
383 });
384 }
385
386 /// Lower `dx.resource.handlefrombinding` intrinsics depending on the shader
387 /// model and taking into account binding information from
388 /// DXILResourceAnalysis.
389 bool lowerHandleFromBinding(Function &F) {
390 if (MMDI.DXILVersion < VersionTuple(1, 6))
391 return lowerToCreateHandle(F);
392 return lowerToBindAndAnnotateHandle(F);
393 }
394
395 /// Replace uses of \c Intrin with the values in the `dx.ResRet` of \c Op.
396 /// Since we expect to be post-scalarization, make an effort to avoid vectors.
397 Error replaceResRetUses(CallInst *Intrin, CallInst *Op, bool HasCheckBit) {
398 IRBuilder<> &IRB = OpBuilder.getIRB();
399
400 Instruction *OldResult = Intrin;
401 Type *OldTy = Intrin->getType();
402
403 if (HasCheckBit) {
404 auto *ST = cast<StructType>(OldTy);
405
406 Value *CheckOp = nullptr;
407 Type *Int32Ty = IRB.getInt32Ty();
408 for (Use &U : make_early_inc_range(OldResult->uses())) {
409 if (auto *EVI = dyn_cast<ExtractValueInst>(U.getUser())) {
410 ArrayRef<unsigned> Indices = EVI->getIndices();
411 assert(Indices.size() == 1);
412 // We're only interested in uses of the check bit for now.
413 if (Indices[0] != 1)
414 continue;
415 if (!CheckOp) {
416 Value *NewEVI = IRB.CreateExtractValue(Op, 4);
417 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
418 OpCode::CheckAccessFullyMapped, {NewEVI},
419 OldResult->hasName() ? OldResult->getName() + "_check"
420 : Twine(),
421 Int32Ty);
422 if (Error E = OpCall.takeError())
423 return E;
424 CheckOp = *OpCall;
425 }
426 EVI->replaceAllUsesWith(CheckOp);
427 EVI->eraseFromParent();
428 }
429 }
430
431 if (OldResult->use_empty()) {
432 // Only the check bit was used, so we're done here.
433 OldResult->eraseFromParent();
434 return Error::success();
435 }
436
437 assert(OldResult->hasOneUse() &&
438 isa<ExtractValueInst>(*OldResult->user_begin()) &&
439 "Expected only use to be extract of first element");
440 OldResult = cast<Instruction>(*OldResult->user_begin());
441 OldTy = ST->getElementType(0);
442 }
443
444 // For scalars, we just extract the first element.
445 if (!isa<FixedVectorType>(OldTy)) {
446 Value *EVI = IRB.CreateExtractValue(Op, 0);
447 OldResult->replaceAllUsesWith(EVI);
448 OldResult->eraseFromParent();
449 if (OldResult != Intrin) {
450 assert(Intrin->use_empty() && "Intrinsic still has uses?");
451 Intrin->eraseFromParent();
452 }
453 return Error::success();
454 }
455
456 std::array<Value *, 4> Extracts = {};
457 SmallVector<ExtractElementInst *> DynamicAccesses;
458
459 // The users of the operation should all be scalarized, so we attempt to
460 // replace the extractelements with extractvalues directly.
461 for (Use &U : make_early_inc_range(OldResult->uses())) {
462 if (auto *EEI = dyn_cast<ExtractElementInst>(U.getUser())) {
463 if (auto *IndexOp = dyn_cast<ConstantInt>(EEI->getIndexOperand())) {
464 size_t IndexVal = IndexOp->getZExtValue();
465 assert(IndexVal < 4 && "Index into buffer load out of range");
466 if (!Extracts[IndexVal])
467 Extracts[IndexVal] = IRB.CreateExtractValue(Op, IndexVal);
468 EEI->replaceAllUsesWith(Extracts[IndexVal]);
469 EEI->eraseFromParent();
470 } else {
471 DynamicAccesses.push_back(EEI);
472 }
473 }
474 }
475
476 const auto *VecTy = cast<FixedVectorType>(OldTy);
477 const unsigned N = VecTy->getNumElements();
478
479 // If there's a dynamic access we need to round trip through stack memory so
480 // that we don't leave vectors around.
481 if (!DynamicAccesses.empty()) {
482 Type *Int32Ty = IRB.getInt32Ty();
483 Constant *Zero = ConstantInt::get(Int32Ty, 0);
484
485 Type *ElTy = VecTy->getElementType();
486 Type *ArrayTy = ArrayType::get(ElTy, N);
487 Value *Alloca = IRB.CreateAlloca(ArrayTy);
488
489 for (int I = 0, E = N; I != E; ++I) {
490 if (!Extracts[I])
491 Extracts[I] = IRB.CreateExtractValue(Op, I);
493 ArrayTy, Alloca, {Zero, ConstantInt::get(Int32Ty, I)});
494 IRB.CreateStore(Extracts[I], GEP);
495 }
496
497 for (ExtractElementInst *EEI : DynamicAccesses) {
498 Value *GEP = IRB.CreateInBoundsGEP(ArrayTy, Alloca,
499 {Zero, EEI->getIndexOperand()});
500 Value *Load = IRB.CreateLoad(ElTy, GEP);
501 EEI->replaceAllUsesWith(Load);
502 EEI->eraseFromParent();
503 }
504 }
505
506 // If we still have uses, then we're not fully scalarized and need to
507 // recreate the vector. This should only happen for things like exported
508 // functions from libraries.
509 if (!OldResult->use_empty()) {
510 for (int I = 0, E = N; I != E; ++I)
511 if (!Extracts[I])
512 Extracts[I] = IRB.CreateExtractValue(Op, I);
513
514 Value *Vec = PoisonValue::get(OldTy);
515 for (int I = 0, E = N; I != E; ++I)
516 Vec = IRB.CreateInsertElement(Vec, Extracts[I], I);
517 OldResult->replaceAllUsesWith(Vec);
518 }
519
520 OldResult->eraseFromParent();
521 if (OldResult != Intrin) {
522 assert(Intrin->use_empty() && "Intrinsic still has uses?");
523 Intrin->eraseFromParent();
524 }
525
526 return Error::success();
527 }
528
529 [[nodiscard]] bool lowerTypedBufferLoad(Function &F, bool HasCheckBit) {
530 IRBuilder<> &IRB = OpBuilder.getIRB();
531 Type *Int32Ty = IRB.getInt32Ty();
532
533 return replaceFunction(F, [&](CallInst *CI) -> Error {
534 IRB.SetInsertPoint(CI);
535
536 Value *Handle =
537 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
538 Value *Index0 = CI->getArgOperand(1);
539 Value *Index1 = UndefValue::get(Int32Ty);
540
541 Type *OldTy = CI->getType();
542 if (HasCheckBit)
543 OldTy = cast<StructType>(OldTy)->getElementType(0);
544 Type *NewRetTy = OpBuilder.getResRetType(OldTy->getScalarType());
545
546 std::array<Value *, 3> Args{Handle, Index0, Index1};
547 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
548 OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
549 if (Error E = OpCall.takeError())
550 return E;
551 if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
552 return E;
553
554 return Error::success();
555 });
556 }
557
558 [[nodiscard]] bool lowerRawBufferLoad(Function &F) {
559 const DataLayout &DL = F.getDataLayout();
560 IRBuilder<> &IRB = OpBuilder.getIRB();
561 Type *Int8Ty = IRB.getInt8Ty();
562 Type *Int32Ty = IRB.getInt32Ty();
563
564 return replaceFunction(F, [&](CallInst *CI) -> Error {
565 IRB.SetInsertPoint(CI);
566
567 Type *OldTy = cast<StructType>(CI->getType())->getElementType(0);
568 Type *ScalarTy = OldTy->getScalarType();
569 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
570
571 Value *Handle =
572 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
573 Value *Index0 = CI->getArgOperand(1);
574 Value *Index1 = CI->getArgOperand(2);
575 uint64_t NumElements =
576 DL.getTypeSizeInBits(OldTy) / DL.getTypeSizeInBits(ScalarTy);
577 Value *Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
578 Value *Align =
579 ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value());
580
581 if (Error E = validateRawBufferElementIndex(CI->getOperand(0), Index1))
582 return E;
583 if (isa<PoisonValue>(Index1))
584 Index1 = UndefValue::get(Index1->getType());
585
586 Expected<CallInst *> OpCall =
587 MMDI.DXILVersion >= VersionTuple(1, 2)
588 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
589 {Handle, Index0, Index1, Mask, Align},
590 CI->getName(), NewRetTy)
591 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
592 {Handle, Index0, Index1}, CI->getName(),
593 NewRetTy);
594 if (Error E = OpCall.takeError())
595 return E;
596 if (Error E = replaceResRetUses(CI, *OpCall, /*HasCheckBit=*/true))
597 return E;
598
599 return Error::success();
600 });
601 }
602
603 [[nodiscard]] bool lowerCBufferLoad(Function &F) {
604 IRBuilder<> &IRB = OpBuilder.getIRB();
605
606 return replaceFunction(F, [&](CallInst *CI) -> Error {
607 IRB.SetInsertPoint(CI);
608
609 Type *OldTy = cast<StructType>(CI->getType())->getElementType(0);
610 Type *ScalarTy = OldTy->getScalarType();
611 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
612
613 Value *Handle =
614 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
615 Value *Index = CI->getArgOperand(1);
616
617 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
618 OpCode::CBufferLoadLegacy, {Handle, Index}, CI->getName(), NewRetTy);
619 if (Error E = OpCall.takeError())
620 return E;
621 if (Error E = replaceNamedStructUses(CI, *OpCall))
622 return E;
623
624 CI->eraseFromParent();
625 return Error::success();
626 });
627 }
628
629 [[nodiscard]] bool lowerUpdateCounter(Function &F) {
630 IRBuilder<> &IRB = OpBuilder.getIRB();
631 Type *Int32Ty = IRB.getInt32Ty();
632
633 return replaceFunction(F, [&](CallInst *CI) -> Error {
634 IRB.SetInsertPoint(CI);
635 Value *Handle =
636 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
637 Value *Op1 = CI->getArgOperand(1);
638
639 std::array<Value *, 2> Args{Handle, Op1};
640
641 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
642 OpCode::UpdateCounter, Args, CI->getName(), Int32Ty);
643
644 if (Error E = OpCall.takeError())
645 return E;
646
647 CI->replaceAllUsesWith(*OpCall);
648 CI->eraseFromParent();
649 return Error::success();
650 });
651 }
652
653 [[nodiscard]] bool lowerGetDimensionsX(Function &F) {
654 IRBuilder<> &IRB = OpBuilder.getIRB();
655 Type *Int32Ty = IRB.getInt32Ty();
656
657 return replaceFunction(F, [&](CallInst *CI) -> Error {
658 IRB.SetInsertPoint(CI);
659 Value *Handle =
660 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
662
663 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
664 OpCode::GetDimensions, {Handle, Undef}, CI->getName(), Int32Ty);
665 if (Error E = OpCall.takeError())
666 return E;
667 Value *Dim = IRB.CreateExtractValue(*OpCall, 0);
668
669 CI->replaceAllUsesWith(Dim);
670 CI->eraseFromParent();
671 return Error::success();
672 });
673 }
674
675 [[nodiscard]] bool lowerGetPointer(Function &F) {
676 // These should have already been handled in DXILResourceAccess, so we can
677 // just clean up the dead prototype.
678 assert(F.user_empty() && "getpointer operations should have been removed");
679 F.eraseFromParent();
680 return false;
681 }
682
683 [[nodiscard]] bool lowerBufferStore(Function &F, bool IsRaw) {
684 const DataLayout &DL = F.getDataLayout();
685 IRBuilder<> &IRB = OpBuilder.getIRB();
686 Type *Int8Ty = IRB.getInt8Ty();
687 Type *Int32Ty = IRB.getInt32Ty();
688
689 return replaceFunction(F, [&](CallInst *CI) -> Error {
690 IRB.SetInsertPoint(CI);
691
692 Value *Handle =
693 createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
694 Value *Index0 = CI->getArgOperand(1);
695 Value *Index1 = IsRaw ? CI->getArgOperand(2) : UndefValue::get(Int32Ty);
696
697 if (IsRaw) {
698 if (Error E = validateRawBufferElementIndex(CI->getOperand(0), Index1))
699 return E;
700 if (isa<PoisonValue>(Index1))
701 Index1 = UndefValue::get(Index1->getType());
702 }
703
704 Value *Data = CI->getArgOperand(IsRaw ? 3 : 2);
705 Type *DataTy = Data->getType();
706 Type *ScalarTy = DataTy->getScalarType();
707
708 uint64_t NumElements =
709 DL.getTypeSizeInBits(DataTy) / DL.getTypeSizeInBits(ScalarTy);
710 Value *Mask =
711 ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements) : 15U);
712
713 // TODO: check that we only have vector or scalar...
714 if (NumElements > 4)
716 "Buffer store data must have at most 4 elements",
718
719 std::array<Value *, 4> DataElements{nullptr, nullptr, nullptr, nullptr};
720 if (DataTy == ScalarTy)
721 DataElements[0] = Data;
722 else {
723 // Since we're post-scalarizer, if we see a vector here it's likely
724 // constructed solely for the argument of the store. Just use the scalar
725 // values from before they're inserted into the temporary.
727 while (IEI) {
728 auto *IndexOp = dyn_cast<ConstantInt>(IEI->getOperand(2));
729 if (!IndexOp)
730 break;
731 size_t IndexVal = IndexOp->getZExtValue();
732 assert(IndexVal < 4 && "Too many elements for buffer store");
733 DataElements[IndexVal] = IEI->getOperand(1);
734 IEI = dyn_cast<InsertElementInst>(IEI->getOperand(0));
735 }
736 }
737
738 // If for some reason we weren't able to forward the arguments from the
739 // scalarizer artifact, then we may need to actually extract elements from
740 // the vector.
741 for (int I = 0, E = NumElements; I < E; ++I)
742 if (DataElements[I] == nullptr)
743 DataElements[I] =
744 IRB.CreateExtractElement(Data, ConstantInt::get(Int32Ty, I));
745
746 // For any elements beyond the length of the vector, we should fill it up
747 // with undef - however, for typed buffers we repeat the first element to
748 // match DXC.
749 for (int I = NumElements, E = 4; I < E; ++I)
750 if (DataElements[I] == nullptr)
751 DataElements[I] = IsRaw ? UndefValue::get(ScalarTy) : DataElements[0];
752
753 dxil::OpCode Op = OpCode::BufferStore;
755 Handle, Index0, Index1, DataElements[0],
756 DataElements[1], DataElements[2], DataElements[3], Mask};
757 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
758 Op = OpCode::RawBufferStore;
759 // RawBufferStore requires the alignment
760 Args.push_back(
761 ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value()));
762 }
763 Expected<CallInst *> OpCall =
764 OpBuilder.tryCreateOp(Op, Args, CI->getName());
765 if (Error E = OpCall.takeError())
766 return E;
767
768 CI->eraseFromParent();
769 // Clean up any leftover `insertelement`s
771 while (IEI && IEI->use_empty()) {
772 InsertElementInst *Tmp = IEI;
773 IEI = dyn_cast<InsertElementInst>(IEI->getOperand(0));
774 Tmp->eraseFromParent();
775 }
776
777 return Error::success();
778 });
779 }
780
781 [[nodiscard]] bool lowerCtpopToCountBits(Function &F) {
782 IRBuilder<> &IRB = OpBuilder.getIRB();
783 Type *Int32Ty = IRB.getInt32Ty();
784
785 return replaceFunction(F, [&](CallInst *CI) -> Error {
786 IRB.SetInsertPoint(CI);
788 Args.append(CI->arg_begin(), CI->arg_end());
789
790 Type *RetTy = Int32Ty;
791 Type *FRT = F.getReturnType();
792 if (const auto *VT = dyn_cast<VectorType>(FRT))
793 RetTy = VectorType::get(RetTy, VT);
794
795 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
796 dxil::OpCode::CountBits, Args, CI->getName(), RetTy);
797 if (Error E = OpCall.takeError())
798 return E;
799
800 // If the result type is 32 bits we can do a direct replacement.
801 if (FRT->isIntOrIntVectorTy(32)) {
802 CI->replaceAllUsesWith(*OpCall);
803 CI->eraseFromParent();
804 return Error::success();
805 }
806
807 unsigned CastOp;
808 unsigned CastOp2;
809 if (FRT->isIntOrIntVectorTy(16)) {
810 CastOp = Instruction::ZExt;
811 CastOp2 = Instruction::SExt;
812 } else { // must be 64 bits
813 assert(FRT->isIntOrIntVectorTy(64) &&
814 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
815 is supported.");
816 CastOp = Instruction::Trunc;
817 CastOp2 = Instruction::Trunc;
818 }
819
820 // It is correct to replace the ctpop with the dxil op and
821 // remove all casts to i32
822 bool NeedsCast = false;
823 for (User *User : make_early_inc_range(CI->users())) {
825 if (I && (I->getOpcode() == CastOp || I->getOpcode() == CastOp2) &&
826 I->getType() == RetTy) {
827 I->replaceAllUsesWith(*OpCall);
828 I->eraseFromParent();
829 } else
830 NeedsCast = true;
831 }
832
833 // It is correct to replace a ctpop with the dxil op and
834 // a cast from i32 to the return type of the ctpop
835 // the cast is emitted here if there is a non-cast to i32
836 // instr which uses the ctpop
837 if (NeedsCast) {
838 Value *Cast =
839 IRB.CreateZExtOrTrunc(*OpCall, F.getReturnType(), "ctpop.cast");
840 CI->replaceAllUsesWith(Cast);
841 }
842
843 CI->eraseFromParent();
844 return Error::success();
845 });
846 }
847
848 [[nodiscard]] bool lowerLifetimeIntrinsic(Function &F) {
849 IRBuilder<> &IRB = OpBuilder.getIRB();
850 return replaceFunction(F, [&](CallInst *CI) -> Error {
851 IRB.SetInsertPoint(CI);
852 Value *Ptr = CI->getArgOperand(0);
853 assert(Ptr->getType()->isPointerTy() &&
854 "Expected operand of lifetime intrinsic to be a pointer");
855
856 auto ZeroOrUndef = [&](Type *Ty) {
857 return MMDI.ValidatorVersion < VersionTuple(1, 6)
859 : UndefValue::get(Ty);
860 };
861
862 Value *Val = nullptr;
863 if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) {
864 if (GV->hasInitializer() || GV->isExternallyInitialized())
865 return Error::success();
866 Val = ZeroOrUndef(GV->getValueType());
867 } else if (auto *AI = dyn_cast<AllocaInst>(Ptr))
868 Val = ZeroOrUndef(AI->getAllocatedType());
869
870 assert(Val && "Expected operand of lifetime intrinsic to be a global "
871 "variable or alloca instruction");
872 IRB.CreateStore(Val, Ptr, false);
873
874 CI->eraseFromParent();
875 return Error::success();
876 });
877 }
878
879 [[nodiscard]] bool lowerIsFPClass(Function &F) {
880 IRBuilder<> &IRB = OpBuilder.getIRB();
881 Type *RetTy = IRB.getInt1Ty();
882
883 return replaceFunction(F, [&](CallInst *CI) -> Error {
884 IRB.SetInsertPoint(CI);
886 Value *Fl = CI->getArgOperand(0);
887 Args.push_back(Fl);
888
890 Value *T = CI->getArgOperand(1);
891 auto *TCI = dyn_cast<ConstantInt>(T);
892 switch (TCI->getZExtValue()) {
893 case FPClassTest::fcInf:
894 OpCode = dxil::OpCode::IsInf;
895 break;
896 case FPClassTest::fcNan:
897 OpCode = dxil::OpCode::IsNaN;
898 break;
899 case FPClassTest::fcNormal:
900 OpCode = dxil::OpCode::IsNormal;
901 break;
902 case FPClassTest::fcFinite:
903 OpCode = dxil::OpCode::IsFinite;
904 break;
905 default:
906 SmallString<128> Msg =
907 formatv("Unsupported FPClassTest {0} for DXIL Op Lowering",
908 TCI->getZExtValue());
910 }
911
912 Expected<CallInst *> OpCall =
913 OpBuilder.tryCreateOp(OpCode, Args, CI->getName(), RetTy);
914 if (Error E = OpCall.takeError())
915 return E;
916
917 CI->replaceAllUsesWith(*OpCall);
918 CI->eraseFromParent();
919 return Error::success();
920 });
921 }
922
923 bool lowerIntrinsics() {
924 bool Updated = false;
925 bool HasErrors = false;
926
927 for (Function &F : make_early_inc_range(M.functions())) {
928 if (!F.isDeclaration())
929 continue;
930 Intrinsic::ID ID = F.getIntrinsicID();
931 switch (ID) {
932 // NOTE: Skip dx_resource_casthandle here. They are
933 // resolved after this loop in cleanupHandleCasts.
934 case Intrinsic::dx_resource_casthandle:
935 // NOTE: llvm.dbg.value is supported as is in DXIL.
936 case Intrinsic::dbg_value:
938 if (F.use_empty())
939 F.eraseFromParent();
940 continue;
941 default:
942 if (F.use_empty())
943 F.eraseFromParent();
944 else {
945 SmallString<128> Msg = formatv(
946 "Unsupported intrinsic {0} for DXIL lowering", F.getName());
947 M.getContext().emitError(Msg);
948 HasErrors |= true;
949 }
950 break;
951
952#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
953 case Intrin: \
954 HasErrors |= replaceFunctionWithOp( \
955 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
956 break;
957#include "DXILOperation.inc"
958 case Intrinsic::dx_resource_handlefrombinding:
959 HasErrors |= lowerHandleFromBinding(F);
960 break;
961 case Intrinsic::dx_resource_getpointer:
962 HasErrors |= lowerGetPointer(F);
963 break;
964 case Intrinsic::dx_resource_nonuniformindex:
965 assert(!CleanupNURI &&
966 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
967 CleanupNURI = &F;
968 break;
969 case Intrinsic::dx_resource_load_typedbuffer:
970 HasErrors |= lowerTypedBufferLoad(F, /*HasCheckBit=*/true);
971 break;
972 case Intrinsic::dx_resource_store_typedbuffer:
973 HasErrors |= lowerBufferStore(F, /*IsRaw=*/false);
974 break;
975 case Intrinsic::dx_resource_load_rawbuffer:
976 HasErrors |= lowerRawBufferLoad(F);
977 break;
978 case Intrinsic::dx_resource_store_rawbuffer:
979 HasErrors |= lowerBufferStore(F, /*IsRaw=*/true);
980 break;
981 case Intrinsic::dx_resource_load_cbufferrow_2:
982 case Intrinsic::dx_resource_load_cbufferrow_4:
983 case Intrinsic::dx_resource_load_cbufferrow_8:
984 HasErrors |= lowerCBufferLoad(F);
985 break;
986 case Intrinsic::dx_resource_updatecounter:
987 HasErrors |= lowerUpdateCounter(F);
988 break;
989 case Intrinsic::dx_resource_getdimensions_x:
990 HasErrors |= lowerGetDimensionsX(F);
991 break;
992 case Intrinsic::ctpop:
993 HasErrors |= lowerCtpopToCountBits(F);
994 break;
995 case Intrinsic::lifetime_start:
996 case Intrinsic::lifetime_end:
997 if (F.use_empty())
998 F.eraseFromParent();
999 else {
1000 if (MMDI.DXILVersion < VersionTuple(1, 6))
1001 HasErrors |= lowerLifetimeIntrinsic(F);
1002 else
1003 continue;
1004 }
1005 break;
1006 case Intrinsic::is_fpclass:
1007 HasErrors |= lowerIsFPClass(F);
1008 break;
1009 }
1010 Updated = true;
1011 }
1012 if (Updated && !HasErrors) {
1013 cleanupHandleCasts();
1014 cleanupNonUniformResourceIndexCalls();
1015 }
1016
1017 return Updated;
1018 }
1019};
1020} // namespace
1021
1023 DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
1024 DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
1025 const ModuleMetadataInfo MMDI = MAM.getResult<DXILMetadataAnalysis>(M);
1026
1027 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1028 if (!MadeChanges)
1029 return PreservedAnalyses::all();
1035 return PA;
1036}
1037
1038namespace {
1039class DXILOpLoweringLegacy : public ModulePass {
1040public:
1041 bool runOnModule(Module &M) override {
1042 DXILResourceMap &DRM =
1043 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1044 DXILResourceTypeMap &DRTM =
1045 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1046 const ModuleMetadataInfo MMDI =
1047 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1048
1049 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1050 }
1051 StringRef getPassName() const override { return "DXIL Op Lowering"; }
1052 DXILOpLoweringLegacy() : ModulePass(ID) {}
1053
1054 static char ID; // Pass identification.
1055 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
1056 AU.addRequired<DXILResourceTypeWrapperPass>();
1057 AU.addRequired<DXILResourceWrapperPass>();
1058 AU.addRequired<DXILMetadataAnalysisWrapperPass>();
1059 AU.addPreserved<DXILResourceWrapperPass>();
1060 AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
1061 AU.addPreserved<ShaderFlagsAnalysisWrapper>();
1062 AU.addPreserved<RootSignatureAnalysisWrapper>();
1063 }
1064};
1065char DXILOpLoweringLegacy::ID = 0;
1066} // end anonymous namespace
1067
1068INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",
1069 false, false)
1072INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,
1073 false)
1074
1076 return new DXILOpLoweringLegacy();
1077}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
DXIL Resource Implicit Binding
#define DEBUG_TYPE
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This defines the Use class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
ModuleAnalysisManager MAM
if(PassOpts->AAPipeline)
#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 defines the SmallVector class.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Value * getArgOperand(unsigned i) const
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Diagnostic information for unsupported feature in backend.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Definition Function.h:244
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2579
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
Definition IRBuilder.h:1833
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
Definition IRBuilder.h:547
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2567
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Definition IRBuilder.h:2103
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2626
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition IRBuilder.h:562
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Definition IRBuilder.h:1934
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition IRBuilder.h:1850
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition IRBuilder.h:1863
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1403
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:207
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Definition IRBuilder.h:552
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
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
iterator erase(const_iterator CI)
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
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isIntOrIntVectorTy() const
Return true if this is an integer type or a vector of integer types.
Definition Type.h:246
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:267
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:352
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * getOperand(unsigned i) const
Definition User.h:233
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
user_iterator user_begin()
Definition Value.h:402
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition Value.h:439
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
iterator_range< user_iterator > users()
Definition Value.h:426
bool use_empty() const
Definition Value.h:346
iterator_range< use_iterator > uses()
Definition Value.h:380
bool hasName() const
Definition Value.h:262
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
bool user_empty() const
Definition Value.h:389
TargetExtType * getHandleTy() const
LLVM_ABI std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const
const ResourceBinding & getBinding() const
dxil::ResourceClass getResourceClass() const
An efficient, type-erasing, non-owning reference to a callable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Undef
Value of the register doesn't matter.
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:296
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
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 unique(Range &&R, Predicate P)
Definition STLExtras.h:2124
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1634
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
ModulePass * createDXILOpLoweringLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
#define N