diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h index 1756ab0b555ff..3da36f6da525d 100644 --- a/llvm/include/llvm/BinaryFormat/DXContainer.h +++ b/llvm/include/llvm/BinaryFormat/DXContainer.h @@ -258,6 +258,10 @@ LLVM_ABI ArrayRef> getStaticBorderColors(); LLVM_ABI PartType parsePartType(StringRef S); +bool isDebugProgramPart(PartType PT); + +const char *getProgramPartName(bool IsDebug); + struct VertexPSVInfo { uint8_t OutputPositionPresent; uint8_t Unused[3]; diff --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def index f576d958037cd..f9f4472b0ebce 100644 --- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def +++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def @@ -1,6 +1,7 @@ #ifdef CONTAINER_PART CONTAINER_PART(DXIL) +CONTAINER_PART(ILDB) CONTAINER_PART(SFI0) CONTAINER_PART(HASH) CONTAINER_PART(PSV0) diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h index c5888b87d6ad7..8d1b17844227e 100644 --- a/llvm/include/llvm/Object/DXContainer.h +++ b/llvm/include/llvm/Object/DXContainer.h @@ -468,6 +468,7 @@ class DXContainer { dxbc::Header Header; SmallVector PartOffsets; std::optional DXIL; + std::optional DebugDXIL; std::optional ShaderFeatureFlags; std::optional Hash; std::optional PSVInfo; @@ -478,7 +479,7 @@ class DXContainer { Error parseHeader(); Error parsePartOffsets(); - Error parseDXILHeader(StringRef Part); + Error parseDXILHeader(dxbc::PartType PT, StringRef Part); Error parseShaderFeatureFlags(StringRef Part); Error parseHash(StringRef Part); Error parseRootSignature(StringRef Part); @@ -561,7 +562,16 @@ class DXContainer { const dxbc::Header &getHeader() const { return Header; } - const std::optional &getDXIL() const { return DXIL; } + const std::optional &getDXIL(bool Debug) const { + return Debug ? DebugDXIL : DXIL; + } + + std::optional getShaderKind() const { + const auto &ProgramPart = DXIL ? DXIL : DebugDXIL; + if (!ProgramPart) + return std::nullopt; + return ProgramPart->first.ShaderKind; + } std::optional getShaderFeatureFlags() const { return ShaderFeatureFlags; diff --git a/llvm/lib/BinaryFormat/DXContainer.cpp b/llvm/lib/BinaryFormat/DXContainer.cpp index 22f518067b318..384ef6811346c 100644 --- a/llvm/lib/BinaryFormat/DXContainer.cpp +++ b/llvm/lib/BinaryFormat/DXContainer.cpp @@ -110,6 +110,12 @@ dxbc::PartType dxbc::parsePartType(StringRef S) { .Default(dxbc::PartType::Unknown); } +bool dxbc::isDebugProgramPart(PartType PT) { return PT == PartType::ILDB; } + +const char *dxbc::getProgramPartName(bool IsDebug) { + return IsDebug ? "ILDB" : "DXIL"; +} + bool ShaderHash::isPopulated() { static uint8_t Zeros[16] = {0}; return Flags > 0 || 0 != memcmp(&Digest, &Zeros, 16); diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp index 7b7b8d88c63fc..0779c8079af9b 100644 --- a/llvm/lib/Object/DXContainer.cpp +++ b/llvm/lib/Object/DXContainer.cpp @@ -61,9 +61,13 @@ Error DXContainer::parseHeader() { return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header); } -Error DXContainer::parseDXILHeader(StringRef Part) { +Error DXContainer::parseDXILHeader(dxbc::PartType PT, StringRef Part) { + bool IsDebug = dxbc::isDebugProgramPart(PT); + std::optional &DXIL = IsDebug ? this->DebugDXIL : this->DXIL; + if (DXIL) - return parseFailed("More than one DXIL part is present in the file"); + return parseFailed(formatv("More than one {0} part is present in the file", + dxbc::getProgramPartName(IsDebug))); const char *Current = Part.begin(); dxbc::ProgramHeader Header; if (Error Err = readStruct(Part, Current, Header)) @@ -173,8 +177,10 @@ Error DXContainer::parsePartOffsets() { StringRef PartData = Data.getBuffer().substr(PartDataStart, PartSize); LastOffset = PartOffset + PartSize; switch (PT) { + case dxbc::PartType::ILDB: + [[fallthrough]]; case dxbc::PartType::DXIL: - if (Error Err = parseDXILHeader(PartData)) + if (Error Err = parseDXILHeader(PT, PartData)) return Err; break; case dxbc::PartType::SFI0: @@ -210,13 +216,19 @@ Error DXContainer::parsePartOffsets() { } } + if (DXIL && DebugDXIL && + DXIL->first.ShaderKind != DebugDXIL->first.ShaderKind) + return parseFailed( + "ILDB part shader kind does not match DXIL part shader kind"); + // Fully parsing the PSVInfo requires knowing the shader kind which we read // out of the program header in the DXIL part. if (PSVInfo) { - if (!DXIL) + auto ShaderKind = getShaderKind(); + if (!ShaderKind) return parseFailed("Cannot fully parse pipeline state validation " - "information without DXIL part."); - if (Error Err = PSVInfo->parse(DXIL->first.ShaderKind)) + "information without DXIL or ILDB part"); + if (Error Err = PSVInfo->parse(*ShaderKind)) return Err; } return Error::success(); diff --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp index b00e45d912be1..225ab0ef39bb4 100644 --- a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp +++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp @@ -128,6 +128,8 @@ Error DXContainerWriter::writeParts(raw_ostream &OS) { uint64_t DataStart = OS.tell(); switch (PT) { + case dxbc::PartType::ILDB: + [[fallthrough]]; case dxbc::PartType::DXIL: { if (!P.Program) continue; diff --git a/llvm/test/ObjectYAML/DXContainer/ILDB-ShaderKind-mismatch.yaml b/llvm/test/ObjectYAML/DXContainer/ILDB-ShaderKind-mismatch.yaml new file mode 100644 index 0000000000000..e1462a27b4c7f --- /dev/null +++ b/llvm/test/ObjectYAML/DXContainer/ILDB-ShaderKind-mismatch.yaml @@ -0,0 +1,33 @@ +# RUN: yaml2obj %s | obj2yaml +# XFAIL: * + +--- !dxcontainer +Header: + Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ] + Version: + Major: 1 + Minor: 0 + PartCount: 2 +Parts: + - Name: DXIL + Size: 24 + Program: + MajorVersion: 6 + MinorVersion: 0 + ShaderKind: 4 + Size: 6 + DXILMajorVersion: 0 + DXILMinorVersion: 1 + DXILSize: 0 + - Name: ILDB + Size: 24 + Program: + MajorVersion: 6 + MinorVersion: 0 + ShaderKind: 5 + Size: 6 + DXILMajorVersion: 0 + DXILMinorVersion: 1 + DXILSize: 0 +... diff --git a/llvm/test/ObjectYAML/DXContainer/PSVv0-ILDB.yaml b/llvm/test/ObjectYAML/DXContainer/PSVv0-ILDB.yaml new file mode 100644 index 0000000000000..13c47ae0ae250 --- /dev/null +++ b/llvm/test/ObjectYAML/DXContainer/PSVv0-ILDB.yaml @@ -0,0 +1,57 @@ +# 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 + PartCount: 2 +Parts: + - Name: PSV0 + Size: 144 + PSVInfo: + Version: 0 + ShaderStage: 5 + MinimumWaveLaneCount: 0 + MaximumWaveLaneCount: 4294967295 + ResourceStride: 16 + Resources: + - Type: Sampler + Space: 2 + LowerBound: 3 + UpperBound: 4 + - Type: Invalid + Space: 32768 + LowerBound: 8388608 + UpperBound: 2147483648 + - Name: ILDB + Size: 24 + Program: + MajorVersion: 6 + MinorVersion: 0 + ShaderKind: 5 + Size: 6 + DXILMajorVersion: 0 + DXILMinorVersion: 1 + DXILSize: 0 +... + +# CHECK: Name: PSV0 +# CHECK: PSVInfo: +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: ShaderStage: 5 +# CHECK-NEXT: MinimumWaveLaneCount: 0 +# CHECK-NEXT: MaximumWaveLaneCount: 4294967295 +# CHECK-NEXT: ResourceStride: 16 +# CHECK-NEXT: Resources: +# CHECK-NEXT: - Type: Sampler +# CHECK-NEXT: Space: 2 +# CHECK-NEXT: LowerBound: 3 +# CHECK-NEXT: UpperBound: 4 +# CHECK-NEXT: - Type: Invalid +# CHECK-NEXT: Space: 32768 +# CHECK-NEXT: LowerBound: 8388608 +# CHECK-NEXT: UpperBound: 2147483648 +# CHECK-NEXT: Name diff --git a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml index 58508f2dcc1e4..1749c7bd44d48 100644 --- a/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml +++ b/llvm/test/tools/obj2yaml/DXContainer/DXILPart.yaml @@ -11,9 +11,9 @@ Header: Version: Major: 1 Minor: 0 - FileSize: 3548 - PartCount: 7 - PartOffsets: [ 60, 76, 92, 108, 236, 1932, 1960 ] + FileSize: 2040 + PartCount: 8 + PartOffsets: [ 64, 80, 96, 112, 240, 1936, 1964, 2000 ] Parts: - Name: FKE0 Size: 8 @@ -33,11 +33,22 @@ Parts: MajorVersion: 6 MinorVersion: 5 ShaderKind: 5 - Size: 8 + Size: 7 DXILMajorVersion: 1 DXILMinorVersion: 5 DXILSize: 4 DXIL: [ 0x42, 0x43, 0xC0, 0xDE, ] + - Name: ILDB + Size: 32 + Program: + MajorVersion: 6 + MinorVersion: 5 + ShaderKind: 5 + Size: 8 + DXILMajorVersion: 1 + DXILMinorVersion: 5 + DXILSize: 8 + DXIL: [ 0x42, 0x43, 0xC0, 0xDE, 0x21, 0x0C, 0x00, 0x00, ] ... @@ -49,8 +60,19 @@ Parts: #CHECK-NEXT: MajorVersion: 6 #CHECK-NEXT: MinorVersion: 5 #CHECK-NEXT: ShaderKind: 5 -#CHECK-NEXT: Size: 8 +#CHECK-NEXT: Size: 7 #CHECK-NEXT: DXILMajorVersion: 1 #CHECK-NEXT: DXILMinorVersion: 5 #CHECK-NEXT: DXILSize: 4 #CHECK-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE +#CHECK: - Name: ILDB +#CHECK-NEXT: Size: 32 +#CHECK-NEXT: Program: +#CHECK-NEXT: MajorVersion: 6 +#CHECK-NEXT: MinorVersion: 5 +#CHECK-NEXT: ShaderKind: 5 +#CHECK-NEXT: Size: 8 +#CHECK-NEXT: DXILMajorVersion: 1 +#CHECK-NEXT: DXILMinorVersion: 5 +#CHECK-NEXT: DXILSize: 8 +#CHECK-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE, 0x21, 0xC, 0x0, 0x0 diff --git a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp index c727595406767..05912ce31ab6d 100644 --- a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp +++ b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp @@ -53,9 +53,12 @@ dumpDXContainer(MemoryBufferRef Source) { DXContainerYAML::Part &NewPart = Obj->Parts.back(); dxbc::PartType PT = dxbc::parsePartType(P.Part.getName()); switch (PT) { + case dxbc::PartType::ILDB: + [[fallthrough]]; case dxbc::PartType::DXIL: { - std::optional DXIL = Container.getDXIL(); - assert(DXIL && "Since we are iterating and found a DXIL part, " + std::optional DXIL = + Container.getDXIL(dxbc::isDebugProgramPart(PT)); + assert(DXIL && "Since we are iterating and found a DXIL/ILDB part, " "this should never not have a value"); NewPart.Program = DXContainerYAML::DXILProgram{ DXIL->first.getMajorVersion(), @@ -89,10 +92,10 @@ dumpDXContainer(MemoryBufferRef Source) { break; if (const auto *P = std::get_if(&PSVInfo->getInfo())) { - if (!Container.getDXIL()) + auto ShaderKind = Container.getShaderKind(); + if (!ShaderKind) break; - NewPart.Info = - DXContainerYAML::PSVInfo(P, Container.getDXIL()->first.ShaderKind); + NewPart.Info = DXContainerYAML::PSVInfo(P, *ShaderKind); } else if (const auto *P = std::get_if( &PSVInfo->getInfo())) NewPart.Info = DXContainerYAML::PSVInfo(P); diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp index d6f7b26b99cd7..309063631ec99 100644 --- a/llvm/unittests/Object/DXContainerTest.cpp +++ b/llvm/unittests/Object/DXContainerTest.cpp @@ -209,7 +209,7 @@ TEST(DXCFile, ParseDXILPart) { DXContainer C = llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer))); EXPECT_EQ(C.getHeader().PartCount, 1u); - const std::optional &DXIL = C.getDXIL(); + const std::optional &DXIL = C.getDXIL(false); EXPECT_TRUE(DXIL.has_value()); dxbc::ProgramHeader Header = DXIL->first; EXPECT_EQ(Header.getMajorVersion(), 6u); @@ -220,6 +220,52 @@ TEST(DXCFile, ParseDXILPart) { EXPECT_EQ(Header.Bitcode.MinorVersion, 5u); } +// This test verifies that ILDB part is correctly parsed. +// This test is based on the binary output constructed from this 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 +// PartCount: 1 +// Parts: +// - Name: ILDB +// Size: 28 +// Program: +// MajorVersion: 6 +// MinorVersion: 5 +// ShaderKind: 5 +// Size: 8 +// DXILMajorVersion: 1 +// DXILMinorVersion: 5 +// DXILSize: 4 +// DXIL: [ 0x42, 0x43, 0xC0, 0xDE, ] +// ... +TEST(DXCFile, ParseILDBPart) { + 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, + 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x49, 0x4c, 0x44, 0x42, 0x1c, 0x00, 0x00, 0x00, 0x65, 0x00, 0x05, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde}; + DXContainer C = + llvm::cantFail(DXContainer::create(getMemoryBuffer<116>(Buffer))); + EXPECT_EQ(C.getHeader().PartCount, 1u); + const std::optional &DXIL = C.getDXIL(true); + EXPECT_TRUE(DXIL.has_value()); + dxbc::ProgramHeader Header = DXIL->first; + EXPECT_EQ(Header.getMajorVersion(), 6u); + EXPECT_EQ(Header.getMinorVersion(), 5u); + EXPECT_EQ(Header.ShaderKind, 5u); + EXPECT_EQ(Header.Size, 8u); + EXPECT_EQ(Header.Bitcode.MajorVersion, 1u); + EXPECT_EQ(Header.Bitcode.MinorVersion, 5u); + EXPECT_TRUE(memcmp(DXIL->second, "\x42\x43\xc0\xde", 4) == 0); +} + static Expected generateDXContainer(StringRef Yaml, SmallVectorImpl &BinaryData) { DXContainerYAML::Object Obj;