LLVM: lib/Analysis/DXILResource.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

17#include "llvm/IR/IntrinsicsDirectX.h"

22

23#define DEBUG_TYPE "dxil-resource"

24

25using namespace llvm;

26using namespace dxil;

27

29 switch (RC) {

30 case ResourceClass::SRV:

31 return "SRV";

32 case ResourceClass::UAV:

33 return "UAV";

34 case ResourceClass::CBuffer:

35 return "CBuffer";

36 case ResourceClass::Sampler:

37 return "Sampler";

38 }

40}

41

43 switch (RK) {

44 case ResourceKind::Texture1D:

45 return "Texture1D";

46 case ResourceKind::Texture2D:

47 return "Texture2D";

48 case ResourceKind::Texture2DMS:

49 return "Texture2DMS";

50 case ResourceKind::Texture3D:

51 return "Texture3D";

52 case ResourceKind::TextureCube:

53 return "TextureCube";

54 case ResourceKind::Texture1DArray:

55 return "Texture1DArray";

56 case ResourceKind::Texture2DArray:

57 return "Texture2DArray";

58 case ResourceKind::Texture2DMSArray:

59 return "Texture2DMSArray";

60 case ResourceKind::TextureCubeArray:

61 return "TextureCubeArray";

62 case ResourceKind::TypedBuffer:

63 return "TypedBuffer";

64 case ResourceKind::RawBuffer:

65 return "RawBuffer";

66 case ResourceKind::StructuredBuffer:

67 return "StructuredBuffer";

68 case ResourceKind::CBuffer:

69 return "CBuffer";

70 case ResourceKind::Sampler:

71 return "Sampler";

72 case ResourceKind::TBuffer:

73 return "TBuffer";

74 case ResourceKind::RTAccelerationStructure:

75 return "RTAccelerationStructure";

76 case ResourceKind::FeedbackTexture2D:

77 return "FeedbackTexture2D";

78 case ResourceKind::FeedbackTexture2DArray:

79 return "FeedbackTexture2DArray";

80 case ResourceKind::NumEntries:

81 case ResourceKind::Invalid:

82 return "";

83 }

85}

86

88 switch (ET) {

89 case ElementType::I1:

90 return "i1";

91 case ElementType::I16:

92 return "i16";

93 case ElementType::U16:

94 return "u16";

95 case ElementType::I32:

96 return "i32";

97 case ElementType::U32:

98 return "u32";

99 case ElementType::I64:

100 return "i64";

101 case ElementType::U64:

102 return "u64";

103 case ElementType::F16:

104 return "f16";

105 case ElementType::F32:

106 return "f32";

107 case ElementType::F64:

108 return "f64";

109 case ElementType::SNormF16:

110 return "snorm_f16";

111 case ElementType::UNormF16:

112 return "unorm_f16";

113 case ElementType::SNormF32:

114 return "snorm_f32";

115 case ElementType::UNormF32:

116 return "unorm_f32";

117 case ElementType::SNormF64:

118 return "snorm_f64";

119 case ElementType::UNormF64:

120 return "unorm_f64";

121 case ElementType::PackedS8x32:

122 return "p32i8";

123 case ElementType::PackedU8x32:

124 return "p32u8";

125 case ElementType::Invalid:

126 return "";

127 }

129}

130

132 switch (ST) {

133 case SamplerType::Default:

134 return "Default";

135 case SamplerType::Comparison:

136 return "Comparison";

137 case SamplerType::Mono:

138 return "Mono";

139 }

141}

142

144 switch (SFT) {

145 case SamplerFeedbackType::MinMip:

146 return "MinMip";

147 case SamplerFeedbackType::MipRegionUsed:

148 return "MipRegionUsed";

149 }

151}

152

154

156

159 case 16:

160 return IsSigned ? ElementType::I16 : ElementType::U16;

161 case 32:

162 return IsSigned ? ElementType::I32 : ElementType::U32;

163 case 64:

164 return IsSigned ? ElementType::I64 : ElementType::U64;

165 case 1:

166 default:

167 return ElementType::Invalid;

168 }

170 return ElementType::F32;

172 return ElementType::F64;

174 return ElementType::F16;

175 }

176

177 return ElementType::Invalid;

178}

179

183 bool GloballyCoherent, bool HasCounter)

184 : HandleTy(HandleTy), GloballyCoherent(GloballyCoherent),

185 HasCounter(HasCounter) {

186

188 RC = RC_;

189 Kind = Kind_;

190 return;

191 }

192

