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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,19 @@ 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);

// NativeHalfType corresponds to the -fnative-half-type clang option which is
// aliased by clang-dxc's -enable-16bit-types option. This option is used to
// set the UseNativeLowPrecision DXIL module flag in the DirectX backend
if (LangOpts.NativeHalfType)
M.setModuleFlag(llvm::Module::ModFlagBehavior::Error, "dx.nativelowprec",
1);

generateGlobalCtorDtorCalls();
}

Expand Down
7 changes: 7 additions & 0 deletions clang/test/CodeGenHLSL/enable-16bit-types.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %clang_dxc -enable-16bit-types -T lib_6_3 -HV 202x -Vd -Xclang -emit-llvm %s | FileCheck %s --check-prefix=FLAG
// RUN: %clang_dxc -T lib_6_3 -HV 202x -Vd -Xclang -emit-llvm %s | FileCheck %s --check-prefix=NOFLAG

// FLAG-DAG: ![[NLP:.*]] = !{i32 1, !"dx.nativelowprec", i32 1}
// FLAG-DAG: !llvm.module.flags = !{{{.*}}![[NLP]]{{.*}}}

// NOFLAG-NOT: dx.nativelowprec
7 changes: 7 additions & 0 deletions llvm/lib/Target/DirectX/DXILShaderFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ 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 (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.

NativeLowPrec->getValue() != 0)
SCCSF.UseNativeLowPrecision = true;

ComputedShaderFlags CSF;
for (const auto &BB : *F)
for (const auto &I : BB)
Expand Down
14 changes: 3 additions & 11 deletions llvm/test/CodeGen/DirectX/ShaderFlags/low-precision.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
; 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"

Expand All @@ -13,26 +12,19 @@ target triple = "dxil-pc-shadermodel6.7-library"
;CHECK-NEXT: ; Shader Flags for Module Functions

;CHECK-LABEL: ; Function add_i16 : 0x00000020
define i16 @add_i16(i16 %a, i16 %b) #0 {
define i16 @add_i16(i16 %a, i16 %b) {
%sum = add i16 %a, %b
ret i16 %sum
}

;CHECK-LABEL: ; Function add_i32 : 0x00000000
define i32 @add_i32(i32 %a, i32 %b) #0 {
define i32 @add_i32(i32 %a, i32 %b) {
%sum = add i32 %a, %b
ret i32 %sum
}

;CHECK-LABEL: ; Function add_half : 0x00000020
define half @add_half(half %a, half %b) #0 {
define half @add_half(half %a, half %b) {
%sum = fadd half %a, %b
ret half %sum
}

attributes #0 = { convergent norecurse nounwind "hlsl.export"}

; DXC: - Name: SFI0
; DXC-NEXT: Size: 8
; DXC-NOT: Flags:
; DXC: ...
37 changes: 37 additions & 0 deletions llvm/test/CodeGen/DirectX/ShaderFlags/use-native-low-precision.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s

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) {
%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) {
%sum = add i32 %a, %b
ret i32 %sum
}

;CHECK-LABEL: ; Function add_half : 0x00800020
define half @add_half(half %a, half %b) {
%sum = fadd half %a, %b
ret half %sum
}

!llvm.module.flags = !{!0}
!0 = !{i32 1, !"dx.nativelowprec", i32 1}
Loading