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
reportInvalidDirection(Module & M,DXILResourceMap & DRM)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
reportOverlappingError(Module & M,ResourceInfo R1,ResourceInfo R2)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
reportOverlappingBinding(Module & M,DXILResourceMap & DRM)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
reportErrors(Module & M,DXILResourceMap & DRM,DXILResourceBindingInfo & DRBI)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
run(Module & M,ModuleAnalysisManager & MAM)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:
runOnModule(Module & M)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 }
getPassName() const119 StringRef getPassName() const override {
120 return "DXIL Post Optimization Validation";
121 }
DXILPostOptimizationValidationLegacy()122 DXILPostOptimizationValidationLegacy() : ModulePass(ID) {}
123
124 static char ID; // Pass identification.
getAnalysisUsage(llvm::AnalysisUsage & AU) const125 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)
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)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