193 if (auto *Ty = dyn_cast(HandleTy)) {

197 } else if (auto *Ty = dyn_cast(HandleTy)) {

200 } else if (auto *Ty = dyn_cast(HandleTy)) {

202 Kind = Ty->getDimension();

203 } else if (auto *Ty = dyn_cast(HandleTy)) {

205 Kind = Ty->getDimension();

206 } else if (auto *Ty = dyn_cast(HandleTy)) {

208 Kind = Ty->getDimension();

209 } else if (isa(HandleTy)) {

212 } else if (isa(HandleTy)) {

215 } else

217}

218

220 bool isWriteable, bool isROV) {

221 Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";

222 Dest += Name;

223}

224

227

228 switch (Kind) {

236 auto *RTy = cast(HandleTy);

238 RTy->isROV());

240 }

243 auto *RTy = cast(HandleTy);

245 false);

247 }

249 auto *RTy = cast(HandleTy);

251 RTy->isROV());

253 }

255 auto *RTy = cast(HandleTy);

256 formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),

257 RTy->isROV());

259 TypeName);

260 }

262 auto *RTy = cast(HandleTy);

263 formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),

264 RTy->isROV());

266 }

269 auto *RTy = cast(HandleTy);

273 TypeName);

274 }

278 auto *RTy = cast(HandleTy);

279 TypeName = formatv("SamplerState<{0}>",

282 TypeName);

283 }

290 }

292}

293

295

298}

299

302}

303

306}

307

309 switch (Kind) {

320 return true;

329 return false;

333 }

335}

336

340}

341

345}

346

348 switch (Kind) {

356 return cast(Ty)->isROV();

358 return cast(Ty)->isROV();

361 return cast(Ty)->isROV();

366 return false;

374 }

376}

377

380 return {GloballyCoherent, HasCounter, isROV(Kind, HandleTy)};

381}

382

385 return cast(HandleTy)->getCBufferSize();

386}

387

390 return cast(HandleTy)->getSamplerType();

391}

392

396

397 Type *ElTy = cast(HandleTy)->getResourceType();

398

399 uint32_t Stride = DL.getTypeAllocSize(ElTy);

401 if (auto *STy = dyn_cast(ElTy))

403 uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0;

404 return {Stride, AlignLog2};

405}

406

409 switch (Kind) {

417 auto *RTy = cast(Ty);

418 return {RTy->getResourceType(), RTy->isSigned()};

419 }

422 auto *RTy = cast(Ty);

423 return {RTy->getResourceType(), RTy->isSigned()};

424 }

426 auto *RTy = cast(Ty);

427 return {RTy->getResourceType(), RTy->isSigned()};

428 }

440 }

442}

443

446

450 if (auto *VTy = dyn_cast(ElTy))

451 Count = VTy->getNumElements();

452 return {ET, Count};

453}

454

457 return cast(HandleTy)->getFeedbackType();

458}

461 return cast(HandleTy)->getSampleCount();

462}

463

465 return std::tie(HandleTy, GloballyCoherent, HasCounter) ==

466 std::tie(RHS.HandleTy, RHS.GloballyCoherent, RHS.HasCounter);

467}

468

470

472 if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind))

473 return true;

476 return true;

478 return true;

480 return true;

483 return true;

486 return true;

488 return true;

491 return true;

492 return false;

493}

494

498

503 } else {

507 << " HasCounter: " << UAVFlags.HasCounter << "\n"

508 << " IsROV: " << UAVFlags.IsROV << "\n";

509 }

512

515 OS << " Buffer Stride: " << Struct.Stride << "\n";

516 OS << " Alignment: " << Struct.AlignLog2 << "\n";

520 << " Element Count: " << Typed.ElementCount << "\n";

523 << "\n";

524 }

525}

526

529 assert(!Symbol && "Symbol has already been created");

530 Symbol = new GlobalVariable(M, Ty, true,

532 nullptr, Name);

533 return Symbol;

534}

535

540

542

545 auto getIntMD = [&I32Ty](uint32_t V) {

548 };

549 auto getBoolMD = [&I1Ty](uint32_t V) {

552 };

553

555 assert(Symbol && "Cannot yet create useful resource metadata without symbol");

561

568 } else {

570

571 if (RTI.isUAV()) {

576 } else {

577

578

579

582 MDVals.push_back(getIntMD(SampleCount));

583 }

584

585

591 } else if (RTI.isTyped()) {

598 }

600 }

601

603}

604

605std::pair<uint32_t, uint32_t>

609

612 bool IsUAV = RTI.isUAV();

615 bool IsROV = IsUAV && UAVFlags.IsROV;

616 bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent;

617 uint8_t SamplerCmpOrHasCounter = 0;

618 if (IsUAV)

619 SamplerCmpOrHasCounter = UAVFlags.HasCounter;

