clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
402 lines
12 KiB
C++
402 lines
12 KiB
C++
//===- DXContainer.h - DXContainer file implementation ----------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file declares the DXContainerFile class, which implements the ObjectFile
|
|
// interface for DXContainer files.
|
|
//
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_OBJECT_DXCONTAINER_H
|
|
#define LLVM_OBJECT_DXCONTAINER_H
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/BinaryFormat/DXContainer.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/MemoryBufferRef.h"
|
|
#include "llvm/TargetParser/Triple.h"
|
|
#include <array>
|
|
#include <variant>
|
|
|
|
namespace llvm {
|
|
namespace object {
|
|
|
|
namespace detail {
|
|
template <typename T>
|
|
std::enable_if_t<std::is_arithmetic<T>::value, void> swapBytes(T &value) {
|
|
sys::swapByteOrder(value);
|
|
}
|
|
|
|
template <typename T>
|
|
std::enable_if_t<std::is_class<T>::value, void> swapBytes(T &value) {
|
|
value.swapBytes();
|
|
}
|
|
} // namespace detail
|
|
|
|
// This class provides a view into the underlying resource array. The Resource
|
|
// data is little-endian encoded and may not be properly aligned to read
|
|
// directly from. The dereference operator creates a copy of the data and byte
|
|
// swaps it as appropriate.
|
|
template <typename T> struct ViewArray {
|
|
StringRef Data;
|
|
uint32_t Stride = sizeof(T); // size of each element in the list.
|
|
|
|
ViewArray() = default;
|
|
ViewArray(StringRef D, size_t S) : Data(D), Stride(S) {}
|
|
|
|
using value_type = T;
|
|
static constexpr uint32_t MaxStride() {
|
|
return static_cast<uint32_t>(sizeof(value_type));
|
|
}
|
|
|
|
struct iterator {
|
|
StringRef Data;
|
|
uint32_t Stride; // size of each element in the list.
|
|
const char *Current;
|
|
|
|
iterator(const ViewArray &A, const char *C)
|
|
: Data(A.Data), Stride(A.Stride), Current(C) {}
|
|
iterator(const iterator &) = default;
|
|
|
|
value_type operator*() {
|
|
// Explicitly zero the structure so that unused fields are zeroed. It is
|
|
// up to the user to know if the fields are used by verifying the PSV
|
|
// version.
|
|
value_type Val;
|
|
std::memset(&Val, 0, sizeof(value_type));
|
|
if (Current >= Data.end())
|
|
return Val;
|
|
memcpy(static_cast<void *>(&Val), Current, std::min(Stride, MaxStride()));
|
|
if (sys::IsBigEndianHost)
|
|
detail::swapBytes(Val);
|
|
return Val;
|
|
}
|
|
|
|
iterator operator++() {
|
|
if (Current < Data.end())
|
|
Current += Stride;
|
|
return *this;
|
|
}
|
|
|
|
iterator operator++(int) {
|
|
iterator Tmp = *this;
|
|
++*this;
|
|
return Tmp;
|
|
}
|
|
|
|
iterator operator--() {
|
|
if (Current > Data.begin())
|
|
Current -= Stride;
|
|
return *this;
|
|
}
|
|
|
|
iterator operator--(int) {
|
|
iterator Tmp = *this;
|
|
--*this;
|
|
return Tmp;
|
|
}
|
|
|
|
bool operator==(const iterator I) { return I.Current == Current; }
|
|
bool operator!=(const iterator I) { return !(*this == I); }
|
|
};
|
|
|
|
iterator begin() const { return iterator(*this, Data.begin()); }
|
|
|
|
iterator end() const { return iterator(*this, Data.end()); }
|
|
|
|
size_t size() const { return Data.size() / Stride; }
|
|
|
|
bool isEmpty() const { return Data.empty(); }
|
|
};
|
|
|
|
namespace DirectX {
|
|
class PSVRuntimeInfo {
|
|
|
|
using ResourceArray = ViewArray<dxbc::PSV::v2::ResourceBindInfo>;
|
|
using SigElementArray = ViewArray<dxbc::PSV::v0::SignatureElement>;
|
|
|
|
StringRef Data;
|
|
uint32_t Size;
|
|
using InfoStruct =
|
|
std::variant<std::monostate, dxbc::PSV::v0::RuntimeInfo,
|
|
dxbc::PSV::v1::RuntimeInfo, dxbc::PSV::v2::RuntimeInfo,
|
|
dxbc::PSV::v3::RuntimeInfo>;
|
|
InfoStruct BasicInfo;
|
|
ResourceArray Resources;
|
|
StringRef StringTable;
|
|
SmallVector<uint32_t> SemanticIndexTable;
|
|
SigElementArray SigInputElements;
|
|
SigElementArray SigOutputElements;
|
|
SigElementArray SigPatchOrPrimElements;
|
|
|
|
std::array<ViewArray<uint32_t>, 4> OutputVectorMasks;
|
|
ViewArray<uint32_t> PatchOrPrimMasks;
|
|
std::array<ViewArray<uint32_t>, 4> InputOutputMap;
|
|
ViewArray<uint32_t> InputPatchMap;
|
|
ViewArray<uint32_t> PatchOutputMap;
|
|
|
|
public:
|
|
PSVRuntimeInfo(StringRef D) : Data(D), Size(0) {}
|
|
|
|
// Parsing depends on the shader kind
|
|
Error parse(uint16_t ShaderKind);
|
|
|
|
uint32_t getSize() const { return Size; }
|
|
uint32_t getResourceCount() const { return Resources.size(); }
|
|
ResourceArray getResources() const { return Resources; }
|
|
|
|
uint32_t getVersion() const {
|
|
return Size >= sizeof(dxbc::PSV::v3::RuntimeInfo)
|
|
? 3
|
|
: (Size >= sizeof(dxbc::PSV::v2::RuntimeInfo) ? 2
|
|
: (Size >= sizeof(dxbc::PSV::v1::RuntimeInfo)) ? 1
|
|
: 0);
|
|
}
|
|
|
|
uint32_t getResourceStride() const { return Resources.Stride; }
|
|
|
|
const InfoStruct &getInfo() const { return BasicInfo; }
|
|
|
|
template <typename T> const T *getInfoAs() const {
|
|
if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo))
|
|
return static_cast<const T *>(P);
|
|
if (std::is_same<T, dxbc::PSV::v3::RuntimeInfo>::value)
|
|
return nullptr;
|
|
|
|
if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo))
|
|
return static_cast<const T *>(P);
|
|
if (std::is_same<T, dxbc::PSV::v2::RuntimeInfo>::value)
|
|
return nullptr;
|
|
|
|
if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo))
|
|
return static_cast<const T *>(P);
|
|
if (std::is_same<T, dxbc::PSV::v1::RuntimeInfo>::value)
|
|
return nullptr;
|
|
|
|
if (const auto *P = std::get_if<dxbc::PSV::v0::RuntimeInfo>(&BasicInfo))
|
|
return static_cast<const T *>(P);
|
|
return nullptr;
|
|
}
|
|
|
|
StringRef getStringTable() const { return StringTable; }
|
|
ArrayRef<uint32_t> getSemanticIndexTable() const {
|
|
return SemanticIndexTable;
|
|
}
|
|
|
|
uint8_t getSigInputCount() const;
|
|
uint8_t getSigOutputCount() const;
|
|
uint8_t getSigPatchOrPrimCount() const;
|
|
|
|
SigElementArray getSigInputElements() const { return SigInputElements; }
|
|
SigElementArray getSigOutputElements() const { return SigOutputElements; }
|
|
SigElementArray getSigPatchOrPrimElements() const {
|
|
return SigPatchOrPrimElements;
|
|
}
|
|
|
|
ViewArray<uint32_t> getOutputVectorMasks(size_t Idx) const {
|
|
assert(Idx < 4);
|
|
return OutputVectorMasks[Idx];
|
|
}
|
|
|
|
ViewArray<uint32_t> getPatchOrPrimMasks() const { return PatchOrPrimMasks; }
|
|
|
|
ViewArray<uint32_t> getInputOutputMap(size_t Idx) const {
|
|
assert(Idx < 4);
|
|
return InputOutputMap[Idx];
|
|
}
|
|
|
|
ViewArray<uint32_t> getInputPatchMap() const { return InputPatchMap; }
|
|
ViewArray<uint32_t> getPatchOutputMap() const { return PatchOutputMap; }
|
|
|
|
uint32_t getSigElementStride() const { return SigInputElements.Stride; }
|
|
|
|
bool usesViewID() const {
|
|
if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
|
|
return P->UsesViewID != 0;
|
|
return false;
|
|
}
|
|
|
|
uint8_t getInputVectorCount() const {
|
|
if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
|
|
return P->SigInputVectors;
|
|
return 0;
|
|
}
|
|
|
|
ArrayRef<uint8_t> getOutputVectorCounts() const {
|
|
if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
|
|
return ArrayRef<uint8_t>(P->SigOutputVectors);
|
|
return ArrayRef<uint8_t>();
|
|
}
|
|
|
|
uint8_t getPatchConstOrPrimVectorCount() const {
|
|
if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>())
|
|
return P->GeomData.SigPatchConstOrPrimVectors;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
class Signature {
|
|
ViewArray<dxbc::ProgramSignatureElement> Parameters;
|
|
uint32_t StringTableOffset;
|
|
StringRef StringTable;
|
|
|
|
public:
|
|
ViewArray<dxbc::ProgramSignatureElement>::iterator begin() const {
|
|
return Parameters.begin();
|
|
}
|
|
|
|
ViewArray<dxbc::ProgramSignatureElement>::iterator end() const {
|
|
return Parameters.end();
|
|
}
|
|
|
|
StringRef getName(uint32_t Offset) const {
|
|
assert(Offset >= StringTableOffset &&
|
|
Offset < StringTableOffset + StringTable.size() &&
|
|
"Offset out of range.");
|
|
// Name offsets are from the start of the signature data, not from the start
|
|
// of the string table. The header encodes the start offset of the sting
|
|
// table, so we convert the offset here.
|
|
uint32_t TableOffset = Offset - StringTableOffset;
|
|
return StringTable.slice(TableOffset, StringTable.find('\0', TableOffset));
|
|
}
|
|
|
|
bool isEmpty() const { return Parameters.isEmpty(); }
|
|
|
|
Error initialize(StringRef Part);
|
|
};
|
|
|
|
} // namespace DirectX
|
|
|
|
class DXContainer {
|
|
public:
|
|
using DXILData = std::pair<dxbc::ProgramHeader, const char *>;
|
|
|
|
private:
|
|
DXContainer(MemoryBufferRef O);
|
|
|
|
MemoryBufferRef Data;
|
|
dxbc::Header Header;
|
|
SmallVector<uint32_t, 4> PartOffsets;
|
|
std::optional<DXILData> DXIL;
|
|
std::optional<uint64_t> ShaderFeatureFlags;
|
|
std::optional<dxbc::ShaderHash> Hash;
|
|
std::optional<DirectX::PSVRuntimeInfo> PSVInfo;
|
|
DirectX::Signature InputSignature;
|
|
DirectX::Signature OutputSignature;
|
|
DirectX::Signature PatchConstantSignature;
|
|
|
|
Error parseHeader();
|
|
Error parsePartOffsets();
|
|
Error parseDXILHeader(StringRef Part);
|
|
Error parseShaderFeatureFlags(StringRef Part);
|
|
Error parseHash(StringRef Part);
|
|
Error parsePSVInfo(StringRef Part);
|
|
Error parseSignature(StringRef Part, DirectX::Signature &Array);
|
|
friend class PartIterator;
|
|
|
|
public:
|
|
// The PartIterator is a wrapper around the iterator for the PartOffsets
|
|
// member of the DXContainer. It contains a refernce to the container, and the
|
|
// current iterator value, as well as storage for a parsed part header.
|
|
class PartIterator {
|
|
const DXContainer &Container;
|
|
SmallVectorImpl<uint32_t>::const_iterator OffsetIt;
|
|
struct PartData {
|
|
dxbc::PartHeader Part;
|
|
uint32_t Offset;
|
|
StringRef Data;
|
|
} IteratorState;
|
|
|
|
friend class DXContainer;
|
|
|
|
PartIterator(const DXContainer &C,
|
|
SmallVectorImpl<uint32_t>::const_iterator It)
|
|
: Container(C), OffsetIt(It) {
|
|
if (OffsetIt == Container.PartOffsets.end())
|
|
updateIteratorImpl(Container.PartOffsets.back());
|
|
else
|
|
updateIterator();
|
|
}
|
|
|
|
// Updates the iterator's state data. This results in copying the part
|
|
// header into the iterator and handling any required byte swapping. This is
|
|
// called when incrementing or decrementing the iterator.
|
|
void updateIterator() {
|
|
if (OffsetIt != Container.PartOffsets.end())
|
|
updateIteratorImpl(*OffsetIt);
|
|
}
|
|
|
|
// Implementation for updating the iterator state based on a specified
|
|
// offest.
|
|
void updateIteratorImpl(const uint32_t Offset);
|
|
|
|
public:
|
|
PartIterator &operator++() {
|
|
if (OffsetIt == Container.PartOffsets.end())
|
|
return *this;
|
|
++OffsetIt;
|
|
updateIterator();
|
|
return *this;
|
|
}
|
|
|
|
PartIterator operator++(int) {
|
|
PartIterator Tmp = *this;
|
|
++(*this);
|
|
return Tmp;
|
|
}
|
|
|
|
bool operator==(const PartIterator &RHS) const {
|
|
return OffsetIt == RHS.OffsetIt;
|
|
}
|
|
|
|
bool operator!=(const PartIterator &RHS) const {
|
|
return OffsetIt != RHS.OffsetIt;
|
|
}
|
|
|
|
const PartData &operator*() { return IteratorState; }
|
|
const PartData *operator->() { return &IteratorState; }
|
|
};
|
|
|
|
PartIterator begin() const {
|
|
return PartIterator(*this, PartOffsets.begin());
|
|
}
|
|
|
|
PartIterator end() const { return PartIterator(*this, PartOffsets.end()); }
|
|
|
|
StringRef getData() const { return Data.getBuffer(); }
|
|
static Expected<DXContainer> create(MemoryBufferRef Object);
|
|
|
|
const dxbc::Header &getHeader() const { return Header; }
|
|
|
|
const std::optional<DXILData> &getDXIL() const { return DXIL; }
|
|
|
|
std::optional<uint64_t> getShaderFeatureFlags() const {
|
|
return ShaderFeatureFlags;
|
|
}
|
|
|
|
std::optional<dxbc::ShaderHash> getShaderHash() const { return Hash; }
|
|
|
|
const std::optional<DirectX::PSVRuntimeInfo> &getPSVInfo() const {
|
|
return PSVInfo;
|
|
};
|
|
|
|
const DirectX::Signature &getInputSignature() const { return InputSignature; }
|
|
const DirectX::Signature &getOutputSignature() const {
|
|
return OutputSignature;
|
|
}
|
|
const DirectX::Signature &getPatchConstantSignature() const {
|
|
return PatchConstantSignature;
|
|
}
|
|
};
|
|
|
|
} // namespace object
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_OBJECT_DXCONTAINER_H
|