From 3d4cce9aeda612df3da7f73d6c32a862822e14b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 19 Nov 2025 16:50:50 +0100 Subject: [PATCH 1/2] [HLSL][SPIR-V] Implements SV_Position for VS/PS I/O Current implementation for SV_Position was very basic to allow implementing/testing some semantics. Now that semantic support is more robust, I can move forward and implement the whole semantic logic. DX part is still a bit placeholder. --- clang/include/clang/Sema/SemaHLSL.h | 11 ++++-- clang/lib/CodeGen/CGHLSLRuntime.cpp | 29 ++++++++++----- clang/lib/Sema/SemaHLSL.cpp | 37 ++++++++++++------- .../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 20 +++++++--- .../CodeGenHLSL/semantics/SV_Position.vs.hlsl | 26 +++++++++++++ .../test/SemaHLSL/Semantics/position.ps.hlsl | 14 ++----- .../test/SemaHLSL/Semantics/position.vs.hlsl | 6 --- .../CodeGen/SPIRV/semantics/position.ps.ll | 32 ++++++++++++++++ .../CodeGen/SPIRV/semantics/position.vs.ll | 31 ++++++++++++++++ 9 files changed, 159 insertions(+), 47 deletions(-) create mode 100644 clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl delete mode 100644 clang/test/SemaHLSL/Semantics/position.vs.hlsl create mode 100644 llvm/test/CodeGen/SPIRV/semantics/position.ps.ll create mode 100644 llvm/test/CodeGen/SPIRV/semantics/position.vs.ll diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 86da323892f98..15edb7e77a22b 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -250,15 +250,20 @@ class SemaHLSL : public SemaBase { const RecordType *RT); void checkSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, - const HLSLAppliedSemanticAttr *SemanticAttr); + const HLSLAppliedSemanticAttr *SemanticAttr, + bool IsInput); + bool determineActiveSemanticOnScalar(FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, - llvm::StringSet<> &ActiveInputSemantics); + llvm::StringSet<> &ActiveSemantics, + bool IsInput); + bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, - llvm::StringSet<> &ActiveInputSemantics); + llvm::StringSet<> &ActiveSemantics, + bool IsInput); void processExplicitBindingsOnDecl(VarDecl *D); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 2a5f3f6895609..daaaa1d5004a9 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -731,10 +731,18 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( } if (SemanticName == "SV_POSITION") { - if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel) - return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, - Semantic->getAttrName()->getName(), - /* BuiltIn::FragCoord */ 15); + if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel) { + if (CGM.getTarget().getTriple().isSPIRV()) + return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, + Semantic->getAttrName()->getName(), + /* BuiltIn::FragCoord */ 15); + if (CGM.getTarget().getTriple().isDXIL()) + return emitDXILUserSemanticLoad(B, Type, Semantic, Index); + } + + if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Vertex) { + return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); + } } llvm_unreachable("non-handled system semantic. FIXME."); @@ -760,11 +768,14 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source, std::optional Index) { std::string SemanticName = Semantic->getAttrName()->getName().upper(); - if (SemanticName == "SV_POSITION") - createSPIRVBuiltinStore(B, CGM.getModule(), Source, - Semantic->getAttrName()->getName(), - /* BuiltIn::Position */ 0); - else + if (SemanticName == "SV_POSITION") { + if (CGM.getTarget().getTriple().isDXIL()) + emitDXILUserSemanticStore(B, Source, Semantic, Index); + else if (CGM.getTarget().getTriple().isSPIRV()) + createSPIRVBuiltinStore(B, CGM.getModule(), Source, + Semantic->getAttrName()->getName(), + /* BuiltIn::Position */ 0); + } else llvm_unreachable("non-handled system semantic. FIXME."); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index c5666941fd36a..4eac34c90e6bc 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -771,9 +771,12 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { } } -bool SemaHLSL::determineActiveSemanticOnScalar( - FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) { +bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD, + DeclaratorDecl *OutputDecl, + DeclaratorDecl *D, + SemanticInfo &ActiveSemantic, + llvm::StringSet<> &UsedSemantics, + bool IsInput) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr(); if (ActiveSemantic.Semantic) @@ -792,7 +795,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar( if (!A) return false; - checkSemanticAnnotation(FD, D, A); + checkSemanticAnnotation(FD, D, A, IsInput); OutputDecl->addAttr(A); unsigned Location = ActiveSemantic.Index.value_or(0); @@ -820,7 +823,8 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, - llvm::StringSet<> &UsedSemantics) { + llvm::StringSet<> &UsedSemantics, + bool IsInput) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr(); if (ActiveSemantic.Semantic) @@ -833,12 +837,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, const RecordType *RT = dyn_cast(T); if (!RT) return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic, - UsedSemantics); + UsedSemantics, IsInput); const RecordDecl *RD = RT->getDecl(); for (FieldDecl *Field : RD->fields()) { SemanticInfo Info = ActiveSemantic; - if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) { + if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics, + IsInput)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -920,7 +925,7 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { // FIXME: Verify output semantics in parameters. if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic, - ActiveInputSemantics)) { + ActiveInputSemantics, /* IsInput= */ true)) { Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); } @@ -932,12 +937,13 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { if (ActiveSemantic.Semantic) ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex(); if (!FD->getReturnType()->isVoidType()) - determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics); + determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics, + /* IsInput= */ false); } void SemaHLSL::checkSemanticAnnotation( FunctionDecl *EntryPoint, const Decl *Param, - const HLSLAppliedSemanticAttr *SemanticAttr) { + const HLSLAppliedSemanticAttr *SemanticAttr, bool IsInput) { auto *ShaderAttr = EntryPoint->getAttr(); assert(ShaderAttr && "Entry point has no shader attribute"); llvm::Triple::EnvironmentType ST = ShaderAttr->getType(); @@ -961,11 +967,14 @@ void SemaHLSL::checkSemanticAnnotation( } if (SemanticName == "SV_POSITION") { - // TODO(#143523): allow use on other shader types & output once the overall - // semantic logic is implemented. - if (ST == llvm::Triple::Pixel) + // SV_Position can is I/O for vertex shaders. + // For pixel shaders, only valid as input. + // Note: for SPIR-V, not backed by a builtin when used as input in a vertex + // shaders. + if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput)) return; - DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel}); + DiagnoseAttrStageMismatch(SemanticAttr, ST, + {llvm::Triple::Pixel, llvm::Triple::Vertex}); return; } diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl index be30e79438831..b7d2283ea7766 100644 --- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl @@ -1,11 +1,21 @@ -// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s +// 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: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 +// CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]] // CHECK: define void @main() {{.*}} { float4 main(float4 p : SV_Position) : A { - // 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]]) - // CHECK: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16 + // CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 16 + // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]]) + // CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16 + + // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) + // CHECK-DXIL: %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0) + // CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]]) return p; } + +// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]]} +// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 15} +// | `-> BuiltIn Position +// `-> SPIR-V decoration 'FragCoord' diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl new file mode 100644 index 0000000000000..0156c0bb816c1 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.8-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-DXIL %s +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-SPIRV %s + +// CHECK-SPIRV: @SV_Position0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]] +// CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_2:]] + +// CHECK: define void @main() {{.*}} { +float4 main(float4 p : SV_Position) : SV_Position { + // CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position0, align 16 + // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]]) + // CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @SV_Position, align 16 + + // CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) + // CHECK-DXIL: %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0) + // CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]]) + return p; +} + +// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]]} +// CHECK-SPIRV-DAG: ![[#MD_2]] = !{![[#MD_3:]]} +// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 30, i32 0} +// | `-> Location 0 +// `-> SPIR-V decoration 'Location' +// CHECK-SPIRV-DAG: ![[#MD_3]] = !{i32 11, i32 0} +// | `-> BuiltIn Position +// `-> SPIR-V decoration 'BuiltIn' diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl index 2d02384821d90..47d07887911d6 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -1,13 +1,7 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s +// 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 -// FIXME(Keenuts): change output semantic to something valid for pixels shaders -float4 main(float4 a : SV_Position2) : A { -// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)' -// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 'float4':'vector' -// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 -// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "SV_Position" 2 - -// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 -// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} "A" 0 +float4 main(float4 a : A) : SV_Position { +// expected-error@-1 {{attribute 'SV_Position' is unsupported in 'pixel' shaders, requires one of the following: pixel, vertex}} return a; } diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl deleted file mode 100644 index 9d0ff285ce055..0000000000000 --- a/clang/test/SemaHLSL/Semantics/position.vs.hlsl +++ /dev/null @@ -1,6 +0,0 @@ -// 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) : A { - return a; -} diff --git a/llvm/test/CodeGen/SPIRV/semantics/position.ps.ll b/llvm/test/CodeGen/SPIRV/semantics/position.ps.ll new file mode 100644 index 0000000000000..2c02987f73928 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/semantics/position.ps.ll @@ -0,0 +1,32 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: OpDecorate %[[#INPUT:]] BuiltIn FragCoord +; CHECK-DAG: OpDecorate %[[#OUTPUT:]] Location 0 + +; CHECK-DAG: %[[#float:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#v4:]] = OpTypeVector %[[#float]] 4 +; CHECK-DAG: %[[#ptr_i:]] = OpTypePointer Input %[[#v4]] +; CHECK-DAG: %[[#ptr_o:]] = OpTypePointer Output %[[#v4]] + +; CHECK-DAG: %[[#INPUT]] = OpVariable %[[#ptr_i]] Input +; CHECK-DAG: %[[#OUTPUT]] = OpVariable %[[#ptr_o]] Output + +@SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 +@A0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !2 + +define void @main() #1 { +entry: + %0 = load <4 x float>, ptr addrspace(7) @SV_Position, align 16 + store <4 x float> %0, ptr addrspace(8) @A0, align 16 + ret void + +; CHECK: %[[#TMP:]] = OpLoad %[[#v4]] %[[#INPUT]] Aligned 16 +; CHECK: OpStore %[[#OUTPUT]] %[[#TMP]] Aligned 16 +} + +!0 = !{!1} +!1 = !{i32 11, i32 15} +!2 = !{!3} +!3 = !{i32 30, i32 0} + diff --git a/llvm/test/CodeGen/SPIRV/semantics/position.vs.ll b/llvm/test/CodeGen/SPIRV/semantics/position.vs.ll new file mode 100644 index 0000000000000..73165f3719a97 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/semantics/position.vs.ll @@ -0,0 +1,31 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: OpDecorate %[[#INPUT:]] Location 0 +; CHECK-DAG: OpDecorate %[[#OUTPUT:]] BuiltIn Position + +; CHECK-DAG: %[[#float:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#v4:]] = OpTypeVector %[[#float]] 4 +; CHECK-DAG: %[[#ptr_i:]] = OpTypePointer Input %[[#v4]] +; CHECK-DAG: %[[#ptr_o:]] = OpTypePointer Output %[[#v4]] + +; CHECK-DAG: %[[#INPUT]] = OpVariable %[[#ptr_i]] Input +; CHECK-DAG: %[[#OUTPUT]] = OpVariable %[[#ptr_o]] Output + +@SV_Position0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0 +@SV_Position = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !2 + +define void @main() #1 { +entry: + %0 = load <4 x float>, ptr addrspace(7) @SV_Position0, align 16 + store <4 x float> %0, ptr addrspace(8) @SV_Position, align 16 + ret void + +; CHECK: %[[#TMP:]] = OpLoad %[[#v4]] %[[#INPUT]] Aligned 16 +; CHECK: OpStore %[[#OUTPUT]] %[[#TMP]] Aligned 16 +} + +!0 = !{!1} +!1 = !{i32 30, i32 0} +!2 = !{!3} +!3 = !{i32 11, i32 0} From f0f3c6ffc9c6f00296faef0186e49a68411af3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 21 Nov 2025 16:36:53 +0100 Subject: [PATCH 2/2] pr-feedback --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 18 +++++++++++---- clang/lib/Sema/SemaHLSL.cpp | 6 ++--- .../HLSL/semantic-input-struct-shadow.hlsl | 21 +++++++++++++++++ .../test/AST/HLSL/semantic-input-struct.hlsl | 20 ++++++++++++++++ clang/test/AST/HLSL/semantic-input.hlsl | 9 ++++++++ .../HLSL/semantic-output-struct-shadow.hlsl | 23 +++++++++++++++++++ .../test/AST/HLSL/semantic-output-struct.hlsl | 22 ++++++++++++++++++ clang/test/AST/HLSL/semantic-output.hlsl | 9 ++++++++ 8 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 clang/test/AST/HLSL/semantic-input-struct-shadow.hlsl create mode 100644 clang/test/AST/HLSL/semantic-input-struct.hlsl create mode 100644 clang/test/AST/HLSL/semantic-input.hlsl create mode 100644 clang/test/AST/HLSL/semantic-output-struct-shadow.hlsl create mode 100644 clang/test/AST/HLSL/semantic-output-struct.hlsl create mode 100644 clang/test/AST/HLSL/semantic-output.hlsl diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index daaaa1d5004a9..f5c07fe2e33ff 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -745,7 +745,8 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( } } - llvm_unreachable("non-handled system semantic. FIXME."); + llvm_unreachable( + "Load hasn't been implemented yet for this system semantic. FIXME"); } static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M, @@ -769,14 +770,21 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source, std::string SemanticName = Semantic->getAttrName()->getName().upper(); if (SemanticName == "SV_POSITION") { - if (CGM.getTarget().getTriple().isDXIL()) + if (CGM.getTarget().getTriple().isDXIL()) { emitDXILUserSemanticStore(B, Source, Semantic, Index); - else if (CGM.getTarget().getTriple().isSPIRV()) + return; + } + + if (CGM.getTarget().getTriple().isSPIRV()) { createSPIRVBuiltinStore(B, CGM.getModule(), Source, Semantic->getAttrName()->getName(), /* BuiltIn::Position */ 0); - } else - llvm_unreachable("non-handled system semantic. FIXME."); + return; + } + } + + llvm_unreachable( + "Store hasn't been implemented yet for this system semantic. FIXME"); } llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad( diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 4eac34c90e6bc..3c746230a7c60 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -967,10 +967,8 @@ void SemaHLSL::checkSemanticAnnotation( } if (SemanticName == "SV_POSITION") { - // SV_Position can is I/O for vertex shaders. - // For pixel shaders, only valid as input. - // Note: for SPIR-V, not backed by a builtin when used as input in a vertex - // shaders. + // SV_Position can be an input or output in vertex shaders, + // but only an input in pixel shaders. if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput)) return; DiagnoseAttrStageMismatch(SemanticAttr, ST, diff --git a/clang/test/AST/HLSL/semantic-input-struct-shadow.hlsl b/clang/test/AST/HLSL/semantic-input-struct-shadow.hlsl new file mode 100644 index 0000000000000..d4d89bd5d26ba --- /dev/null +++ b/clang/test/AST/HLSL/semantic-input-struct-shadow.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + + +// CHECK: CXXRecordDecl {{.*}} referenced struct S definition +// CHECK: FieldDecl {{.*}} field1 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0 +// CHECK: FieldDecl {{.*}} field2 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4 + +struct S { + int field1 : A; + int field2 : B4; +}; + +// CHECK: FunctionDecl {{.*}} main 'void (S)' +// CHECK-NEXT: ParmVarDecl {{.*}} s 'S' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "C" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "C" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "C" 1 +void main(S s : C) {} diff --git a/clang/test/AST/HLSL/semantic-input-struct.hlsl b/clang/test/AST/HLSL/semantic-input-struct.hlsl new file mode 100644 index 0000000000000..d71fdcff631f4 --- /dev/null +++ b/clang/test/AST/HLSL/semantic-input-struct.hlsl @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + + +// CHECK: CXXRecordDecl {{.*}} referenced struct S definition +// CHECK: FieldDecl {{.*}} field1 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0 +// CHECK: FieldDecl {{.*}} field2 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4 + +struct S { + int field1 : A; + int field2 : B4; +}; + +// CHECK: FunctionDecl {{.*}} main 'void (S)' +// CHECK-NEXT: ParmVarDecl {{.*}} s 'S' +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "A" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "B" 4 +void main(S s) {} diff --git a/clang/test/AST/HLSL/semantic-input.hlsl b/clang/test/AST/HLSL/semantic-input.hlsl new file mode 100644 index 0000000000000..4dc3ab9db7392 --- /dev/null +++ b/clang/test/AST/HLSL/semantic-input.hlsl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + +// CHECK: ParmVarDecl {{.*}} a 'float4':'vector' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "ABC" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "ABC" 0 + +void main(float4 a : ABC) { +} diff --git a/clang/test/AST/HLSL/semantic-output-struct-shadow.hlsl b/clang/test/AST/HLSL/semantic-output-struct-shadow.hlsl new file mode 100644 index 0000000000000..e83901bb17943 --- /dev/null +++ b/clang/test/AST/HLSL/semantic-output-struct-shadow.hlsl @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + + +// CHECK: CXXRecordDecl {{.*}} referenced struct S definition +// CHECK: FieldDecl {{.*}} referenced field1 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0 +// CHECK: FieldDecl {{.*}} referenced field2 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4 + +struct S { + int field1 : A; + int field2 : B4; +}; + +// CHECK: FunctionDecl {{.*}} main 'S ()' +// CHECK: HLSLParsedSemanticAttr {{.*}} "DEF" 0 +// CHECK: HLSLAppliedSemanticAttr {{.*}} "DEF" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "DEF" 1 +S main() : DEF { + S tmp; + return tmp; +} diff --git a/clang/test/AST/HLSL/semantic-output-struct.hlsl b/clang/test/AST/HLSL/semantic-output-struct.hlsl new file mode 100644 index 0000000000000..727c0f3040641 --- /dev/null +++ b/clang/test/AST/HLSL/semantic-output-struct.hlsl @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + + +// CHECK: CXXRecordDecl {{.*}} referenced struct S definition +// CHECK: FieldDecl {{.*}} referenced field1 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0 +// CHECK: FieldDecl {{.*}} referenced field2 'int' +// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4 + +struct S { + int field1 : A; + int field2 : B4; +}; + +// CHECK: FunctionDecl {{.*}} main 'S ()' +// CHECK: HLSLAppliedSemanticAttr {{.*}} "A" 0 +// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "B" 4 +S main() { + S tmp; + return tmp; +} diff --git a/clang/test/AST/HLSL/semantic-output.hlsl b/clang/test/AST/HLSL/semantic-output.hlsl new file mode 100644 index 0000000000000..63429387f8d66 --- /dev/null +++ b/clang/test/AST/HLSL/semantic-output.hlsl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s + +// CHECK: FunctionDecl {{.*}} main 'uint ()' +// CHECK: HLSLParsedSemanticAttr {{.*}} "ABC" 0 +// CHECK: HLSLAppliedSemanticAttr {{.*}} "ABC" 0 +uint main() : ABC { + return 0; +}