622

623

624

627 Word0 |= (AlignLog2 & 0xF) << 8;

628 Word0 |= (IsUAV & 1) << 12;

629 Word0 |= (IsROV & 1) << 13;

630 Word0 |= (IsGloballyCoherent & 1) << 14;

631 Word0 |= (SamplerCmpOrHasCounter & 1) << 15;

632

640 else if (RTI.isTyped()) {

645

646 Word1 |= (CompType & 0xFF) << 0;

647 Word1 |= (CompCount & 0xFF) << 8;

648 Word1 |= (SampleCount & 0xFF) << 16;

649 }

650

651 return {Word0, Word1};

652}

653

656 if (Symbol) {

657 OS << " Symbol: ";

659 OS << "\n";

660 }

661

662 OS << " Binding:\n"

663 << " Record ID: " << Binding.RecordID << "\n"

664 << " Space: " << Binding.Space << "\n"

665 << " Lower Bound: " << Binding.LowerBound << "\n"

666 << " Size: " << Binding.Size << "\n";

667

669}

670

671

672

675

677 return !PAC.preservedWhenStateless();

678}

679

680

681

684 CIToInfos;

685

686 for (Function &F : M.functions()) {

687 if (F.isDeclaration())

688 continue;

689 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");

691 switch (ID) {

692 default:

693 continue;

694 case Intrinsic::dx_resource_handlefrombinding: {

695 auto *HandleTy = cast(F.getReturnType());

697

698 for (User *U : F.users())

699 if (CallInst *CI = dyn_cast(U)) {

702 cast(CI->getArgOperand(0))->getZExtValue();

704 cast(CI->getArgOperand(1))->getZExtValue();

706 cast(CI->getArgOperand(2))->getZExtValue();

708 0, Space, LowerBound, Size, HandleTy};

709

711 }

712

713 break;

714 }

715 }

716 }

717

719 const auto &[LCI, LRBI, LRTI] = LHS;

720 const auto &[RCI, RRBI, RRTI] = RHS;

721

722

725

726 return std::tie(LRC, LRBI, LRTI) < std::tie(RRC, RRBI, RRTI);

727 });

728 for (auto [CI, RBI, RTI] : CIToInfos) {

729 if (Infos.empty() || RBI != Infos.back())

730 Infos.push_back(RBI);

731 CallMap[CI] = Infos.size() - 1;

732 }

733

734 unsigned Size = Infos.size();

735

736 FirstUAV = FirstCBuffer = FirstSampler = Size;

738 for (unsigned I = 0, E = Size; I != E; ++I) {

741 if (RTI.isUAV() && FirstUAV == Size) {

742 FirstUAV = I;

743 NextID = 0;

744 } else if (RTI.isCBuffer() && FirstCBuffer == Size) {

745 FirstCBuffer = I;

746 NextID = 0;

747 } else if (RTI.isSampler() && FirstSampler == Size) {

748 FirstSampler = I;

749 NextID = 0;

750 }

751

752

754 }

755}

756

759 for (unsigned I = 0, E = Infos.size(); I != E; ++I) {

760 OS << "Binding " << I << ":\n";

763 OS << "\n";

764 }

765

766 for (const auto &[CI, Index] : CallMap) {

767 OS << "Call bound to " << Index << ":";

768 CI->print(OS);

769 OS << "\n";

770 }

771}

772

773

774

775AnalysisKey DXILResourceTypeAnalysis::Key;

776AnalysisKey DXILResourceBindingAnalysis::Key;

777

782 Data.populate(M, DRTM);

784}

785

790

791 DBM.print(OS, DRTM, M.getDataLayout());

793}

794

795void DXILResourceTypeWrapperPass::anchor() {}

796

799}

800

802 "DXIL Resource Type Analysis", false, true)

804

807}

808

813}

814

816

820}

821

824

825 DRTM = &getAnalysis().getResourceTypeMap();

826 Map->populate(M, *DRTM);

827

828 return false;

829}

830

832

834 const Module *M) const {

835 if (!Map) {

836 OS << "No resource map has been built!\n";

837 return;

838 }

839 Map->print(OS, *DRTM, M->getDataLayout());

840}

841

842#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

845#endif

846

848 "DXIL Resource Binding Analysis", false, true)

850

853}

This file implements a class to represent arbitrary precision integral constant values and operations...

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned)

static StringRef getResourceClassName(ResourceClass RC)

static StringRef getElementTypeName(ElementType ET)

static void formatTypeName(SmallString< 64 > &Dest, StringRef Name, bool isWriteable, bool isROV)

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)

#define LLVM_DUMP_METHOD

