Skip to content

[DirectX] Implement UseNativeLowPrecision shader flag analysis #134288

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 8 commits into from
Apr 10, 2025

Conversation

Icohedron
Copy link
Contributor

@Icohedron Icohedron commented Apr 3, 2025

Fixes #112267

Implement the shader flag analysis to set the UseNativeLowPrecision DXIL module flag.

The flag is only able to be set when the command-line flag -enable-16bit-types is passed to clang-dxc, or equivalently -fnative-half-type is passed to clang.
When the command-line flag is passed, a module metadata flag called "dx.nativelowprec" is set to 1.
The DXILShaderFlags shader flags analysis checks that the module metadata flag "dx.nativelowprec" is set to 1 and the DXIL Version is 1.2 or greater before setting the UseNativeLowPrecision DXIL module flag.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. backend:DirectX HLSL HLSL Language Support labels Apr 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-backend-directx

@llvm/pr-subscribers-clang-codegen

Author: Deric C. (Icohedron)

Changes

Fixes #112267


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

4 Files Affected:

  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+3)
  • (added) clang/test/CodeGenHLSL/enable-16bit-types.hlsl (+9)
  • (modified) llvm/lib/Target/DirectX/DXILShaderFlags.cpp (+6)
  • (added) llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision.ll (+45)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 3b1810b62a2cd..ca5f180d2a64c 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -282,10 +282,13 @@ void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
 
 void CGHLSLRuntime::finishCodeGen() {
   auto &TargetOpts = CGM.getTarget().getTargetOpts();
+  auto &LangOpts = CGM.getLangOpts();
   llvm::Module &M = CGM.getModule();
   Triple T(M.getTargetTriple());
   if (T.getArch() == Triple::ArchType::dxil)
     addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+  if (LangOpts.NativeHalfType)
+    M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec", 1);
 
   generateGlobalCtorDtorCalls();
 }
diff --git a/clang/test/CodeGenHLSL/enable-16bit-types.hlsl b/clang/test/CodeGenHLSL/enable-16bit-types.hlsl
new file mode 100644
index 0000000000000..7da66a3ed863b
--- /dev/null
+++ b/clang/test/CodeGenHLSL/enable-16bit-types.hlsl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fnative-half-type -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=FLAG
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=NOFLAG
+
+// NOTE: -enable-16bit-types is a DXCFlag that aliases -fnative-half-type
+
+// FLAG-DAG: ![[NLP:.*]] = !{i32 1, !"dx.nativelowprec", i32 1}
+// FLAG-DAG: !llvm.module.flags = !{{{.*}}![[NLP]]{{.*}}}
+
+// NOFLAG-NOT: dx.nativelowprec
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index babf495220393..437d1402ccedc 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -188,6 +188,12 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
         continue;
       }
 
+      // Set UseNativeLowPrecision using dx.nativelowprec module metadata
+      if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(
+              M.getModuleFlag("dx.nativelowprec")))
+        if (NativeLowPrec->getValue() != 0)
+          SCCSF.UseNativeLowPrecision = true;
+
       ComputedShaderFlags CSF;
       for (const auto &BB : *F)
         for (const auto &I : BB)
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision.ll
new file mode 100644
index 0000000000000..95c916b169cdf
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision.ll
@@ -0,0 +1,45 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+;CHECK: ; Combined Shader Flags for Module
+;CHECK-NEXT: ; Shader Flags Value: 0x00800020
+;CHECK-NEXT: ;
+;CHECK-NEXT: ; Note: shader requires additional functionality:
+;CHECK-NEXT: ; Note: extra DXIL module flags:
+;CHECK-NEXT: ;       D3D11_1_SB_GLOBAL_FLAG_ENABLE_MINIMUM_PRECISION
+;CHECK-NEXT: ;       Native 16bit types enabled
+;CHECK-NEXT: ;
+;CHECK-NEXT: ; Shader Flags for Module Functions
+
+;CHECK-LABEL: ; Function add_i16 : 0x00800020
+define i16 @add_i16(i16 %a, i16 %b) #0 {
+  %sum = add i16 %a, %b
+  ret i16 %sum
+}
+
+; NOTE: The flag for native low precision is set for every function in the
+; module regardless of whether or not the function uses low precision data
+; types. This matches the behavior in DXC
+;CHECK-LABEL: ; Function add_i32 : 0x00800000
+define i32 @add_i32(i32 %a, i32 %b) #0 {
+  %sum = add i32 %a, %b
+  ret i32 %sum
+}
+
+;CHECK-LABEL: ; Function add_half : 0x00800020
+define half @add_half(half %a, half %b) #0 {
+  %sum = fadd half %a, %b
+  ret half %sum
+}
+
+attributes #0 = { convergent norecurse nounwind "hlsl.export" }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.nativelowprec", i32 1}
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NOT:     Flags:
+; DXC: ...

