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