Skip to content

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

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
May 14, 2025
6 changes: 3 additions & 3 deletions llvm/include/llvm/BinaryFormat/DXContainerConstants.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down
49 changes: 31 additions & 18 deletions llvm/lib/Target/DirectX/DXILShaderFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand Down Expand Up @@ -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())
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Target/DirectX/DXILShaderFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 18 additions & 4 deletions llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
; 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"

;CHECK: ; Combined Shader Flags for Module
;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: ...
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
; 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"

;CHECK: ; Combined Shader Flags for Module
;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: ...
32 changes: 21 additions & 11 deletions llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision-1.ll
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
; 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"

;CHECK: ; Combined Shader Flags for Module
;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: ...