Copy link

github-actions bot commented Apr 3, 2025

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

Copy link
Contributor

@inbelic inbelic left a comment

Choose a reason for hiding this comment

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

Assuming -fnative-half-type can be directly used as an alias to enable-16bit-types in DXC, this LGTM. Just some nits otherwise

@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -fnative-half-type -finclude-default-header -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=FLAG
Copy link
Member

Choose a reason for hiding this comment

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

NIT: For future cleanup and test organization could we move the Shader Flag tests into their own directory like the Builtins have their own directory? Not asking for this PR.

// Set UseNativeLowPrecision using dx.nativelowprec module metadata
if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(
M.getModuleFlag("dx.nativelowprec")))
if (MMDI.DXILVersion >= VersionTuple(1, 2) &&
Copy link
Member

Choose a reason for hiding this comment

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

So I know the frontend likely has checks to confirm SM 6.2 or greater for this flag. If the backend is dxil-pc-shadermodel6.1 what would happen in a test case like use-native-low-precision.ll? Would we just expect to not see !0 = !{i32 1, !"dx.nativelowprec", i32 1}?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The frontend is what is adding !0 = !{i32 1, !"dx.nativelowprec", i32 1}, so we wouldn't see it in the module.

If it is manually added to a module that is SM 6.1 or older, then it should have no effect on the shader flags.
Should I add a test for this?

Copy link
Member

Choose a reason for hiding this comment

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

My concern was if the validator would allow the dxil if it was less than sm 6.2 and we saw nativelowprec set. The backend would be our last place to catch that and avoid the validator complaining.

If that isn't a concern then I don't think we need a test.

Copy link
Contributor Author

@Icohedron Icohedron Apr 8, 2025

Choose a reason for hiding this comment

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

I don't think the validator interprets any module metadata flag named "dx.nativelowpres", so it would just be ignored if it is present in the DXIL even when the SM is lower than 6.2.

@farzonl
Copy link
Member

farzonl commented Apr 8, 2025

Codgen looks right. The only changes I want to see are around testing.

@Icohedron Icohedron merged commit 747d4a9 into llvm:main Apr 10, 2025
11 of 12 checks passed
AllinLeeYL pushed a commit to AllinLeeYL/llvm-project that referenced this pull request Apr 10, 2025
…134288)

Fixes llvm#112267 

Implement the shader flag analysis to set the UseNativeLowPrecision DXIL
module flag.

The flag is only able to be set when the command-line flag
`-enable-16bit-types` is passed to clang-dxc, or equivalently
`-fnative-half-type` is passed to clang.
When the command-line flag is passed, a module metadata flag called
"dx.nativelowprec" is set to 1.
The DXILShaderFlags shader flags analysis checks that the module
metadata flag "dx.nativelowprec" is set to 1 and the DXIL Version is 1.2
or greater before setting the UseNativeLowPrecision DXIL module flag.
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…134288)

Fixes llvm#112267 

Implement the shader flag analysis to set the UseNativeLowPrecision DXIL
module flag.

The flag is only able to be set when the command-line flag
`-enable-16bit-types` is passed to clang-dxc, or equivalently
`-fnative-half-type` is passed to clang.
When the command-line flag is passed, a module metadata flag called
"dx.nativelowprec" is set to 1.
The DXILShaderFlags shader flags analysis checks that the module
metadata flag "dx.nativelowprec" is set to 1 and the DXIL Version is 1.2
or greater before setting the UseNativeLowPrecision DXIL module flag.
@damyanp damyanp moved this to Closed in HLSL Support Apr 25, 2025
@damyanp damyanp removed this from HLSL Support Jun 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DirectX] Shader Flag Analysis for UseNativeLowPrecision
4 participants