[llvm] 80fa621 - [DirectX] Set shader feature flags MinimumPrecision and NativeLowPrecision, and refactor the logic for setting low-precision-related flags (#139623)

via llvm-commits llvm-commits at lists.llvm.org
Wed May 14 10:37:31 PDT 2025


Author: Deric C.
Date: 2025-05-14T10:37:27-07:00
New Revision: 80fa6214821582511c687d00a484929530df1661

URL: https://github.com/llvm/llvm-project/commit/80fa6214821582511c687d00a484929530df1661
DIFF: https://github.com/llvm/llvm-project/commit/80fa6214821582511c687d00a484929530df1661.diff

LOG: [DirectX] Set shader feature flags MinimumPrecision and NativeLowPrecision, and refactor the logic for setting low-precision-related flags (#139623)

Fixes #138997 and does refactoring for low-precision-related flags.

The shader feature flags MinimumPrecision and NativeLowPrecision were
not being set, leading to validation errors.
This PR sets these shader feature flags [as in
DXC](https://github.com/microsoft/DirectXShaderCompiler/blob/377c4ca6d82adb83bf2eaf978a7040443848d6fd/lib/DXIL/DxilShaderFlags.cpp#L58-L63)
and adds tests for them.

This PR also performs some refactoring of low-precision-related flags to
make it less confusing.
- The `UseNativeLowPrecision` DXIL module flag has been renamed to
`NativeLowPrecisionMode` to imply that it is setting some execution
state which the module should be interpreted with
- The LLVM module flag `dx.nativelowprec` is now read only once and sets
a bool to be used by `updateFunctionFlags()` and for setting the DXIL
module flag `NativeLowPrecisionMode`
- The `MinimumPrecision`, `NativeLowPrecision`, and
`LowPrecisionPresent` shader feature flags are all set together under
`updateFunctionFlags()`
- Moved the logic for setting DXIL module flags `NativeLowPrecisionMode`
and `ResMayNotAlias` out of the per-function loop and placed it
alongside the logic for setting other DXIL module flags
(`DisableOptimizations`, `Max64UAVs`, and `UAVsAtEveryStage` flags)

---------

Co-authored-by: Justin Bogner <mail at justinbogner.com>

Added: 
    

Modified: 
    llvm/include/llvm/BinaryFormat/DXContainerConstants.def
    llvm/lib/Target/DirectX/DXILShaderFlags.cpp
    llvm/lib/Target/DirectX/DXILShaderFlags.h
    llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
    llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-sm6.7.ll
    llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-0.ll
    llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
index 1645018aebedb..81d2c54b6e07c 100644
--- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
+++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def
@@ -34,7 +34,7 @@ SHADER_FEATURE_FLAG(14, 19, WaveOps, "Wave level operations")
 SHADER_FEATURE_FLAG(15, 20, Int64Ops, "64-Bit integer")
 SHADER_FEATURE_FLAG(16, 21, ViewID, "View Instancing")
 SHADER_FEATURE_FLAG(17, 22, Barycentrics, "Barycentrics")
-SHADER_FEATURE_FLAG(18, -1, NativeLowPrecision, "Use native low precision")
+SHADER_FEATURE_FLAG(18, -1, NativeLowPrecision, "Native low-precision data types")
 SHADER_FEATURE_FLAG(19, 24, ShadingRate, "Shading Rate")
 SHADER_FEATURE_FLAG(20, 25, Raytracing_Tier_1_1, "Raytracing tier 1.1 features")
 SHADER_FEATURE_FLAG(21, 26, SamplerFeedback, "Sampler feedback")
@@ -115,9 +115,9 @@ DXIL_MODULE_FLAG( 0,  DisableOptimizations,   "Disable shader optimizations")
 DXIL_MODULE_FLAG( 1,  DisableMathRefactoring, "Disable math refactoring")
 DXIL_MODULE_FLAG( 3,  ForceEarlyDepthStencil, "Force early depth-stencil test")
 DXIL_MODULE_FLAG( 4,  EnableRawAndStructuredBuffers, "Raw and structured buffers")
-DXIL_MODULE_FLAG( 5,  LowPrecisionPresent, "Low-precision data types")
+DXIL_MODULE_FLAG( 5,  LowPrecisionPresent, "Low-precision data types present")
 DXIL_MODULE_FLAG( 8,  AllResourcesBound, "All resources bound for the duration of shader execution")
-DXIL_MODULE_FLAG(23,  UseNativeLowPrecision, "Use native low precision")
+DXIL_MODULE_FLAG(23,  NativeLowPrecisionMode, "Enable native low-precision data types")
 DXIL_MODULE_FLAG(33,  ResMayNotAlias, "Any UAV may not alias any other UAV")
 
 #undef DXIL_MODULE_FLAG

diff  --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index b50a9b5d6051c..8bdaf68e18e70 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -142,6 +142,13 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
     }
   }
 
+  if (CSF.LowPrecisionPresent) {
+    if (CanSetNativeLowPrecisionMode)
+      CSF.NativeLowPrecision = true;
+    else
+      CSF.MinimumPrecision = true;
+  }
+
   if (!CSF.Int64Ops)
     CSF.Int64Ops = I.getType()->isIntegerTy(64);
 
@@ -206,13 +213,20 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
                                    const ModuleMetadataInfo &MMDI) {
 
   CanSetResMayNotAlias = MMDI.DXILVersion >= VersionTuple(1, 7);
-
-  // Check if -res-may-alias was provided on the command line.
-  // The command line option will set the dx.resmayalias module flag to 1.
-  if (auto *RMA = mdconst::extract_or_null<ConstantInt>(
+  // The command line option -res-may-alias will set the dx.resmayalias module
+  // flag to 1, thereby disabling the ability to set the ResMayNotAlias flag
+  if (auto *ResMayAlias = mdconst::extract_or_null<ConstantInt>(
           M.getModuleFlag("dx.resmayalias")))
-    if (RMA->getValue() != 0)
-      CanSetResMayNotAlias = false;
+    CanSetResMayNotAlias = !ResMayAlias->getValue().getBoolValue();
+
+  // NativeLowPrecisionMode can only be set when the command line option
+  // -enable-16bit-types is provided. This is indicated by the dx.nativelowprec
+  // module flag being set
+  CanSetNativeLowPrecisionMode = false;
+  if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(
+          M.getModuleFlag("dx.nativelowprec")))
+    if (MMDI.ShaderModelVersion >= VersionTuple(6, 2))
+      CanSetNativeLowPrecisionMode = NativeLowPrec->getValue().getBoolValue();
 
   CallGraph CG(M);
 
@@ -238,18 +252,6 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
         continue;
       }
 
-      // Set ResMayNotAlias to true if DXIL validator version < 1.8 and there
-      // are UAVs present globally.
-      if (CanSetResMayNotAlias && MMDI.ValidatorVersion < VersionTuple(1, 8))
-        SCCSF.ResMayNotAlias = !DRM.uavs().empty();
-
-      // Set UseNativeLowPrecision using dx.nativelowprec module metadata
-      if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(
-              M.getModuleFlag("dx.nativelowprec")))
-        if (MMDI.ShaderModelVersion >= VersionTuple(6, 2) &&
-            NativeLowPrec->getValue() != 0)
-          SCCSF.UseNativeLowPrecision = true;
-
       ComputedShaderFlags CSF;
       for (const auto &BB : *F)
         for (const auto &I : BB)
@@ -286,6 +288,17 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
             *(EntryFunProps.Entry), "Inconsistent optnone attribute "));
   }
 
+  // Set ResMayNotAlias to true if DXIL validator version < 1.8 and there
+  // are UAVs present globally.
+  if (CanSetResMayNotAlias && MMDI.ValidatorVersion < VersionTuple(1, 8))
+    CombinedSFMask.ResMayNotAlias = !DRM.uavs().empty();
+
+  // Set the module flag that enables native low-precision execution mode. This
+  // is needed even if the module does not use 16-bit types because a
+  // corresponding debug module may include 16-bit types, and tools that use the
+  // debug module may expect it to have the same flags as the original
+  CombinedSFMask.NativeLowPrecisionMode = CanSetNativeLowPrecisionMode;
+
   // Set the Max64UAVs flag if the number of UAVs is > 8
   uint32_t NumUAVs = 0;
   for (auto &UAV : DRM.uavs())

diff  --git a/llvm/lib/Target/DirectX/DXILShaderFlags.h b/llvm/lib/Target/DirectX/DXILShaderFlags.h
index 0e0bd0036349e..c4eef4e708cfd 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.h
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.h
@@ -91,7 +91,10 @@ struct ModuleShaderFlags {
   const ComputedShaderFlags &getCombinedFlags() const { return CombinedSFMask; }
 
 private:
-  bool CanSetResMayNotAlias;
+  // Booleans set by module flags
+  bool CanSetResMayNotAlias;         // dx.resmayalias
+  bool CanSetNativeLowPrecisionMode; // dx.nativelowprec
+
   /// Map of Function-Shader Flag Mask pairs representing properties of each of
   /// the functions in the module. Shader Flags of each function represent both
   /// module-level and function-level flags

diff  --git a/llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
index 561e09bb1e9dc..5ecac3980d044 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
@@ -1,4 +1,10 @@
 ; 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
+
+; Check that when the dx.nativelowprec module flag is not specified, the
+; module-level shader flag UseNativeLowPrecision is not set, and the
+; MinimumPrecision feature flag is set due to the presence of half and i16
+; without native low precision.
 
 target triple = "dxil-pc-shadermodel6.7-library"
 
@@ -6,25 +12,33 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ;CHECK-NEXT: ; Shader Flags Value: 0x00000020
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Note: shader requires additional functionality:
+;CHECK-NEXT: ;       Minimum-precision data types
 ;CHECK-NEXT: ; Note: extra DXIL module flags:
-;CHECK-NEXT: ;       Low-precision data types
+;CHECK-NEXT: ;       Low-precision data types present
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Shader Flags for Module Functions
 
 ;CHECK-LABEL: ; Function add_i16 : 0x00000020
-define i16 @add_i16(i16 %a, i16 %b) {
+define i16 @add_i16(i16 %a, i16 %b) "hlsl.export" {
   %sum = add i16 %a, %b
   ret i16 %sum
 }
 
 ;CHECK-LABEL: ; Function add_i32 : 0x00000000
-define i32 @add_i32(i32 %a, i32 %b) {
+define i32 @add_i32(i32 %a, i32 %b) "hlsl.export" {
   %sum = add i32 %a, %b
   ret i32 %sum
 }
 
 ;CHECK-LABEL: ; Function add_half : 0x00000020
-define half @add_half(half %a, half %b) {
+define half @add_half(half %a, half %b) "hlsl.export" {
   %sum = fadd half %a, %b
   ret half %sum
 }
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NEXT:     Flags:
+; DXC:      MinimumPrecision: true
+; DXC:      NativeLowPrecision: false
+; DXC: ...

diff  --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-sm6.7.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-sm6.7.ll
index 934319557a11f..fc6560e321b4b 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-sm6.7.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-sm6.7.ll
@@ -2,8 +2,8 @@
 
 ; This test checks to ensure the behavior of the DXIL shader flag analysis
 ; for the flag ResMayNotAlias is correct when the DXIL Version is >= 1.7 and the
-; DXIL Validator Version < 1.8. The ResMayNotAlias flag (0x20000000) should be
-; set on all functions if there are one or more UAVs present globally in the
+; DXIL Validator Version < 1.8. The ResMayNotAlias module flag (0x20000000)
+; should be set if there are one or more UAVs present globally in the
 ; module.
 
 target triple = "dxil-pc-shadermodel6.7-library"
@@ -19,7 +19,7 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ; CHECK:       Any UAV may not alias any other UAV
 ;
 
-; CHECK: Function loadUAV : 0x200000000
+; CHECK: Function loadUAV : 0x00000000
 define float @loadUAV() #0 {
   %res = call target("dx.TypedBuffer", float, 1, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
@@ -29,7 +29,7 @@ define float @loadUAV() #0 {
   ret float %val
 }
 
-; CHECK: Function loadSRV : 0x200000010
+; CHECK: Function loadSRV : 0x00000010
 define float @loadSRV() #0 {
   %res = tail call target("dx.RawBuffer", float, 0, 0)
       @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)

diff  --git a/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-0.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-0.ll
index c537a01482f39..2e68fe375a42c 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-0.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-0.ll
@@ -1,7 +1,9 @@
 ; 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
 
 ; Check that when the dx.nativelowprec module flag is set to 0, the module-level
-; shader flag UseNativeLowPrecision is not set
+; shader flag UseNativeLowPrecision is not set, and the MinimumPrecision feature
+; flag is set due to the presence of half and i16 without native low precision.
 
 target triple = "dxil-pc-shadermodel6.7-library"
 
@@ -9,29 +11,37 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ;CHECK-NEXT: ; Shader Flags Value: 0x00000020
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Note: shader requires additional functionality:
+;CHECK-NEXT: ;       Minimum-precision data types
 ;CHECK-NEXT: ; Note: extra DXIL module flags:
-;CHECK-NEXT: ;       Low-precision data types
-;CHECK-NOT:  ;       Native 16bit types enabled
+;CHECK-NEXT: ;       Low-precision data types present
+;CHECK-NOT:  ;       Enable native low-precision data types
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Shader Flags for Module Functions
 
 ;CHECK-LABEL: ; Function add_i16 : 0x00000020
-define i16 @add_i16(i16 %a, i16 %b) {
+define i16 @add_i16(i16 %a, i16 %b) "hlsl.export" {
   %sum = add i16 %a, %b
   ret i16 %sum
 }
 
 ;CHECK-LABEL: ; Function add_i32 : 0x00000000
-define i32 @add_i32(i32 %a, i32 %b) {
+define i32 @add_i32(i32 %a, i32 %b) "hlsl.export" {
   %sum = add i32 %a, %b
   ret i32 %sum
 }
 
 ;CHECK-LABEL: ; Function add_half : 0x00000020
-define half @add_half(half %a, half %b) {
+define half @add_half(half %a, half %b) "hlsl.export" {
   %sum = fadd half %a, %b
   ret half %sum
 }
 
 !llvm.module.flags = !{!0}
 !0 = !{i32 1, !"dx.nativelowprec", i32 0}
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NEXT:     Flags:
+; DXC:      MinimumPrecision: true
+; DXC:      NativeLowPrecision: false
+; DXC: ...

diff  --git a/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll
index 07c4b9064d666..cb3b486cebce5 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll
@@ -1,4 +1,9 @@
 ; 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
+
+; Check that when the dx.nativelowprec module flag is set to 1, the module-level
+; shader flag UseNativeLowPrecision is set, and the NativeLowPrecision feature
+; flag is set
 
 target triple = "dxil-pc-shadermodel6.7-library"
 
@@ -6,32 +11,37 @@ target triple = "dxil-pc-shadermodel6.7-library"
 ;CHECK-NEXT: ; Shader Flags Value: 0x00800020
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Note: shader requires additional functionality:
+;CHECK-NEXT: ;       Native low-precision data types
 ;CHECK-NEXT: ; Note: extra DXIL module flags:
-;CHECK-NEXT: ;       Low-precision data types
-;CHECK-NEXT: ;       Use native low precision
+;CHECK-NEXT: ;       Low-precision data types present
+;CHECK-NEXT: ;       Enable native low-precision data types
 ;CHECK-NEXT: ;
 ;CHECK-NEXT: ; Shader Flags for Module Functions
 
-;CHECK-LABEL: ; Function add_i16 : 0x00800020
-define i16 @add_i16(i16 %a, i16 %b) {
+;CHECK-LABEL: ; Function add_i16 : 0x00000020
+define i16 @add_i16(i16 %a, i16 %b) "hlsl.export" {
   %sum = add i16 %a, %b
   ret i16 %sum
 }
 
-; NOTE: The flag for native low precision (0x80000) is set for every function
-; in the module regardless of whether or not the function uses low precision
-; data types (flag 0x20). This matches the behavior in DXC
-;CHECK-LABEL: ; Function add_i32 : 0x00800000
-define i32 @add_i32(i32 %a, i32 %b) {
+;CHECK-LABEL: ; Function add_i32 : 0x00000000
+define i32 @add_i32(i32 %a, i32 %b) "hlsl.export" {
   %sum = add i32 %a, %b
   ret i32 %sum
 }
 
-;CHECK-LABEL: ; Function add_half : 0x00800020
-define half @add_half(half %a, half %b) {
+;CHECK-LABEL: ; Function add_half : 0x00000020
+define half @add_half(half %a, half %b) "hlsl.export" {
   %sum = fadd half %a, %b
   ret half %sum
 }
 
 !llvm.module.flags = !{!0}
 !0 = !{i32 1, !"dx.nativelowprec", i32 1}
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NEXT:     Flags:
+; DXC:      MinimumPrecision: false
+; DXC:      NativeLowPrecision: true
+; DXC: ...


        


More information about the llvm-commits mailing list