1 //===- DXILPostOptimizationValidation.cpp - Opt DXIL validation ----------===// 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 "DXILPostOptimizationValidation.h" 10 #include "DXILShaderFlags.h" 11 #include "DirectX.h" 12 #include "llvm/ADT/SmallString.h" 13 #include "llvm/Analysis/DXILMetadataAnalysis.h" 14 #include "llvm/Analysis/DXILResource.h" 15 #include "llvm/IR/DiagnosticInfo.h" 16 #include "llvm/IR/Instructions.h" 17 #include "llvm/IR/IntrinsicsDirectX.h" 18 #include "llvm/IR/Module.h" 19 #include "llvm/InitializePasses.h" 20 21 #define DEBUG_TYPE "dxil-post-optimization-validation" 22 23 using namespace llvm; 24 using namespace llvm::dxil; 25 26 namespace { 27 28 static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) { 29 for (const auto &UAV : DRM.uavs()) { 30 if (UAV.CounterDirection != ResourceCounterDirection::Invalid) 31 continue; 32 33 CallInst *ResourceHandle = nullptr; 34 for (CallInst *MaybeHandle : DRM.calls()) { 35 if (*DRM.find(MaybeHandle) == UAV) { 36 ResourceHandle = MaybeHandle; 37 break; 38 } 39 } 40 41 StringRef Message = "RWStructuredBuffers may increment or decrement their " 42 "counters, but not both."; 43 for (const auto &U : ResourceHandle->users()) { 44 const CallInst *CI = dyn_cast<CallInst>(U); 45 if (!CI && CI->getIntrinsicID() != Intrinsic::dx_resource_updatecounter) 46 continue; 47 48 M.getContext().diagnose(DiagnosticInfoGenericWithLoc( 49 Message, *CI->getFunction(), CI->getDebugLoc())); 50 } 51 } 52 } 53 54 static void reportOverlappingError(Module &M, ResourceInfo R1, 55 ResourceInfo R2) { 56 SmallString<128> Message; 57 raw_svector_ostream OS(Message); 58 OS << "resource " << R1.getName() << " at register " 59 << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName() 60 << " at register " << R2.getBinding().LowerBound << " in space " 61 << R2.getBinding().Space; 62 M.getContext().diagnose(DiagnosticInfoGeneric(Message)); 63 } 64 65 static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { 66 if (DRM.empty()) 67 return; 68 69 for (const auto &ResList : 70 {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) { 71 if (ResList.empty()) 72 continue; 73 const ResourceInfo *PrevRI = &*ResList.begin(); 74 for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) { 75 const ResourceInfo *CurrentRI = &*I; 76 const ResourceInfo *RI = CurrentRI; 77 while (RI != ResList.end() && 78 PrevRI->getBinding().overlapsWith(RI->getBinding())) { 79 reportOverlappingError(M, *PrevRI, *RI); 80 RI++; 81 } 82 PrevRI = CurrentRI; 83 } 84 } 85 } 86 87 static void reportErrors(Module &M, DXILResourceMap &DRM, 88 DXILResourceBindingInfo &DRBI) { 89 if (DRM.hasInvalidCounterDirection()) 90 reportInvalidDirection(M, DRM); 91 92 if (DRBI.hasOverlappingBinding()) 93 reportOverlappingBinding(M, DRM); 94 95 assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in " 96 "DXILResourceImplicitBinding pass"); 97 } 98 } // namespace 99 100 PreservedAnalyses 101 DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { 102 DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M); 103 DXILResourceBindingInfo &DRBI = MAM.getResult<DXILResourceBindingAnalysis>(M); 104 reportErrors(M, DRM, DRBI); 105 return PreservedAnalyses::all(); 106 } 107 108 namespace { 109 class DXILPostOptimizationValidationLegacy : public ModulePass { 110 public: 111 bool runOnModule(Module &M) override { 112 DXILResourceMap &DRM = 113 getAnalysis<DXILResourceWrapperPass>().getResourceMap(); 114 DXILResourceBindingInfo &DRBI = 115 getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo(); 116 reportErrors(M, DRM, DRBI); 117 return false; 118 } 119 StringRef getPassName() const override { 120 return "DXIL Post Optimization Validation"; 121 } 122 DXILPostOptimizationValidationLegacy() : ModulePass(ID) {} 123 124 static char ID; // Pass identification. 125 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { 126 AU.addRequired<DXILResourceWrapperPass>(); 127 AU.addRequired<DXILResourceBindingWrapperPass>(); 128 AU.addPreserved<DXILResourceWrapperPass>(); 129 AU.addPreserved<DXILResourceBindingWrapperPass>(); 130 AU.addPreserved<DXILMetadataAnalysisWrapperPass>(); 131 AU.addPreserved<ShaderFlagsAnalysisWrapper>(); 132 } 133 }; 134 char DXILPostOptimizationValidationLegacy::ID = 0; 135 } // end anonymous namespace 136 137 INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, 138 "DXIL Post Optimization Validation", false, false) 139 INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass) 140 INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass) 141 INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass) 142 INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, 143 "DXIL Post Optimization Validation", false, false) 144 145 ModulePass *llvm::createDXILPostOptimizationValidationLegacyPass() { 146 return new DXILPostOptimizationValidationLegacy(); 147 } 148