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