//===- DXILPostOptimizationValidation.cpp - Opt DXIL validation ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DXILPostOptimizationValidation.h" #include "DXILShaderFlags.h" #include "DirectX.h" #include "llvm/ADT/SmallString.h" #include "llvm/Analysis/DXILMetadataAnalysis.h" #include "llvm/Analysis/DXILResource.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicsDirectX.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #define DEBUG_TYPE "dxil-post-optimization-validation" using namespace llvm; using namespace llvm::dxil; namespace { static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) { for (const auto &UAV : DRM.uavs()) { if (UAV.CounterDirection != ResourceCounterDirection::Invalid) continue; CallInst *ResourceHandle = nullptr; for (CallInst *MaybeHandle : DRM.calls()) { if (*DRM.find(MaybeHandle) == UAV) { ResourceHandle = MaybeHandle; break; } } StringRef Message = "RWStructuredBuffers may increment or decrement their " "counters, but not both."; for (const auto &U : ResourceHandle->users()) { const CallInst *CI = dyn_cast(U); if (!CI && CI->getIntrinsicID() != Intrinsic::dx_resource_updatecounter) continue; M.getContext().diagnose(DiagnosticInfoGenericWithLoc( Message, *CI->getFunction(), CI->getDebugLoc())); } } } static void reportOverlappingError(Module &M, ResourceInfo R1, ResourceInfo R2) { SmallString<128> Message; raw_svector_ostream OS(Message); OS << "resource " << R1.getName() << " at register " << R1.getBinding().LowerBound << " overlaps with resource " << R2.getName() << " at register " << R2.getBinding().LowerBound << " in space " << R2.getBinding().Space; M.getContext().diagnose(DiagnosticInfoGeneric(Message)); } static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { if (DRM.empty()) return; for (const auto &ResList : {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) { if (ResList.empty()) continue; const ResourceInfo *PrevRI = &*ResList.begin(); for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) { const ResourceInfo *CurrentRI = &*I; const ResourceInfo *RI = CurrentRI; while (RI != ResList.end() && PrevRI->getBinding().overlapsWith(RI->getBinding())) { reportOverlappingError(M, *PrevRI, *RI); RI++; } PrevRI = CurrentRI; } } } static void reportErrors(Module &M, DXILResourceMap &DRM, DXILResourceBindingInfo &DRBI) { if (DRM.hasInvalidCounterDirection()) reportInvalidDirection(M, DRM); if (DRBI.hasOverlappingBinding()) reportOverlappingBinding(M, DRM); assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in " "DXILResourceImplicitBinding pass"); } } // namespace PreservedAnalyses DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) { DXILResourceMap &DRM = MAM.getResult(M); DXILResourceBindingInfo &DRBI = MAM.getResult(M); reportErrors(M, DRM, DRBI); return PreservedAnalyses::all(); } namespace { class DXILPostOptimizationValidationLegacy : public ModulePass { public: bool runOnModule(Module &M) override { DXILResourceMap &DRM = getAnalysis().getResourceMap(); DXILResourceBindingInfo &DRBI = getAnalysis().getBindingInfo(); reportErrors(M, DRM, DRBI); return false; } StringRef getPassName() const override { return "DXIL Post Optimization Validation"; } DXILPostOptimizationValidationLegacy() : ModulePass(ID) {} static char ID; // Pass identification. void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); } }; char DXILPostOptimizationValidationLegacy::ID = 0; } // end anonymous namespace INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, "DXIL Post Optimization Validation", false, false) INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass) INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass) INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass) INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE, "DXIL Post Optimization Validation", false, false) ModulePass *llvm::createDXILPostOptimizationValidationLegacyPass() { return new DXILPostOptimizationValidationLegacy(); }