Mark debug helper function definitions like dump() that should not be stripped from debug builds.

This file contains the declarations for the subclasses of Constant, which represent the different fla...

Module.h This file contains the declarations for the Module class.

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallString class.

Class for arbitrary precision integers.

API to communicate dependencies between analyses during invalidation.

A container for analyses that lazily runs them and caches their results.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

Represent the analysis usage information of a pass.

void setPreservesAll()

Set by analyses that do not transform their input at all.

AnalysisUsage & addRequiredTransitive()

This class represents a function call, abstracting a target machine's calling convention.

static 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...

void print(raw_ostream &OS, DXILResourceTypeMap &DRTM, const DataLayout &DL) const

DXILBindingMap run(Module &M, ModuleAnalysisManager &AM)

Gather resource info for the module M.

PreservedAnalyses 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...

~DXILResourceBindingWrapperPass() override

DXILResourceBindingWrapperPass()

void print(raw_ostream &OS, const Module *M) const override

print - Print out the internal state of the pass.

void releaseMemory() override

releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...

bool invalidate(Module &M, const PreservedAnalyses &PA, ModuleAnalysisManager::Invalidator &Inv)

DXILResourceTypeWrapperPass()

A parsed version of the target data layout string in and methods for querying it.

@ ExternalLinkage

Externally visible function.

ImmutablePass class - This class is used to provide information that does not need to be run.

This is an important class for using LLVM in a threaded context.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

static MDString * get(LLVMContext &Context, StringRef Str)

Align getAlignment() const

Return alignment of the basic block.

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

A Module instance is used to store all the information related to an LLVM module.

static PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

PreservedAnalysisChecker getChecker() const

Build a checker for this PreservedAnalyses and the specified analysis type.

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

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.

StringRef - Represent a constant reference to a string, i.e.

Class to represent struct types.

static StructType * create(LLVMContext &Context, StringRef Name)

This creates an identified struct.

Class to represent target extensions types, which are generally unintrospectable from target-independ...

The instances of the Type class are immutable: once they are created, they are never changed.

unsigned getIntegerBitWidth() const

static IntegerType * getInt1Ty(LLVMContext &C)

bool isFloatTy() const

Return true if this is 'float', a 32-bit IEEE fp type.

bool isHalfTy() const

Return true if this is 'half', a 16-bit IEEE fp type.

LLVMContext & getContext() const

Return the LLVMContext in which this type was uniqued.

bool isDoubleTy() const

Return true if this is 'double', a 64-bit IEEE fp type.

static IntegerType * getInt32Ty(LLVMContext &C)

bool isIntegerTy() const

True if this is an instance of IntegerType.

Type * getScalarType() const

If this is a vector type, return the element type, otherwise return 'this'.

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.

StringRef getName() const

Return a constant reference to the value's name.

void setBindingID(unsigned ID)

GlobalVariable * createSymbol(Module &M, StructType *Ty, StringRef Name="")

std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const

TargetExtType * getHandleTy() const

MDTuple * getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const

void print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI, const DataLayout &DL) const

uint32_t getMultiSampleCount() const

uint32_t getCBufferSize(const DataLayout &DL) const

bool operator<(const ResourceTypeInfo &RHS) const

bool isMultiSample() const

dxil::SamplerType getSamplerType() const

TypedInfo getTyped() const

StructType * createElementStruct()

StructInfo getStruct(const DataLayout &DL) const

ResourceTypeInfo(TargetExtType *HandleTy, const dxil::ResourceClass RC, const dxil::ResourceKind Kind, bool GloballyCoherent=false, bool HasCounter=false)

dxil::SamplerFeedbackType getFeedbackType() const

bool operator==(const ResourceTypeInfo &RHS) const

dxil::ResourceKind getResourceKind() const

void print(raw_ostream &OS, const DataLayout &DL) const

This class implements an extremely fast bulk output stream that can only output to a stream.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

@ RRC

Y = RRC X, rotate right via carry.

ResourceKind

The kind of resource for an SRV or UAV resource.

@ RTAccelerationStructure

ElementType

The element type of an SRV or UAV resource.

This is an optimization pass for GlobalISel generic memory operations.

void stable_sort(R &&Range)

void initializeDXILResourceTypeWrapperPassPass(PassRegistry &)

ModulePass * createDXILResourceTypeWrapperPassPass()

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

void initializeDXILResourceBindingWrapperPassPass(PassRegistry &)

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

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.

ModulePass * createDXILResourceBindingWrapperPassPass()

A special type used by analysis passes to provide an address that identifies that particular analysis...

This struct is a compact representation of a valid (power of two) or undefined (0) alignment.

dxil::ElementType ElementTy