-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[HLSL][SPIR-V] Implements SV_Position for VS/PS I/O #168735
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
base: main
Are you sure you want to change the base?
Conversation
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.
|
@llvm/pr-subscribers-backend-spir-v @llvm/pr-subscribers-clang-codegen Author: Nathan Gauër (Keenuts) ChangesCurrent 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. Full diff: https://github.com/llvm/llvm-project/pull/168735.diff 9 Files Affected:
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 0371af417bdab..b9bdce521c989 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -730,10 +730,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.");
@@ -759,11 +767,14 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
std::optional<unsigned> 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 e7ee3b1adf941..5beb4e7fe8546 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<HLSLParsedSemanticAttr>();
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<HLSLParsedSemanticAttr>();
if (ActiveSemantic.Semantic)
@@ -833,12 +837,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
const RecordType *RT = dyn_cast<RecordType>(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<HLSLShaderAttr>();
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<float, 4>'
-// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
-// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
-
-// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <line:4:40> "A" 0
-// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:40> "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}
|
|
@llvm/pr-subscribers-hlsl Author: Nathan Gauër (Keenuts) ChangesCurrent 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. Full diff: https://github.com/llvm/llvm-project/pull/168735.diff 9 Files Affected:
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 0371af417bdab..b9bdce521c989 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -730,10 +730,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.");
@@ -759,11 +767,14 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
std::optional<unsigned> 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 e7ee3b1adf941..5beb4e7fe8546 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<HLSLParsedSemanticAttr>();
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<HLSLParsedSemanticAttr>();
if (ActiveSemantic.Semantic)
@@ -833,12 +837,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
const RecordType *RT = dyn_cast<RecordType>(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<HLSLShaderAttr>();
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<float, 4>'
-// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
-// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
-
-// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <line:4:40> "A" 0
-// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:40> "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}
|
🐧 Linux x64 Test Results
|
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.