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 9 #include "llvm/Analysis/DXILResource.h" 10 #include "llvm/ADT/APInt.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/SmallString.h" 13 #include "llvm/ADT/SmallVector.h" 14 #include "llvm/IR/Constants.h" 15 #include "llvm/IR/DerivedTypes.h" 16 #include "llvm/IR/DiagnosticInfo.h" 17 #include "llvm/IR/Instructions.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" 22 #include "llvm/InitializePasses.h" 23 #include "llvm/Support/FormatVariadic.h" 24 #include <cstdint> 25 #include <optional> 26 27 #define DEBUG_TYPE "dxil-resource" 28 29 using namespace llvm; 30 using namespace dxil; 31 32 static StringRef getResourceClassName(ResourceClass RC) { 33 switch (RC) { 34 case ResourceClass::SRV: 35 return "SRV"; 36 case ResourceClass::UAV: 37 return "UAV"; 38 case ResourceClass::CBuffer: 39 return "CBuffer"; 40 case ResourceClass::Sampler: 41 return "Sampler"; 42 } 43 llvm_unreachable("Unhandled ResourceClass"); 44 } 45 46 static StringRef getResourceKindName(ResourceKind RK) { 47 switch (RK) { 48 case ResourceKind::Texture1D: 49 return "Texture1D"; 50 case ResourceKind::Texture2D: 51 return "Texture2D"; 52 case ResourceKind::Texture2DMS: 53 return "Texture2DMS"; 54 case ResourceKind::Texture3D: 55 return "Texture3D"; 56 case ResourceKind::TextureCube: 57 return "TextureCube"; 58 case ResourceKind::Texture1DArray: 59 return "Texture1DArray"; 60 case ResourceKind::Texture2DArray: 61 return "Texture2DArray"; 62 case ResourceKind::Texture2DMSArray: 63 return "Texture2DMSArray"; 64 case ResourceKind::TextureCubeArray: 65 return "TextureCubeArray"; 66 case ResourceKind::TypedBuffer: 67 return "Buffer"; 68 case ResourceKind::RawBuffer: 69 return "RawBuffer"; 70 case ResourceKind::StructuredBuffer: 71 return "StructuredBuffer"; 72 case ResourceKind::CBuffer: 73 return "CBuffer"; 74 case ResourceKind::Sampler: 75 return "Sampler"; 76 case ResourceKind::TBuffer: 77 return "TBuffer"; 78 case ResourceKind::RTAccelerationStructure: 79 return "RTAccelerationStructure"; 80 case ResourceKind::FeedbackTexture2D: 81 return "FeedbackTexture2D"; 82 case ResourceKind::FeedbackTexture2DArray: 83 return "FeedbackTexture2DArray"; 84 case ResourceKind::NumEntries: 85 case ResourceKind::Invalid: 86 return "<invalid>"; 87 } 88 llvm_unreachable("Unhandled ResourceKind"); 89 } 90 91 static StringRef getElementTypeName(ElementType ET) { 92 switch (ET) { 93 case ElementType::I1: 94 return "i1"; 95 case ElementType::I16: 96 return "i16"; 97 case ElementType::U16: 98 return "u16"; 99 case ElementType::I32: 100 return "i32"; 101 case ElementType::U32: 102 return "u32"; 103 case ElementType::I64: 104 return "i64"; 105 case ElementType::U64: 106 return "u64"; 107 case ElementType::F16: 108 return "f16"; 109 case ElementType::F32: 110 return "f32"; 111 case ElementType::F64: 112 return "f64"; 113 case ElementType::SNormF16: 114 return "snorm_f16"; 115 case ElementType::UNormF16: 116 return "unorm_f16"; 117 case ElementType::SNormF32: 118 return "snorm_f32"; 119 case ElementType::UNormF32: 120 return "unorm_f32"; 121 case ElementType::SNormF64: 122 return "snorm_f64"; 123 case ElementType::UNormF64: 124 return "unorm_f64"; 125 case ElementType::PackedS8x32: 126 return "p32i8"; 127 case ElementType::PackedU8x32: 128 return "p32u8"; 129 case ElementType::Invalid: 130 return "<invalid>"; 131 } 132 llvm_unreachable("Unhandled ElementType"); 133 } 134 135 static StringRef getElementTypeNameForTemplate(ElementType ET) { 136 switch (ET) { 137 case ElementType::I1: 138 return "bool"; 139 case ElementType::I16: 140 return "int16_t"; 141 case ElementType::U16: 142 return "uint16_t"; 143 case ElementType::I32: 144 return "int32_t"; 145 case ElementType::U32: 146 return "uint32_t"; 147 case ElementType::I64: 148 return "int64_t"; 149 case ElementType::U64: 150 return "uint32_t"; 151 case ElementType::F16: 152 case ElementType::SNormF16: 153 case ElementType::UNormF16: 154 return "half"; 155 case ElementType::F32: 156 case ElementType::SNormF32: 157 case ElementType::UNormF32: 158 return "float"; 159 case ElementType::F64: 160 case ElementType::SNormF64: 161 case ElementType::UNormF64: 162 return "double"; 163 case ElementType::PackedS8x32: 164 return "int8_t4_packed"; 165 case ElementType::PackedU8x32: 166 return "uint8_t4_packed"; 167 case ElementType::Invalid: 168 return "<invalid>"; 169 } 170 llvm_unreachable("Unhandled ElementType"); 171 } 172 173 static StringRef getSamplerTypeName(SamplerType ST) { 174 switch (ST) { 175 case SamplerType::Default: 176 return "Default"; 177 case SamplerType::Comparison: 178 return "Comparison"; 179 case SamplerType::Mono: 180 return "Mono"; 181 } 182 llvm_unreachable("Unhandled SamplerType"); 183 } 184 185 static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) { 186 switch (SFT) { 187 case SamplerFeedbackType::MinMip: 188 return "MinMip"; 189 case SamplerFeedbackType::MipRegionUsed: 190 return "MipRegionUsed"; 191 } 192 llvm_unreachable("Unhandled SamplerFeedbackType"); 193 } 194 195 static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) { 196 // TODO: Handle unorm, snorm, and packed. 197 Ty = Ty->getScalarType(); 198 199 if (Ty->isIntegerTy()) { 200 switch (Ty->getIntegerBitWidth()) { 201 case 16: 202 return IsSigned ? ElementType::I16 : ElementType::U16; 203 case 32: 204 return IsSigned ? ElementType::I32 : ElementType::U32; 205 case 64: 206 return IsSigned ? ElementType::I64 : ElementType::U64; 207 case 1: 208 default: 209 return ElementType::Invalid; 210 } 211 } else if (Ty->isFloatTy()) { 212 return ElementType::F32; 213 } else if (Ty->isDoubleTy()) { 214 return ElementType::F64; 215 } else if (Ty->isHalfTy()) { 216 return ElementType::F16; 217 } 218 219 return ElementType::Invalid; 220 } 221 222 ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy, 223 const dxil::ResourceClass RC_, 224 const dxil::ResourceKind Kind_) 225 : HandleTy(HandleTy) { 226 // If we're provided a resource class and kind, trust them. 227 if (Kind_ != dxil::ResourceKind::Invalid) { 228 RC = RC_; 229 Kind = Kind_; 230 return; 231 } 232 233 if (auto *Ty = dyn_cast<RawBufferExtType>(HandleTy)) { 234 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 235 Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer 236 : ResourceKind::RawBuffer; 237 } else if (auto *Ty = dyn_cast<TypedBufferExtType>(HandleTy)) { 238 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 239 Kind = ResourceKind::TypedBuffer; 240 } else if (auto *Ty = dyn_cast<TextureExtType>(HandleTy)) { 241 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 242 Kind = Ty->getDimension(); 243 } else if (auto *Ty = dyn_cast<MSTextureExtType>(HandleTy)) { 244 RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; 245 Kind = Ty->getDimension(); 246 } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(HandleTy)) { 247 RC = ResourceClass::UAV; 248 Kind = Ty->getDimension(); 249 } else if (isa<CBufferExtType>(HandleTy)) { 250 RC = ResourceClass::CBuffer; 251 Kind = ResourceKind::CBuffer; 252 } else if (isa<SamplerExtType>(HandleTy)) { 253 RC = ResourceClass::Sampler; 254 Kind = ResourceKind::Sampler; 255 } else 256 llvm_unreachable("Unknown handle type"); 257 } 258 259 static void formatTypeName(SmallString<64> &Dest, StringRef Name, 260 bool IsWriteable, bool IsROV, 261 Type *ContainedType = nullptr, 262 bool IsSigned = true) { 263 raw_svector_ostream DestStream(Dest); 264 if (IsWriteable) 265 DestStream << (IsROV ? "RasterizerOrdered" : "RW"); 266 DestStream << Name; 267 268 if (!ContainedType) 269 return; 270 271 StringRef ElementName; 272 ElementType ET = toDXILElementType(ContainedType, IsSigned); 273 if (ET != ElementType::Invalid) { 274 ElementName = getElementTypeNameForTemplate(ET); 275 } else { 276 assert(isa<StructType>(ContainedType) && 277 "invalid element type for raw buffer"); 278 StructType *ST = cast<StructType>(ContainedType); 279 if (!ST->hasName()) 280 return; 281 ElementName = ST->getStructName(); 282 } 283 284 DestStream << "<" << ElementName; 285 if (const FixedVectorType *VTy = dyn_cast<FixedVectorType>(ContainedType)) 286 DestStream << VTy->getNumElements(); 287 DestStream << ">"; 288 } 289 290 static StructType *getOrCreateElementStruct(Type *ElemType, StringRef Name) { 291 StructType *Ty = StructType::getTypeByName(ElemType->getContext(), Name); 292 if (Ty && Ty->getNumElements() == 1 && Ty->getElementType(0) == ElemType) 293 return Ty; 294 return StructType::create(ElemType, Name); 295 } 296 297 StructType *ResourceTypeInfo::createElementStruct(StringRef CBufferName) { 298 SmallString<64> TypeName; 299 300 switch (Kind) { 301 case ResourceKind::Texture1D: 302 case ResourceKind::Texture2D: 303 case ResourceKind::Texture3D: 304 case ResourceKind::TextureCube: 305 case ResourceKind::Texture1DArray: 306 case ResourceKind::Texture2DArray: 307 case ResourceKind::TextureCubeArray: { 308 auto *RTy = cast<TextureExtType>(HandleTy); 309 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 310 RTy->isROV(), RTy->getResourceType(), RTy->isSigned()); 311 return getOrCreateElementStruct(RTy->getResourceType(), TypeName); 312 } 313 case ResourceKind::Texture2DMS: 314 case ResourceKind::Texture2DMSArray: { 315 auto *RTy = cast<MSTextureExtType>(HandleTy); 316 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 317 /*IsROV=*/false, RTy->getResourceType(), RTy->isSigned()); 318 return getOrCreateElementStruct(RTy->getResourceType(), TypeName); 319 } 320 case ResourceKind::TypedBuffer: { 321 auto *RTy = cast<TypedBufferExtType>(HandleTy); 322 formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(), 323 RTy->isROV(), RTy->getResourceType(), RTy->isSigned()); 324 return getOrCreateElementStruct(RTy->getResourceType(), TypeName); 325 } 326 case ResourceKind::RawBuffer: { 327 auto *RTy = cast<RawBufferExtType>(HandleTy); 328 formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(), 329 RTy->isROV()); 330 return getOrCreateElementStruct(Type::getInt32Ty(HandleTy->getContext()), 331 TypeName); 332 } 333 case ResourceKind::StructuredBuffer: { 334 auto *RTy = cast<RawBufferExtType>(HandleTy); 335 Type *Ty = RTy->getResourceType(); 336 formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(), 337 RTy->isROV(), RTy->getResourceType(), true); 338 return getOrCreateElementStruct(Ty, TypeName); 339 } 340 case ResourceKind::FeedbackTexture2D: 341 case ResourceKind::FeedbackTexture2DArray: { 342 auto *RTy = cast<FeedbackTextureExtType>(HandleTy); 343 TypeName = formatv("{0}<{1}>", getResourceKindName(Kind), 344 llvm::to_underlying(RTy->getFeedbackType())); 345 return getOrCreateElementStruct(Type::getInt32Ty(HandleTy->getContext()), 346 TypeName); 347 } 348 case ResourceKind::CBuffer: { 349 auto *RTy = cast<CBufferExtType>(HandleTy); 350 LayoutExtType *LayoutType = cast<LayoutExtType>(RTy->getResourceType()); 351 StructType *Ty = cast<StructType>(LayoutType->getWrappedType()); 352 SmallString<64> Name = getResourceKindName(Kind); 353 if (!CBufferName.empty()) { 354 Name.append("."); 355 Name.append(CBufferName); 356 } 357 return StructType::create(Ty->elements(), Name); 358 } 359 case ResourceKind::Sampler: { 360 auto *RTy = cast<SamplerExtType>(HandleTy); 361 TypeName = formatv("SamplerState<{0}>", 362 llvm::to_underlying(RTy->getSamplerType())); 363 return getOrCreateElementStruct(Type::getInt32Ty(HandleTy->getContext()), 364 TypeName); 365 } 366 case ResourceKind::TBuffer: 367 case ResourceKind::RTAccelerationStructure: 368 llvm_unreachable("Unhandled resource kind"); 369 case ResourceKind::Invalid: 370 case ResourceKind::NumEntries: 371 llvm_unreachable("Invalid resource kind"); 372 } 373 llvm_unreachable("Unhandled ResourceKind enum"); 374 } 375 376 bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; } 377 378 bool ResourceTypeInfo::isCBuffer() const { 379 return RC == ResourceClass::CBuffer; 380 } 381 382 bool ResourceTypeInfo::isSampler() const { 383 return RC == ResourceClass::Sampler; 384 } 385 386 bool ResourceTypeInfo::isStruct() const { 387 return Kind == ResourceKind::StructuredBuffer; 388 } 389 390 bool ResourceTypeInfo::isTyped() const { 391 switch (Kind) { 392 case ResourceKind::Texture1D: 393 case ResourceKind::Texture2D: 394 case ResourceKind::Texture2DMS: 395 case ResourceKind::Texture3D: 396 case ResourceKind::TextureCube: 397 case ResourceKind::Texture1DArray: 398 case ResourceKind::Texture2DArray: 399 case ResourceKind::Texture2DMSArray: 400 case ResourceKind::TextureCubeArray: 401 case ResourceKind::TypedBuffer: 402 return true; 403 case ResourceKind::RawBuffer: 404 case ResourceKind::StructuredBuffer: 405 case ResourceKind::FeedbackTexture2D: 406 case ResourceKind::FeedbackTexture2DArray: 407 case ResourceKind::CBuffer: 408 case ResourceKind::Sampler: 409 case ResourceKind::TBuffer: 410 case ResourceKind::RTAccelerationStructure: 411 return false; 412 case ResourceKind::Invalid: 413 case ResourceKind::NumEntries: 414 llvm_unreachable("Invalid resource kind"); 415 } 416 llvm_unreachable("Unhandled ResourceKind enum"); 417 } 418 419 bool ResourceTypeInfo::isFeedback() const { 420 return Kind == ResourceKind::FeedbackTexture2D || 421 Kind == ResourceKind::FeedbackTexture2DArray; 422 } 423 424 bool ResourceTypeInfo::isMultiSample() const { 425 return Kind == ResourceKind::Texture2DMS || 426 Kind == ResourceKind::Texture2DMSArray; 427 } 428 429 static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) { 430 switch (Kind) { 431 case ResourceKind::Texture1D: 432 case ResourceKind::Texture2D: 433 case ResourceKind::Texture3D: 434 case ResourceKind::TextureCube: 435 case ResourceKind::Texture1DArray: 436 case ResourceKind::Texture2DArray: 437 case ResourceKind::TextureCubeArray: 438 return cast<TextureExtType>(Ty)->isROV(); 439 case ResourceKind::TypedBuffer: 440 return cast<TypedBufferExtType>(Ty)->isROV(); 441 case ResourceKind::RawBuffer: 442 case ResourceKind::StructuredBuffer: 443 return cast<RawBufferExtType>(Ty)->isROV(); 444 case ResourceKind::Texture2DMS: 445 case ResourceKind::Texture2DMSArray: 446 case ResourceKind::FeedbackTexture2D: 447 case ResourceKind::FeedbackTexture2DArray: 448 return false; 449 case ResourceKind::CBuffer: 450 case ResourceKind::Sampler: 451 case ResourceKind::TBuffer: 452 case ResourceKind::RTAccelerationStructure: 453 case ResourceKind::Invalid: 454 case ResourceKind::NumEntries: 455 llvm_unreachable("Resource cannot be ROV"); 456 } 457 llvm_unreachable("Unhandled ResourceKind enum"); 458 } 459 460 ResourceTypeInfo::UAVInfo ResourceTypeInfo::getUAV() const { 461 assert(isUAV() && "Not a UAV"); 462 return {isROV(Kind, HandleTy)}; 463 } 464 465 uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const { 466 assert(isCBuffer() && "Not a CBuffer"); 467 468 Type *ElTy = cast<CBufferExtType>(HandleTy)->getResourceType(); 469 470 if (auto *LayoutTy = dyn_cast<LayoutExtType>(ElTy)) 471 return LayoutTy->getSize(); 472 473 // TODO: What should we do with unannotated arrays? 474 return DL.getTypeAllocSize(ElTy); 475 } 476 477 dxil::SamplerType ResourceTypeInfo::getSamplerType() const { 478 assert(isSampler() && "Not a Sampler"); 479 return cast<SamplerExtType>(HandleTy)->getSamplerType(); 480 } 481 482 ResourceTypeInfo::StructInfo 483 ResourceTypeInfo::getStruct(const DataLayout &DL) const { 484 assert(isStruct() && "Not a Struct"); 485 486 Type *ElTy = cast<RawBufferExtType>(HandleTy)->getResourceType(); 487 488 uint32_t Stride = DL.getTypeAllocSize(ElTy); 489 MaybeAlign Alignment; 490 if (auto *STy = dyn_cast<StructType>(ElTy)) 491 Alignment = DL.getStructLayout(STy)->getAlignment(); 492 uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0; 493 return {Stride, AlignLog2}; 494 } 495 496 static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind, 497 TargetExtType *Ty) { 498 switch (Kind) { 499 case ResourceKind::Texture1D: 500 case ResourceKind::Texture2D: 501 case ResourceKind::Texture3D: 502 case ResourceKind::TextureCube: 503 case ResourceKind::Texture1DArray: 504 case ResourceKind::Texture2DArray: 505 case ResourceKind::TextureCubeArray: { 506 auto *RTy = cast<TextureExtType>(Ty); 507 return {RTy->getResourceType(), RTy->isSigned()}; 508 } 509 case ResourceKind::Texture2DMS: 510 case ResourceKind::Texture2DMSArray: { 511 auto *RTy = cast<MSTextureExtType>(Ty); 512 return {RTy->getResourceType(), RTy->isSigned()}; 513 } 514 case ResourceKind::TypedBuffer: { 515 auto *RTy = cast<TypedBufferExtType>(Ty); 516 return {RTy->getResourceType(), RTy->isSigned()}; 517 } 518 case ResourceKind::RawBuffer: 519 case ResourceKind::StructuredBuffer: 520 case ResourceKind::FeedbackTexture2D: 521 case ResourceKind::FeedbackTexture2DArray: 522 case ResourceKind::CBuffer: 523 case ResourceKind::Sampler: 524 case ResourceKind::TBuffer: 525 case ResourceKind::RTAccelerationStructure: 526 case ResourceKind::Invalid: 527 case ResourceKind::NumEntries: 528 llvm_unreachable("Resource is not typed"); 529 } 530 llvm_unreachable("Unhandled ResourceKind enum"); 531 } 532 533 ResourceTypeInfo::TypedInfo ResourceTypeInfo::getTyped() const { 534 assert(isTyped() && "Not typed"); 535 536 auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy); 537 dxil::ElementType ET = toDXILElementType(ElTy, IsSigned); 538 uint32_t Count = 1; 539 if (auto *VTy = dyn_cast<FixedVectorType>(ElTy)) 540 Count = VTy->getNumElements(); 541 return {ET, Count}; 542 } 543 544 dxil::SamplerFeedbackType ResourceTypeInfo::getFeedbackType() const { 545 assert(isFeedback() && "Not Feedback"); 546 return cast<FeedbackTextureExtType>(HandleTy)->getFeedbackType(); 547 } 548 uint32_t ResourceTypeInfo::getMultiSampleCount() const { 549 assert(isMultiSample() && "Not MultiSampled"); 550 return cast<MSTextureExtType>(HandleTy)->getSampleCount(); 551 } 552 553 bool ResourceTypeInfo::operator==(const ResourceTypeInfo &RHS) const { 554 return HandleTy == RHS.HandleTy; 555 } 556 557 bool ResourceTypeInfo::operator<(const ResourceTypeInfo &RHS) const { 558 // An empty datalayout is sufficient for sorting purposes. 559 DataLayout DummyDL; 560 if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind)) 561 return true; 562 if (isCBuffer() && RHS.isCBuffer() && 563 getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL)) 564 return true; 565 if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType()) 566 return true; 567 if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV()) 568 return true; 569 if (isStruct() && RHS.isStruct() && 570 getStruct(DummyDL) < RHS.getStruct(DummyDL)) 571 return true; 572 if (isFeedback() && RHS.isFeedback() && 573 getFeedbackType() < RHS.getFeedbackType()) 574 return true; 575 if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped()) 576 return true; 577 if (isMultiSample() && RHS.isMultiSample() && 578 getMultiSampleCount() < RHS.getMultiSampleCount()) 579 return true; 580 return false; 581 } 582 583 void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const { 584 OS << " Class: " << getResourceClassName(RC) << "\n" 585 << " Kind: " << getResourceKindName(Kind) << "\n"; 586 587 if (isCBuffer()) { 588 OS << " CBuffer size: " << getCBufferSize(DL) << "\n"; 589 } else if (isSampler()) { 590 OS << " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n"; 591 } else { 592 if (isUAV()) { 593 UAVInfo UAVFlags = getUAV(); 594 OS << " IsROV: " << UAVFlags.IsROV << "\n"; 595 } 596 if (isMultiSample()) 597 OS << " Sample Count: " << getMultiSampleCount() << "\n"; 598 599 if (isStruct()) { 600 StructInfo Struct = getStruct(DL); 601 OS << " Buffer Stride: " << Struct.Stride << "\n"; 602 OS << " Alignment: " << Struct.AlignLog2 << "\n"; 603 } else if (isTyped()) { 604 TypedInfo Typed = getTyped(); 605 OS << " Element Type: " << getElementTypeName(Typed.ElementTy) << "\n" 606 << " Element Count: " << Typed.ElementCount << "\n"; 607 } else if (isFeedback()) 608 OS << " Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType()) 609 << "\n"; 610 } 611 } 612 613 GlobalVariable *ResourceInfo::createSymbol(Module &M, StructType *Ty) { 614 assert(!Symbol && "Symbol has already been created"); 615 Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true, 616 GlobalValue::ExternalLinkage, 617 /*Initializer=*/nullptr, Name); 618 return Symbol; 619 } 620 621 MDTuple *ResourceInfo::getAsMetadata(Module &M, 622 dxil::ResourceTypeInfo &RTI) const { 623 LLVMContext &Ctx = M.getContext(); 624 const DataLayout &DL = M.getDataLayout(); 625 626 SmallVector<Metadata *, 11> MDVals; 627 628 Type *I32Ty = Type::getInt32Ty(Ctx); 629 Type *I1Ty = Type::getInt1Ty(Ctx); 630 auto getIntMD = [&I32Ty](uint32_t V) { 631 return ConstantAsMetadata::get( 632 Constant::getIntegerValue(I32Ty, APInt(32, V))); 633 }; 634 auto getBoolMD = [&I1Ty](uint32_t V) { 635 return ConstantAsMetadata::get( 636 Constant::getIntegerValue(I1Ty, APInt(1, V))); 637 }; 638 639 MDVals.push_back(getIntMD(Binding.RecordID)); 640 assert(Symbol && "Cannot yet create useful resource metadata without symbol"); 641 MDVals.push_back(ValueAsMetadata::get(Symbol)); 642 MDVals.push_back(MDString::get(Ctx, Name)); 643 MDVals.push_back(getIntMD(Binding.Space)); 644 MDVals.push_back(getIntMD(Binding.LowerBound)); 645 MDVals.push_back(getIntMD(Binding.Size)); 646 647 if (RTI.isCBuffer()) { 648 MDVals.push_back(getIntMD(RTI.getCBufferSize(DL))); 649 MDVals.push_back(nullptr); 650 } else if (RTI.isSampler()) { 651 MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getSamplerType()))); 652 MDVals.push_back(nullptr); 653 } else { 654 MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind()))); 655 656 if (RTI.isUAV()) { 657 ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV(); 658 MDVals.push_back(getBoolMD(GloballyCoherent)); 659 MDVals.push_back(getBoolMD(hasCounter())); 660 MDVals.push_back(getBoolMD(UAVFlags.IsROV)); 661 } else { 662 // All SRVs include sample count in the metadata, but it's only meaningful 663 // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+, 664 // but this just isn't reflected in the metadata at all. 665 uint32_t SampleCount = 666 RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0; 667 MDVals.push_back(getIntMD(SampleCount)); 668 } 669 670 // Further properties are attached to a metadata list of tag-value pairs. 671 SmallVector<Metadata *> Tags; 672 if (RTI.isStruct()) { 673 Tags.push_back( 674 getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride))); 675 Tags.push_back(getIntMD(RTI.getStruct(DL).Stride)); 676 } else if (RTI.isTyped()) { 677 Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType))); 678 Tags.push_back(getIntMD(llvm::to_underlying(RTI.getTyped().ElementTy))); 679 } else if (RTI.isFeedback()) { 680 Tags.push_back( 681 getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind))); 682 Tags.push_back(getIntMD(llvm::to_underlying(RTI.getFeedbackType()))); 683 } 684 MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags)); 685 } 686 687 return MDNode::get(Ctx, MDVals); 688 } 689 690 std::pair<uint32_t, uint32_t> 691 ResourceInfo::getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const { 692 const DataLayout &DL = M.getDataLayout(); 693 694 uint32_t ResourceKind = llvm::to_underlying(RTI.getResourceKind()); 695 uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0; 696 bool IsUAV = RTI.isUAV(); 697 ResourceTypeInfo::UAVInfo UAVFlags = 698 IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{}; 699 bool IsROV = IsUAV && UAVFlags.IsROV; 700 bool IsGloballyCoherent = IsUAV && GloballyCoherent; 701 uint8_t SamplerCmpOrHasCounter = 0; 702 if (IsUAV) 703 SamplerCmpOrHasCounter = hasCounter(); 704 else if (RTI.isSampler()) 705 SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison; 706 707 // TODO: Document this format. Currently the only reference is the 708 // implementation of dxc's DxilResourceProperties struct. 709 uint32_t Word0 = 0; 710 Word0 |= ResourceKind & 0xFF; 711 Word0 |= (AlignLog2 & 0xF) << 8; 712 Word0 |= (IsUAV & 1) << 12; 713 Word0 |= (IsROV & 1) << 13; 714 Word0 |= (IsGloballyCoherent & 1) << 14; 715 Word0 |= (SamplerCmpOrHasCounter & 1) << 15; 716 717 uint32_t Word1 = 0; 718 if (RTI.isStruct()) 719 Word1 = RTI.getStruct(DL).Stride; 720 else if (RTI.isCBuffer()) 721 Word1 = RTI.getCBufferSize(DL); 722 else if (RTI.isFeedback()) 723 Word1 = llvm::to_underlying(RTI.getFeedbackType()); 724 else if (RTI.isTyped()) { 725 ResourceTypeInfo::TypedInfo Typed = RTI.getTyped(); 726 uint32_t CompType = llvm::to_underlying(Typed.ElementTy); 727 uint32_t CompCount = Typed.ElementCount; 728 uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0; 729 730 Word1 |= (CompType & 0xFF) << 0; 731 Word1 |= (CompCount & 0xFF) << 8; 732 Word1 |= (SampleCount & 0xFF) << 16; 733 } 734 735 return {Word0, Word1}; 736 } 737 738 void ResourceInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI, 739 const DataLayout &DL) const { 740 if (!Name.empty()) 741 OS << " Name: " << Name << "\n"; 742 743 if (Symbol) { 744 OS << " Symbol: "; 745 Symbol->printAsOperand(OS); 746 OS << "\n"; 747 } 748 749 OS << " Binding:\n" 750 << " Record ID: " << Binding.RecordID << "\n" 751 << " Space: " << Binding.Space << "\n" 752 << " Lower Bound: " << Binding.LowerBound << "\n" 753 << " Size: " << Binding.Size << "\n"; 754 755 OS << " Globally Coherent: " << GloballyCoherent << "\n"; 756 OS << " Counter Direction: "; 757 758 switch (CounterDirection) { 759 case ResourceCounterDirection::Increment: 760 OS << "Increment\n"; 761 break; 762 case ResourceCounterDirection::Decrement: 763 OS << "Decrement\n"; 764 break; 765 case ResourceCounterDirection::Unknown: 766 OS << "Unknown\n"; 767 break; 768 case ResourceCounterDirection::Invalid: 769 OS << "Invalid\n"; 770 break; 771 } 772 773 RTI.print(OS, DL); 774 } 775 776 //===----------------------------------------------------------------------===// 777 778 bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA, 779 ModuleAnalysisManager::Invalidator &Inv) { 780 // Passes that introduce resource types must explicitly invalidate this pass. 781 auto PAC = PA.getChecker<DXILResourceTypeAnalysis>(); 782 return !PAC.preservedWhenStateless(); 783 } 784 785 //===----------------------------------------------------------------------===// 786 static bool isUpdateCounterIntrinsic(Function &F) { 787 return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter; 788 } 789 790 StringRef dxil::getResourceNameFromBindingCall(CallInst *CI) { 791 Value *Op = nullptr; 792 switch (CI->getCalledFunction()->getIntrinsicID()) { 793 default: 794 llvm_unreachable("unexpected handle creation intrinsic"); 795 case Intrinsic::dx_resource_handlefrombinding: 796 case Intrinsic::dx_resource_handlefromimplicitbinding: 797 Op = CI->getArgOperand(5); 798 break; 799 } 800 801 auto *GV = dyn_cast<llvm::GlobalVariable>(Op); 802 if (!GV) 803 return ""; 804 805 auto *CA = dyn_cast<ConstantDataArray>(GV->getInitializer()); 806 assert(CA && CA->isString() && "expected constant string"); 807 StringRef Name = CA->getAsString(); 808 // strip trailing 0 809 if (Name.ends_with('\0')) 810 Name = Name.drop_back(1); 811 return Name; 812 } 813 814 void DXILResourceMap::populateResourceInfos(Module &M, 815 DXILResourceTypeMap &DRTM) { 816 SmallVector<std::tuple<CallInst *, ResourceInfo, ResourceTypeInfo>> CIToInfos; 817 818 for (Function &F : M.functions()) { 819 if (!F.isDeclaration()) 820 continue; 821 LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); 822 Intrinsic::ID ID = F.getIntrinsicID(); 823 switch (ID) { 824 default: 825 continue; 826 case Intrinsic::dx_resource_handlefrombinding: { 827 auto *HandleTy = cast<TargetExtType>(F.getReturnType()); 828 ResourceTypeInfo &RTI = DRTM[HandleTy]; 829 830 for (User *U : F.users()) 831 if (CallInst *CI = dyn_cast<CallInst>(U)) { 832 LLVM_DEBUG(dbgs() << " Visiting: " << *U << "\n"); 833 uint32_t Space = 834 cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(); 835 uint32_t LowerBound = 836 cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 837 uint32_t Size = 838 cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 839 StringRef Name = getResourceNameFromBindingCall(CI); 840 841 ResourceInfo RI = 842 ResourceInfo{/*RecordID=*/0, Space, LowerBound, 843 Size, HandleTy, Name}; 844 845 CIToInfos.emplace_back(CI, RI, RTI); 846 } 847 848 break; 849 } 850 } 851 } 852 853 llvm::stable_sort(CIToInfos, [](auto &LHS, auto &RHS) { 854 const auto &[LCI, LRI, LRTI] = LHS; 855 const auto &[RCI, RRI, RRTI] = RHS; 856 // Sort by resource class first for grouping purposes, and then by the 857 // binding and type so we can remove duplicates. 858 ResourceClass LRC = LRTI.getResourceClass(); 859 ResourceClass RRC = RRTI.getResourceClass(); 860 861 return std::tie(LRC, LRI, LRTI) < std::tie(RRC, RRI, RRTI); 862 }); 863 for (auto [CI, RI, RTI] : CIToInfos) { 864 if (Infos.empty() || RI != Infos.back()) 865 Infos.push_back(RI); 866 CallMap[CI] = Infos.size() - 1; 867 } 868 869 unsigned Size = Infos.size(); 870 // In DXC, Record ID is unique per resource type. Match that. 871 FirstUAV = FirstCBuffer = FirstSampler = Size; 872 uint32_t NextID = 0; 873 for (unsigned I = 0, E = Size; I != E; ++I) { 874 ResourceInfo &RI = Infos[I]; 875 ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()]; 876 if (RTI.isUAV() && FirstUAV == Size) { 877 FirstUAV = I; 878 NextID = 0; 879 } else if (RTI.isCBuffer() && FirstCBuffer == Size) { 880 FirstCBuffer = I; 881 NextID = 0; 882 } else if (RTI.isSampler() && FirstSampler == Size) { 883 FirstSampler = I; 884 NextID = 0; 885 } 886 887 // We need to make sure the types of resource are ordered even if some are 888 // missing. 889 FirstCBuffer = std::min({FirstCBuffer, FirstSampler}); 890 FirstUAV = std::min({FirstUAV, FirstCBuffer}); 891 892 // Adjust the resource binding to use the next ID. 893 RI.setBindingID(NextID++); 894 } 895 } 896 897 void DXILResourceMap::populateCounterDirections(Module &M) { 898 for (Function &F : M.functions()) { 899 if (!isUpdateCounterIntrinsic(F)) 900 continue; 901 902 LLVM_DEBUG(dbgs() << "Update Counter Function: " << F.getName() << "\n"); 903 904 for (const User *U : F.users()) { 905 const CallInst *CI = dyn_cast<CallInst>(U); 906 assert(CI && "Users of dx_resource_updateCounter must be call instrs"); 907 908 // Determine if the use is an increment or decrement 909 Value *CountArg = CI->getArgOperand(1); 910 ConstantInt *CountValue = cast<ConstantInt>(CountArg); 911 int64_t CountLiteral = CountValue->getSExtValue(); 912 913 // 0 is an unknown direction and shouldn't result in an insert 914 if (CountLiteral == 0) 915 continue; 916 917 ResourceCounterDirection Direction = ResourceCounterDirection::Decrement; 918 if (CountLiteral > 0) 919 Direction = ResourceCounterDirection::Increment; 920 921 // Collect all potential creation points for the handle arg 922 Value *HandleArg = CI->getArgOperand(0); 923 SmallVector<ResourceInfo *> RBInfos = findByUse(HandleArg); 924 for (ResourceInfo *RBInfo : RBInfos) { 925 if (RBInfo->CounterDirection == ResourceCounterDirection::Unknown) 926 RBInfo->CounterDirection = Direction; 927 else if (RBInfo->CounterDirection != Direction) { 928 RBInfo->CounterDirection = ResourceCounterDirection::Invalid; 929 HasInvalidDirection = true; 930 } 931 } 932 } 933 } 934 } 935 936 void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) { 937 populateResourceInfos(M, DRTM); 938 populateCounterDirections(M); 939 } 940 941 void DXILResourceMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM, 942 const DataLayout &DL) const { 943 for (unsigned I = 0, E = Infos.size(); I != E; ++I) { 944 OS << "Resource " << I << ":\n"; 945 const dxil::ResourceInfo &RI = Infos[I]; 946 RI.print(OS, DRTM[RI.getHandleTy()], DL); 947 OS << "\n"; 948 } 949 950 for (const auto &[CI, Index] : CallMap) { 951 OS << "Call bound to " << Index << ":"; 952 CI->print(OS); 953 OS << "\n"; 954 } 955 } 956 957 SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) { 958 if (const PHINode *Phi = dyn_cast<PHINode>(Key)) { 959 SmallVector<dxil::ResourceInfo *> Children; 960 for (const Value *V : Phi->operands()) { 961 Children.append(findByUse(V)); 962 } 963 return Children; 964 } 965 966 const CallInst *CI = dyn_cast<CallInst>(Key); 967 if (!CI) 968 return {}; 969 970 switch (CI->getIntrinsicID()) { 971 // Found the create, return the binding 972 case Intrinsic::dx_resource_handlefrombinding: { 973 auto Pos = CallMap.find(CI); 974 assert(Pos != CallMap.end() && "HandleFromBinding must be in resource map"); 975 return {&Infos[Pos->second]}; 976 } 977 default: 978 break; 979 } 980 981 // Check if any of the parameters are the resource we are following. If so 982 // keep searching. If none of them are return an empty list 983 const Type *UseType = CI->getType(); 984 SmallVector<dxil::ResourceInfo *> Children; 985 for (const Value *V : CI->args()) { 986 if (V->getType() != UseType) 987 continue; 988 989 Children.append(findByUse(V)); 990 } 991 992 return Children; 993 } 994 995 //===----------------------------------------------------------------------===// 996 997 void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) { 998 struct Binding { 999 ResourceClass RC; 1000 uint32_t Space; 1001 uint32_t LowerBound; 1002 uint32_t UpperBound; 1003 Value *Name; 1004 Binding(ResourceClass RC, uint32_t Space, uint32_t LowerBound, 1005 uint32_t UpperBound, Value *Name) 1006 : RC(RC), Space(Space), LowerBound(LowerBound), UpperBound(UpperBound), 1007 Name(Name) {} 1008 }; 1009 SmallVector<Binding> Bindings; 1010 1011 // collect all of the llvm.dx.resource.handlefrombinding calls; 1012 // make a note if there is llvm.dx.resource.handlefromimplicitbinding 1013 for (Function &F : M.functions()) { 1014 if (!F.isDeclaration()) 1015 continue; 1016 1017 switch (F.getIntrinsicID()) { 1018 default: 1019 continue; 1020 case Intrinsic::dx_resource_handlefrombinding: { 1021 auto *HandleTy = cast<TargetExtType>(F.getReturnType()); 1022 ResourceTypeInfo &RTI = DRTM[HandleTy]; 1023 1024 for (User *U : F.users()) 1025 if (CallInst *CI = dyn_cast<CallInst>(U)) { 1026 uint32_t Space = 1027 cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(); 1028 uint32_t LowerBound = 1029 cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 1030 int32_t Size = 1031 cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 1032 Value *Name = CI->getArgOperand(5); 1033 1034 // negative size means unbounded resource array; 1035 // upper bound register overflow should be detected in Sema 1036 assert((Size < 0 || (unsigned)LowerBound + Size - 1 <= UINT32_MAX) && 1037 "upper bound register overflow"); 1038 uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1; 1039 Bindings.emplace_back(RTI.getResourceClass(), Space, LowerBound, 1040 UpperBound, Name); 1041 } 1042 break; 1043 } 1044 case Intrinsic::dx_resource_handlefromimplicitbinding: { 1045 ImplicitBinding = true; 1046 break; 1047 } 1048 } 1049 } 1050 1051 // sort all the collected bindings 1052 llvm::stable_sort(Bindings, [](auto &LHS, auto &RHS) { 1053 return std::tie(LHS.RC, LHS.Space, LHS.LowerBound) < 1054 std::tie(RHS.RC, RHS.Space, RHS.LowerBound); 1055 }); 1056 1057 // remove duplicates 1058 Binding *NewEnd = llvm::unique(Bindings, [](auto &LHS, auto &RHS) { 1059 return std::tie(LHS.RC, LHS.Space, LHS.LowerBound, LHS.UpperBound, 1060 LHS.Name) == std::tie(RHS.RC, RHS.Space, RHS.LowerBound, 1061 RHS.UpperBound, RHS.Name); 1062 }); 1063 if (NewEnd != Bindings.end()) 1064 Bindings.erase(NewEnd); 1065 1066 // Go over the sorted bindings and build up lists of free register ranges 1067 // for each binding type and used spaces. Bindings are sorted by resource 1068 // class, space, and lower bound register slot. 1069 BindingSpaces *BS = &SRVSpaces; 1070 for (const Binding &B : Bindings) { 1071 if (BS->RC != B.RC) 1072 // move to the next resource class spaces 1073 BS = &getBindingSpaces(B.RC); 1074 1075 RegisterSpace *S = BS->Spaces.empty() ? &BS->Spaces.emplace_back(B.Space) 1076 : &BS->Spaces.back(); 1077 assert(S->Space <= B.Space && "bindings not sorted correctly?"); 1078 if (B.Space != S->Space) 1079 // add new space 1080 S = &BS->Spaces.emplace_back(B.Space); 1081 1082 // the space is full - set flag to report overlapping binding later 1083 if (S->FreeRanges.empty()) { 1084 OverlappingBinding = true; 1085 continue; 1086 } 1087 1088 // adjust the last free range lower bound, split it in two, or remove it 1089 BindingRange &LastFreeRange = S->FreeRanges.back(); 1090 assert(LastFreeRange.UpperBound == UINT32_MAX); 1091 if (LastFreeRange.LowerBound == B.LowerBound) { 1092 if (B.UpperBound < UINT32_MAX) 1093 LastFreeRange.LowerBound = B.UpperBound + 1; 1094 else 1095 S->FreeRanges.pop_back(); 1096 } else if (LastFreeRange.LowerBound < B.LowerBound) { 1097 LastFreeRange.UpperBound = B.LowerBound - 1; 1098 if (B.UpperBound < UINT32_MAX) 1099 S->FreeRanges.emplace_back(B.UpperBound + 1, UINT32_MAX); 1100 } else { 1101 OverlappingBinding = true; 1102 if (B.UpperBound < UINT32_MAX) 1103 LastFreeRange.LowerBound = 1104 std::max(LastFreeRange.LowerBound, B.UpperBound + 1); 1105 else 1106 S->FreeRanges.pop_back(); 1107 } 1108 } 1109 } 1110 1111 // returns std::nulopt if binding could not be found in given space 1112 std::optional<uint32_t> 1113 DXILResourceBindingInfo::findAvailableBinding(dxil::ResourceClass RC, 1114 uint32_t Space, int32_t Size) { 1115 BindingSpaces &BS = getBindingSpaces(RC); 1116 RegisterSpace &RS = BS.getOrInsertSpace(Space); 1117 return RS.findAvailableBinding(Size); 1118 } 1119 1120 DXILResourceBindingInfo::RegisterSpace & 1121 DXILResourceBindingInfo::BindingSpaces::getOrInsertSpace(uint32_t Space) { 1122 for (auto *I = Spaces.begin(); I != Spaces.end(); ++I) { 1123 if (I->Space == Space) 1124 return *I; 1125 if (I->Space < Space) 1126 continue; 1127 return *Spaces.insert(I, Space); 1128 } 1129 return Spaces.emplace_back(Space); 1130 } 1131 1132 std::optional<uint32_t> 1133 DXILResourceBindingInfo::RegisterSpace::findAvailableBinding(int32_t Size) { 1134 assert((Size == -1 || Size > 0) && "invalid size"); 1135 1136 if (FreeRanges.empty()) 1137 return std::nullopt; 1138 1139 // unbounded array 1140 if (Size == -1) { 1141 BindingRange &Last = FreeRanges.back(); 1142 if (Last.UpperBound != UINT32_MAX) 1143 // this space is already occupied by an unbounded array 1144 return std::nullopt; 1145 uint32_t RegSlot = Last.LowerBound; 1146 FreeRanges.pop_back(); 1147 return RegSlot; 1148 } 1149 1150 // single resource or fixed-size array 1151 for (BindingRange &R : FreeRanges) { 1152 // compare the size as uint64_t to prevent overflow for range (0, 1153 // UINT32_MAX) 1154 if ((uint64_t)R.UpperBound - R.LowerBound + 1 < (uint64_t)Size) 1155 continue; 1156 uint32_t RegSlot = R.LowerBound; 1157 // This might create a range where (LowerBound == UpperBound + 1). When 1158 // that happens, the next time this function is called the range will 1159 // skipped over by the check above (at this point Size is always > 0). 1160 R.LowerBound += Size; 1161 return RegSlot; 1162 } 1163 1164 return std::nullopt; 1165 } 1166 1167 //===----------------------------------------------------------------------===// 1168 1169 AnalysisKey DXILResourceTypeAnalysis::Key; 1170 AnalysisKey DXILResourceAnalysis::Key; 1171 AnalysisKey DXILResourceBindingAnalysis::Key; 1172 1173 DXILResourceMap DXILResourceAnalysis::run(Module &M, 1174 ModuleAnalysisManager &AM) { 1175 DXILResourceMap Data; 1176 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M); 1177 Data.populate(M, DRTM); 1178 return Data; 1179 } 1180 1181 DXILResourceBindingInfo 1182 DXILResourceBindingAnalysis::run(Module &M, ModuleAnalysisManager &AM) { 1183 DXILResourceBindingInfo Data; 1184 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M); 1185 Data.populate(M, DRTM); 1186 return Data; 1187 } 1188 1189 PreservedAnalyses DXILResourcePrinterPass::run(Module &M, 1190 ModuleAnalysisManager &AM) { 1191 DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(M); 1192 DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M); 1193 1194 DRM.print(OS, DRTM, M.getDataLayout()); 1195 return PreservedAnalyses::all(); 1196 } 1197 1198 void DXILResourceTypeWrapperPass::anchor() {} 1199 1200 DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() 1201 : ImmutablePass(ID) {} 1202 1203 INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type", 1204 "DXIL Resource Type Analysis", false, true) 1205 char DXILResourceTypeWrapperPass::ID = 0; 1206 1207 ModulePass *llvm::createDXILResourceTypeWrapperPassPass() { 1208 return new DXILResourceTypeWrapperPass(); 1209 } 1210 1211 DXILResourceWrapperPass::DXILResourceWrapperPass() : ModulePass(ID) {} 1212 1213 DXILResourceWrapperPass::~DXILResourceWrapperPass() = default; 1214 1215 void DXILResourceWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 1216 AU.addRequiredTransitive<DXILResourceTypeWrapperPass>(); 1217 AU.setPreservesAll(); 1218 } 1219 1220 bool DXILResourceWrapperPass::runOnModule(Module &M) { 1221 Map.reset(new DXILResourceMap()); 1222 1223 DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); 1224 Map->populate(M, *DRTM); 1225 1226 return false; 1227 } 1228 1229 void DXILResourceWrapperPass::releaseMemory() { Map.reset(); } 1230 1231 void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *M) const { 1232 if (!Map) { 1233 OS << "No resource map has been built!\n"; 1234 return; 1235 } 1236 Map->print(OS, *DRTM, M->getDataLayout()); 1237 } 1238 1239 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1240 LLVM_DUMP_METHOD 1241 void DXILResourceWrapperPass::dump() const { print(dbgs(), nullptr); } 1242 #endif 1243 1244 INITIALIZE_PASS(DXILResourceWrapperPass, "dxil-resources", 1245 "DXIL Resources Analysis", false, true) 1246 char DXILResourceWrapperPass::ID = 0; 1247 1248 ModulePass *llvm::createDXILResourceWrapperPassPass() { 1249 return new DXILResourceWrapperPass(); 1250 } 1251 1252 DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass() 1253 : ModulePass(ID) {} 1254 1255 DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default; 1256 1257 void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 1258 AU.addRequiredTransitive<DXILResourceTypeWrapperPass>(); 1259 AU.setPreservesAll(); 1260 } 1261 1262 bool DXILResourceBindingWrapperPass::runOnModule(Module &M) { 1263 BindingInfo.reset(new DXILResourceBindingInfo()); 1264 1265 DXILResourceTypeMap &DRTM = 1266 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap(); 1267 BindingInfo->populate(M, DRTM); 1268 1269 return false; 1270 } 1271 1272 void DXILResourceBindingWrapperPass::releaseMemory() { BindingInfo.reset(); } 1273 1274 INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding", 1275 "DXIL Resource Binding Analysis", false, true) 1276 char DXILResourceBindingWrapperPass::ID = 0; 1277 1278 ModulePass *llvm::createDXILResourceBindingWrapperPassPass() { 1279 return new DXILResourceWrapperPass(); 1280 } 1281