Skip to content

[DirectX] Fix DXIL part header version encoding #91506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 10, 2024

Conversation

python3kgae
Copy link
Contributor

@python3kgae python3kgae commented May 8, 2024

Move MinorVersion be the lower 8 bit.
Set DXIL version in DXContainerObjectWriter::writeObject.

Fixes #89952

Move MinorVersion be the lower 8 bit.
Set DXIL version in DXContainerObjectWriter::writeObject.

Also always normalize target triple in llc to get DXIL version from subArch.

Fixes llvm#89952
@llvmbot
Copy link
Member

llvmbot commented May 8, 2024

@llvm/pr-subscribers-mc
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-backend-directx

Author: Xiang Li (python3kgae)

Changes

Move MinorVersion be the lower 8 bit.
Set DXIL version in DXContainerObjectWriter::writeObject.

Also always normalize target triple in llc to get DXIL version from subArch.

Fixes #89952


Full diff: https://github.com/llvm/llvm-project/pull/91506.diff

5 Files Affected:

  • (modified) llvm/include/llvm/BinaryFormat/DXContainer.h (+1-1)
  • (modified) llvm/lib/MC/MCDXContainerWriter.cpp (+3)
  • (modified) llvm/test/CodeGen/DirectX/embed-dxil.ll (+2-2)
  • (modified) llvm/tools/llc/llc.cpp (+2-2)
  • (modified) llvm/unittests/Object/DXContainerTest.cpp (+51-6)
diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h
index e8d03f806715f..e5fcda63910d4 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainer.h
+++ b/llvm/include/llvm/BinaryFormat/DXContainer.h
@@ -103,8 +103,8 @@ struct PartHeader {
 
 struct BitcodeHeader {
   uint8_t Magic[4];     // ACSII "DXIL".
-  uint8_t MajorVersion; // DXIL version.
   uint8_t MinorVersion; // DXIL version.
+  uint8_t MajorVersion; // DXIL version.
   uint16_t Unused;
   uint32_t Offset; // Offset to LLVM bitcode (from start of header).
   uint32_t Size;   // Size of LLVM bitcode (in bytes).
diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
index 0580dc7e42826..015899278f379 100644
--- a/llvm/lib/MC/MCDXContainerWriter.cpp
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -127,6 +127,9 @@ uint64_t DXContainerObjectWriter::writeObject(MCAssembler &Asm,
       // The program header's size field is in 32-bit words.
       Header.Size = (SectionSize + sizeof(dxbc::ProgramHeader) + 3) / 4;
       memcpy(Header.Bitcode.Magic, "DXIL", 4);
+      VersionTuple DXILVersion = TT.getDXILVersion();
+      Header.Bitcode.MajorVersion = DXILVersion.getMajor();
+      Header.Bitcode.MinorVersion = DXILVersion.getMinor().value_or(0);
       Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
       Header.Bitcode.Size = SectionSize;
       if (sys::IsBigEndianHost)
diff --git a/llvm/test/CodeGen/DirectX/embed-dxil.ll b/llvm/test/CodeGen/DirectX/embed-dxil.ll
index 306e5c385b5a3..9f4fb19d86fa0 100644
--- a/llvm/test/CodeGen/DirectX/embed-dxil.ll
+++ b/llvm/test/CodeGen/DirectX/embed-dxil.ll
@@ -42,8 +42,8 @@ define i32 @add(i32 %a, i32 %b) {
 ; DXC-NEXT:       MinorVersion:    5
 ; DXC-NEXT:       ShaderKind:      6
 ; DXC-NEXT:       Size:            [[#div(SIZE,4)]]
-; DXC-NEXT:       DXILMajorVersion: [[#]]
-; DXC-NEXT:       DXILMinorVersion: [[#]]
+; DXC-NEXT:       DXILMajorVersion: 1
+; DXC-NEXT:       DXILMinorVersion: 5
 ; DXC-NEXT:       DXILSize:        [[#SIZE - 24]]
 ; DXC-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE,
 ; DXC:      - Name:            SFI0
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index b292f70ba89de..5825e79156774 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -537,8 +537,8 @@ static int compileModule(char **argv, LLVMContext &Context) {
       // If we are supposed to override the target triple, do so now.
       std::string IRTargetTriple = DataLayoutTargetTriple.str();
       if (!TargetTriple.empty())
-        IRTargetTriple = Triple::normalize(TargetTriple);
-      TheTriple = Triple(IRTargetTriple);
+        IRTargetTriple = TargetTriple;
+      TheTriple = Triple(Triple::normalize(IRTargetTriple));
       if (TheTriple.getTriple().empty())
         TheTriple.setTriple(sys::getDefaultTargetTriple());
 
diff --git a/llvm/unittests/Object/DXContainerTest.cpp b/llvm/unittests/Object/DXContainerTest.cpp
index da640225617d4..28df84578113d 100644
--- a/llvm/unittests/Object/DXContainerTest.cpp
+++ b/llvm/unittests/Object/DXContainerTest.cpp
@@ -126,6 +126,51 @@ TEST(DXCFile, ParseOverlappingParts) {
           "Part offset for part 1 begins before the previous part ends"));
 }
 
+// This test verify DXILMajorVersion and DXILMinorVersion are 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:            DXIL
+//     Size:            28
+//     Program:
+//       MajorVersion:    6
+//       MinorVersion:    5
+//       ShaderKind:      5
+//       Size:            8
+//       DXILMajorVersion: 1
+//       DXILMinorVersion: 5
+//       DXILSize:        4
+//       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE, ]
+// ...
+TEST(DXCFile, ParseDXILPart) {
+  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,
+      0x44, 0x58, 0x49, 0x4c, 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<object::DXContainer::DXILData> &DXIL = C.getDXIL();
+  EXPECT_TRUE(DXIL.has_value());
+  dxbc::ProgramHeader Header = DXIL->first;
+  EXPECT_EQ(Header.MajorVersion, 6u);
+  EXPECT_EQ(Header.MinorVersion, 5u);
+  EXPECT_EQ(Header.ShaderKind, 5u);
+  EXPECT_EQ(Header.Size, 8u);
+  EXPECT_EQ(Header.Bitcode.MajorVersion, 1u);
+  EXPECT_EQ(Header.Bitcode.MinorVersion, 5u);
+}
+
 TEST(DXCFile, ParseEmptyParts) {
   uint8_t Buffer[] = {
       0x44, 0x58, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -240,8 +285,8 @@ TEST(DXCFile, PSVResourceIterators) {
       MinorVersion:    0
       ShaderKind:      14
       Size:            6
-      DXILMajorVersion: 0
-      DXILMinorVersion: 1
+      DXILMajorVersion: 1
+      DXILMinorVersion: 0
       DXILSize:        0
 ...
 )";
@@ -361,8 +406,8 @@ TEST(DXCFile, PSVResourceIterators) {
 //       MinorVersion:    0
 //       ShaderKind:      14
 //       Size:            6
-//       DXILMajorVersion: 0
-//       DXILMinorVersion: 1
+//       DXILMajorVersion: 1
+//       DXILMinorVersion: 0
 //       DXILSize:        0
 //   - Name:            PSV0
 //     Size:            36
@@ -491,8 +536,8 @@ TEST(DXCFile, MaliciousFiles) {
 //       MinorVersion:    0
 //       ShaderKind:      14
 //       Size:            6
-//       DXILMajorVersion: 0
-//       DXILMinorVersion: 1
+//       DXILMajorVersion: 1
+//       DXILMinorVersion: 0
 //       DXILSize:        0
 //   - Name:            PSV0
 //     Size:            100

Copy link

github-actions bot commented May 8, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@bharadwajy bharadwajy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see failures of LLVM regression tests (target check-llvm) with these changes.

Total Discovered Tests: 59475
Skipped : 346 (0.58%)
Unsupported : 27503 (46.24%)
Passed : 31174 (52.42%)
Expectedly Failed: 63 (0.11%)
Failed : 389 (0.65%)
FAILED: test/CMakeFiles/check-llvm /workspace/github/oss/llvm-build/hlsl/Debug/test/CMakeFiles/check-llvm

No such failures without this change (i.e., commit set to 8d9b154)

Total Discovered Tests: 59474
Skipped : 346 (0.58%)
Unsupported : 27503 (46.24%)
Passed : 31562 (53.07%)
Expectedly Failed: 63 (0.11%)

Failures appear to be related to changes in llvm/tools/llc/llc.cpp

Please double check. Thanks!

@python3kgae
Copy link
Contributor Author

I see failures of LLVM regression tests (target check-llvm) with these changes.

Total Discovered Tests: 59475 Skipped : 346 (0.58%) Unsupported : 27503 (46.24%) Passed : 31174 (52.42%) Expectedly Failed: 63 (0.11%) Failed : 389 (0.65%) FAILED: test/CMakeFiles/check-llvm /workspace/github/oss/llvm-build/hlsl/Debug/test/CMakeFiles/check-llvm

No such failures without this change (i.e., commit set to 8d9b154)

Total Discovered Tests: 59474 Skipped : 346 (0.58%) Unsupported : 27503 (46.24%) Passed : 31562 (53.07%) Expectedly Failed: 63 (0.11%)

Failures appear to be related to changes in llvm/tools/llc/llc.cpp

Please double check. Thanks!

Thanks. Looking at it.

IRTargetTriple = Triple::normalize(TargetTriple);
IRTargetTriple = TargetTriple;
if (!IRTargetTriple.empty())
IRTargetTriple = Triple::normalize(IRTargetTriple);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be changing llc to choose to always normalize triples buried in a DirectX change like this. This is a pretty significant change to the behaviour of llc when a module has an non-normalized triple, and if we really want to normalize the triple unconditionally I think that's a bigger change that needs wider discussion. Note that the Triple class deliberately does not normalize on construction, so that non-normalized triples can be worked with when appropriate (such as if it's intentionally broken for testing purposes, or something along those lines)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

IRTargetTriple = TargetTriple;
if (!IRTargetTriple.empty())
IRTargetTriple = Triple::normalize(IRTargetTriple);
IRTargetTriple = Triple::normalize(TargetTriple);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change still needed? Is it possible to avoid making changes to this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. There's no change in llc.cpp now.

Copy link
Contributor

@bharadwajy bharadwajy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a reminder to make sure the sentence

"Also always normalize target triple in llc to get DXIL version from subArch."

is edited out of the "Squash and Merge" commit message.

@@ -1510,6 +1510,8 @@ VersionTuple Triple::getDXILVersion() const {
if (getArch() != dxil || getOS() != ShaderModel)
llvm_unreachable("invalid DXIL triple");
StringRef Arch = getArchName();
if (Arch == "dxil")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can say getSubArch() == NoSubArch here instead of using string comparison

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@python3kgae
Copy link
Contributor Author

Just a reminder to make sure the sentence

"Also always normalize target triple in llc to get DXIL version from subArch."

is edited out of the "Squash and Merge" commit message.
Good catch.
Updated.

@python3kgae python3kgae merged commit 195d8ac into llvm:main May 10, 2024
@python3kgae python3kgae deleted the dx_ver_order branch May 10, 2024 13:29
bogner added a commit that referenced this pull request May 10, 2024
bogner added a commit that referenced this pull request May 10, 2024
Test failures on big endian bots after this change.

Reverts #91506
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[DirectX] Fix DXIL part header version encoding
6 participants