1b365dbbdSJustin Bogner //===- DXILResource.cpp - Representations of DXIL resources ---------------===// 2b365dbbdSJustin Bogner // 3b365dbbdSJustin Bogner // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b365dbbdSJustin Bogner // See https://llvm.org/LICENSE.txt for license information. 5b365dbbdSJustin Bogner // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b365dbbdSJustin Bogner // 7b365dbbdSJustin Bogner //===----------------------------------------------------------------------===// 8b365dbbdSJustin Bogner 9b365dbbdSJustin Bogner #include "llvm/Analysis/DXILResource.h" 10b365dbbdSJustin Bogner #include "llvm/ADT/APInt.h" 11482237e8SJustin Bogner #include "llvm/ADT/SmallString.h" 1251ede55eSJustin Bogner #include "llvm/IR/Constants.h" 13b365dbbdSJustin Bogner #include "llvm/IR/DerivedTypes.h" 1451ede55eSJustin Bogner #include "llvm/IR/DiagnosticInfo.h" 15372ddcd1SJustin Bogner #include "llvm/IR/Instructions.h" 1651ede55eSJustin Bogner #include "llvm/IR/Intrinsics.h" 1751ede55eSJustin Bogner #include "llvm/IR/IntrinsicsDirectX.h" 1882c21f08SJustin Bogner #include "llvm/IR/Metadata.h" 1951ede55eSJustin Bogner #include "llvm/IR/Module.h" 20372ddcd1SJustin Bogner #include "llvm/InitializePasses.h" 21482237e8SJustin Bogner #include "llvm/Support/FormatVariadic.h" 22372ddcd1SJustin Bogner 23372ddcd1SJustin Bogner #define DEBUG_TYPE "dxil-resource" 24b365dbbdSJustin Bogner 25b365dbbdSJustin Bogner using namespace llvm; 26b365dbbdSJustin Bogner using namespace dxil; 27b365dbbdSJustin Bogner 2851ede55eSJustin Bogner static StringRef getResourceClassName(ResourceClass RC) { 2951ede55eSJustin Bogner switch (RC) { 3051ede55eSJustin Bogner case ResourceClass::SRV: 3151ede55eSJustin Bogner return "SRV"; 3251ede55eSJustin Bogner case ResourceClass::UAV: 3351ede55eSJustin Bogner return "UAV"; 3451ede55eSJustin Bogner case ResourceClass::CBuffer: 3551ede55eSJustin Bogner return "CBuffer"; 3651ede55eSJustin Bogner case ResourceClass::Sampler: 3751ede55eSJustin Bogner return "Sampler"; 3851ede55eSJustin Bogner } 3951ede55eSJustin Bogner llvm_unreachable("Unhandled ResourceClass"); 4051ede55eSJustin Bogner } 4151ede55eSJustin Bogner 4251ede55eSJustin Bogner static StringRef getResourceKindName(ResourceKind RK) { 4351ede55eSJustin Bogner switch (RK) { 4451ede55eSJustin Bogner case ResourceKind::Texture1D: 4551ede55eSJustin Bogner return "Texture1D"; 4651ede55eSJustin Bogner case ResourceKind::Texture2D: 4751ede55eSJustin Bogner return "Texture2D"; 4851ede55eSJustin Bogner case ResourceKind::Texture2DMS: 4951ede55eSJustin Bogner return "Texture2DMS"; 5051ede55eSJustin Bogner case ResourceKind::Texture3D: 5151ede55eSJustin Bogner return "Texture3D"; 5251ede55eSJustin Bogner case ResourceKind::TextureCube: 5351ede55eSJustin Bogner return "TextureCube"; 5451ede55eSJustin Bogner case ResourceKind::Texture1DArray: 5551ede55eSJustin Bogner return "Texture1DArray"; 5651ede55eSJustin Bogner case ResourceKind::Texture2DArray: 5751ede55eSJustin Bogner return "Texture2DArray"; 5851ede55eSJustin Bogner case ResourceKind::Texture2DMSArray: 5951ede55eSJustin Bogner return "Texture2DMSArray"; 6051ede55eSJustin Bogner case ResourceKind::TextureCubeArray: 6151ede55eSJustin Bogner return "TextureCubeArray"; 6251ede55eSJustin Bogner case ResourceKind::TypedBuffer: 6351ede55eSJustin Bogner return "TypedBuffer"; 6451ede55eSJustin Bogner case ResourceKind::RawBuffer: 6551ede55eSJustin Bogner return "RawBuffer"; 6651ede55eSJustin Bogner case ResourceKind::StructuredBuffer: 6751ede55eSJustin Bogner return "StructuredBuffer"; 6851ede55eSJustin Bogner case ResourceKind::CBuffer: 6951ede55eSJustin Bogner return "CBuffer"; 7051ede55eSJustin Bogner case ResourceKind::Sampler: 7151ede55eSJustin Bogner return "Sampler"; 7251ede55eSJustin Bogner case ResourceKind::TBuffer: 7351ede55eSJustin Bogner return "TBuffer"; 7451ede55eSJustin Bogner case ResourceKind::RTAccelerationStructure: 7551ede55eSJustin Bogner return "RTAccelerationStructure"; 7651ede55eSJustin Bogner case ResourceKind::FeedbackTexture2D: 7751ede55eSJustin Bogner return "FeedbackTexture2D"; 7851ede55eSJustin Bogner case ResourceKind::FeedbackTexture2DArray: 7951ede55eSJustin Bogner return "FeedbackTexture2DArray"; 8051ede55eSJustin Bogner case ResourceKind::NumEntries: 8151ede55eSJustin Bogner case ResourceKind::Invalid: 8251ede55eSJustin Bogner return "<invalid>"; 8351ede55eSJustin Bogner } 8451ede55eSJustin Bogner llvm_unreachable("Unhandled ResourceKind"); 8551ede55eSJustin Bogner } 8651ede55eSJustin Bogner 8751ede55eSJustin Bogner static StringRef getElementTypeName(ElementType ET) { 8851ede55eSJustin Bogner switch (ET) { 8951ede55eSJustin Bogner case ElementType::I1: 9051ede55eSJustin Bogner return "i1"; 9151ede55eSJustin Bogner case ElementType::I16: 9251ede55eSJustin Bogner return "i16"; 9351ede55eSJustin Bogner case ElementType::U16: 9451ede55eSJustin Bogner return "u16"; 9551ede55eSJustin Bogner case ElementType::I32: 9651ede55eSJustin Bogner return "i32"; 9751ede55eSJustin Bogner case ElementType::U32: 9851ede55eSJustin Bogner return "u32"; 9951ede55eSJustin Bogner case ElementType::I64: 10051ede55eSJustin Bogner return "i64"; 10151ede55eSJustin Bogner case ElementType::U64: 10251ede55eSJustin Bogner return "u64"; 10351ede55eSJustin Bogner case ElementType::F16: 10451ede55eSJustin Bogner return "f16"; 10551ede55eSJustin Bogner case ElementType::F32: 10651ede55eSJustin Bogner return "f32"; 10751ede55eSJustin Bogner case ElementType::F64: 10851ede55eSJustin Bogner return "f64"; 10951ede55eSJustin Bogner case ElementType::SNormF16: 11051ede55eSJustin Bogner return "snorm_f16"; 11151ede55eSJustin Bogner case ElementType::UNormF16: 11251ede55eSJustin Bogner return "unorm_f16"; 11351ede55eSJustin Bogner case ElementType::SNormF32: 11451ede55eSJustin Bogner return "snorm_f32"; 11551ede55eSJustin Bogner case ElementType::UNormF32: 11651ede55eSJustin Bogner return "unorm_f32"; 11751ede55eSJustin Bogner case ElementType::SNormF64: 11851ede55eSJustin Bogner return "snorm_f64"; 11951ede55eSJustin Bogner case ElementType::UNormF64: 12051ede55eSJustin Bogner return "unorm_f64"; 12151ede55eSJustin Bogner case ElementType::PackedS8x32: 12251ede55eSJustin Bogner return "p32i8"; 12351ede55eSJustin Bogner case ElementType::PackedU8x32: 12451ede55eSJustin Bogner return "p32u8"; 12551ede55eSJustin Bogner case ElementType::Invalid: 12651ede55eSJustin Bogner return "<invalid>"; 12751ede55eSJustin Bogner } 12851ede55eSJustin Bogner llvm_unreachable("Unhandled ElementType"); 12951ede55eSJustin Bogner } 13051ede55eSJustin Bogner 13151ede55eSJustin Bogner static StringRef getSamplerTypeName(SamplerType ST) { 13251ede55eSJustin Bogner switch (ST) { 13351ede55eSJustin Bogner case SamplerType::Default: 13451ede55eSJustin Bogner return "Default"; 13551ede55eSJustin Bogner case SamplerType::Comparison: 13651ede55eSJustin Bogner return "Comparison"; 13751ede55eSJustin Bogner case SamplerType::Mono: 13851ede55eSJustin Bogner return "Mono"; 13951ede55eSJustin Bogner } 14051ede55eSJustin Bogner llvm_unreachable("Unhandled SamplerType"); 14151ede55eSJustin Bogner } 14251ede55eSJustin Bogner 14351ede55eSJustin Bogner static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) { 14451ede55eSJustin Bogner switch (SFT) { 14551ede55eSJustin Bogner case SamplerFeedbackType::MinMip: 14651ede55eSJustin Bogner return "MinMip"; 14751ede55eSJustin Bogner case SamplerFeedbackType::MipRegionUsed: 14851ede55eSJustin Bogner return "MipRegionUsed"; 14951ede55eSJustin Bogner } 15051ede55eSJustin Bogner llvm_unreachable("Unhandled SamplerFeedbackType"); 15151ede55eSJustin Bogner } 15251ede55eSJustin Bogner 153482237e8SJustin Bogner static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) { 154482237e8SJustin Bogner // TODO: Handle unorm, snorm, and packed. 155482237e8SJustin Bogner Ty = Ty->getScalarType(); 156482237e8SJustin Bogner 157482237e8SJustin Bogner if (Ty->isIntegerTy()) { 158482237e8SJustin Bogner switch (Ty->getIntegerBitWidth()) { 159482237e8SJustin Bogner case 16: 160482237e8SJustin Bogner return IsSigned ? ElementType::I16 : ElementType::U16; 161482237e8SJustin Bogner case 32: 162482237e8SJustin Bogner return IsSigned ? ElementType::I32 : ElementType::U32; 163482237e8SJustin Bogner case 64: 164482237e8SJustin Bogner return IsSigned ? ElementType::I64 : ElementType::U64; 165482237e8SJustin Bogner case 1: 166482237e8SJustin Bogner default: 167482237e8SJustin Bogner return ElementType::Invalid; 168482237e8SJustin Bogner } 169482237e8SJustin Bogner } else if (Ty->isFloatTy()) { 170482237e8SJustin Bogner return ElementType::F32; 171482237e8SJustin Bogner } else if (Ty->isDoubleTy()) { 172482237e8SJustin Bogner return ElementType::F64; 173482237e8SJustin Bogner } else if (Ty->isHalfTy()) { 174482237e8SJustin Bogner return ElementType::F16; 175482237e8SJustin Bogner } 176482237e8SJustin Bogner 177482237e8SJustin Bogner return ElementType::Invalid; 178482237e8SJustin Bogner } 179482237e8SJustin Bogner 1803eca15cbSJustin Bogner ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy, 1813eca15cbSJustin Bogner const dxil::ResourceClass RC_, 1823eca15cbSJustin Bogner const dxil::ResourceKind Kind_, 1833eca15cbSJustin Bogner bool GloballyCoherent, bool HasCounter) 1843eca15cbSJustin Bogner : HandleTy(HandleTy), GloballyCoherent(GloballyCoherent), 1853eca15cbSJustin Bogner HasCounter(HasCounter) { 1863eca15cbSJustin Bogner // If we're provided a resource class and kind, trust them. 1873eca15cbSJustin Bogner if (Kind_ != dxil::ResourceKind::Invalid) { 1883eca15cbSJustin Bogner RC = RC_; 1893eca15cbSJustin Bogner Kind = Kind_; 1903eca15cbSJustin Bogner return; 1913eca15cbSJustin Bogner } 1923eca15cbSJustin Bogner 193482237e8SJustin Bogner if (auto *Ty = dyn_cast<RawBufferExtType>(HandleTy)) { 194482237e8SJustin Bogner RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 195482237e8SJustin Bogner Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer 196482237e8SJustin Bogner : ResourceKind::RawBuffer; 197482237e8SJustin Bogner } else if (auto *Ty = dyn_cast<TypedBufferExtType>(HandleTy)) { 198482237e8SJustin Bogner RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 199482237e8SJustin Bogner Kind = ResourceKind::TypedBuffer; 200482237e8SJustin Bogner } else if (auto *Ty = dyn_cast<TextureExtType>(HandleTy)) { 201482237e8SJustin Bogner RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 202482237e8SJustin Bogner Kind = Ty->getDimension(); 203482237e8SJustin Bogner } else if (auto *Ty = dyn_cast<MSTextureExtType>(HandleTy)) { 204482237e8SJustin Bogner RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 205482237e8SJustin Bogner Kind = Ty->getDimension(); 206482237e8SJustin Bogner } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(HandleTy)) { 207482237e8SJustin Bogner RC = ResourceClass::UAV; 208482237e8SJustin Bogner Kind = Ty->getDimension(); 209482237e8SJustin Bogner } else if (isa<CBufferExtType>(HandleTy)) { 210482237e8SJustin Bogner RC = ResourceClass::CBuffer; 211482237e8SJustin Bogner Kind = ResourceKind::CBuffer; 212482237e8SJustin Bogner } else if (isa<SamplerExtType>(HandleTy)) { 213482237e8SJustin Bogner RC = ResourceClass::Sampler; 214482237e8SJustin Bogner Kind = ResourceKind::Sampler; 215482237e8SJustin Bogner } else 216482237e8SJustin Bogner llvm_unreachable("Unknown handle type"); 217482237e8SJustin Bogner } 218482237e8SJustin Bogner 2190e2466f6SJustin Bogner static void formatTypeName(SmallString<64> &Dest, StringRef Name, 2200e2466f6SJustin Bogner bool isWriteable, bool isROV) { 2210e2466f6SJustin Bogner Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : ""; 2220e2466f6SJustin Bogner Dest += Name; 2230e2466f6SJustin Bogner } 2240e2466f6SJustin Bogner 2250e2466f6SJustin Bogner StructType *ResourceTypeInfo::createElementStruct() { 2260e2466f6SJustin Bogner SmallString<64> TypeName; 2270e2466f6SJustin Bogner 2280e2466f6SJustin Bogner switch (Kind) { 2290e2466f6SJustin Bogner case ResourceKind::Texture1D: 2300e2466f6SJustin Bogner case ResourceKind::Texture2D: 2310e2466f6SJustin Bogner case ResourceKind::Texture3D: 2320e2466f6SJustin Bogner case ResourceKind::TextureCube: 2330e2466f6SJustin Bogner case ResourceKind::Texture1DArray: 2340e2466f6SJustin Bogner case ResourceKind::Texture2DArray: 2350e2466f6SJustin Bogner case ResourceKind::TextureCubeArray: { 2360e2466f6SJustin Bogner auto *RTy = cast<TextureExtType>(HandleTy); 2370e2466f6SJustin Bogner formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 2380e2466f6SJustin Bogner RTy->isROV()); 2390e2466f6SJustin Bogner return StructType::create(RTy->getResourceType(), TypeName); 2400e2466f6SJustin Bogner } 2410e2466f6SJustin Bogner case ResourceKind::Texture2DMS: 2420e2466f6SJustin Bogner case ResourceKind::Texture2DMSArray: { 2430e2466f6SJustin Bogner auto *RTy = cast<MSTextureExtType>(HandleTy); 2440e2466f6SJustin Bogner formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 2450e2466f6SJustin Bogner /*IsROV=*/false); 2460e2466f6SJustin Bogner return StructType::create(RTy->getResourceType(), TypeName); 2470e2466f6SJustin Bogner } 2480e2466f6SJustin Bogner case ResourceKind::TypedBuffer: { 2490e2466f6SJustin Bogner auto *RTy = cast<TypedBufferExtType>(HandleTy); 2500e2466f6SJustin Bogner formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 2510e2466f6SJustin Bogner RTy->isROV()); 2520e2466f6SJustin Bogner return StructType::create(RTy->getResourceType(), TypeName); 2530e2466f6SJustin Bogner } 2540e2466f6SJustin Bogner case ResourceKind::RawBuffer: { 2550e2466f6SJustin Bogner auto *RTy = cast<RawBufferExtType>(HandleTy); 2560e2466f6SJustin Bogner formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(), 2570e2466f6SJustin Bogner RTy->isROV()); 2580e2466f6SJustin Bogner return StructType::create(Type::getInt32Ty(HandleTy->getContext()), 2590e2466f6SJustin Bogner TypeName); 2600e2466f6SJustin Bogner } 2610e2466f6SJustin Bogner case ResourceKind::StructuredBuffer: { 2620e2466f6SJustin Bogner auto *RTy = cast<RawBufferExtType>(HandleTy); 2630e2466f6SJustin Bogner formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(), 2640e2466f6SJustin Bogner RTy->isROV()); 2650e2466f6SJustin Bogner return StructType::create(RTy->getResourceType(), TypeName); 2660e2466f6SJustin Bogner } 2670e2466f6SJustin Bogner case ResourceKind::FeedbackTexture2D: 2680e2466f6SJustin Bogner case ResourceKind::FeedbackTexture2DArray: { 2690e2466f6SJustin Bogner auto *RTy = cast<FeedbackTextureExtType>(HandleTy); 2700e2466f6SJustin Bogner TypeName = formatv("{0}<{1}>", getResourceKindName(Kind), 2710e2466f6SJustin Bogner llvm::to_underlying(RTy->getFeedbackType())); 2720e2466f6SJustin Bogner return StructType::create(Type::getInt32Ty(HandleTy->getContext()), 2730e2466f6SJustin Bogner TypeName); 2740e2466f6SJustin Bogner } 2750e2466f6SJustin Bogner case ResourceKind::CBuffer: 2760e2466f6SJustin Bogner return StructType::create(HandleTy->getContext(), "cbuffer"); 2770e2466f6SJustin Bogner case ResourceKind::Sampler: { 2780e2466f6SJustin Bogner auto *RTy = cast<SamplerExtType>(HandleTy); 2790e2466f6SJustin Bogner TypeName = formatv("SamplerState<{0}>", 2800e2466f6SJustin Bogner llvm::to_underlying(RTy->getSamplerType())); 2810e2466f6SJustin Bogner return StructType::create(Type::getInt32Ty(HandleTy->getContext()), 2820e2466f6SJustin Bogner TypeName); 2830e2466f6SJustin Bogner } 2840e2466f6SJustin Bogner case ResourceKind::TBuffer: 2850e2466f6SJustin Bogner case ResourceKind::RTAccelerationStructure: 2860e2466f6SJustin Bogner llvm_unreachable("Unhandled resource kind"); 2870e2466f6SJustin Bogner case ResourceKind::Invalid: 2880e2466f6SJustin Bogner case ResourceKind::NumEntries: 2890e2466f6SJustin Bogner llvm_unreachable("Invalid resource kind"); 2900e2466f6SJustin Bogner } 2910e2466f6SJustin Bogner llvm_unreachable("Unhandled ResourceKind enum"); 2920e2466f6SJustin Bogner } 2930e2466f6SJustin Bogner 2943eca15cbSJustin Bogner bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; } 295b365dbbdSJustin Bogner 2963eca15cbSJustin Bogner bool ResourceTypeInfo::isCBuffer() const { 2973eca15cbSJustin Bogner return RC == ResourceClass::CBuffer; 2983eca15cbSJustin Bogner } 299b365dbbdSJustin Bogner 3003eca15cbSJustin Bogner bool ResourceTypeInfo::isSampler() const { 3013eca15cbSJustin Bogner return RC == ResourceClass::Sampler; 3023eca15cbSJustin Bogner } 303b365dbbdSJustin Bogner 3043eca15cbSJustin Bogner bool ResourceTypeInfo::isStruct() const { 305b365dbbdSJustin Bogner return Kind == ResourceKind::StructuredBuffer; 306b365dbbdSJustin Bogner } 307b365dbbdSJustin Bogner 3083eca15cbSJustin Bogner bool ResourceTypeInfo::isTyped() const { 309b365dbbdSJustin Bogner switch (Kind) { 310b365dbbdSJustin Bogner case ResourceKind::Texture1D: 311b365dbbdSJustin Bogner case ResourceKind::Texture2D: 312b365dbbdSJustin Bogner case ResourceKind::Texture2DMS: 313b365dbbdSJustin Bogner case ResourceKind::Texture3D: 314b365dbbdSJustin Bogner case ResourceKind::TextureCube: 315b365dbbdSJustin Bogner case ResourceKind::Texture1DArray: 316b365dbbdSJustin Bogner case ResourceKind::Texture2DArray: 317b365dbbdSJustin Bogner case ResourceKind::Texture2DMSArray: 318b365dbbdSJustin Bogner case ResourceKind::TextureCubeArray: 319b365dbbdSJustin Bogner case ResourceKind::TypedBuffer: 320b365dbbdSJustin Bogner return true; 321b365dbbdSJustin Bogner case ResourceKind::RawBuffer: 322b365dbbdSJustin Bogner case ResourceKind::StructuredBuffer: 323b365dbbdSJustin Bogner case ResourceKind::FeedbackTexture2D: 324b365dbbdSJustin Bogner case ResourceKind::FeedbackTexture2DArray: 325b365dbbdSJustin Bogner case ResourceKind::CBuffer: 326b365dbbdSJustin Bogner case ResourceKind::Sampler: 327b365dbbdSJustin Bogner case ResourceKind::TBuffer: 328b365dbbdSJustin Bogner case ResourceKind::RTAccelerationStructure: 329b365dbbdSJustin Bogner return false; 330b365dbbdSJustin Bogner case ResourceKind::Invalid: 331b365dbbdSJustin Bogner case ResourceKind::NumEntries: 332b365dbbdSJustin Bogner llvm_unreachable("Invalid resource kind"); 333b365dbbdSJustin Bogner } 334b365dbbdSJustin Bogner llvm_unreachable("Unhandled ResourceKind enum"); 335b365dbbdSJustin Bogner } 336b365dbbdSJustin Bogner 3373eca15cbSJustin Bogner bool ResourceTypeInfo::isFeedback() const { 338b365dbbdSJustin Bogner return Kind == ResourceKind::FeedbackTexture2D || 339b365dbbdSJustin Bogner Kind == ResourceKind::FeedbackTexture2DArray; 340b365dbbdSJustin Bogner } 341b365dbbdSJustin Bogner 3423eca15cbSJustin Bogner bool ResourceTypeInfo::isMultiSample() const { 343b365dbbdSJustin Bogner return Kind == ResourceKind::Texture2DMS || 344b365dbbdSJustin Bogner Kind == ResourceKind::Texture2DMSArray; 345b365dbbdSJustin Bogner } 346b365dbbdSJustin Bogner 347482237e8SJustin Bogner static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) { 348482237e8SJustin Bogner switch (Kind) { 349482237e8SJustin Bogner case ResourceKind::Texture1D: 350482237e8SJustin Bogner case ResourceKind::Texture2D: 351482237e8SJustin Bogner case ResourceKind::Texture3D: 352482237e8SJustin Bogner case ResourceKind::TextureCube: 353482237e8SJustin Bogner case ResourceKind::Texture1DArray: 354482237e8SJustin Bogner case ResourceKind::Texture2DArray: 355482237e8SJustin Bogner case ResourceKind::TextureCubeArray: 356482237e8SJustin Bogner return cast<TextureExtType>(Ty)->isROV(); 357482237e8SJustin Bogner case ResourceKind::TypedBuffer: 358482237e8SJustin Bogner return cast<TypedBufferExtType>(Ty)->isROV(); 359482237e8SJustin Bogner case ResourceKind::RawBuffer: 360482237e8SJustin Bogner case ResourceKind::StructuredBuffer: 361482237e8SJustin Bogner return cast<RawBufferExtType>(Ty)->isROV(); 362482237e8SJustin Bogner case ResourceKind::Texture2DMS: 363482237e8SJustin Bogner case ResourceKind::Texture2DMSArray: 364482237e8SJustin Bogner case ResourceKind::FeedbackTexture2D: 365482237e8SJustin Bogner case ResourceKind::FeedbackTexture2DArray: 366b365dbbdSJustin Bogner return false; 367482237e8SJustin Bogner case ResourceKind::CBuffer: 368482237e8SJustin Bogner case ResourceKind::Sampler: 369482237e8SJustin Bogner case ResourceKind::TBuffer: 370482237e8SJustin Bogner case ResourceKind::RTAccelerationStructure: 371482237e8SJustin Bogner case ResourceKind::Invalid: 372482237e8SJustin Bogner case ResourceKind::NumEntries: 373482237e8SJustin Bogner llvm_unreachable("Resource cannot be ROV"); 374482237e8SJustin Bogner } 375482237e8SJustin Bogner llvm_unreachable("Unhandled ResourceKind enum"); 376b365dbbdSJustin Bogner } 377b365dbbdSJustin Bogner 3783eca15cbSJustin Bogner ResourceTypeInfo::UAVInfo ResourceTypeInfo::getUAV() const { 379482237e8SJustin Bogner assert(isUAV() && "Not a UAV"); 380482237e8SJustin Bogner return {GloballyCoherent, HasCounter, isROV(Kind, HandleTy)}; 381782bc4f6SJustin Bogner } 382782bc4f6SJustin Bogner 3833eca15cbSJustin Bogner uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const { 384482237e8SJustin Bogner assert(isCBuffer() && "Not a CBuffer"); 385482237e8SJustin Bogner return cast<CBufferExtType>(HandleTy)->getCBufferSize(); 386482237e8SJustin Bogner } 387482237e8SJustin Bogner 3883eca15cbSJustin Bogner dxil::SamplerType ResourceTypeInfo::getSamplerType() const { 389482237e8SJustin Bogner assert(isSampler() && "Not a Sampler"); 390482237e8SJustin Bogner return cast<SamplerExtType>(HandleTy)->getSamplerType(); 391482237e8SJustin Bogner } 392482237e8SJustin Bogner 3933eca15cbSJustin Bogner ResourceTypeInfo::StructInfo 3943eca15cbSJustin Bogner ResourceTypeInfo::getStruct(const DataLayout &DL) const { 395482237e8SJustin Bogner assert(isStruct() && "Not a Struct"); 396482237e8SJustin Bogner 397482237e8SJustin Bogner Type *ElTy = cast<RawBufferExtType>(HandleTy)->getResourceType(); 398482237e8SJustin Bogner 399482237e8SJustin Bogner uint32_t Stride = DL.getTypeAllocSize(ElTy); 400482237e8SJustin Bogner MaybeAlign Alignment; 401482237e8SJustin Bogner if (auto *STy = dyn_cast<StructType>(ElTy)) 402482237e8SJustin Bogner Alignment = DL.getStructLayout(STy)->getAlignment(); 403482237e8SJustin Bogner uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0; 404482237e8SJustin Bogner return {Stride, AlignLog2}; 405482237e8SJustin Bogner } 406482237e8SJustin Bogner 407482237e8SJustin Bogner static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind, 408482237e8SJustin Bogner TargetExtType *Ty) { 409482237e8SJustin Bogner switch (Kind) { 410482237e8SJustin Bogner case ResourceKind::Texture1D: 411482237e8SJustin Bogner case ResourceKind::Texture2D: 412482237e8SJustin Bogner case ResourceKind::Texture3D: 413482237e8SJustin Bogner case ResourceKind::TextureCube: 414482237e8SJustin Bogner case ResourceKind::Texture1DArray: 415482237e8SJustin Bogner case ResourceKind::Texture2DArray: 416482237e8SJustin Bogner case ResourceKind::TextureCubeArray: { 417482237e8SJustin Bogner auto *RTy = cast<TextureExtType>(Ty); 418482237e8SJustin Bogner return {RTy->getResourceType(), RTy->isSigned()}; 419482237e8SJustin Bogner } 420482237e8SJustin Bogner case ResourceKind::Texture2DMS: 421482237e8SJustin Bogner case ResourceKind::Texture2DMSArray: { 422482237e8SJustin Bogner auto *RTy = cast<MSTextureExtType>(Ty); 423482237e8SJustin Bogner return {RTy->getResourceType(), RTy->isSigned()}; 424482237e8SJustin Bogner } 425482237e8SJustin Bogner case ResourceKind::TypedBuffer: { 426482237e8SJustin Bogner auto *RTy = cast<TypedBufferExtType>(Ty); 427482237e8SJustin Bogner return {RTy->getResourceType(), RTy->isSigned()}; 428482237e8SJustin Bogner } 429482237e8SJustin Bogner case ResourceKind::RawBuffer: 430482237e8SJustin Bogner case ResourceKind::StructuredBuffer: 431482237e8SJustin Bogner case ResourceKind::FeedbackTexture2D: 432482237e8SJustin Bogner case ResourceKind::FeedbackTexture2DArray: 433482237e8SJustin Bogner case ResourceKind::CBuffer: 434482237e8SJustin Bogner case ResourceKind::Sampler: 435482237e8SJustin Bogner case ResourceKind::TBuffer: 436482237e8SJustin Bogner case ResourceKind::RTAccelerationStructure: 437482237e8SJustin Bogner case ResourceKind::Invalid: 438482237e8SJustin Bogner case ResourceKind::NumEntries: 439482237e8SJustin Bogner llvm_unreachable("Resource is not typed"); 440482237e8SJustin Bogner } 441482237e8SJustin Bogner llvm_unreachable("Unhandled ResourceKind enum"); 442482237e8SJustin Bogner } 443482237e8SJustin Bogner 4443eca15cbSJustin Bogner ResourceTypeInfo::TypedInfo ResourceTypeInfo::getTyped() const { 445482237e8SJustin Bogner assert(isTyped() && "Not typed"); 446482237e8SJustin Bogner 447482237e8SJustin Bogner auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy); 448482237e8SJustin Bogner dxil::ElementType ET = toDXILElementType(ElTy, IsSigned); 449482237e8SJustin Bogner uint32_t Count = 1; 450482237e8SJustin Bogner if (auto *VTy = dyn_cast<FixedVectorType>(ElTy)) 451482237e8SJustin Bogner Count = VTy->getNumElements(); 452482237e8SJustin Bogner return {ET, Count}; 453482237e8SJustin Bogner } 454482237e8SJustin Bogner 4553eca15cbSJustin Bogner dxil::SamplerFeedbackType ResourceTypeInfo::getFeedbackType() const { 456482237e8SJustin Bogner assert(isFeedback() && "Not Feedback"); 457482237e8SJustin Bogner return cast<FeedbackTextureExtType>(HandleTy)->getFeedbackType(); 458482237e8SJustin Bogner } 4593eca15cbSJustin Bogner uint32_t ResourceTypeInfo::getMultiSampleCount() const { 460482237e8SJustin Bogner assert(isMultiSample() && "Not MultiSampled"); 461482237e8SJustin Bogner return cast<MSTextureExtType>(HandleTy)->getSampleCount(); 462482237e8SJustin Bogner } 463482237e8SJustin Bogner 4643eca15cbSJustin Bogner bool ResourceTypeInfo::operator==(const ResourceTypeInfo &RHS) const { 4653eca15cbSJustin Bogner return std::tie(HandleTy, GloballyCoherent, HasCounter) == 4663eca15cbSJustin Bogner std::tie(RHS.HandleTy, RHS.GloballyCoherent, RHS.HasCounter); 467b365dbbdSJustin Bogner } 468b365dbbdSJustin Bogner 4693eca15cbSJustin Bogner bool ResourceTypeInfo::operator<(const ResourceTypeInfo &RHS) const { 470482237e8SJustin Bogner // An empty datalayout is sufficient for sorting purposes. 471482237e8SJustin Bogner DataLayout DummyDL; 4723eca15cbSJustin Bogner if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind)) 473482237e8SJustin Bogner return true; 474482237e8SJustin Bogner if (isCBuffer() && RHS.isCBuffer() && 475482237e8SJustin Bogner getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL)) 476482237e8SJustin Bogner return true; 477482237e8SJustin Bogner if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType()) 478482237e8SJustin Bogner return true; 479482237e8SJustin Bogner if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV()) 480482237e8SJustin Bogner return true; 481482237e8SJustin Bogner if (isStruct() && RHS.isStruct() && 482482237e8SJustin Bogner getStruct(DummyDL) < RHS.getStruct(DummyDL)) 483482237e8SJustin Bogner return true; 484482237e8SJustin Bogner if (isFeedback() && RHS.isFeedback() && 485482237e8SJustin Bogner getFeedbackType() < RHS.getFeedbackType()) 486482237e8SJustin Bogner return true; 487482237e8SJustin Bogner if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped()) 488482237e8SJustin Bogner return true; 489482237e8SJustin Bogner if (isMultiSample() && RHS.isMultiSample() && 490482237e8SJustin Bogner getMultiSampleCount() < RHS.getMultiSampleCount()) 491482237e8SJustin Bogner return true; 492482237e8SJustin Bogner return false; 493482237e8SJustin Bogner } 494482237e8SJustin Bogner 4953eca15cbSJustin Bogner void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const { 496482237e8SJustin Bogner OS << " Class: " << getResourceClassName(RC) << "\n" 49751ede55eSJustin Bogner << " Kind: " << getResourceKindName(Kind) << "\n"; 49851ede55eSJustin Bogner 49951ede55eSJustin Bogner if (isCBuffer()) { 500482237e8SJustin Bogner OS << " CBuffer size: " << getCBufferSize(DL) << "\n"; 50151ede55eSJustin Bogner } else if (isSampler()) { 502482237e8SJustin Bogner OS << " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n"; 50351ede55eSJustin Bogner } else { 50451ede55eSJustin Bogner if (isUAV()) { 505482237e8SJustin Bogner UAVInfo UAVFlags = getUAV(); 50651ede55eSJustin Bogner OS << " Globally Coherent: " << UAVFlags.GloballyCoherent << "\n" 50751ede55eSJustin Bogner << " HasCounter: " << UAVFlags.HasCounter << "\n" 50851ede55eSJustin Bogner << " IsROV: " << UAVFlags.IsROV << "\n"; 50951ede55eSJustin Bogner } 51051ede55eSJustin Bogner if (isMultiSample()) 511482237e8SJustin Bogner OS << " Sample Count: " << getMultiSampleCount() << "\n"; 51251ede55eSJustin Bogner 51351ede55eSJustin Bogner if (isStruct()) { 514482237e8SJustin Bogner StructInfo Struct = getStruct(DL); 51551ede55eSJustin Bogner OS << " Buffer Stride: " << Struct.Stride << "\n"; 51651ede55eSJustin Bogner OS << " Alignment: " << Struct.AlignLog2 << "\n"; 51751ede55eSJustin Bogner } else if (isTyped()) { 518482237e8SJustin Bogner TypedInfo Typed = getTyped(); 51951ede55eSJustin Bogner OS << " Element Type: " << getElementTypeName(Typed.ElementTy) << "\n" 52051ede55eSJustin Bogner << " Element Count: " << Typed.ElementCount << "\n"; 52151ede55eSJustin Bogner } else if (isFeedback()) 522482237e8SJustin Bogner OS << " Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType()) 52351ede55eSJustin Bogner << "\n"; 52451ede55eSJustin Bogner } 52551ede55eSJustin Bogner } 52651ede55eSJustin Bogner 5270e2466f6SJustin Bogner GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty, 5280e2466f6SJustin Bogner StringRef Name) { 5290e2466f6SJustin Bogner assert(!Symbol && "Symbol has already been created"); 5300e2466f6SJustin Bogner Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true, 5310e2466f6SJustin Bogner GlobalValue::ExternalLinkage, 5320e2466f6SJustin Bogner /*Initializer=*/nullptr, Name); 5330e2466f6SJustin Bogner return Symbol; 5340e2466f6SJustin Bogner } 5350e2466f6SJustin Bogner 5363eca15cbSJustin Bogner MDTuple *ResourceBindingInfo::getAsMetadata(Module &M, 5373eca15cbSJustin Bogner dxil::ResourceTypeInfo &RTI) const { 5383eca15cbSJustin Bogner LLVMContext &Ctx = M.getContext(); 5393eca15cbSJustin Bogner const DataLayout &DL = M.getDataLayout(); 5403eca15cbSJustin Bogner 5413eca15cbSJustin Bogner SmallVector<Metadata *, 11> MDVals; 5423eca15cbSJustin Bogner 5433eca15cbSJustin Bogner Type *I32Ty = Type::getInt32Ty(Ctx); 5443eca15cbSJustin Bogner Type *I1Ty = Type::getInt1Ty(Ctx); 5453eca15cbSJustin Bogner auto getIntMD = [&I32Ty](uint32_t V) { 5463eca15cbSJustin Bogner return ConstantAsMetadata::get( 5473eca15cbSJustin Bogner Constant::getIntegerValue(I32Ty, APInt(32, V))); 5483eca15cbSJustin Bogner }; 5493eca15cbSJustin Bogner auto getBoolMD = [&I1Ty](uint32_t V) { 5503eca15cbSJustin Bogner return ConstantAsMetadata::get( 5513eca15cbSJustin Bogner Constant::getIntegerValue(I1Ty, APInt(1, V))); 5523eca15cbSJustin Bogner }; 5533eca15cbSJustin Bogner 5543eca15cbSJustin Bogner MDVals.push_back(getIntMD(Binding.RecordID)); 5550e2466f6SJustin Bogner assert(Symbol && "Cannot yet create useful resource metadata without symbol"); 5560e2466f6SJustin Bogner MDVals.push_back(ValueAsMetadata::get(Symbol)); 5570e2466f6SJustin Bogner MDVals.push_back(MDString::get(Ctx, Symbol->getName())); 5583eca15cbSJustin Bogner MDVals.push_back(getIntMD(Binding.Space)); 5593eca15cbSJustin Bogner MDVals.push_back(getIntMD(Binding.LowerBound)); 5603eca15cbSJustin Bogner MDVals.push_back(getIntMD(Binding.Size)); 5613eca15cbSJustin Bogner 5623eca15cbSJustin Bogner if (RTI.isCBuffer()) { 5633eca15cbSJustin Bogner MDVals.push_back(getIntMD(RTI.getCBufferSize(DL))); 5643eca15cbSJustin Bogner MDVals.push_back(nullptr); 5653eca15cbSJustin Bogner } else if (RTI.isSampler()) { 5663eca15cbSJustin Bogner MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getSamplerType()))); 5673eca15cbSJustin Bogner MDVals.push_back(nullptr); 5683eca15cbSJustin Bogner } else { 5693eca15cbSJustin Bogner MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind()))); 5703eca15cbSJustin Bogner 5713eca15cbSJustin Bogner if (RTI.isUAV()) { 5723eca15cbSJustin Bogner ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV(); 5733eca15cbSJustin Bogner MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent)); 5743eca15cbSJustin Bogner MDVals.push_back(getBoolMD(UAVFlags.HasCounter)); 5753eca15cbSJustin Bogner MDVals.push_back(getBoolMD(UAVFlags.IsROV)); 5763eca15cbSJustin Bogner } else { 5773eca15cbSJustin Bogner // All SRVs include sample count in the metadata, but it's only meaningful 5783eca15cbSJustin Bogner // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+, 5793eca15cbSJustin Bogner // but this just isn't reflected in the metadata at all. 5803eca15cbSJustin Bogner uint32_t SampleCount = 5813eca15cbSJustin Bogner RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0; 5823eca15cbSJustin Bogner MDVals.push_back(getIntMD(SampleCount)); 5833eca15cbSJustin Bogner } 5843eca15cbSJustin Bogner 5853eca15cbSJustin Bogner // Further properties are attached to a metadata list of tag-value pairs. 5863eca15cbSJustin Bogner SmallVector<Metadata *> Tags; 5873eca15cbSJustin Bogner if (RTI.isStruct()) { 5883eca15cbSJustin Bogner Tags.push_back( 5893eca15cbSJustin Bogner getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride))); 5903eca15cbSJustin Bogner Tags.push_back(getIntMD(RTI.getStruct(DL).Stride)); 5913eca15cbSJustin Bogner } else if (RTI.isTyped()) { 5923eca15cbSJustin Bogner Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType))); 5933eca15cbSJustin Bogner Tags.push_back(getIntMD(llvm::to_underlying(RTI.getTyped().ElementTy))); 5943eca15cbSJustin Bogner } else if (RTI.isFeedback()) { 5953eca15cbSJustin Bogner Tags.push_back( 5963eca15cbSJustin Bogner getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind))); 5973eca15cbSJustin Bogner Tags.push_back(getIntMD(llvm::to_underlying(RTI.getFeedbackType()))); 5983eca15cbSJustin Bogner } 5993eca15cbSJustin Bogner MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags)); 6003eca15cbSJustin Bogner } 6013eca15cbSJustin Bogner 6023eca15cbSJustin Bogner return MDNode::get(Ctx, MDVals); 6033eca15cbSJustin Bogner } 6043eca15cbSJustin Bogner 6053eca15cbSJustin Bogner std::pair<uint32_t, uint32_t> 6063eca15cbSJustin Bogner ResourceBindingInfo::getAnnotateProps(Module &M, 6073eca15cbSJustin Bogner dxil::ResourceTypeInfo &RTI) const { 6083eca15cbSJustin Bogner const DataLayout &DL = M.getDataLayout(); 6093eca15cbSJustin Bogner 6103eca15cbSJustin Bogner uint32_t ResourceKind = llvm::to_underlying(RTI.getResourceKind()); 6113eca15cbSJustin Bogner uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0; 6123eca15cbSJustin Bogner bool IsUAV = RTI.isUAV(); 6133eca15cbSJustin Bogner ResourceTypeInfo::UAVInfo UAVFlags = 6143eca15cbSJustin Bogner IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{}; 6153eca15cbSJustin Bogner bool IsROV = IsUAV && UAVFlags.IsROV; 6163eca15cbSJustin Bogner bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent; 6173eca15cbSJustin Bogner uint8_t SamplerCmpOrHasCounter = 0; 6183eca15cbSJustin Bogner if (IsUAV) 6193eca15cbSJustin Bogner SamplerCmpOrHasCounter = UAVFlags.HasCounter; 6203eca15cbSJustin Bogner else if (RTI.isSampler()) 6213eca15cbSJustin Bogner SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison; 6223eca15cbSJustin Bogner 6233eca15cbSJustin Bogner // TODO: Document this format. Currently the only reference is the 6243eca15cbSJustin Bogner // implementation of dxc's DxilResourceProperties struct. 6253eca15cbSJustin Bogner uint32_t Word0 = 0; 6263eca15cbSJustin Bogner Word0 |= ResourceKind & 0xFF; 6273eca15cbSJustin Bogner Word0 |= (AlignLog2 & 0xF) << 8; 6283eca15cbSJustin Bogner Word0 |= (IsUAV & 1) << 12; 6293eca15cbSJustin Bogner Word0 |= (IsROV & 1) << 13; 6303eca15cbSJustin Bogner Word0 |= (IsGloballyCoherent & 1) << 14; 6313eca15cbSJustin Bogner Word0 |= (SamplerCmpOrHasCounter & 1) << 15; 6323eca15cbSJustin Bogner 6333eca15cbSJustin Bogner uint32_t Word1 = 0; 6343eca15cbSJustin Bogner if (RTI.isStruct()) 6353eca15cbSJustin Bogner Word1 = RTI.getStruct(DL).Stride; 6363eca15cbSJustin Bogner else if (RTI.isCBuffer()) 6373eca15cbSJustin Bogner Word1 = RTI.getCBufferSize(DL); 6383eca15cbSJustin Bogner else if (RTI.isFeedback()) 6393eca15cbSJustin Bogner Word1 = llvm::to_underlying(RTI.getFeedbackType()); 6403eca15cbSJustin Bogner else if (RTI.isTyped()) { 6413eca15cbSJustin Bogner ResourceTypeInfo::TypedInfo Typed = RTI.getTyped(); 6423eca15cbSJustin Bogner uint32_t CompType = llvm::to_underlying(Typed.ElementTy); 6433eca15cbSJustin Bogner uint32_t CompCount = Typed.ElementCount; 6443eca15cbSJustin Bogner uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0; 6453eca15cbSJustin Bogner 6463eca15cbSJustin Bogner Word1 |= (CompType & 0xFF) << 0; 6473eca15cbSJustin Bogner Word1 |= (CompCount & 0xFF) << 8; 6483eca15cbSJustin Bogner Word1 |= (SampleCount & 0xFF) << 16; 6493eca15cbSJustin Bogner } 6503eca15cbSJustin Bogner 6513eca15cbSJustin Bogner return {Word0, Word1}; 6523eca15cbSJustin Bogner } 6533eca15cbSJustin Bogner 6543eca15cbSJustin Bogner void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI, 6553eca15cbSJustin Bogner const DataLayout &DL) const { 6560e2466f6SJustin Bogner if (Symbol) { 6570e2466f6SJustin Bogner OS << " Symbol: "; 6580e2466f6SJustin Bogner Symbol->printAsOperand(OS); 6590e2466f6SJustin Bogner OS << "\n"; 6600e2466f6SJustin Bogner } 6610e2466f6SJustin Bogner 6623eca15cbSJustin Bogner OS << " Binding:\n" 6633eca15cbSJustin Bogner << " Record ID: " << Binding.RecordID << "\n" 6643eca15cbSJustin Bogner << " Space: " << Binding.Space << "\n" 6653eca15cbSJustin Bogner << " Lower Bound: " << Binding.LowerBound << "\n" 6663eca15cbSJustin Bogner << " Size: " << Binding.Size << "\n"; 6673eca15cbSJustin Bogner 6683eca15cbSJustin Bogner RTI.print(OS, DL); 6693eca15cbSJustin Bogner } 6703eca15cbSJustin Bogner 67151ede55eSJustin Bogner //===----------------------------------------------------------------------===// 67251ede55eSJustin Bogner 6733eca15cbSJustin Bogner bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA, 6743eca15cbSJustin Bogner ModuleAnalysisManager::Invalidator &Inv) { 6753eca15cbSJustin Bogner // Passes that introduce resource types must explicitly invalidate this pass. 6763eca15cbSJustin Bogner auto PAC = PA.getChecker<DXILResourceTypeAnalysis>(); 6773eca15cbSJustin Bogner return !PAC.preservedWhenStateless(); 6783eca15cbSJustin Bogner } 6793eca15cbSJustin Bogner 6803eca15cbSJustin Bogner //===----------------------------------------------------------------------===// 6813eca15cbSJustin Bogner 6823eca15cbSJustin Bogner void DXILBindingMap::populate(Module &M, DXILResourceTypeMap &DRTM) { 6833eca15cbSJustin Bogner SmallVector<std::tuple<CallInst *, ResourceBindingInfo, ResourceTypeInfo>> 6843eca15cbSJustin Bogner CIToInfos; 68551ede55eSJustin Bogner 68651ede55eSJustin Bogner for (Function &F : M.functions()) { 68751ede55eSJustin Bogner if (!F.isDeclaration()) 68851ede55eSJustin Bogner continue; 68951ede55eSJustin Bogner LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); 69051ede55eSJustin Bogner Intrinsic::ID ID = F.getIntrinsicID(); 69151ede55eSJustin Bogner switch (ID) { 69251ede55eSJustin Bogner default: 69351ede55eSJustin Bogner continue; 694*aa07f922SJustin Bogner case Intrinsic::dx_resource_handlefrombinding: { 695482237e8SJustin Bogner auto *HandleTy = cast<TargetExtType>(F.getReturnType()); 6963eca15cbSJustin Bogner ResourceTypeInfo &RTI = DRTM[HandleTy]; 697482237e8SJustin Bogner 698482237e8SJustin Bogner for (User *U : F.users()) 699482237e8SJustin Bogner if (CallInst *CI = dyn_cast<CallInst>(U)) { 70051ede55eSJustin Bogner LLVM_DEBUG(dbgs() << " Visiting: " << *U << "\n"); 701482237e8SJustin Bogner uint32_t Space = 702482237e8SJustin Bogner cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(); 703482237e8SJustin Bogner uint32_t LowerBound = 704482237e8SJustin Bogner cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 705482237e8SJustin Bogner uint32_t Size = 706482237e8SJustin Bogner cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 7073eca15cbSJustin Bogner ResourceBindingInfo RBI = ResourceBindingInfo{ 7083eca15cbSJustin Bogner /*RecordID=*/0, Space, LowerBound, Size, HandleTy}; 709482237e8SJustin Bogner 7103eca15cbSJustin Bogner CIToInfos.emplace_back(CI, RBI, RTI); 71151ede55eSJustin Bogner } 712482237e8SJustin Bogner 71351ede55eSJustin Bogner break; 71451ede55eSJustin Bogner } 71551ede55eSJustin Bogner } 71651ede55eSJustin Bogner } 71751ede55eSJustin Bogner 7183eca15cbSJustin Bogner llvm::stable_sort(CIToInfos, [](auto &LHS, auto &RHS) { 7193eca15cbSJustin Bogner const auto &[LCI, LRBI, LRTI] = LHS; 7203eca15cbSJustin Bogner const auto &[RCI, RRBI, RRTI] = RHS; 7213eca15cbSJustin Bogner // Sort by resource class first for grouping purposes, and then by the 7223eca15cbSJustin Bogner // binding and type so we can remove duplicates. 7233eca15cbSJustin Bogner ResourceClass LRC = LRTI.getResourceClass(); 7243eca15cbSJustin Bogner ResourceClass RRC = RRTI.getResourceClass(); 7253eca15cbSJustin Bogner 7263eca15cbSJustin Bogner return std::tie(LRC, LRBI, LRTI) < std::tie(RRC, RRBI, RRTI); 727782bc4f6SJustin Bogner }); 7283eca15cbSJustin Bogner for (auto [CI, RBI, RTI] : CIToInfos) { 7293eca15cbSJustin Bogner if (Infos.empty() || RBI != Infos.back()) 7303eca15cbSJustin Bogner Infos.push_back(RBI); 731482237e8SJustin Bogner CallMap[CI] = Infos.size() - 1; 732782bc4f6SJustin Bogner } 733782bc4f6SJustin Bogner 734482237e8SJustin Bogner unsigned Size = Infos.size(); 735782bc4f6SJustin Bogner // In DXC, Record ID is unique per resource type. Match that. 736782bc4f6SJustin Bogner FirstUAV = FirstCBuffer = FirstSampler = Size; 737782bc4f6SJustin Bogner uint32_t NextID = 0; 738782bc4f6SJustin Bogner for (unsigned I = 0, E = Size; I != E; ++I) { 7393eca15cbSJustin Bogner ResourceBindingInfo &RBI = Infos[I]; 7403eca15cbSJustin Bogner ResourceTypeInfo &RTI = DRTM[RBI.getHandleTy()]; 7413eca15cbSJustin Bogner if (RTI.isUAV() && FirstUAV == Size) { 742782bc4f6SJustin Bogner FirstUAV = I; 743782bc4f6SJustin Bogner NextID = 0; 7443eca15cbSJustin Bogner } else if (RTI.isCBuffer() && FirstCBuffer == Size) { 745782bc4f6SJustin Bogner FirstCBuffer = I; 746782bc4f6SJustin Bogner NextID = 0; 7473eca15cbSJustin Bogner } else if (RTI.isSampler() && FirstSampler == Size) { 748782bc4f6SJustin Bogner FirstSampler = I; 749782bc4f6SJustin Bogner NextID = 0; 750782bc4f6SJustin Bogner } 751782bc4f6SJustin Bogner 752782bc4f6SJustin Bogner // Adjust the resource binding to use the next ID. 7533eca15cbSJustin Bogner RBI.setBindingID(NextID++); 754782bc4f6SJustin Bogner } 755782bc4f6SJustin Bogner } 756782bc4f6SJustin Bogner 7573eca15cbSJustin Bogner void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM, 7583eca15cbSJustin Bogner const DataLayout &DL) const { 759482237e8SJustin Bogner for (unsigned I = 0, E = Infos.size(); I != E; ++I) { 760782bc4f6SJustin Bogner OS << "Binding " << I << ":\n"; 7613eca15cbSJustin Bogner const dxil::ResourceBindingInfo &RBI = Infos[I]; 7623eca15cbSJustin Bogner RBI.print(OS, DRTM[RBI.getHandleTy()], DL); 763782bc4f6SJustin Bogner OS << "\n"; 764782bc4f6SJustin Bogner } 765782bc4f6SJustin Bogner 766782bc4f6SJustin Bogner for (const auto &[CI, Index] : CallMap) { 767782bc4f6SJustin Bogner OS << "Call bound to " << Index << ":"; 768782bc4f6SJustin Bogner CI->print(OS); 769782bc4f6SJustin Bogner OS << "\n"; 770782bc4f6SJustin Bogner } 771782bc4f6SJustin Bogner } 772782bc4f6SJustin Bogner 773372ddcd1SJustin Bogner //===----------------------------------------------------------------------===// 774372ddcd1SJustin Bogner 7753eca15cbSJustin Bogner AnalysisKey DXILResourceTypeAnalysis::Key; 7763eca15cbSJustin Bogner AnalysisKey DXILResourceBindingAnalysis::Key; 777372ddcd1SJustin Bogner 7783eca15cbSJustin Bogner DXILBindingMap DXILResourceBindingAnalysis::run(Module &M, 779372ddcd1SJustin Bogner ModuleAnalysisManager &AM) { 7803eca15cbSJustin Bogner DXILBindingMap Data; 7813eca15cbSJustin Bogner DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M); 7823eca15cbSJustin Bogner Data.populate(M, DRTM); 783372ddcd1SJustin Bogner return Data; 784372ddcd1SJustin Bogner } 785372ddcd1SJustin Bogner 7863eca15cbSJustin Bogner PreservedAnalyses 7873eca15cbSJustin Bogner DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) { 7883eca15cbSJustin Bogner DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M); 7893eca15cbSJustin Bogner DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M); 790482237e8SJustin Bogner 7913eca15cbSJustin Bogner DBM.print(OS, DRTM, M.getDataLayout()); 792372ddcd1SJustin Bogner return PreservedAnalyses::all(); 793372ddcd1SJustin Bogner } 794372ddcd1SJustin Bogner 7953eca15cbSJustin Bogner void DXILResourceTypeWrapperPass::anchor() {} 7963eca15cbSJustin Bogner 7973eca15cbSJustin Bogner DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) { 7983eca15cbSJustin Bogner initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry()); 799372ddcd1SJustin Bogner } 800372ddcd1SJustin Bogner 8013eca15cbSJustin Bogner INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type", 8023eca15cbSJustin Bogner "DXIL Resource Type Analysis", false, true) 8033eca15cbSJustin Bogner char DXILResourceTypeWrapperPass::ID = 0; 804372ddcd1SJustin Bogner 8053eca15cbSJustin Bogner ModulePass *llvm::createDXILResourceTypeWrapperPassPass() { 8063eca15cbSJustin Bogner return new DXILResourceTypeWrapperPass(); 8073eca15cbSJustin Bogner } 8083eca15cbSJustin Bogner 8093eca15cbSJustin Bogner DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass() 8103eca15cbSJustin Bogner : ModulePass(ID) { 8113eca15cbSJustin Bogner initializeDXILResourceBindingWrapperPassPass( 8123eca15cbSJustin Bogner *PassRegistry::getPassRegistry()); 8133eca15cbSJustin Bogner } 8143eca15cbSJustin Bogner 8153eca15cbSJustin Bogner DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default; 8163eca15cbSJustin Bogner 8173eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 8183eca15cbSJustin Bogner AU.addRequiredTransitive<DXILResourceTypeWrapperPass>(); 819372ddcd1SJustin Bogner AU.setPreservesAll(); 820372ddcd1SJustin Bogner } 821372ddcd1SJustin Bogner 8223eca15cbSJustin Bogner bool DXILResourceBindingWrapperPass::runOnModule(Module &M) { 8233eca15cbSJustin Bogner Map.reset(new DXILBindingMap()); 824482237e8SJustin Bogner 8253eca15cbSJustin Bogner DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); 8263eca15cbSJustin Bogner Map->populate(M, *DRTM); 827482237e8SJustin Bogner 828372ddcd1SJustin Bogner return false; 829372ddcd1SJustin Bogner } 830372ddcd1SJustin Bogner 8313eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::releaseMemory() { Map.reset(); } 832372ddcd1SJustin Bogner 8333eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::print(raw_ostream &OS, 8343eca15cbSJustin Bogner const Module *M) const { 835482237e8SJustin Bogner if (!Map) { 836372ddcd1SJustin Bogner OS << "No resource map has been built!\n"; 837372ddcd1SJustin Bogner return; 838372ddcd1SJustin Bogner } 8393eca15cbSJustin Bogner Map->print(OS, *DRTM, M->getDataLayout()); 840372ddcd1SJustin Bogner } 841372ddcd1SJustin Bogner 842372ddcd1SJustin Bogner #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 843372ddcd1SJustin Bogner LLVM_DUMP_METHOD 8443eca15cbSJustin Bogner void DXILResourceBindingWrapperPass::dump() const { print(dbgs(), nullptr); } 845372ddcd1SJustin Bogner #endif 846372ddcd1SJustin Bogner 8473eca15cbSJustin Bogner INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding", 8483eca15cbSJustin Bogner "DXIL Resource Binding Analysis", false, true) 8493eca15cbSJustin Bogner char DXILResourceBindingWrapperPass::ID = 0; 850372ddcd1SJustin Bogner 8513eca15cbSJustin Bogner ModulePass *llvm::createDXILResourceBindingWrapperPassPass() { 8523eca15cbSJustin Bogner return new DXILResourceBindingWrapperPass(); 853372ddcd1SJustin Bogner } 854