https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/141759
From 4653aca0444c9ce14893e877eeb88241c9b01934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brio...@google.com> Date: Mon, 5 May 2025 18:01:17 +0200 Subject: [PATCH] [HLSL][SPIR-V] Handle SV_Postion builtin in PS This commit is using the same mechanism as vk::ext_builtin_input to implement the SV_Position semantic input. The HLSL signature is not yet ready for DXIL, hence this commit only implements the SPIR-V side. This is incomplete as it doesn't allow the semantic on hull/domain and other shaders, but it's a first step to validate the overall input/output semantic logic. --- clang/include/clang/Basic/Attr.td | 7 ++++ clang/include/clang/Basic/AttrDocs.td | 14 +++++++ clang/include/clang/Sema/SemaHLSL.h | 2 + clang/lib/CodeGen/CGHLSLRuntime.cpp | 41 ++++++++++++++----- clang/lib/Parse/ParseHLSL.cpp | 1 + clang/lib/Sema/SemaDeclAttr.cpp | 3 ++ clang/lib/Sema/SemaHLSL.cpp | 27 ++++++++++++ .../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 10 +++++ .../test/SemaHLSL/Semantics/position.ps.hlsl | 7 ++++ .../test/SemaHLSL/Semantics/position.vs.hlsl | 6 +++ 10 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl create mode 100644 clang/test/SemaHLSL/Semantics/position.ps.hlsl create mode 100644 clang/test/SemaHLSL/Semantics/position.vs.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7c63279f156a9..ae363a780a674 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4851,6 +4851,13 @@ def HLSLResourceBinding: InheritableAttr { }]; } +def HLSLSV_Position : HLSLAnnotationAttr { + let Spellings = [HLSLAnnotation<"sv_position">]; + let Subjects = SubjectList<[ParmVar, Field]>; + let LangOpts = [HLSL]; + let Documentation = [HLSLSV_PositionDocs]; +} + def HLSLPackOffset: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"packoffset">]; let LangOpts = [HLSL]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 5b58bbb510c54..a09de9220608d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8472,6 +8472,20 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo }]; } +def HLSLSV_PositionDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``SV_Position`` semantic, when applied to an input parameter in a pixel +shader, contains the location of the pixel center (x, y) in screen space. +This semantic can be applied to the parameter, or a field in a struct used +as input parameter. +This attribute is supported as input in pixel, hull, domain and mesh shaders. +This attribute is supported as output in vertex, geometry and domain shaders. + +The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics + }]; +} + def HLSLGroupSharedAddressSpaceDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 66d09f49680be..ba5f06f93dc30 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -125,6 +125,7 @@ class SemaHLSL : public SemaBase { void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL); void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL); + void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL); void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL); void handleShaderAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); @@ -146,6 +147,7 @@ class SemaHLSL : public SemaBase { // Diagnose whether the input ID is uint/unit2/uint3 type. bool diagnoseInputIDType(QualType T, const ParsedAttr &AL); + bool diagnosePositionType(QualType T, const ParsedAttr &AL); bool CanPerformScalarCast(QualType SrcTy, QualType DestTy); bool ContainsBitField(QualType BaseTy); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 6d267e6164845..9115492d1b1dd 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -384,6 +384,28 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { return B.CreateCall(F, {B.getInt32(0)}); } +static void addBuiltinDecoration(llvm::GlobalVariable *GV, unsigned BuiltIn) { + LLVMContext &Ctx = GV->getContext(); + IRBuilder<> B(GV->getContext()); + MDNode *Operands = + MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(11)), + ConstantAsMetadata::get(B.getInt32(BuiltIn))}); + MDNode *Decoration = MDNode::get(Ctx, {Operands}); + GV->addMetadata("spirv.Decorations", *Decoration); +} + +static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, + llvm::Type *Ty, const Twine &Name, + unsigned BuiltInID) { + auto *GV = new llvm::GlobalVariable( + M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 7, /* isExternallyInitialized= */ true); + addBuiltinDecoration(GV, BuiltInID); + return B.CreateLoad(Ty, GV); +} + llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, const ParmVarDecl &D, llvm::Type *Ty) { @@ -407,6 +429,13 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); return buildVectorInput(B, GroupIDIntrinsic, Ty); } + if (D.hasAttr<HLSLSV_PositionAttr>()) { + if (getArch() == llvm::Triple::spirv) + return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position", + /* BuiltIn::Position */ 0); + llvm_unreachable( + "Shader signature for semantics not implemented for DXIL."); + } assert(false && "Unhandled parameter attribute"); return nullptr; } @@ -626,16 +655,8 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *GV) { - if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) { - LLVMContext &Ctx = GV->getContext(); - IRBuilder<> B(GV->getContext()); - MDNode *Operands = MDNode::get( - Ctx, {ConstantAsMetadata::get( - B.getInt32(/* Spirv::Decoration::BuiltIn */ 11)), - ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))}); - MDNode *Decoration = MDNode::get(Ctx, {Operands}); - GV->addMetadata("spirv.Decorations", *Decoration); - } + if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) + addBuiltinDecoration(GV, Attr->getBuiltIn()); } llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 5569605c287b1..53d46465e3362 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -289,6 +289,7 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, case ParsedAttr::AT_HLSLSV_GroupID: case ParsedAttr::AT_HLSLSV_GroupIndex: case ParsedAttr::AT_HLSLSV_DispatchThreadID: + case ParsedAttr::AT_HLSLSV_Position: break; default: llvm_unreachable("invalid HLSL Annotation"); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c829a4426b9f7..e721db5cfb890 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7510,6 +7510,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLWaveSize: S.HLSL().handleWaveSizeAttr(D, AL); break; + case ParsedAttr::AT_HLSLSV_Position: + S.HLSL().handleSV_PositionAttr(D, AL); + break; case ParsedAttr::AT_HLSLVkExtBuiltinInput: S.HLSL().handleVkExtBuiltinInputAttr(D, AL); break; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 9065cc5a1d4a5..bcc7f7b40715e 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -764,6 +764,13 @@ void SemaHLSL::CheckSemanticAnnotation( return; DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute}); break; + case attr::HLSLSV_Position: + // TODO: allow use on other shader types & output once the overall semantic + // logic is implemented. + if (ST == llvm::Triple::Pixel) + return; + DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel}); + break; default: llvm_unreachable("Unknown HLSLAnnotationAttr"); } @@ -1147,6 +1154,26 @@ void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { HLSLSV_DispatchThreadIDAttr(getASTContext(), AL)); } +bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) { + const auto *VT = T->getAs<VectorType>(); + + if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) { + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "float/float1/float2/float3"; + return false; + } + + return true; +} + +void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) { + auto *VD = cast<ValueDecl>(D); + if (!diagnosePositionType(VD->getType(), AL)) + return; + + D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL)); +} + void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) { auto *VD = cast<ValueDecl>(D); if (!diagnoseInputIDType(VD->getType(), AL)) diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl new file mode 100644 index 0000000000000..58b91fc9264dd --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s + +// CHECK: @sv_position = external thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 + +// CHECK: define void @main() {{.*}} { +float4 main(float4 p : SV_Position) { + // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @sv_position, align 16 + // CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]]) + return p; +} diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl new file mode 100644 index 0000000000000..32bc5f55b2abd --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s + +float4 main(float4 a : SV_Position) { +// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 'float4':'vector<float, 4>' +// CHECK-NEXT: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}> +} diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl new file mode 100644 index 0000000000000..19f781fa3757c --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify + +// expected-error@+1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}} +float4 main(float4 a : SV_Position) { + return a; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits