173 changes: 108 additions & 65 deletions llvm/include/llvm/Object/DXContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
namespace llvm {
namespace object {

namespace DirectX {

namespace detail {
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, void> swapBytes(T &value) {
Expand All @@ -40,82 +38,85 @@ std::enable_if_t<std::is_class<T>::value, void> swapBytes(T &value) {
value.swapBytes();
}
} // namespace detail
class PSVRuntimeInfo {

// 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.
// 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) {}
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));
}
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);
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++() {
if (Current < Data.end())
Current += Stride;
return *this;
}

iterator operator++(int) {
iterator Tmp = *this;
++*this;
return Tmp;
}
iterator operator++(int) {
iterator Tmp = *this;
++*this;
return Tmp;
}

iterator operator--() {
if (Current > Data.begin())
Current -= Stride;
return *this;
}
iterator operator--() {
if (Current > Data.begin())
Current -= Stride;
return *this;
}

iterator operator--(int) {
iterator Tmp = *this;
--*this;
return Tmp;
}

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); }
};

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 begin() const { return iterator(*this, Data.begin()); }
iterator end() const { return iterator(*this, Data.end()); }

iterator end() const { return iterator(*this, Data.end()); }
size_t size() const { return Data.size() / Stride; }

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>;
Expand Down Expand Up @@ -232,6 +233,36 @@ class PSVRuntimeInfo {
}
};

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 {
Expand All @@ -248,13 +279,17 @@ class DXContainer {
std::optional<uint64_t> ShaderFlags;
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 parseShaderFlags(StringRef Part);
Error parseHash(StringRef Part);
Error parsePSVInfo(StringRef Part);
Error parseSignature(StringRef Part, DirectX::Signature &Array);
friend class PartIterator;

public:
Expand Down Expand Up @@ -340,6 +375,14 @@ class DXContainer {
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
Expand Down
29 changes: 29 additions & 0 deletions llvm/include/llvm/ObjectYAML/DXContainerYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ struct PSVInfo {
PSVInfo(const dxbc::PSV::v2::RuntimeInfo *P);
};

struct SignatureParameter {
uint32_t Stream;
std::string Name;
uint32_t Index;
dxbc::D3DSystemValue SystemValue;
dxbc::SigComponentType CompType;
uint32_t Register;
uint8_t Mask;
uint8_t ExclusiveMask;
dxbc::SigMinPrecision MinPrecision;
};

struct Signature {
llvm::SmallVector<SignatureParameter> Parameters;
};

struct Part {
Part() = default;
Part(std::string N, uint32_t S) : Name(N), Size(S) {}
Expand All @@ -138,6 +154,7 @@ struct Part {
std::optional<ShaderFlags> Flags;
std::optional<ShaderHash> Hash;
std::optional<PSVInfo> Info;
std::optional<Signature> Signature;
};

struct Object {
Expand All @@ -152,9 +169,13 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::Part)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::ResourceBindInfo)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::SignatureElement)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::PSVInfo::MaskVector)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DXContainerYAML::SignatureParameter)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::SemanticKind)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::ComponentType)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::PSV::InterpolationMode)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::D3DSystemValue)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::SigComponentType)
LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::dxbc::SigMinPrecision)

namespace llvm {

Expand Down Expand Up @@ -202,6 +223,14 @@ template <> struct MappingTraits<DXContainerYAML::SignatureElement> {
static void mapping(IO &IO, llvm::DXContainerYAML::SignatureElement &El);
};

template <> struct MappingTraits<DXContainerYAML::SignatureParameter> {
static void mapping(IO &IO, llvm::DXContainerYAML::SignatureParameter &El);
};

template <> struct MappingTraits<DXContainerYAML::Signature> {
static void mapping(IO &IO, llvm::DXContainerYAML::Signature &El);
};

} // namespace yaml

} // namespace llvm
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/BinaryFormat/DXContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,36 @@ bool ShaderHash::isPopulated() {
return Flags > 0 || 0 != memcmp(&Digest, &Zeros, 16);
}

#define COMPONENT_PRECISION(Val, Enum) {#Enum, SigMinPrecision::Enum},

static const EnumEntry<SigMinPrecision> SigMinPrecisionNames[] = {
#include "llvm/BinaryFormat/DXContainerConstants.def"
};

ArrayRef<EnumEntry<SigMinPrecision>> dxbc::getSigMinPrecisions() {
return ArrayRef(SigMinPrecisionNames);
}

#define D3D_SYSTEM_VALUE(Val, Enum) {#Enum, D3DSystemValue::Enum},

static const EnumEntry<D3DSystemValue> D3DSystemValueNames[] = {
#include "llvm/BinaryFormat/DXContainerConstants.def"
};

ArrayRef<EnumEntry<D3DSystemValue>> dxbc::getD3DSystemValues() {
return ArrayRef(D3DSystemValueNames);
}

#define COMPONENT_TYPE(Val, Enum) {#Enum, SigComponentType::Enum},

static const EnumEntry<SigComponentType> SigComponentTypes[] = {
#include "llvm/BinaryFormat/DXContainerConstants.def"
};

ArrayRef<EnumEntry<SigComponentType>> dxbc::getSigComponentTypes() {
return ArrayRef(SigComponentTypes);
}

#define SEMANTIC_KIND(Val, Enum) {#Enum, PSV::SemanticKind::Enum},

static const EnumEntry<PSV::SemanticKind> SemanticKindNames[] = {
Expand Down
48 changes: 48 additions & 0 deletions llvm/lib/MC/DXContainerPSVInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,51 @@ void PSVRuntimeInfo::write(raw_ostream &OS, uint32_t Version) const {
support::endian::write_array(OS, ArrayRef<uint32_t>(PatchOutputMap),
support::little);
}

void Signature::write(raw_ostream &OS) {
SmallVector<dxbc::ProgramSignatureElement> SigParams;
SigParams.reserve(Params.size());
StringTableBuilder StrTabBuilder((StringTableBuilder::DWARF));

// Name offsets are from the start of the part. Pre-calculate the offset to
// the start of the string table so that it can be added to the table offset.
uint32_t TableStart = sizeof(dxbc::ProgramSignatureHeader) +
(sizeof(dxbc::ProgramSignatureElement) * Params.size());

for (const auto &P : Params) {
// zero out the data
dxbc::ProgramSignatureElement FinalElement;
memset(&FinalElement, 0, sizeof(dxbc::ProgramSignatureElement));
FinalElement.Stream = P.Stream;
FinalElement.NameOffset =
static_cast<uint32_t>(StrTabBuilder.add(P.Name)) + TableStart;
FinalElement.Index = P.Index;
FinalElement.SystemValue = P.SystemValue;
FinalElement.CompType = P.CompType;
FinalElement.Register = P.Register;
FinalElement.Mask = P.Mask;
FinalElement.ExclusiveMask = P.ExclusiveMask;
FinalElement.MinPrecision = P.MinPrecision;
SigParams.push_back(FinalElement);
}

StrTabBuilder.finalizeInOrder();
stable_sort(SigParams, [&](const dxbc::ProgramSignatureElement &L,
const dxbc::ProgramSignatureElement R) {
return std::tie(L.Stream, L.Register, L.NameOffset) <
std::tie(R.Stream, R.Register, R.NameOffset);
});
if (sys::IsBigEndianHost)
for (auto &El : SigParams)
El.swapBytes();

dxbc::ProgramSignatureHeader Header = {static_cast<uint32_t>(Params.size()),
sizeof(dxbc::ProgramSignatureHeader)};
if (sys::IsBigEndianHost)
Header.swapBytes();
OS.write(reinterpret_cast<const char *>(&Header),
sizeof(dxbc::ProgramSignatureHeader));
OS.write(reinterpret_cast<const char *>(SigParams.data()),
sizeof(dxbc::ProgramSignatureElement) * SigParams.size());
StrTabBuilder.write(OS);
}
37 changes: 37 additions & 0 deletions llvm/lib/Object/DXContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,31 @@ Error DXContainer::parsePSVInfo(StringRef Part) {
return Error::success();
}

Error DirectX::Signature::initialize(StringRef Part) {
dxbc::ProgramSignatureHeader SigHeader;
if (Error Err = readStruct(Part, Part.begin(), SigHeader))
return Err;
size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount;

if (Part.size() < Size + SigHeader.FirstParamOffset)
return parseFailed("Signature parameters extend beyond the part boundary");

Parameters.Data = Part.substr(SigHeader.FirstParamOffset, Size);

StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size);
StringTable = Part.substr(SigHeader.FirstParamOffset + Size);

for (const auto &Param : Parameters) {
if (Param.NameOffset < StringTableOffset)
return parseFailed("Invalid parameter name offset: name starts before "
"the first name offset");
if (Param.NameOffset - StringTableOffset > StringTable.size())
return parseFailed("Invalid parameter name offset: name starts after the "
"end of the part data");
}
return Error::success();
}

Error DXContainer::parsePartOffsets() {
uint32_t LastOffset =
sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t));
Expand Down Expand Up @@ -154,6 +179,18 @@ Error DXContainer::parsePartOffsets() {
if (Error Err = parsePSVInfo(PartData))
return Err;
break;
case dxbc::PartType::ISG1:
if (Error Err = InputSignature.initialize(PartData))
return Err;
break;
case dxbc::PartType::OSG1:
if (Error Err = OutputSignature.initialize(PartData))
return Err;
break;
case dxbc::PartType::PSG1:
if (Error Err = PatchConstantSignature.initialize(PartData))
return Err;
break;
case dxbc::PartType::Unknown:
break;
}
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/ObjectYAML/DXContainerEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,20 @@ void DXContainerWriter::writeParts(raw_ostream &OS) {
PSV.write(OS, P.Info->Version);
break;
}
case dxbc::PartType::ISG1:
case dxbc::PartType::OSG1:
case dxbc::PartType::PSG1: {
mcdxbc::Signature Sig;
if (P.Signature.has_value()) {
for (const auto &Param : P.Signature->Parameters) {
Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
Param.CompType, Param.Register, Param.Mask,
Param.ExclusiveMask, Param.MinPrecision);
}
}
Sig.write(OS);
break;
}
case dxbc::PartType::Unknown:
break; // Skip any handling for unrecognized parts.
}
Expand Down
37 changes: 37 additions & 0 deletions llvm/lib/ObjectYAML/DXContainerYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@ void MappingTraits<DXContainerYAML::PSVInfo>::mapping(
IO.mapRequired("PatchOutputMap", PSV.PatchOutputMap);
}

void MappingTraits<DXContainerYAML::SignatureParameter>::mapping(
IO &IO, DXContainerYAML::SignatureParameter &S) {
IO.mapRequired("Stream", S.Stream);
IO.mapRequired("Name", S.Name);
IO.mapRequired("Index", S.Index);
IO.mapRequired("SystemValue", S.SystemValue);
IO.mapRequired("CompType", S.CompType);
IO.mapRequired("Register", S.Register);
IO.mapRequired("Mask", S.Mask);
IO.mapRequired("ExclusiveMask", S.ExclusiveMask);
IO.mapRequired("MinPrecision", S.MinPrecision);
}

void MappingTraits<DXContainerYAML::Signature>::mapping(
IO &IO, DXContainerYAML::Signature &S) {
IO.mapRequired("Parameters", S.Parameters);
}

void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
DXContainerYAML::Part &P) {
IO.mapRequired("Name", P.Name);
Expand All @@ -167,6 +185,7 @@ void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
IO.mapOptional("Flags", P.Flags);
IO.mapOptional("Hash", P.Hash);
IO.mapOptional("PSVInfo", P.Info);
IO.mapOptional("Signature", P.Signature);
}

void MappingTraits<DXContainerYAML::Object>::mapping(
Expand Down Expand Up @@ -224,6 +243,24 @@ void ScalarEnumerationTraits<dxbc::PSV::InterpolationMode>::enumeration(
IO.enumCase(Value, E.Name.str().c_str(), E.Value);
}

void ScalarEnumerationTraits<dxbc::D3DSystemValue>::enumeration(
IO &IO, dxbc::D3DSystemValue &Value) {
for (const auto &E : dxbc::getD3DSystemValues())
IO.enumCase(Value, E.Name.str().c_str(), E.Value);
}

void ScalarEnumerationTraits<dxbc::SigMinPrecision>::enumeration(
IO &IO, dxbc::SigMinPrecision &Value) {
for (const auto &E : dxbc::getSigMinPrecisions())
IO.enumCase(Value, E.Name.str().c_str(), E.Value);
}

void ScalarEnumerationTraits<dxbc::SigComponentType>::enumeration(
IO &IO, dxbc::SigComponentType &Value) {
for (const auto &E : dxbc::getSigComponentTypes())
IO.enumCase(Value, E.Name.str().c_str(), E.Value);
}

} // namespace yaml

void DXContainerYAML::PSVInfo::mapInfoForVersion(yaml::IO &IO) {
Expand Down
254 changes: 254 additions & 0 deletions llvm/test/ObjectYAML/DXContainer/SignatureParts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !dxcontainer
Header:
Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
Version:
Major: 1
Minor: 0
FileSize: 600
PartCount: 3
PartOffsets: [ 64, 124, 184 ]
Parts:
- Name: ISG1
Size: 52
Signature:
Parameters:
- Stream: 0
Name: AAA_HSFoo
Index: 0
SystemValue: Undefined
CompType: Float32
Register: 0
Mask: 7
ExclusiveMask: 2
MinPrecision: Default
- Name: OSG1
Size: 52
Signature:
Parameters:
- Stream: 0
Name: SV_Position
Index: 0
SystemValue: Position
CompType: Float32
Register: 0
Mask: 15
ExclusiveMask: 0
MinPrecision: Default
- Name: PSG1
Size: 372
Signature:
Parameters:
- Stream: 0
Name: SV_TessFactor
Index: 0
SystemValue: FinalQuadEdgeTessfactor
CompType: Float32
Register: 0
Mask: 8
ExclusiveMask: 8
MinPrecision: Default
- Stream: 0
Name: BBB
Index: 0
SystemValue: Undefined
CompType: Float32
Register: 0
Mask: 7
ExclusiveMask: 0
MinPrecision: Default
- Stream: 0
Name: SV_TessFactor
Index: 1
SystemValue: FinalQuadEdgeTessfactor
CompType: Float32
Register: 1
Mask: 8
ExclusiveMask: 8
MinPrecision: Default
- Stream: 0
Name: BBB
Index: 1
SystemValue: Undefined
CompType: Float32
Register: 1
Mask: 7
ExclusiveMask: 0
MinPrecision: Default
- Stream: 0
Name: SV_TessFactor
Index: 2
SystemValue: FinalQuadEdgeTessfactor
CompType: Float32
Register: 2
Mask: 8
ExclusiveMask: 8
MinPrecision: Default
- Stream: 0
Name: BBB
Index: 2
SystemValue: Undefined
CompType: Float32
Register: 2
Mask: 7
ExclusiveMask: 0
MinPrecision: Default
- Stream: 0
Name: SV_TessFactor
Index: 3
SystemValue: FinalQuadEdgeTessfactor
CompType: Float32
Register: 3
Mask: 8
ExclusiveMask: 8
MinPrecision: Default
- Stream: 0
Name: SV_InsideTessFactor
Index: 0
SystemValue: FinalQuadInsideTessfactor
CompType: Float32
Register: 4
Mask: 8
ExclusiveMask: 0
MinPrecision: Default
- Stream: 0
Name: SV_InsideTessFactor
Index: 1
SystemValue: FinalQuadInsideTessfactor
CompType: Float32
Register: 5
Mask: 8
ExclusiveMask: 0
MinPrecision: Default
- Stream: 0
Name: AAA
Index: 0
SystemValue: Undefined
CompType: Float32
Register: 6
Mask: 15
ExclusiveMask: 4
MinPrecision: Default
...

# CHECK: - Name: ISG1
# CHECK-NEXT: Size: 52
# CHECK-NEXT: Signature:
# CHECK-NEXT: Parameters:
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: AAA_HSFoo
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: Undefined
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 0
# CHECK-NEXT: Mask: 7
# CHECK-NEXT: ExclusiveMask: 2
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Name: OSG1
# CHECK-NEXT: Size: 52
# CHECK-NEXT: Signature:
# CHECK-NEXT: Parameters:
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_Position
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: Position
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 0
# CHECK-NEXT: Mask: 15
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Name: PSG1
# CHECK-NEXT: Size: 372
# CHECK-NEXT: Signature:
# CHECK-NEXT: Parameters:
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_TessFactor
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: FinalQuadEdgeTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 0
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 8
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: BBB
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: Undefined
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 0
# CHECK-NEXT: Mask: 7
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_TessFactor
# CHECK-NEXT: Index: 1
# CHECK-NEXT: SystemValue: FinalQuadEdgeTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 1
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 8
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: BBB
# CHECK-NEXT: Index: 1
# CHECK-NEXT: SystemValue: Undefined
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 1
# CHECK-NEXT: Mask: 7
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_TessFactor
# CHECK-NEXT: Index: 2
# CHECK-NEXT: SystemValue: FinalQuadEdgeTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 2
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 8
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: BBB
# CHECK-NEXT: Index: 2
# CHECK-NEXT: SystemValue: Undefined
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 2
# CHECK-NEXT: Mask: 7
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_TessFactor
# CHECK-NEXT: Index: 3
# CHECK-NEXT: SystemValue: FinalQuadEdgeTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 3
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 8
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_InsideTessFactor
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: FinalQuadInsideTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 4
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: SV_InsideTessFactor
# CHECK-NEXT: Index: 1
# CHECK-NEXT: SystemValue: FinalQuadInsideTessfactor
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 5
# CHECK-NEXT: Mask: 8
# CHECK-NEXT: ExclusiveMask: 0
# CHECK-NEXT: MinPrecision: Default
# CHECK-NEXT: - Stream: 0
# CHECK-NEXT: Name: AAA
# CHECK-NEXT: Index: 0
# CHECK-NEXT: SystemValue: Undefined
# CHECK-NEXT: CompType: Float32
# CHECK-NEXT: Register: 6
# CHECK-NEXT: Mask: 15
# CHECK-NEXT: ExclusiveMask: 4
# CHECK-NEXT: MinPrecision: Default
19 changes: 19 additions & 0 deletions llvm/tools/obj2yaml/dxcontainer2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
using namespace llvm;
using namespace llvm::object;

static DXContainerYAML::Signature dumpSignature(const DirectX::Signature &Sig) {
DXContainerYAML::Signature YAML;
for (auto Param : Sig)
YAML.Parameters.push_back(DXContainerYAML::SignatureParameter{
Param.Stream, Sig.getName(Param.NameOffset).str(), Param.Index,
Param.SystemValue, Param.CompType, Param.Register, Param.Mask,
Param.ExclusiveMask, Param.MinPrecision});
return YAML;
}

static Expected<DXContainerYAML::Object *>
dumpDXContainer(MemoryBufferRef Source) {
assert(file_magic::dxcontainer_object == identify_magic(Source.getBuffer()));
Expand Down Expand Up @@ -129,6 +139,15 @@ dumpDXContainer(MemoryBufferRef Source) {

break;
}
case dxbc::PartType::ISG1:
NewPart.Signature = dumpSignature(Container.getInputSignature());
break;
case dxbc::PartType::OSG1:
NewPart.Signature = dumpSignature(Container.getOutputSignature());
break;
case dxbc::PartType::PSG1:
NewPart.Signature = dumpSignature(Container.getPatchConstantSignature());
break;
case dxbc::PartType::Unknown:
break;
}
Expand Down
136 changes: 136 additions & 0 deletions llvm/unittests/Object/DXContainerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,3 +640,139 @@ TEST(DXCFile, SigElementsExtendBeyondPart) {
FailedWithMessage(
"Signature elements extend beyond the size of the part"));
}

TEST(DXCFile, MalformedSignature) {
/*
The tests here exercise the DXContainer Signature section parser. These tests
are based on modifying the binary described by the following yaml:
--- !dxcontainer
Header:
Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
Version:
Major: 1
Minor: 0
FileSize: 128
PartCount: 1
PartOffsets: [ 64 ]
Parts:
- Name: ISG1
Size: 52
Signature:
Parameters:
- Stream: 0
Name: AAA
Index: 0
SystemValue: Undefined
CompType: Float32
Register: 0
Mask: 7
ExclusiveMask: 2
MinPrecision: Default
...
The unmodified hex sequence is:
uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
*/

{

// This binary says the signature has 10 parameters, but the part data is
// only big enough for 1.
uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT_EXPECTED(
DXContainer::create(getMemoryBuffer<164>(Buffer)),
FailedWithMessage(
"Signature parameters extend beyond the part boundary"));
}

{

// This binary only has one parameter, but the start offset is beyond the
// size of the part.
uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT_EXPECTED(
DXContainer::create(getMemoryBuffer<164>(Buffer)),
FailedWithMessage(
"Signature parameters extend beyond the part boundary"));
}

{

// This parameter has a name offset of 3, which is before the start of the
// string table.
uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT_EXPECTED(
DXContainer::create(getMemoryBuffer<164>(Buffer)),
FailedWithMessage("Invalid parameter name offset: name starts before "
"the first name offset"));
}

{
// This parameter has a name offset of 255, which is after the end of the
// part.
uint8_t Buffer[] = {
0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
EXPECT_THAT_EXPECTED(
DXContainer::create(getMemoryBuffer<164>(Buffer)),
FailedWithMessage("Invalid parameter name offset: name starts after "
"the end of the part data"));
}
}