https://github.com/jzakharovnv updated https://github.com/llvm/llvm-project/pull/232071
>From 8821ccdd30e5dd3b75caaac605d55c0b69091fc3 Mon Sep 17 00:00:00 2001 From: Jonathan Zakharov <[email protected]> Date: Wed, 14 Oct 2026 12:54:57 -0700 Subject: [PATCH 1/5] [HLSL][SPIRV] Implement SV_IsFrontFace --- .../clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/CodeGen/CGHLSLRuntime.cpp | 34 +++++++++++++++---- clang/lib/Sema/SemaHLSL.cpp | 9 ++++- .../semantics/SV_IsFrontFace.ps.hlsl | 20 +++++++++++ .../Semantics/isfrontface.output.hlsl | 8 +++++ .../SemaHLSL/Semantics/isfrontface.ps.hlsl | 31 +++++++++++++++++ .../SemaHLSL/Semantics/isfrontface.vs.hlsl | 7 ++++ 7 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl create mode 100644 clang/test/SemaHLSL/Semantics/isfrontface.output.hlsl create mode 100644 clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl create mode 100644 clang/test/SemaHLSL/Semantics/isfrontface.vs.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 94fe19a6636f72..a9d32f7d2590be 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13796,7 +13796,7 @@ def err_hlsl_semantic_invalid_type "%select{scalar|scalar or vector of up to %2 components}1 of " "%select{16 or 32 bit integer|32 bit integer|" "16 or 32 bit floating-point|16 or 32 bit unsigned integer|" - "32 bit unsigned integer}3 type (was %4)">; + "32 bit unsigned integer|bool}3 type (was %4)">; def err_hlsl_init_priority_unsupported : Error< "initializer priorities are not supported in HLSL">; def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 35a31942c3b591..f486259e171b13 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1094,15 +1094,20 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { } static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, - unsigned BuiltIn) { + unsigned BuiltIn, bool NeedsFlat = false) { LLVMContext &Ctx = GV->getContext(); IRBuilder<> B(*GV->getParent()); - MDNode *Operands = MDNode::get( + // Emit all decorations as a single spirv.Decorations node. + SmallVector<Metadata *, 2> Decorations; + Decorations.push_back(MDNode::get( Ctx, {ConstantAsMetadata::get(B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)), - ConstantAsMetadata::get(B.getInt32(BuiltIn))}); - MDNode *Decoration = MDNode::get(Ctx, {Operands}); - GV->addMetadata("spirv.Decorations", *Decoration); + ConstantAsMetadata::get(B.getInt32(BuiltIn))})); + if (NeedsFlat) + Decorations.push_back( + MDNode::get(Ctx, {ConstantAsMetadata::get( + B.getInt32(/* Spirv::Decoration::Flat */ 14))})); + GV->addMetadata("spirv.Decorations", *MDNode::get(Ctx, Decorations)); } static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) { @@ -1137,13 +1142,14 @@ static bool inputRequiresFlatDecoration(llvm::Type *Ty) { static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, - unsigned BuiltInID) { + unsigned BuiltInID, + bool NeedsFlat = false) { auto *GV = new llvm::GlobalVariable( M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr, llvm::GlobalVariable::GeneralDynamicTLSModel, /* AddressSpace */ 7, /* isExternallyInitialized= */ true); - addSPIRVBuiltinDecoration(GV, BuiltInID); + addSPIRVBuiltinDecoration(GV, BuiltInID, NeedsFlat); GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return B.CreateLoad(Ty, GV); } @@ -1566,6 +1572,20 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature); break; + case llvm::dxbc::PSV::SemanticKind::IsFrontFace: + assert(Stage == llvm::Triple::Pixel && + "SV_IsFrontFace is in an unavailable stage and should have been " + "diagnosed by Sema"); + if (CGM.getTarget().getTriple().isSPIRV()) + // Non-float pixel inputs cannot be interpolated and must be Flat. + return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, + Semantic->getAttrName()->getName(), + /* BuiltIn::FrontFacing */ 17, + inputRequiresFlatDecoration(Type)); + if (CGM.getTarget().getTriple().isDXIL()) + return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, + Signature); + break; default: break; } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 4fe7ed151e9180..24155ce76b3030 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1004,6 +1004,8 @@ static bool isVkPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD, return true; case SemanticKind::InstanceID: return ST == llvm::Triple::Vertex && IsInput; + case SemanticKind::IsFrontFace: + return ST == llvm::Triple::Pixel && IsInput; default: return false; } @@ -1381,6 +1383,12 @@ void SemaHLSL::diagnoseSemanticType(const Decl *D, << /* 16 or 32 bit unsigned integer / 32 bit unsigned integer */ (IsSPIRV ? 4 : 3) << DeclaredTy; return; + case SemanticKind::IsFrontFace: + if (!T->isBooleanType()) + Diag(A->getLoc(), diag::err_hlsl_semantic_invalid_type) + << A->getAttrName() << /* scalar */ 0 << 1 << /* bool */ 5 + << DeclaredTy; + return; default: // Other semantics only have the general signature type restrictions. break; @@ -2186,7 +2194,6 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { case SemanticKind::PrimitiveID: case SemanticKind::GSInstanceID: case SemanticKind::SampleIndex: - case SemanticKind::IsFrontFace: case SemanticKind::Coverage: case SemanticKind::InnerCoverage: case SemanticKind::Depth: diff --git a/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl new file mode 100644 index 00000000000000..73e989601cb251 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-DXIL + +// CHECK-SPIRV: @SV_IsFrontFace = external hidden thread_local addrspace(7) externally_initialized constant i1, !spirv.Decorations ![[#MD_0:]] + +// CHECK: define void @main() {{.*}} { +float4 main(bool ff : SV_IsFrontFace) : SV_Target { + // CHECK-SPIRV: %[[FF:.*]] = load i1, ptr addrspace(7) @SV_IsFrontFace + // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainb(i1 %[[FF]]) + + // CHECK-DXIL: %[[INPUT:.*]] = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison) + // CHECK-DXIL: %[[BOOL:.*]] = icmp ne i32 %[[INPUT]], 0 + // CHECK-DXIL: %[[R:.*]] = call <4 x float> @_Z4mainb(i1 %[[BOOL]]) + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +// Two decorations in one node: BuiltIn FrontFacing (17) and Flat (14). +// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]], ![[#MD_2:]]} +// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 17} +// CHECK-SPIRV-DAG: ![[#MD_2]] = !{i32 14} diff --git a/clang/test/SemaHLSL/Semantics/isfrontface.output.hlsl b/clang/test/SemaHLSL/Semantics/isfrontface.output.hlsl new file mode 100644 index 00000000000000..91379e44e03512 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/isfrontface.output.hlsl @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel -finclude-default-header -x hlsl -verify -o - %s +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -x hlsl -verify -o - %s + +float4 main(out bool ff : SV_IsFrontFace) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' is not supported in pixel shader outputs}} + ff = true; // Written, so the parameter is used. + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} diff --git a/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl b/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl new file mode 100644 index 00000000000000..b2e92ff4938060 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -verify -o - %s +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -finclude-default-header -x hlsl -verify -o - %s + +[shader("pixel")] +float4 bad_uint(uint ff : SV_IsFrontFace) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'uint' (aka 'unsigned int'))}} + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +[shader("pixel")] +float4 bad_float(float ff : SV_IsFrontFace) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'float')}} + return (ff.x > 0.f) ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +[shader("pixel")] +float4 bad_vec(bool3 ff : SV_IsFrontFace) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'bool3' (aka 'vector<bool, 3>'))}} + return ff.x ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +[shader("pixel")] +float4 bad_index(bool ff : SV_IsFrontFace1) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' does not allow indexing}} + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +[shader("pixel")] +float4 ok(bool ff : SV_IsFrontFace) : SV_Target { + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} diff --git a/clang/test/SemaHLSL/Semantics/isfrontface.vs.hlsl b/clang/test/SemaHLSL/Semantics/isfrontface.vs.hlsl new file mode 100644 index 00000000000000..d3474838dc6040 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/isfrontface.vs.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s + +float4 main(bool ff : SV_IsFrontFace) : SV_Position { +// expected-error@-1 {{semantic 'SV_IsFrontFace' is not supported in vertex shader inputs}} + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} >From b47e7374c95fbb2c7f5af8eac87df088fc793f08 Mon Sep 17 00:00:00 2001 From: Jonathan Zakharov <[email protected]> Date: Wed, 14 Oct 2026 13:14:23 -0700 Subject: [PATCH 2/5] formatting --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index f486259e171b13..92dd5aae038905 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1094,7 +1094,8 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { } static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, - unsigned BuiltIn, bool NeedsFlat = false) { + unsigned BuiltIn, + bool NeedsFlat = false) { LLVMContext &Ctx = GV->getContext(); IRBuilder<> B(*GV->getParent()); // Emit all decorations as a single spirv.Decorations node. @@ -1578,10 +1579,9 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( "diagnosed by Sema"); if (CGM.getTarget().getTriple().isSPIRV()) // Non-float pixel inputs cannot be interpolated and must be Flat. - return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, - Semantic->getAttrName()->getName(), - /* BuiltIn::FrontFacing */ 17, - inputRequiresFlatDecoration(Type)); + return createSPIRVBuiltinLoad( + B, CGM.getModule(), Type, Semantic->getAttrName()->getName(), + /* BuiltIn::FrontFacing */ 17, inputRequiresFlatDecoration(Type)); if (CGM.getTarget().getTriple().isDXIL()) return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature); >From 39d60ddd05ac374305be058678239873cbb64845 Mon Sep 17 00:00:00 2001 From: Jonathan Zakharov <[email protected]> Date: Wed, 14 Oct 2026 14:21:43 -0700 Subject: [PATCH 3/5] fix codegen test --- clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl index 73e989601cb251..7065fa5ab50ace 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.ps.hlsl @@ -3,7 +3,8 @@ // CHECK-SPIRV: @SV_IsFrontFace = external hidden thread_local addrspace(7) externally_initialized constant i1, !spirv.Decorations ![[#MD_0:]] -// CHECK: define void @main() {{.*}} { +// CHECK-SPIRV: define void @main() {{.*}} { +// CHECK-DXIL: define void @main() {{.*}} { float4 main(bool ff : SV_IsFrontFace) : SV_Target { // CHECK-SPIRV: %[[FF:.*]] = load i1, ptr addrspace(7) @SV_IsFrontFace // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainb(i1 %[[FF]]) >From 8eaf42c750a430bd21a669c465560eed1299ce8e Mon Sep 17 00:00:00 2001 From: Jonathan Zakharov <[email protected]> Date: Fri, 16 Oct 2026 14:13:48 -0700 Subject: [PATCH 4/5] review: fixed check divergence --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++- clang/lib/CodeGen/CGHLSLRuntime.cpp | 14 +++++++++---- clang/lib/Sema/SemaHLSL.cpp | 9 +++++--- .../semantics/SV_IsFrontFace.uint.ps.hlsl | 21 +++++++++++++++++++ .../SemaHLSL/Semantics/isfrontface.ps.hlsl | 15 +++++++++---- 5 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.uint.ps.hlsl diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a9d32f7d2590be..937d8aeabe191d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13796,7 +13796,8 @@ def err_hlsl_semantic_invalid_type "%select{scalar|scalar or vector of up to %2 components}1 of " "%select{16 or 32 bit integer|32 bit integer|" "16 or 32 bit floating-point|16 or 32 bit unsigned integer|" - "32 bit unsigned integer|bool}3 type (was %4)">; + "32 bit unsigned integer|bool or 32 bit unsigned integer}3 type " + "(was %4)">; def err_hlsl_init_priority_unsupported : Error< "initializer priorities are not supported in HLSL">; def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 92dd5aae038905..b5ad9ac49775ea 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -1577,11 +1577,17 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( assert(Stage == llvm::Triple::Pixel && "SV_IsFrontFace is in an unavailable stage and should have been " "diagnosed by Sema"); - if (CGM.getTarget().getTriple().isSPIRV()) + if (CGM.getTarget().getTriple().isSPIRV()) { + // The FrontFacing BuiltIn is always a bool in SPIR-V, whatever type the + // entry point declares. Load it as bool, then convert below. + llvm::Type *BoolTy = B.getInt1Ty(); // Non-float pixel inputs cannot be interpolated and must be Flat. - return createSPIRVBuiltinLoad( - B, CGM.getModule(), Type, Semantic->getAttrName()->getName(), - /* BuiltIn::FrontFacing */ 17, inputRequiresFlatDecoration(Type)); + llvm::Value *FF = createSPIRVBuiltinLoad( + B, CGM.getModule(), BoolTy, Semantic->getAttrName()->getName(), + /* BuiltIn::FrontFacing */ 17, /* NeedsFlat= */ true); + // Convert to the declared parameter type (eg uint). + return Type == BoolTy ? FF : B.CreateZExt(FF, Type); + } if (CGM.getTarget().getTriple().isDXIL()) return emitDXILUserSemanticLoad(B, Type, Decl, Semantic, Index, Signature); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 24155ce76b3030..522894ee9a2cc6 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1384,10 +1384,13 @@ void SemaHLSL::diagnoseSemanticType(const Decl *D, (IsSPIRV ? 4 : 3) << DeclaredTy; return; case SemanticKind::IsFrontFace: - if (!T->isBooleanType()) + // DXC accepts bool and uint. The SPIR-V FrontFacing variable is always + // bool, so CodeGen converts it to the declared type. + if (!T->isBooleanType() && + !(T->isUnsignedIntegerType() && isIntElementOfWidth(Ctx, T, 32))) Diag(A->getLoc(), diag::err_hlsl_semantic_invalid_type) - << A->getAttrName() << /* scalar */ 0 << 1 << /* bool */ 5 - << DeclaredTy; + << A->getAttrName() << /* scalar */ 0 << 1 + << /* bool or 32 bit unsigned integer */ 5 << DeclaredTy; return; default: // Other semantics only have the general signature type restrictions. diff --git a/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.uint.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.uint.ps.hlsl new file mode 100644 index 00000000000000..c23ff46b176708 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_IsFrontFace.uint.ps.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-DXIL + +// The SPIR-V FrontFacing variable stays bool even when the parameter is uint. +// CHECK-SPIRV: @SV_IsFrontFace = external hidden thread_local addrspace(7) externally_initialized constant i1, !spirv.Decorations ![[#MD_0:]] + +// CHECK-SPIRV: define void @main() {{.*}} { +// CHECK-DXIL: define void @main() {{.*}} { +float4 main(uint ff : SV_IsFrontFace) : SV_Target { + // CHECK-SPIRV: %[[FF:.*]] = load i1, ptr addrspace(7) @SV_IsFrontFace + // CHECK-SPIRV: %[[U:.*]] = zext i1 %[[FF]] to i32 + // CHECK-SPIRV: %[[R:.*]] = call spir_func <4 x float> @_Z4mainj(i32 %[[U]]) + + // CHECK-DXIL: %[[INPUT:.*]] = call i32 @llvm.dx.load.input.i32(i32 0, i32 0, i8 0, i32 poison) + // CHECK-DXIL: %[[R:.*]] = call <4 x float> @_Z4mainj(i32 %[[INPUT]]) + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]], ![[#MD_2:]]} +// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 17} +// CHECK-SPIRV-DAG: ![[#MD_2]] = !{i32 14} diff --git a/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl b/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl index b2e92ff4938060..698185f27e095e 100644 --- a/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl +++ b/clang/test/SemaHLSL/Semantics/isfrontface.ps.hlsl @@ -1,21 +1,28 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -verify -o - %s // RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-library -finclude-default-header -x hlsl -verify -o - %s +// DXC accepts both bool and uint. The SPIR-V FrontFacing variable is always +// bool, and CodeGen converts it to the declared type. [shader("pixel")] -float4 bad_uint(uint ff : SV_IsFrontFace) : SV_Target { -// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'uint' (aka 'unsigned int'))}} +float4 ok_uint(uint ff : SV_IsFrontFace) : SV_Target { + return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); +} + +[shader("pixel")] +float4 bad_int(int ff : SV_IsFrontFace) : SV_Target { +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool or 32 bit unsigned integer type (was 'int')}} return ff ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); } [shader("pixel")] float4 bad_float(float ff : SV_IsFrontFace) : SV_Target { -// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'float')}} +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool or 32 bit unsigned integer type (was 'float')}} return (ff.x > 0.f) ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); } [shader("pixel")] float4 bad_vec(bool3 ff : SV_IsFrontFace) : SV_Target { -// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool type (was 'bool3' (aka 'vector<bool, 3>'))}} +// expected-error@-1 {{semantic 'SV_IsFrontFace' must be a scalar of bool or 32 bit unsigned integer type (was 'bool3' (aka 'vector<bool, 3>'))}} return ff.x ? float4(1, 0, 0, 1) : float4(0, 0, 1, 1); } >From ec6edd66b05054e13d7f480de3843d2f2c83d398 Mon Sep 17 00:00:00 2001 From: Jonathan Zakharov <[email protected]> Date: Fri, 16 Oct 2026 14:52:40 -0700 Subject: [PATCH 5/5] [HLSL] Accept uint for SV_IsFrontFace, convert from bool FrontFacing in SPIR-V --- clang/lib/Sema/SemaHLSL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 522894ee9a2cc6..4362c99f2f1098 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1384,8 +1384,8 @@ void SemaHLSL::diagnoseSemanticType(const Decl *D, (IsSPIRV ? 4 : 3) << DeclaredTy; return; case SemanticKind::IsFrontFace: - // DXC accepts bool and uint. The SPIR-V FrontFacing variable is always - // bool, so CodeGen converts it to the declared type. + // Accept bool or uint; SPIR-V FrontFacing BuiltIn is always a bool + // and CodeGen converts it to the declared type. if (!T->isBooleanType() && !(T->isUnsignedIntegerType() && isIntElementOfWidth(Ctx, T, 32))) Diag(A->getLoc(), diag::err_hlsl_semantic_invalid_type) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
