Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:17

0001 //===- DXContainer.h - DXContainer file implementation ----------*- 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 // This file declares the DXContainerFile class, which implements the ObjectFile
0010 // interface for DXContainer files.
0011 //
0012 //
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_OBJECT_DXCONTAINER_H
0016 #define LLVM_OBJECT_DXCONTAINER_H
0017 
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/ADT/StringRef.h"
0020 #include "llvm/BinaryFormat/DXContainer.h"
0021 #include "llvm/Support/Error.h"
0022 #include "llvm/Support/MemoryBufferRef.h"
0023 #include "llvm/TargetParser/Triple.h"
0024 #include <array>
0025 #include <variant>
0026 
0027 namespace llvm {
0028 namespace object {
0029 
0030 namespace detail {
0031 template <typename T>
0032 std::enable_if_t<std::is_arithmetic<T>::value, void> swapBytes(T &value) {
0033   sys::swapByteOrder(value);
0034 }
0035 
0036 template <typename T>
0037 std::enable_if_t<std::is_class<T>::value, void> swapBytes(T &value) {
0038   value.swapBytes();
0039 }
0040 } // namespace detail
0041 
0042 // This class provides a view into the underlying resource array. The Resource
0043 // data is little-endian encoded and may not be properly aligned to read
0044 // directly from. The dereference operator creates a copy of the data and byte
0045 // swaps it as appropriate.
0046 template <typename T> struct ViewArray {
0047   StringRef Data;
0048   uint32_t Stride = sizeof(T); // size of each element in the list.
0049 
0050   ViewArray() = default;
0051   ViewArray(StringRef D, size_t S) : Data(D), Stride(S) {}
0052 
0053   using value_type = T;
0054   static constexpr uint32_t MaxStride() {
0055     return static_cast<uint32_t>(sizeof(value_type));
0056   }
0057 
0058   struct iterator {
0059     StringRef Data;
0060     uint32_t Stride; // size of each element in the list.
0061     const char *Current;
0062 
0063     iterator(const ViewArray &A, const char *C)
0064         : Data(A.Data), Stride(A.Stride), Current(C) {}
0065     iterator(const iterator &) = default;
0066 
0067     value_type operator*() {
0068       // Explicitly zero the structure so that unused fields are zeroed. It is
0069       // up to the user to know if the fields are used by verifying the PSV
0070       // version.
0071       value_type Val;
0072       std::memset(&Val, 0, sizeof(value_type));
0073       if (Current >= Data.end())
0074         return Val;
0075       memcpy(static_cast<void *>(&Val), Current, std::min(Stride, MaxStride()));
0076       if (sys::IsBigEndianHost)
0077         detail::swapBytes(Val);
0078       return Val;
0079     }
0080 
0081     iterator operator++() {
0082       if (Current < Data.end())
0083         Current += Stride;
0084       return *this;
0085     }
0086 
0087     iterator operator++(int) {
0088       iterator Tmp = *this;
0089       ++*this;
0090       return Tmp;
0091     }
0092 
0093     iterator operator--() {
0094       if (Current > Data.begin())
0095         Current -= Stride;
0096       return *this;
0097     }
0098 
0099     iterator operator--(int) {
0100       iterator Tmp = *this;
0101       --*this;
0102       return Tmp;
0103     }
0104 
0105     bool operator==(const iterator I) { return I.Current == Current; }
0106     bool operator!=(const iterator I) { return !(*this == I); }
0107   };
0108 
0109   iterator begin() const { return iterator(*this, Data.begin()); }
0110 
0111   iterator end() const { return iterator(*this, Data.end()); }
0112 
0113   size_t size() const { return Data.size() / Stride; }
0114 
0115   bool isEmpty() const { return Data.empty(); }
0116 };
0117 
0118 namespace DirectX {
0119 class PSVRuntimeInfo {
0120 
0121   using ResourceArray = ViewArray<dxbc::PSV::v2::ResourceBindInfo>;
0122   using SigElementArray = ViewArray<dxbc::PSV::v0::SignatureElement>;
0123 
0124   StringRef Data;
0125   uint32_t Size;
0126   using InfoStruct =
0127       std::variant<std::monostate, dxbc::PSV::v0::RuntimeInfo,
0128                    dxbc::PSV::v1::RuntimeInfo, dxbc::PSV::v2::RuntimeInfo,
0129                    dxbc::PSV::v3::RuntimeInfo>;
0130   InfoStruct BasicInfo;
0131   ResourceArray Resources;
0132   StringRef StringTable;
0133   SmallVector<uint32_t> SemanticIndexTable;
0134   SigElementArray SigInputElements;
0135   SigElementArray SigOutputElements;
0136   SigElementArray SigPatchOrPrimElements;
0137 
0138   std::array<ViewArray<uint32_t>, 4> OutputVectorMasks;
0139   ViewArray<uint32_t> PatchOrPrimMasks;
0140   std::array<ViewArray<uint32_t>, 4> InputOutputMap;
0141   ViewArray<uint32_t> InputPatchMap;
0142   ViewArray<uint32_t> PatchOutputMap;
0143 
0144 public:
0145   PSVRuntimeInfo(StringRef D) : Data(D), Size(0) {}
0146 
0147   // Parsing depends on the shader kind
0148   Error parse(uint16_t ShaderKind);
0149 
0150   uint32_t getSize() const { return Size; }
0151   uint32_t getResourceCount() const { return Resources.size(); }
0152   ResourceArray getResources() const { return Resources; }
0153 
0154   uint32_t getVersion() const {
0155     return Size >= sizeof(dxbc::PSV::v3::RuntimeInfo)
0156                ? 3
0157                : (Size >= sizeof(dxbc::PSV::v2::RuntimeInfo)     ? 2
0158                   : (Size >= sizeof(dxbc::PSV::v1::RuntimeInfo)) ? 1
0159                                                                  : 0);
0160   }
0161 
0162   uint32_t getResourceStride() const { return Resources.Stride; }
0163 
0164   const InfoStruct &getInfo() const { return BasicInfo; }
0165 
0166   template <typename T> const T *getInfoAs() const {
0167     if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
0168       return static_cast<const T *>(P);
0169     if (std::is_same<T, dxbc::PSV::v3::RuntimeInfo>::value)
0170       return nullptr;
0171 
0172     if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
0173       return static_cast<const T *>(P);
0174     if (std::is_same<T, dxbc::PSV::v2::RuntimeInfo>::value)
0175       return nullptr;
0176 
0177     if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
0178       return static_cast<const T *>(P);
0179     if (std::is_same<T, dxbc::PSV::v1::RuntimeInfo>::value)
0180       return nullptr;
0181 
0182     if (const auto *P = std::get_if<dxbc::PSV::v0::RuntimeInfo>(&BasicInfo))
0183       return static_cast<const T *>(P);
0184     return nullptr;
0185   }
0186 
0187   StringRef getStringTable() const { return StringTable; }
0188   ArrayRef<uint32_t> getSemanticIndexTable() const {
0189     return SemanticIndexTable;
0190   }
0191 
0192   uint8_t getSigInputCount() const;
0193   uint8_t getSigOutputCount() const;
0194   uint8_t getSigPatchOrPrimCount() const;
0195 
0196   SigElementArray getSigInputElements() const { return SigInputElements; }
0197   SigElementArray getSigOutputElements() const { return SigOutputElements; }
0198   SigElementArray getSigPatchOrPrimElements() const {
0199     return SigPatchOrPrimElements;
0200   }
0201 
0202   ViewArray<uint32_t> getOutputVectorMasks(size_t Idx) const {
0203     assert(Idx < 4);
0204     return OutputVectorMasks[Idx];
0205   }
0206 
0207   ViewArray<uint32_t> getPatchOrPrimMasks() const { return PatchOrPrimMasks; }
0208 
0209   ViewArray<uint32_t> getInputOutputMap(size_t Idx) const {
0210     assert(Idx < 4);
0211     return InputOutputMap[Idx];
0212   }
0213 
0214   ViewArray<uint32_t> getInputPatchMap() const { return InputPatchMap; }
0215   ViewArray<uint32_t> getPatchOutputMap() const { return PatchOutputMap; }
0216 
0217   uint32_t getSigElementStride() const { return SigInputElements.Stride; }
0218 
0219   bool usesViewID() const {
0220     if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
0221       return P->UsesViewID != 0;
0222     return false;
0223   }
0224 
0225   uint8_t getInputVectorCount() const {
0226     if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
0227       return P->SigInputVectors;
0228     return 0;
0229   }
0230 
0231   ArrayRef<uint8_t> getOutputVectorCounts() const {
0232     if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
0233       return ArrayRef<uint8_t>(P->SigOutputVectors);
0234     return ArrayRef<uint8_t>();
0235   }
0236 
0237   uint8_t getPatchConstOrPrimVectorCount() const {
0238     if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
0239       return P->GeomData.SigPatchConstOrPrimVectors;
0240     return 0;
0241   }
0242 };
0243 
0244 class Signature {
0245   ViewArray<dxbc::ProgramSignatureElement> Parameters;
0246   uint32_t StringTableOffset;
0247   StringRef StringTable;
0248 
0249 public:
0250   ViewArray<dxbc::ProgramSignatureElement>::iterator begin() const {
0251     return Parameters.begin();
0252   }
0253 
0254   ViewArray<dxbc::ProgramSignatureElement>::iterator end() const {
0255     return Parameters.end();
0256   }
0257 
0258   StringRef getName(uint32_t Offset) const {
0259     assert(Offset >= StringTableOffset &&
0260            Offset < StringTableOffset + StringTable.size() &&
0261            "Offset out of range.");
0262     // Name offsets are from the start of the signature data, not from the start
0263     // of the string table. The header encodes the start offset of the sting
0264     // table, so we convert the offset here.
0265     uint32_t TableOffset = Offset - StringTableOffset;
0266     return StringTable.slice(TableOffset, StringTable.find('\0', TableOffset));
0267   }
0268 
0269   bool isEmpty() const { return Parameters.isEmpty(); }
0270 
0271   Error initialize(StringRef Part);
0272 };
0273 
0274 } // namespace DirectX
0275 
0276 class DXContainer {
0277 public:
0278   using DXILData = std::pair<dxbc::ProgramHeader, const char *>;
0279 
0280 private:
0281   DXContainer(MemoryBufferRef O);
0282 
0283   MemoryBufferRef Data;
0284   dxbc::Header Header;
0285   SmallVector<uint32_t, 4> PartOffsets;
0286   std::optional<DXILData> DXIL;
0287   std::optional<uint64_t> ShaderFeatureFlags;
0288   std::optional<dxbc::ShaderHash> Hash;
0289   std::optional<DirectX::PSVRuntimeInfo> PSVInfo;
0290   DirectX::Signature InputSignature;
0291   DirectX::Signature OutputSignature;
0292   DirectX::Signature PatchConstantSignature;
0293 
0294   Error parseHeader();
0295   Error parsePartOffsets();
0296   Error parseDXILHeader(StringRef Part);
0297   Error parseShaderFeatureFlags(StringRef Part);
0298   Error parseHash(StringRef Part);
0299   Error parsePSVInfo(StringRef Part);
0300   Error parseSignature(StringRef Part, DirectX::Signature &Array);
0301   friend class PartIterator;
0302 
0303 public:
0304   // The PartIterator is a wrapper around the iterator for the PartOffsets
0305   // member of the DXContainer. It contains a refernce to the container, and the
0306   // current iterator value, as well as storage for a parsed part header.
0307   class PartIterator {
0308     const DXContainer &Container;
0309     SmallVectorImpl<uint32_t>::const_iterator OffsetIt;
0310     struct PartData {
0311       dxbc::PartHeader Part;
0312       uint32_t Offset;
0313       StringRef Data;
0314     } IteratorState;
0315 
0316     friend class DXContainer;
0317 
0318     PartIterator(const DXContainer &C,
0319                  SmallVectorImpl<uint32_t>::const_iterator It)
0320         : Container(C), OffsetIt(It) {
0321       if (OffsetIt == Container.PartOffsets.end())
0322         updateIteratorImpl(Container.PartOffsets.back());
0323       else
0324         updateIterator();
0325     }
0326 
0327     // Updates the iterator's state data. This results in copying the part
0328     // header into the iterator and handling any required byte swapping. This is
0329     // called when incrementing or decrementing the iterator.
0330     void updateIterator() {
0331       if (OffsetIt != Container.PartOffsets.end())
0332         updateIteratorImpl(*OffsetIt);
0333     }
0334 
0335     // Implementation for updating the iterator state based on a specified
0336     // offest.
0337     void updateIteratorImpl(const uint32_t Offset);
0338 
0339   public:
0340     PartIterator &operator++() {
0341       if (OffsetIt == Container.PartOffsets.end())
0342         return *this;
0343       ++OffsetIt;
0344       updateIterator();
0345       return *this;
0346     }
0347 
0348     PartIterator operator++(int) {
0349       PartIterator Tmp = *this;
0350       ++(*this);
0351       return Tmp;
0352     }
0353 
0354     bool operator==(const PartIterator &RHS) const {
0355       return OffsetIt == RHS.OffsetIt;
0356     }
0357 
0358     bool operator!=(const PartIterator &RHS) const {
0359       return OffsetIt != RHS.OffsetIt;
0360     }
0361 
0362     const PartData &operator*() { return IteratorState; }
0363     const PartData *operator->() { return &IteratorState; }
0364   };
0365 
0366   PartIterator begin() const {
0367     return PartIterator(*this, PartOffsets.begin());
0368   }
0369 
0370   PartIterator end() const { return PartIterator(*this, PartOffsets.end()); }
0371 
0372   StringRef getData() const { return Data.getBuffer(); }
0373   static Expected<DXContainer> create(MemoryBufferRef Object);
0374 
0375   const dxbc::Header &getHeader() const { return Header; }
0376 
0377   const std::optional<DXILData> &getDXIL() const { return DXIL; }
0378 
0379   std::optional<uint64_t> getShaderFeatureFlags() const {
0380     return ShaderFeatureFlags;
0381   }
0382 
0383   std::optional<dxbc::ShaderHash> getShaderHash() const { return Hash; }
0384 
0385   const std::optional<DirectX::PSVRuntimeInfo> &getPSVInfo() const {
0386     return PSVInfo;
0387   };
0388 
0389   const DirectX::Signature &getInputSignature() const { return InputSignature; }
0390   const DirectX::Signature &getOutputSignature() const {
0391     return OutputSignature;
0392   }
0393   const DirectX::Signature &getPatchConstantSignature() const {
0394     return PatchConstantSignature;
0395   }
0396 };
0397 
0398 } // namespace object
0399 } // namespace llvm
0400 
0401 #endif // LLVM_OBJECT_DXCONTAINER_H