Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:12

0001 //===- DXILResource.h - Representations of DXIL resources -------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_ANALYSIS_DXILRESOURCE_H
0010 #define LLVM_ANALYSIS_DXILRESOURCE_H
0011 
0012 #include "llvm/ADT/MapVector.h"
0013 #include "llvm/ADT/StringRef.h"
0014 #include "llvm/IR/DerivedTypes.h"
0015 #include "llvm/IR/GlobalVariable.h"
0016 #include "llvm/IR/PassManager.h"
0017 #include "llvm/Pass.h"
0018 #include "llvm/Support/Alignment.h"
0019 #include "llvm/Support/DXILABI.h"
0020 
0021 namespace llvm {
0022 class CallInst;
0023 class DataLayout;
0024 class LLVMContext;
0025 class MDTuple;
0026 class Value;
0027 
0028 class DXILResourceTypeMap;
0029 
0030 namespace dxil {
0031 
0032 /// The dx.RawBuffer target extension type
0033 ///
0034 /// `target("dx.RawBuffer", Type, IsWriteable, IsROV)`
0035 class RawBufferExtType : public TargetExtType {
0036 public:
0037   RawBufferExtType() = delete;
0038   RawBufferExtType(const RawBufferExtType &) = delete;
0039   RawBufferExtType &operator=(const RawBufferExtType &) = delete;
0040 
0041   bool isStructured() const {
0042     // TODO: We need to be more prescriptive here, but since there's some debate
0043     // over whether byte address buffer should have a void type or an i8 type,
0044     // accept either for now.
0045     Type *Ty = getTypeParameter(0);
0046     return !Ty->isVoidTy() && !Ty->isIntegerTy(8);
0047   }
0048 
0049   Type *getResourceType() const {
0050     return isStructured() ? getTypeParameter(0) : nullptr;
0051   }
0052   bool isWriteable() const { return getIntParameter(0); }
0053   bool isROV() const { return getIntParameter(1); }
0054 
0055   static bool classof(const TargetExtType *T) {
0056     return T->getName() == "dx.RawBuffer";
0057   }
0058   static bool classof(const Type *T) {
0059     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0060   }
0061 };
0062 
0063 /// The dx.TypedBuffer target extension type
0064 ///
0065 /// `target("dx.TypedBuffer", Type, IsWriteable, IsROV, IsSigned)`
0066 class TypedBufferExtType : public TargetExtType {
0067 public:
0068   TypedBufferExtType() = delete;
0069   TypedBufferExtType(const TypedBufferExtType &) = delete;
0070   TypedBufferExtType &operator=(const TypedBufferExtType &) = delete;
0071 
0072   Type *getResourceType() const { return getTypeParameter(0); }
0073   bool isWriteable() const { return getIntParameter(0); }
0074   bool isROV() const { return getIntParameter(1); }
0075   bool isSigned() const { return getIntParameter(2); }
0076 
0077   static bool classof(const TargetExtType *T) {
0078     return T->getName() == "dx.TypedBuffer";
0079   }
0080   static bool classof(const Type *T) {
0081     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0082   }
0083 };
0084 
0085 /// The dx.Texture target extension type
0086 ///
0087 /// `target("dx.Texture", Type, IsWriteable, IsROV, IsSigned, Dimension)`
0088 class TextureExtType : public TargetExtType {
0089 public:
0090   TextureExtType() = delete;
0091   TextureExtType(const TextureExtType &) = delete;
0092   TextureExtType &operator=(const TextureExtType &) = delete;
0093 
0094   Type *getResourceType() const { return getTypeParameter(0); }
0095   bool isWriteable() const { return getIntParameter(0); }
0096   bool isROV() const { return getIntParameter(1); }
0097   bool isSigned() const { return getIntParameter(2); }
0098   dxil::ResourceKind getDimension() const {
0099     return static_cast<dxil::ResourceKind>(getIntParameter(3));
0100   }
0101 
0102   static bool classof(const TargetExtType *T) {
0103     return T->getName() == "dx.Texture";
0104   }
0105   static bool classof(const Type *T) {
0106     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0107   }
0108 };
0109 
0110 /// The dx.MSTexture target extension type
0111 ///
0112 /// `target("dx.MSTexture", Type, IsWriteable, Samples, IsSigned, Dimension)`
0113 class MSTextureExtType : public TargetExtType {
0114 public:
0115   MSTextureExtType() = delete;
0116   MSTextureExtType(const MSTextureExtType &) = delete;
0117   MSTextureExtType &operator=(const MSTextureExtType &) = delete;
0118 
0119   Type *getResourceType() const { return getTypeParameter(0); }
0120   bool isWriteable() const { return getIntParameter(0); }
0121   uint32_t getSampleCount() const { return getIntParameter(1); }
0122   bool isSigned() const { return getIntParameter(2); }
0123   dxil::ResourceKind getDimension() const {
0124     return static_cast<dxil::ResourceKind>(getIntParameter(3));
0125   }
0126 
0127   static bool classof(const TargetExtType *T) {
0128     return T->getName() == "dx.MSTexture";
0129   }
0130   static bool classof(const Type *T) {
0131     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0132   }
0133 };
0134 
0135 /// The dx.FeedbackTexture target extension type
0136 ///
0137 /// `target("dx.FeedbackTexture", FeedbackType, Dimension)`
0138 class FeedbackTextureExtType : public TargetExtType {
0139 public:
0140   FeedbackTextureExtType() = delete;
0141   FeedbackTextureExtType(const FeedbackTextureExtType &) = delete;
0142   FeedbackTextureExtType &operator=(const FeedbackTextureExtType &) = delete;
0143 
0144   dxil::SamplerFeedbackType getFeedbackType() const {
0145     return static_cast<dxil::SamplerFeedbackType>(getIntParameter(0));
0146   }
0147   dxil::ResourceKind getDimension() const {
0148     return static_cast<dxil::ResourceKind>(getIntParameter(1));
0149   }
0150 
0151   static bool classof(const TargetExtType *T) {
0152     return T->getName() == "dx.FeedbackTexture";
0153   }
0154   static bool classof(const Type *T) {
0155     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0156   }
0157 };
0158 
0159 /// The dx.CBuffer target extension type
0160 ///
0161 /// `target("dx.CBuffer", <Type>, ...)`
0162 class CBufferExtType : public TargetExtType {
0163 public:
0164   CBufferExtType() = delete;
0165   CBufferExtType(const CBufferExtType &) = delete;
0166   CBufferExtType &operator=(const CBufferExtType &) = delete;
0167 
0168   Type *getResourceType() const { return getTypeParameter(0); }
0169   uint32_t getCBufferSize() const { return getIntParameter(0); }
0170 
0171   static bool classof(const TargetExtType *T) {
0172     return T->getName() == "dx.CBuffer";
0173   }
0174   static bool classof(const Type *T) {
0175     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0176   }
0177 };
0178 
0179 /// The dx.Sampler target extension type
0180 ///
0181 /// `target("dx.Sampler", SamplerType)`
0182 class SamplerExtType : public TargetExtType {
0183 public:
0184   SamplerExtType() = delete;
0185   SamplerExtType(const SamplerExtType &) = delete;
0186   SamplerExtType &operator=(const SamplerExtType &) = delete;
0187 
0188   dxil::SamplerType getSamplerType() const {
0189     return static_cast<dxil::SamplerType>(getIntParameter(0));
0190   }
0191 
0192   static bool classof(const TargetExtType *T) {
0193     return T->getName() == "dx.Sampler";
0194   }
0195   static bool classof(const Type *T) {
0196     return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
0197   }
0198 };
0199 
0200 //===----------------------------------------------------------------------===//
0201 
0202 class ResourceTypeInfo {
0203 public:
0204   struct UAVInfo {
0205     bool GloballyCoherent;
0206     bool HasCounter;
0207     bool IsROV;
0208 
0209     bool operator==(const UAVInfo &RHS) const {
0210       return std::tie(GloballyCoherent, HasCounter, IsROV) ==
0211              std::tie(RHS.GloballyCoherent, RHS.HasCounter, RHS.IsROV);
0212     }
0213     bool operator!=(const UAVInfo &RHS) const { return !(*this == RHS); }
0214     bool operator<(const UAVInfo &RHS) const {
0215       return std::tie(GloballyCoherent, HasCounter, IsROV) <
0216              std::tie(RHS.GloballyCoherent, RHS.HasCounter, RHS.IsROV);
0217     }
0218   };
0219 
0220   struct StructInfo {
0221     uint32_t Stride;
0222     // Note: we store an integer here rather than using `MaybeAlign` because in
0223     // GCC 7 MaybeAlign isn't trivial so having one in this union would delete
0224     // our move constructor.
0225     // See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html
0226     uint32_t AlignLog2;
0227 
0228     bool operator==(const StructInfo &RHS) const {
0229       return std::tie(Stride, AlignLog2) == std::tie(RHS.Stride, RHS.AlignLog2);
0230     }
0231     bool operator!=(const StructInfo &RHS) const { return !(*this == RHS); }
0232     bool operator<(const StructInfo &RHS) const {
0233       return std::tie(Stride, AlignLog2) < std::tie(RHS.Stride, RHS.AlignLog2);
0234     }
0235   };
0236 
0237   struct TypedInfo {
0238     dxil::ElementType ElementTy;
0239     uint32_t ElementCount;
0240 
0241     bool operator==(const TypedInfo &RHS) const {
0242       return std::tie(ElementTy, ElementCount) ==
0243              std::tie(RHS.ElementTy, RHS.ElementCount);
0244     }
0245     bool operator!=(const TypedInfo &RHS) const { return !(*this == RHS); }
0246     bool operator<(const TypedInfo &RHS) const {
0247       return std::tie(ElementTy, ElementCount) <
0248              std::tie(RHS.ElementTy, RHS.ElementCount);
0249     }
0250   };
0251 
0252 private:
0253   TargetExtType *HandleTy;
0254 
0255   // GloballyCoherent and HasCounter aren't really part of the type and need to
0256   // be determined by analysis, so they're just provided directly by the
0257   // DXILResourceTypeMap when we construct these.
0258   bool GloballyCoherent;
0259   bool HasCounter;
0260 
0261   dxil::ResourceClass RC;
0262   dxil::ResourceKind Kind;
0263 
0264 public:
0265   ResourceTypeInfo(TargetExtType *HandleTy, const dxil::ResourceClass RC,
0266                    const dxil::ResourceKind Kind, bool GloballyCoherent = false,
0267                    bool HasCounter = false);
0268   ResourceTypeInfo(TargetExtType *HandleTy, bool GloballyCoherent = false,
0269                    bool HasCounter = false)
0270       : ResourceTypeInfo(HandleTy, {}, dxil::ResourceKind::Invalid,
0271                          GloballyCoherent, HasCounter) {}
0272 
0273   TargetExtType *getHandleTy() const { return HandleTy; }
0274   StructType *createElementStruct();
0275 
0276   // Conditions to check before accessing specific views.
0277   bool isUAV() const;
0278   bool isCBuffer() const;
0279   bool isSampler() const;
0280   bool isStruct() const;
0281   bool isTyped() const;
0282   bool isFeedback() const;
0283   bool isMultiSample() const;
0284 
0285   // Views into the type.
0286   UAVInfo getUAV() const;
0287   uint32_t getCBufferSize(const DataLayout &DL) const;
0288   dxil::SamplerType getSamplerType() const;
0289   StructInfo getStruct(const DataLayout &DL) const;
0290   TypedInfo getTyped() const;
0291   dxil::SamplerFeedbackType getFeedbackType() const;
0292   uint32_t getMultiSampleCount() const;
0293 
0294   dxil::ResourceClass getResourceClass() const { return RC; }
0295   dxil::ResourceKind getResourceKind() const { return Kind; }
0296 
0297   void setGloballyCoherent(bool V) { GloballyCoherent = V; }
0298   void setHasCounter(bool V) { HasCounter = V; }
0299 
0300   bool operator==(const ResourceTypeInfo &RHS) const;
0301   bool operator!=(const ResourceTypeInfo &RHS) const { return !(*this == RHS); }
0302   bool operator<(const ResourceTypeInfo &RHS) const;
0303 
0304   void print(raw_ostream &OS, const DataLayout &DL) const;
0305 };
0306 
0307 //===----------------------------------------------------------------------===//
0308 
0309 class ResourceBindingInfo {
0310 public:
0311   struct ResourceBinding {
0312     uint32_t RecordID;
0313     uint32_t Space;
0314     uint32_t LowerBound;
0315     uint32_t Size;
0316 
0317     bool operator==(const ResourceBinding &RHS) const {
0318       return std::tie(RecordID, Space, LowerBound, Size) ==
0319              std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
0320     }
0321     bool operator!=(const ResourceBinding &RHS) const {
0322       return !(*this == RHS);
0323     }
0324     bool operator<(const ResourceBinding &RHS) const {
0325       return std::tie(RecordID, Space, LowerBound, Size) <
0326              std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
0327     }
0328   };
0329 
0330 private:
0331   ResourceBinding Binding;
0332   TargetExtType *HandleTy;
0333   GlobalVariable *Symbol = nullptr;
0334 
0335 public:
0336   ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
0337                       uint32_t Size, TargetExtType *HandleTy,
0338                       GlobalVariable *Symbol = nullptr)
0339       : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
0340         Symbol(Symbol) {}
0341 
0342   void setBindingID(unsigned ID) { Binding.RecordID = ID; }
0343 
0344   const ResourceBinding &getBinding() const { return Binding; }
0345   TargetExtType *getHandleTy() const { return HandleTy; }
0346   const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
0347 
0348   bool hasSymbol() const { return Symbol; }
0349   GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
0350   MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const;
0351 
0352   std::pair<uint32_t, uint32_t>
0353   getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const;
0354 
0355   bool operator==(const ResourceBindingInfo &RHS) const {
0356     return std::tie(Binding, HandleTy, Symbol) ==
0357            std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
0358   }
0359   bool operator!=(const ResourceBindingInfo &RHS) const {
0360     return !(*this == RHS);
0361   }
0362   bool operator<(const ResourceBindingInfo &RHS) const {
0363     return Binding < RHS.Binding;
0364   }
0365 
0366   void print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
0367              const DataLayout &DL) const;
0368 };
0369 
0370 } // namespace dxil
0371 
0372 //===----------------------------------------------------------------------===//
0373 
0374 class DXILResourceTypeMap {
0375   DenseMap<TargetExtType *, dxil::ResourceTypeInfo> Infos;
0376 
0377 public:
0378   bool invalidate(Module &M, const PreservedAnalyses &PA,
0379                   ModuleAnalysisManager::Invalidator &Inv);
0380 
0381   dxil::ResourceTypeInfo &operator[](TargetExtType *Ty) {
0382     auto It = Infos.find(Ty);
0383     if (It != Infos.end())
0384       return It->second;
0385     auto [NewIt, Inserted] = Infos.try_emplace(Ty, Ty);
0386     return NewIt->second;
0387   }
0388 };
0389 
0390 class DXILResourceTypeAnalysis
0391     : public AnalysisInfoMixin<DXILResourceTypeAnalysis> {
0392   friend AnalysisInfoMixin<DXILResourceTypeAnalysis>;
0393 
0394   static AnalysisKey Key;
0395 
0396 public:
0397   using Result = DXILResourceTypeMap;
0398 
0399   DXILResourceTypeMap run(Module &M, ModuleAnalysisManager &AM) {
0400     // Running the pass just generates an empty map, which will be filled when
0401     // users of the pass query the results.
0402     return Result();
0403   }
0404 };
0405 
0406 class DXILResourceTypeWrapperPass : public ImmutablePass {
0407   DXILResourceTypeMap DRTM;
0408 
0409   virtual void anchor();
0410 
0411 public:
0412   static char ID;
0413   DXILResourceTypeWrapperPass();
0414 
0415   DXILResourceTypeMap &getResourceTypeMap() { return DRTM; }
0416   const DXILResourceTypeMap &getResourceTypeMap() const { return DRTM; }
0417 };
0418 
0419 ModulePass *createDXILResourceTypeWrapperPassPass();
0420 
0421 //===----------------------------------------------------------------------===//
0422 
0423 class DXILBindingMap {
0424   SmallVector<dxil::ResourceBindingInfo> Infos;
0425   DenseMap<CallInst *, unsigned> CallMap;
0426   unsigned FirstUAV = 0;
0427   unsigned FirstCBuffer = 0;
0428   unsigned FirstSampler = 0;
0429 
0430   /// Populate the map given the resource binding calls in the given module.
0431   void populate(Module &M, DXILResourceTypeMap &DRTM);
0432 
0433 public:
0434   using iterator = SmallVector<dxil::ResourceBindingInfo>::iterator;
0435   using const_iterator = SmallVector<dxil::ResourceBindingInfo>::const_iterator;
0436 
0437   iterator begin() { return Infos.begin(); }
0438   const_iterator begin() const { return Infos.begin(); }
0439   iterator end() { return Infos.end(); }
0440   const_iterator end() const { return Infos.end(); }
0441 
0442   bool empty() const { return Infos.empty(); }
0443 
0444   iterator find(const CallInst *Key) {
0445     auto Pos = CallMap.find(Key);
0446     return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
0447   }
0448 
0449   const_iterator find(const CallInst *Key) const {
0450     auto Pos = CallMap.find(Key);
0451     return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
0452   }
0453 
0454   iterator srv_begin() { return begin(); }
0455   const_iterator srv_begin() const { return begin(); }
0456   iterator srv_end() { return begin() + FirstUAV; }
0457   const_iterator srv_end() const { return begin() + FirstUAV; }
0458   iterator_range<iterator> srvs() { return make_range(srv_begin(), srv_end()); }
0459   iterator_range<const_iterator> srvs() const {
0460     return make_range(srv_begin(), srv_end());
0461   }
0462 
0463   iterator uav_begin() { return begin() + FirstUAV; }
0464   const_iterator uav_begin() const { return begin() + FirstUAV; }
0465   iterator uav_end() { return begin() + FirstCBuffer; }
0466   const_iterator uav_end() const { return begin() + FirstCBuffer; }
0467   iterator_range<iterator> uavs() { return make_range(uav_begin(), uav_end()); }
0468   iterator_range<const_iterator> uavs() const {
0469     return make_range(uav_begin(), uav_end());
0470   }
0471 
0472   iterator cbuffer_begin() { return begin() + FirstCBuffer; }
0473   const_iterator cbuffer_begin() const { return begin() + FirstCBuffer; }
0474   iterator cbuffer_end() { return begin() + FirstSampler; }
0475   const_iterator cbuffer_end() const { return begin() + FirstSampler; }
0476   iterator_range<iterator> cbuffers() {
0477     return make_range(cbuffer_begin(), cbuffer_end());
0478   }
0479   iterator_range<const_iterator> cbuffers() const {
0480     return make_range(cbuffer_begin(), cbuffer_end());
0481   }
0482 
0483   iterator sampler_begin() { return begin() + FirstSampler; }
0484   const_iterator sampler_begin() const { return begin() + FirstSampler; }
0485   iterator sampler_end() { return end(); }
0486   const_iterator sampler_end() const { return end(); }
0487   iterator_range<iterator> samplers() {
0488     return make_range(sampler_begin(), sampler_end());
0489   }
0490   iterator_range<const_iterator> samplers() const {
0491     return make_range(sampler_begin(), sampler_end());
0492   }
0493 
0494   void print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
0495              const DataLayout &DL) const;
0496 
0497   friend class DXILResourceBindingAnalysis;
0498   friend class DXILResourceBindingWrapperPass;
0499 };
0500 
0501 class DXILResourceBindingAnalysis
0502     : public AnalysisInfoMixin<DXILResourceBindingAnalysis> {
0503   friend AnalysisInfoMixin<DXILResourceBindingAnalysis>;
0504 
0505   static AnalysisKey Key;
0506 
0507 public:
0508   using Result = DXILBindingMap;
0509 
0510   /// Gather resource info for the module \c M.
0511   DXILBindingMap run(Module &M, ModuleAnalysisManager &AM);
0512 };
0513 
0514 /// Printer pass for the \c DXILResourceBindingAnalysis results.
0515 class DXILResourceBindingPrinterPass
0516     : public PassInfoMixin<DXILResourceBindingPrinterPass> {
0517   raw_ostream &OS;
0518 
0519 public:
0520   explicit DXILResourceBindingPrinterPass(raw_ostream &OS) : OS(OS) {}
0521 
0522   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
0523 
0524   static bool isRequired() { return true; }
0525 };
0526 
0527 class DXILResourceBindingWrapperPass : public ModulePass {
0528   std::unique_ptr<DXILBindingMap> Map;
0529   DXILResourceTypeMap *DRTM;
0530 
0531 public:
0532   static char ID; // Class identification, replacement for typeinfo
0533 
0534   DXILResourceBindingWrapperPass();
0535   ~DXILResourceBindingWrapperPass() override;
0536 
0537   const DXILBindingMap &getBindingMap() const { return *Map; }
0538   DXILBindingMap &getBindingMap() { return *Map; }
0539 
0540   void getAnalysisUsage(AnalysisUsage &AU) const override;
0541   bool runOnModule(Module &M) override;
0542   void releaseMemory() override;
0543 
0544   void print(raw_ostream &OS, const Module *M) const override;
0545   void dump() const;
0546 };
0547 
0548 ModulePass *createDXILResourceBindingWrapperPassPass();
0549 
0550 } // namespace llvm
0551 
0552 #endif // LLVM_ANALYSIS_DXILRESOURCE_H