LLVM 22.0.0git
DXILResource.cpp
Go to the documentation of this file.
1//===- DXILResource.cpp - Representations of DXIL resources ---------------===//
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 "llvm/ADT/APInt.h"
11#include "llvm/ADT/STLExtras.h"
14#include "llvm/IR/Constants.h"
18#include "llvm/IR/Intrinsics.h"
19#include "llvm/IR/IntrinsicsDirectX.h"
20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
25#include <cstdint>
26#include <optional>
27
28#define DEBUG_TYPE "dxil-resource"
29
30using namespace llvm;
31using namespace dxil;
32
34 switch (RK) {
35 case ResourceKind::Texture1D:
36 return "Texture1D";
37 case ResourceKind::Texture2D:
38 return "Texture2D";
39 case ResourceKind::Texture2DMS:
40 return "Texture2DMS";
41 case ResourceKind::Texture3D:
42 return "Texture3D";
43 case ResourceKind::TextureCube:
44 return "TextureCube";
45 case ResourceKind::Texture1DArray:
46 return "Texture1DArray";
47 case ResourceKind::Texture2DArray:
48 return "Texture2DArray";
49 case ResourceKind::Texture2DMSArray:
50 return "Texture2DMSArray";
51 case ResourceKind::TextureCubeArray:
52 return "TextureCubeArray";
53 case ResourceKind::TypedBuffer:
54 return "Buffer";
55 case ResourceKind::RawBuffer:
56 return "RawBuffer";
57 case ResourceKind::StructuredBuffer:
58 return "StructuredBuffer";
59 case ResourceKind::CBuffer:
60 return "CBuffer";
61 case ResourceKind::Sampler:
62 return "Sampler";
63 case ResourceKind::TBuffer:
64 return "TBuffer";
65 case ResourceKind::RTAccelerationStructure:
66 return "RTAccelerationStructure";
67 case ResourceKind::FeedbackTexture2D:
68 return "FeedbackTexture2D";
69 case ResourceKind::FeedbackTexture2DArray:
70 return "FeedbackTexture2DArray";
71 case ResourceKind::NumEntries:
72 case ResourceKind::Invalid:
73 return "<invalid>";
74 }
75 llvm_unreachable("Unhandled ResourceKind");
76}
77
79 switch (ET) {
80 case ElementType::I1:
81 return "i1";
82 case ElementType::I16:
83 return "i16";
84 case ElementType::U16:
85 return "u16";
86 case ElementType::I32:
87 return "i32";
88 case ElementType::U32:
89 return "u32";
90 case ElementType::I64:
91 return "i64";
92 case ElementType::U64:
93 return "u64";
94 case ElementType::F16:
95 return "f16";
96 case ElementType::F32:
97 return "f32";
98 case ElementType::F64:
99 return "f64";
100 case ElementType::SNormF16:
101 return "snorm_f16";
102 case ElementType::UNormF16:
103 return "unorm_f16";
104 case ElementType::SNormF32:
105 return "snorm_f32";
106 case ElementType::UNormF32:
107 return "unorm_f32";
108 case ElementType::SNormF64:
109 return "snorm_f64";
110 case ElementType::UNormF64:
111 return "unorm_f64";
112 case ElementType::PackedS8x32:
113 return "p32i8";
114 case ElementType::PackedU8x32:
115 return "p32u8";
116 case ElementType::Invalid:
117 return "<invalid>";
118 }
119 llvm_unreachable("Unhandled ElementType");
120}
121
123 switch (ET) {
124 case ElementType::I1:
125 return "bool";
126 case ElementType::I16:
127 return "int16_t";
128 case ElementType::U16:
129 return "uint16_t";
130 case ElementType::I32:
131 return "int32_t";
132 case ElementType::U32:
133 return "uint32_t";
134 case ElementType::I64:
135 return "int64_t";
136 case ElementType::U64:
137 return "uint32_t";
138 case ElementType::F16:
139 case ElementType::SNormF16:
140 case ElementType::UNormF16:
141 return "half";
142 case ElementType::F32:
143 case ElementType::SNormF32:
144 case ElementType::UNormF32:
145 return "float";
146 case ElementType::F64:
147 case ElementType::SNormF64:
148 case ElementType::UNormF64:
149 return "double";
150 case ElementType::PackedS8x32:
151 return "int8_t4_packed";
152 case ElementType::PackedU8x32:
153 return "uint8_t4_packed";
154 case ElementType::Invalid:
155 return "<invalid>";
156 }
157 llvm_unreachable("Unhandled ElementType");
158}
159
161 switch (ST) {
162 case SamplerType::Default:
163 return "Default";
164 case SamplerType::Comparison:
165 return "Comparison";
166 case SamplerType::Mono:
167 return "Mono";
168 }
169 llvm_unreachable("Unhandled SamplerType");
170}
171
173 switch (SFT) {
174 case SamplerFeedbackType::MinMip:
175 return "MinMip";
176 case SamplerFeedbackType::MipRegionUsed:
177 return "MipRegionUsed";
178 }
179 llvm_unreachable("Unhandled SamplerFeedbackType");
180}
181
182static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) {
183 // TODO: Handle unorm, snorm, and packed.
184 Ty = Ty->getScalarType();
185
186 if (Ty->isIntegerTy()) {
187 switch (Ty->getIntegerBitWidth()) {
188 case 16:
189 return IsSigned ? ElementType::I16 : ElementType::U16;
190 case 32:
191 return IsSigned ? ElementType::I32 : ElementType::U32;
192 case 64:
193 return IsSigned ? ElementType::I64 : ElementType::U64;
194 case 1:
195 default:
196 return ElementType::Invalid;
197 }
198 } else if (Ty->isFloatTy()) {
199 return ElementType::F32;
200 } else if (Ty->isDoubleTy()) {
201 return ElementType::F64;
202 } else if (Ty->isHalfTy()) {
203 return ElementType::F16;
204 }
205
206 return ElementType::Invalid;
207}
208
210 const dxil::ResourceClass RC_,
211 const dxil::ResourceKind Kind_)
212 : HandleTy(HandleTy) {
213 // If we're provided a resource class and kind, trust them.
214 if (Kind_ != dxil::ResourceKind::Invalid) {
215 RC = RC_;
216 Kind = Kind_;
217 return;
218 }
219
220 if (auto *Ty = dyn_cast<RawBufferExtType>(HandleTy)) {
221 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
222 Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer
224 } else if (auto *Ty = dyn_cast<TypedBufferExtType>(HandleTy)) {
225 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
227 } else if (auto *Ty = dyn_cast<TextureExtType>(HandleTy)) {
228 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
229 Kind = Ty->getDimension();
230 } else if (auto *Ty = dyn_cast<MSTextureExtType>(HandleTy)) {
231 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
232 Kind = Ty->getDimension();
233 } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(HandleTy)) {
235 Kind = Ty->getDimension();
236 } else if (isa<CBufferExtType>(HandleTy)) {
239 } else if (isa<SamplerExtType>(HandleTy)) {
242 } else
243 llvm_unreachable("Unknown handle type");
244}
245
247 bool IsWriteable, bool IsROV,
248 Type *ContainedType = nullptr,
249 bool IsSigned = true) {
250 raw_svector_ostream DestStream(Dest);
251 if (IsWriteable)
252 DestStream << (IsROV ? "RasterizerOrdered" : "RW");
253 DestStream << Name;
254
255 if (!ContainedType)
256 return;
257
258 StringRef ElementName;
259 ElementType ET = toDXILElementType(ContainedType, IsSigned);
260 if (ET != ElementType::Invalid) {
261 ElementName = getElementTypeNameForTemplate(ET);
262 } else {
263 assert(isa<StructType>(ContainedType) &&
264 "invalid element type for raw buffer");
265 StructType *ST = cast<StructType>(ContainedType);
266 if (!ST->hasName())
267 return;
268 ElementName = ST->getStructName();
269 }
270
271 DestStream << "<" << ElementName;
272 if (const FixedVectorType *VTy = dyn_cast<FixedVectorType>(ContainedType))
273 DestStream << VTy->getNumElements();
274 DestStream << ">";
275}
276
279 if (Ty && Ty->getNumElements() == 1 && Ty->getElementType(0) == ElemType)
280 return Ty;
281 return StructType::create(ElemType, Name);
282}
283
285 SmallString<64> TypeName;
286
287 switch (Kind) {
295 auto *RTy = cast<TextureExtType>(HandleTy);
296 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
297 RTy->isROV(), RTy->getResourceType(), RTy->isSigned());
298 return getOrCreateElementStruct(RTy->getResourceType(), TypeName);
299 }
302 auto *RTy = cast<MSTextureExtType>(HandleTy);
303 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
304 /*IsROV=*/false, RTy->getResourceType(), RTy->isSigned());
305 return getOrCreateElementStruct(RTy->getResourceType(), TypeName);
306 }
308 auto *RTy = cast<TypedBufferExtType>(HandleTy);
309 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
310 RTy->isROV(), RTy->getResourceType(), RTy->isSigned());
311 return getOrCreateElementStruct(RTy->getResourceType(), TypeName);
312 }
314 auto *RTy = cast<RawBufferExtType>(HandleTy);
315 formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
316 RTy->isROV());
318 TypeName);
319 }
321 auto *RTy = cast<RawBufferExtType>(HandleTy);
322 Type *Ty = RTy->getResourceType();
323 formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
324 RTy->isROV(), RTy->getResourceType(), true);
325 return getOrCreateElementStruct(Ty, TypeName);
326 }
329 auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
330 TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
331 llvm::to_underlying(RTy->getFeedbackType()));
333 TypeName);
334 }
336 auto *RTy = cast<CBufferExtType>(HandleTy);
337 LayoutExtType *LayoutType = cast<LayoutExtType>(RTy->getResourceType());
338 StructType *Ty = cast<StructType>(LayoutType->getWrappedType());
340 if (!CBufferName.empty()) {
341 Name.append(".");
342 Name.append(CBufferName);
343 }
344 return StructType::create(Ty->elements(), Name);
345 }
347 auto *RTy = cast<SamplerExtType>(HandleTy);
348 TypeName = formatv("SamplerState<{0}>",
349 llvm::to_underlying(RTy->getSamplerType()));
351 TypeName);
352 }
355 llvm_unreachable("Unhandled resource kind");
358 llvm_unreachable("Invalid resource kind");
359 }
360 llvm_unreachable("Unhandled ResourceKind enum");
361}
362
363bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
364
366 return RC == ResourceClass::CBuffer;
367}
368
370 return RC == ResourceClass::Sampler;
371}
372
374 return Kind == ResourceKind::StructuredBuffer;
375}
376
378 switch (Kind) {
389 return true;
398 return false;
401 llvm_unreachable("Invalid resource kind");
402 }
403 llvm_unreachable("Unhandled ResourceKind enum");
404}
405
407 return Kind == ResourceKind::FeedbackTexture2D ||
409}
410
412 return Kind == ResourceKind::Texture2DMS ||
414}
415
416static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) {
417 switch (Kind) {
425 return cast<TextureExtType>(Ty)->isROV();
427 return cast<TypedBufferExtType>(Ty)->isROV();
430 return cast<RawBufferExtType>(Ty)->isROV();
435 return false;
442 llvm_unreachable("Resource cannot be ROV");
443 }
444 llvm_unreachable("Unhandled ResourceKind enum");
445}
446
448 assert(isUAV() && "Not a UAV");
449 return {isROV(Kind, HandleTy)};
450}
451
453 assert(isCBuffer() && "Not a CBuffer");
454
455 Type *ElTy = cast<CBufferExtType>(HandleTy)->getResourceType();
456
457 if (auto *LayoutTy = dyn_cast<LayoutExtType>(ElTy))
458 return LayoutTy->getSize();
459
460 // TODO: What should we do with unannotated arrays?
461 return DL.getTypeAllocSize(ElTy);
462}
463
465 assert(isSampler() && "Not a Sampler");
466 return cast<SamplerExtType>(HandleTy)->getSamplerType();
467}
468
471 assert(isStruct() && "Not a Struct");
472
473 Type *ElTy = cast<RawBufferExtType>(HandleTy)->getResourceType();
474
475 uint32_t Stride = DL.getTypeAllocSize(ElTy);
476 MaybeAlign Alignment;
477 if (auto *STy = dyn_cast<StructType>(ElTy))
478 Alignment = DL.getStructLayout(STy)->getAlignment();
479 uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0;
480 return {Stride, AlignLog2};
481}
482
483static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind,
484 TargetExtType *Ty) {
485 switch (Kind) {
493 auto *RTy = cast<TextureExtType>(Ty);
494 return {RTy->getResourceType(), RTy->isSigned()};
495 }
498 auto *RTy = cast<MSTextureExtType>(Ty);
499 return {RTy->getResourceType(), RTy->isSigned()};
500 }
502 auto *RTy = cast<TypedBufferExtType>(Ty);
503 return {RTy->getResourceType(), RTy->isSigned()};
504 }
515 llvm_unreachable("Resource is not typed");
516 }
517 llvm_unreachable("Unhandled ResourceKind enum");
518}
519
521 assert(isTyped() && "Not typed");
522
523 auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy);
524 dxil::ElementType ET = toDXILElementType(ElTy, IsSigned);
525 uint32_t Count = 1;
526 if (auto *VTy = dyn_cast<FixedVectorType>(ElTy))
527 Count = VTy->getNumElements();
528 return {ET, Count};
529}
530
532 assert(isFeedback() && "Not Feedback");
533 return cast<FeedbackTextureExtType>(HandleTy)->getFeedbackType();
534}
536 assert(isMultiSample() && "Not MultiSampled");
537 return cast<MSTextureExtType>(HandleTy)->getSampleCount();
538}
539
541 return HandleTy == RHS.HandleTy;
542}
543
545 // An empty datalayout is sufficient for sorting purposes.
546 DataLayout DummyDL;
547 if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind))
548 return true;
549 if (isCBuffer() && RHS.isCBuffer() &&
550 getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL))
551 return true;
552 if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType())
553 return true;
554 if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV())
555 return true;
556 if (isStruct() && RHS.isStruct() &&
557 getStruct(DummyDL) < RHS.getStruct(DummyDL))
558 return true;
559 if (isFeedback() && RHS.isFeedback() &&
560 getFeedbackType() < RHS.getFeedbackType())
561 return true;
562 if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped())
563 return true;
564 if (isMultiSample() && RHS.isMultiSample() &&
565 getMultiSampleCount() < RHS.getMultiSampleCount())
566 return true;
567 return false;
568}
569
571 OS << " Class: " << getResourceClassName(RC) << "\n"
572 << " Kind: " << getResourceKindName(Kind) << "\n";
573
574 if (isCBuffer()) {
575 OS << " CBuffer size: " << getCBufferSize(DL) << "\n";
576 } else if (isSampler()) {
577 OS << " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n";
578 } else {
579 if (isUAV()) {
580 UAVInfo UAVFlags = getUAV();
581 OS << " IsROV: " << UAVFlags.IsROV << "\n";
582 }
583 if (isMultiSample())
584 OS << " Sample Count: " << getMultiSampleCount() << "\n";
585
586 if (isStruct()) {
588 OS << " Buffer Stride: " << Struct.Stride << "\n";
589 OS << " Alignment: " << Struct.AlignLog2 << "\n";
590 } else if (isTyped()) {
591 TypedInfo Typed = getTyped();
592 OS << " Element Type: " << getElementTypeName(Typed.ElementTy) << "\n"
593 << " Element Count: " << Typed.ElementCount << "\n";
594 } else if (isFeedback())
595 OS << " Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType())
596 << "\n";
597 }
598}
599
601 assert(!Symbol && "Symbol has already been created");
602 Type *ResTy = Ty;
603 int64_t Size = Binding.Size;
604 if (Size != 1)
605 // unbounded arrays are represented as zero-sized arrays in LLVM IR
606 ResTy = ArrayType::get(Ty, Size == ~0u ? 0 : Size);
607 Symbol = new GlobalVariable(M, ResTy, /*isConstant=*/true,
609 /*Initializer=*/nullptr, Name);
610 return Symbol;
611}
612
614 dxil::ResourceTypeInfo &RTI) const {
615 LLVMContext &Ctx = M.getContext();
616 const DataLayout &DL = M.getDataLayout();
617
619
620 Type *I32Ty = Type::getInt32Ty(Ctx);
621 Type *I1Ty = Type::getInt1Ty(Ctx);
622 auto getIntMD = [&I32Ty](uint32_t V) {
624 Constant::getIntegerValue(I32Ty, APInt(32, V)));
625 };
626 auto getBoolMD = [&I1Ty](uint32_t V) {
628 Constant::getIntegerValue(I1Ty, APInt(1, V)));
629 };
630
631 MDVals.push_back(getIntMD(Binding.RecordID));
632 assert(Symbol && "Cannot yet create useful resource metadata without symbol");
633 MDVals.push_back(ValueAsMetadata::get(Symbol));
634 MDVals.push_back(MDString::get(Ctx, Name));
635 MDVals.push_back(getIntMD(Binding.Space));
636 MDVals.push_back(getIntMD(Binding.LowerBound));
637 MDVals.push_back(getIntMD(Binding.Size));
638
639 if (RTI.isCBuffer()) {
640 MDVals.push_back(getIntMD(RTI.getCBufferSize(DL)));
641 MDVals.push_back(nullptr);
642 } else if (RTI.isSampler()) {
643 MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getSamplerType())));
644 MDVals.push_back(nullptr);
645 } else {
646 MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind())));
647
648 if (RTI.isUAV()) {
649 ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV();
650 MDVals.push_back(getBoolMD(GloballyCoherent));
651 MDVals.push_back(getBoolMD(hasCounter()));
652 MDVals.push_back(getBoolMD(UAVFlags.IsROV));
653 } else {
654 // All SRVs include sample count in the metadata, but it's only meaningful
655 // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
656 // but this just isn't reflected in the metadata at all.
657 uint32_t SampleCount =
658 RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
659 MDVals.push_back(getIntMD(SampleCount));
660 }
661
662 // Further properties are attached to a metadata list of tag-value pairs.
664 if (RTI.isStruct()) {
665 Tags.push_back(
667 Tags.push_back(getIntMD(RTI.getStruct(DL).Stride));
668 } else if (RTI.isTyped()) {
670 Tags.push_back(getIntMD(llvm::to_underlying(RTI.getTyped().ElementTy)));
671 } else if (RTI.isFeedback()) {
672 Tags.push_back(
674 Tags.push_back(getIntMD(llvm::to_underlying(RTI.getFeedbackType())));
675 }
676 MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags));
677 }
678
679 return MDNode::get(Ctx, MDVals);
680}
681
682std::pair<uint32_t, uint32_t>
684 const DataLayout &DL = M.getDataLayout();
685
687 uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0;
688 bool IsUAV = RTI.isUAV();
690 IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{};
691 bool IsROV = IsUAV && UAVFlags.IsROV;
692 bool IsGloballyCoherent = IsUAV && GloballyCoherent;
693 uint8_t SamplerCmpOrHasCounter = 0;
694 if (IsUAV)
695 SamplerCmpOrHasCounter = hasCounter();
696 else if (RTI.isSampler())
697 SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison;
698
699 // TODO: Document this format. Currently the only reference is the
700 // implementation of dxc's DxilResourceProperties struct.
701 uint32_t Word0 = 0;
702 Word0 |= ResourceKind & 0xFF;
703 Word0 |= (AlignLog2 & 0xF) << 8;
704 Word0 |= (IsUAV & 1) << 12;
705 Word0 |= (IsROV & 1) << 13;
706 Word0 |= (IsGloballyCoherent & 1) << 14;
707 Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
708
709 uint32_t Word1 = 0;
710 if (RTI.isStruct())
711 Word1 = RTI.getStruct(DL).Stride;
712 else if (RTI.isCBuffer())
713 Word1 = RTI.getCBufferSize(DL);
714 else if (RTI.isFeedback())
716 else if (RTI.isTyped()) {
718 uint32_t CompType = llvm::to_underlying(Typed.ElementTy);
719 uint32_t CompCount = Typed.ElementCount;
720 uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
721
722 Word1 |= (CompType & 0xFF) << 0;
723 Word1 |= (CompCount & 0xFF) << 8;
724 Word1 |= (SampleCount & 0xFF) << 16;
725 }
726
727 return {Word0, Word1};
728}
729
731 const DataLayout &DL) const {
732 if (!Name.empty())
733 OS << " Name: " << Name << "\n";
734
735 if (Symbol) {
736 OS << " Symbol: ";
737 Symbol->printAsOperand(OS);
738 OS << "\n";
739 }
740
741 OS << " Binding:\n"
742 << " Record ID: " << Binding.RecordID << "\n"
743 << " Space: " << Binding.Space << "\n"
744 << " Lower Bound: " << Binding.LowerBound << "\n"
745 << " Size: " << Binding.Size << "\n";
746
747 OS << " Globally Coherent: " << GloballyCoherent << "\n";
748 OS << " Counter Direction: ";
749
750 switch (CounterDirection) {
752 OS << "Increment\n";
753 break;
755 OS << "Decrement\n";
756 break;
758 OS << "Unknown\n";
759 break;
761 OS << "Invalid\n";
762 break;
763 }
764
765 RTI.print(OS, DL);
766}
767
768//===----------------------------------------------------------------------===//
769
772 // Passes that introduce resource types must explicitly invalidate this pass.
773 auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
774 return !PAC.preservedWhenStateless();
775}
776
777//===----------------------------------------------------------------------===//
779 return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
780}
781
783 Value *Op = nullptr;
784 switch (CI->getCalledFunction()->getIntrinsicID()) {
785 default:
786 llvm_unreachable("unexpected handle creation intrinsic");
787 case Intrinsic::dx_resource_handlefrombinding:
788 case Intrinsic::dx_resource_handlefromimplicitbinding:
789 Op = CI->getArgOperand(4);
790 break;
791 }
792
793 auto *GV = dyn_cast<llvm::GlobalVariable>(Op);
794 if (!GV)
795 return "";
796
797 auto *CA = dyn_cast<ConstantDataArray>(GV->getInitializer());
798 assert(CA && CA->isString() && "expected constant string");
799 StringRef Name = CA->getAsString();
800 // strip trailing 0
801 if (Name.ends_with('\0'))
802 Name = Name.drop_back(1);
803 return Name;
804}
805
806void DXILResourceMap::populateResourceInfos(Module &M,
807 DXILResourceTypeMap &DRTM) {
809
810 for (Function &F : M.functions()) {
811 if (!F.isDeclaration())
812 continue;
813 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
814 Intrinsic::ID ID = F.getIntrinsicID();
815 switch (ID) {
816 default:
817 continue;
818 case Intrinsic::dx_resource_handlefrombinding: {
819 auto *HandleTy = cast<TargetExtType>(F.getReturnType());
820 ResourceTypeInfo &RTI = DRTM[HandleTy];
821
822 for (User *U : F.users())
823 if (CallInst *CI = dyn_cast<CallInst>(U)) {
824 LLVM_DEBUG(dbgs() << " Visiting: " << *U << "\n");
825 uint32_t Space =
826 cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
827 uint32_t LowerBound =
828 cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
829 uint32_t Size =
830 cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
832
833 ResourceInfo RI =
834 ResourceInfo{/*RecordID=*/0, Space, LowerBound,
835 Size, HandleTy, Name};
836
837 CIToInfos.emplace_back(CI, RI, RTI);
838 }
839
840 break;
841 }
842 }
843 }
844
845 llvm::stable_sort(CIToInfos, [](auto &LHS, auto &RHS) {
846 const auto &[LCI, LRI, LRTI] = LHS;
847 const auto &[RCI, RRI, RRTI] = RHS;
848 // Sort by resource class first for grouping purposes, and then by the
849 // binding and type so we can remove duplicates.
850 ResourceClass LRC = LRTI.getResourceClass();
851 ResourceClass RRC = RRTI.getResourceClass();
852
853 return std::tie(LRC, LRI, LRTI) < std::tie(RRC, RRI, RRTI);
854 });
855 for (auto [CI, RI, RTI] : CIToInfos) {
856 if (Infos.empty() || RI != Infos.back())
857 Infos.push_back(RI);
858 CallMap[CI] = Infos.size() - 1;
859 }
860
861 unsigned Size = Infos.size();
862 // In DXC, Record ID is unique per resource type. Match that.
863 FirstUAV = FirstCBuffer = FirstSampler = Size;
864 uint32_t NextID = 0;
865 for (unsigned I = 0, E = Size; I != E; ++I) {
866 ResourceInfo &RI = Infos[I];
867 ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
868 if (RTI.isUAV() && FirstUAV == Size) {
869 FirstUAV = I;
870 NextID = 0;
871 } else if (RTI.isCBuffer() && FirstCBuffer == Size) {
872 FirstCBuffer = I;
873 NextID = 0;
874 } else if (RTI.isSampler() && FirstSampler == Size) {
875 FirstSampler = I;
876 NextID = 0;
877 }
878
879 // We need to make sure the types of resource are ordered even if some are
880 // missing.
881 FirstCBuffer = std::min({FirstCBuffer, FirstSampler});
882 FirstUAV = std::min({FirstUAV, FirstCBuffer});
883
884 // Adjust the resource binding to use the next ID.
885 RI.setBindingID(NextID++);
886 }
887}
888
889void DXILResourceMap::populateCounterDirections(Module &M) {
890 for (Function &F : M.functions()) {
892 continue;
893
894 LLVM_DEBUG(dbgs() << "Update Counter Function: " << F.getName() << "\n");
895
896 for (const User *U : F.users()) {
897 const CallInst *CI = dyn_cast<CallInst>(U);
898 assert(CI && "Users of dx_resource_updateCounter must be call instrs");
899
900 // Determine if the use is an increment or decrement
901 Value *CountArg = CI->getArgOperand(1);
902 ConstantInt *CountValue = cast<ConstantInt>(CountArg);
903 int64_t CountLiteral = CountValue->getSExtValue();
904
905 // 0 is an unknown direction and shouldn't result in an insert
906 if (CountLiteral == 0)
907 continue;
908
910 if (CountLiteral > 0)
912
913 // Collect all potential creation points for the handle arg
914 Value *HandleArg = CI->getArgOperand(0);
915 SmallVector<ResourceInfo *> RBInfos = findByUse(HandleArg);
916 for (ResourceInfo *RBInfo : RBInfos) {
917 if (RBInfo->CounterDirection == ResourceCounterDirection::Unknown)
918 RBInfo->CounterDirection = Direction;
919 else if (RBInfo->CounterDirection != Direction) {
920 RBInfo->CounterDirection = ResourceCounterDirection::Invalid;
921 HasInvalidDirection = true;
922 }
923 }
924 }
925 }
926}
927
928void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
929 populateResourceInfos(M, DRTM);
930 populateCounterDirections(M);
931}
932
934 const DataLayout &DL) const {
935 for (unsigned I = 0, E = Infos.size(); I != E; ++I) {
936 OS << "Resource " << I << ":\n";
937 const dxil::ResourceInfo &RI = Infos[I];
938 RI.print(OS, DRTM[RI.getHandleTy()], DL);
939 OS << "\n";
940 }
941
942 for (const auto &[CI, Index] : CallMap) {
943 OS << "Call bound to " << Index << ":";
944 CI->print(OS);
945 OS << "\n";
946 }
947}
948
949SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) {
950 if (const PHINode *Phi = dyn_cast<PHINode>(Key)) {
952 for (const Value *V : Phi->operands()) {
953 Children.append(findByUse(V));
954 }
955 return Children;
956 }
957
958 const CallInst *CI = dyn_cast<CallInst>(Key);
959 if (!CI)
960 return {};
961
962 switch (CI->getIntrinsicID()) {
963 // Found the create, return the binding
964 case Intrinsic::dx_resource_handlefrombinding: {
965 auto Pos = CallMap.find(CI);
966 assert(Pos != CallMap.end() && "HandleFromBinding must be in resource map");
967 return {&Infos[Pos->second]};
968 }
969 default:
970 break;
971 }
972
973 // Check if any of the parameters are the resource we are following. If so
974 // keep searching. If none of them are return an empty list
975 const Type *UseType = CI->getType();
977 for (const Value *V : CI->args()) {
978 if (V->getType() != UseType)
979 continue;
980
981 Children.append(findByUse(V));
982 }
983
984 return Children;
985}
986
987//===----------------------------------------------------------------------===//
988
989void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
991
992 // collect all of the llvm.dx.resource.handlefrombinding calls;
993 // make a note if there is llvm.dx.resource.handlefromimplicitbinding
994 for (Function &F : M.functions()) {
995 if (!F.isDeclaration())
996 continue;
997
998 switch (F.getIntrinsicID()) {
999 default:
1000 continue;
1001 case Intrinsic::dx_resource_handlefrombinding: {
1002 auto *HandleTy = cast<TargetExtType>(F.getReturnType());
1003 ResourceTypeInfo &RTI = DRTM[HandleTy];
1004
1005 for (User *U : F.users())
1006 if (CallInst *CI = dyn_cast<CallInst>(U)) {
1007 uint32_t Space =
1008 cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
1009 uint32_t LowerBound =
1010 cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
1011 int32_t Size =
1012 cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
1013 Value *Name = CI->getArgOperand(4);
1014
1015 // negative size means unbounded resource array;
1016 // upper bound register overflow should be detected in Sema
1017 assert((Size < 0 || (unsigned)LowerBound + Size - 1 <= UINT32_MAX) &&
1018 "upper bound register overflow");
1019 uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1;
1020 Builder.trackBinding(RTI.getResourceClass(), Space, LowerBound,
1021 UpperBound, Name);
1022 }
1023 break;
1024 }
1025 case Intrinsic::dx_resource_handlefromimplicitbinding: {
1026 HasImplicitBinding = true;
1027 break;
1028 }
1029 }
1030 }
1031
1032 Bindings = Builder.calculateBindingInfo(
1033 [this](auto, auto) { this->HasOverlappingBinding = true; });
1034}
1035
1036//===----------------------------------------------------------------------===//
1037
1038AnalysisKey DXILResourceTypeAnalysis::Key;
1039AnalysisKey DXILResourceAnalysis::Key;
1040AnalysisKey DXILResourceBindingAnalysis::Key;
1041
1046 Data.populate(M, DRTM);
1047 return Data;
1048}
1049
1054 Data.populate(M, DRTM);
1055 return Data;
1056}
1057
1062
1063 DRM.print(OS, DRTM, M.getDataLayout());
1064 return PreservedAnalyses::all();
1065}
1066
1067void DXILResourceTypeWrapperPass::anchor() {}
1068
1070 : ImmutablePass(ID) {}
1071
1072INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type",
1073 "DXIL Resource Type Analysis", false, true)
1075
1077 return new DXILResourceTypeWrapperPass();
1078}
1079
1081
1083
1086 AU.setPreservesAll();
1087}
1088
1090 Map.reset(new DXILResourceMap());
1091
1092 DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1093 Map->populate(M, *DRTM);
1094
1095 return false;
1096}
1097
1099
1101 if (!Map) {
1102 OS << "No resource map has been built!\n";
1103 return;
1104 }
1105 Map->print(OS, *DRTM, M->getDataLayout());
1106}
1107
1108#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1110void DXILResourceWrapperPass::dump() const { print(dbgs(), nullptr); }
1111#endif
1112
1114 "DXIL Resources Analysis", false, true)
1116
1118 return new DXILResourceWrapperPass();
1119}
1120
1122 : ModulePass(ID) {}
1123
1125
1128 AU.setPreservesAll();
1129}
1130
1132 BindingInfo.reset(new DXILResourceBindingInfo());
1133
1134 DXILResourceTypeMap &DRTM =
1135 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1136 BindingInfo->populate(M, DRTM);
1137
1138 return false;
1139}
1140
1142
1143INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding",
1144 "DXIL Resource Binding Analysis", false, true)
1146
1148 return new DXILResourceWrapperPass();
1149}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:638
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned)
static bool isUpdateCounterIntrinsic(Function &F)
static StructType * getOrCreateElementStruct(Type *ElemType, StringRef Name)
static void formatTypeName(SmallString< 64 > &Dest, StringRef Name, bool IsWriteable, bool IsROV, Type *ContainedType=nullptr, bool IsSigned=true)
static StringRef getElementTypeName(ElementType ET)
static std::pair< Type *, bool > getTypedElementType(dxil::ResourceKind Kind, TargetExtType *Ty)
static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty)
static StringRef getResourceKindName(ResourceKind RK)
static StringRef getSamplerTypeName(SamplerType ST)
static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT)
static StringRef getElementTypeNameForTemplate(ElementType ET)
std::string Name
uint64_t Size
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
This file contains the declarations for metadata subclasses.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:56
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file defines the SmallString class.
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition: Debug.h:119
@ Struct
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition: APInt.h:78
API to communicate dependencies between analyses during invalidation.
Definition: PassManager.h:294
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
AnalysisUsage & addRequiredTransitive()
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1348
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1292
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
Definition: InstrTypes.h:1283
This class represents a function call, abstracting a target machine's calling convention.
static ConstantAsMetadata * get(Constant *C)
Definition: Metadata.h:535
This is the shared class of boolean and integer constants.
Definition: Constants.h:87
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
Definition: Constants.h:169
static LLVM_ABI Constant * getIntegerValue(Type *Ty, const APInt &V)
Return the value for an integer or pointer constant, or a vector thereof, with the given scalar value...
Definition: Constants.cpp:403
This class represents an Operation in the Expression.
LLVM_ABI DXILResourceMap run(Module &M, ModuleAnalysisManager &AM)
Gather resource info for the module M.
LLVM_ABI DXILResourceBindingInfo run(Module &M, ModuleAnalysisManager &AM)
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
void releaseMemory() override
releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...
LLVM_ABI void print(raw_ostream &OS, DXILResourceTypeMap &DRTM, const DataLayout &DL) const
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_ABI bool invalidate(Module &M, const PreservedAnalyses &PA, ModuleAnalysisManager::Invalidator &Inv)
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
void releaseMemory() override
releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...
void print(raw_ostream &OS, const Module *M) const override
print - Print out the internal state of the pass.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
Class to represent fixed width SIMD vectors.
Definition: DerivedTypes.h:592
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
@ ExternalLinkage
Externally visible function.
Definition: GlobalValue.h:53
ImmutablePass class - This class is used to provide information that does not need to be run.
Definition: Pass.h:285
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1565
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition: Metadata.cpp:607
Tuple of metadata.
Definition: Metadata.h:1493
Align getAlignment() const
Return alignment of the basic block.
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
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
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
Definition: Analysis.h:275
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
bool empty() const
Definition: SmallVector.h:82
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:938
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:151
Class to represent struct types.
Definition: DerivedTypes.h:218
ArrayRef< Type * > elements() const
Definition: DerivedTypes.h:360
static LLVM_ABI StructType * getTypeByName(LLVMContext &C, StringRef Name)
Return the type with the specified name, or null if there is none by that name.
Definition: Type.cpp:739
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition: Type.cpp:620
unsigned getNumElements() const
Random access to the elements.
Definition: DerivedTypes.h:368
Type * getElementType(unsigned N) const
Definition: DerivedTypes.h:369
Class to represent target extensions types, which are generally unintrospectable from target-independ...
Definition: DerivedTypes.h:781
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition: Type.h:153
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition: Type.h:142
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition: Type.h:128
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:156
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:240
LLVM_ABI unsigned getIntegerBitWidth() const
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition: Type.h:352
static LLVM_ABI ValueAsMetadata * get(Value *V)
Definition: Metadata.cpp:502
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 print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
Definition: AsmWriter.cpp:5222
LLVM_ABI void printAsOperand(raw_ostream &O, bool PrintType=true, const Module *M=nullptr) const
Print the name of this Value out to the specified raw_ostream.
Definition: AsmWriter.cpp:5305
The dx.Layout target extension type.
Definition: DXILResource.h:228
Type * getWrappedType() const
Definition: DXILResource.h:234
TargetExtType * getHandleTy() const
Definition: DXILResource.h:394
LLVM_ABI std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const
LLVM_ABI void print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI, const DataLayout &DL) const
void setBindingID(unsigned ID)
Definition: DXILResource.h:387
LLVM_ABI GlobalVariable * createSymbol(Module &M, StructType *Ty)
LLVM_ABI MDTuple * getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const
ResourceCounterDirection CounterDirection
Definition: DXILResource.h:379
dxil::ResourceClass getResourceClass() const
Definition: DXILResource.h:324
LLVM_ABI uint32_t getMultiSampleCount() const
LLVM_ABI uint32_t getCBufferSize(const DataLayout &DL) const
LLVM_ABI bool operator<(const ResourceTypeInfo &RHS) const
LLVM_ABI bool isUAV() const
LLVM_ABI bool isMultiSample() const
LLVM_ABI bool isSampler() const
LLVM_ABI bool isTyped() const
LLVM_ABI dxil::SamplerType getSamplerType() const
LLVM_ABI ResourceTypeInfo(TargetExtType *HandleTy, const dxil::ResourceClass RC, const dxil::ResourceKind Kind)
LLVM_ABI bool isCBuffer() const
LLVM_ABI TypedInfo getTyped() const
LLVM_ABI StructType * createElementStruct(StringRef CBufferName="")
LLVM_ABI bool isFeedback() const
LLVM_ABI UAVInfo getUAV() const
LLVM_ABI StructInfo getStruct(const DataLayout &DL) const
LLVM_ABI bool isStruct() const
LLVM_ABI dxil::SamplerFeedbackType getFeedbackType() const
LLVM_ABI bool operator==(const ResourceTypeInfo &RHS) const
dxil::ResourceKind getResourceKind() const
Definition: DXILResource.h:325
LLVM_ABI void print(raw_ostream &OS, const DataLayout &DL) const
Builder class for creating a /c BindingInfo.
Definition: HLSLBinding.h:151
void trackBinding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound, uint32_t UpperBound, const void *Cookie)
Definition: HLSLBinding.h:156
LLVM_ABI BindingInfo calculateBindingInfo(llvm::function_ref< void(const BindingInfoBuilder &Builder, const Binding &Overlapping)> ReportOverlap)
Calculate the binding info - ReportOverlap will be called once for each overlapping binding.
Definition: HLSLBinding.cpp:69
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:692
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI StringRef getResourceClassName(ResourceClass RC)
Definition: DXILABI.cpp:21
ResourceKind
The kind of resource for an SRV or UAV resource.
Definition: DXILABI.h:35
ResourceClass
Definition: DXILABI.h:26
ResourceCounterDirection
Definition: DXILResource.h:336
SamplerFeedbackType
Definition: DXILABI.h:95
ElementType
The element type of an SRV or UAV resource.
Definition: DXILABI.h:59
LLVM_ABI StringRef getResourceNameFromBindingCall(CallInst *CI)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
LLVM_ABI ModulePass * createDXILResourceBindingWrapperPassPass()
void stable_sort(R &&Range)
Definition: STLExtras.h:2077
LLVM_ABI ModulePass * createDXILResourceTypeWrapperPassPass()
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition: Alignment.h:208
LLVM_ABI ModulePass * createDXILResourceWrapperPassPass()
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: Analysis.h:29
Direction
An enum for the direction of the loop.
Definition: LoopInfo.h:217
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition: Alignment.h:117