Skip to content

Commit ee2d404

Browse files
committed
[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.
1 parent 2fc42c7 commit ee2d404

File tree

9 files changed

+159
-47
lines changed

9 files changed

+159
-47
lines changed

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,20 @@ class SemaHLSL : public SemaBase {
250250
const RecordType *RT);
251251

252252
void checkSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
253-
const HLSLAppliedSemanticAttr *SemanticAttr);
253+
const HLSLAppliedSemanticAttr *SemanticAttr,
254+
bool IsInput);
255+
254256
bool determineActiveSemanticOnScalar(FunctionDecl *FD,
255257
DeclaratorDecl *OutputDecl,
256258
DeclaratorDecl *D,
257259
SemanticInfo &ActiveSemantic,
258-
llvm::StringSet<> &ActiveInputSemantics);
260+
llvm::StringSet<> &ActiveSemantics,
261+
bool IsInput);
262+
259263
bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *OutputDecl,
260264
DeclaratorDecl *D, SemanticInfo &ActiveSemantic,
261-
llvm::StringSet<> &ActiveInputSemantics);
265+
llvm::StringSet<> &ActiveSemantics,
266+
bool IsInput);
262267

263268
void processExplicitBindingsOnDecl(VarDecl *D);
264269

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -730,10 +730,18 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
730730
}
731731

732732
if (SemanticName == "SV_POSITION") {
733-
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
734-
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
735-
Semantic->getAttrName()->getName(),
736-
/* BuiltIn::FragCoord */ 15);
733+
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel) {
734+
if (CGM.getTarget().getTriple().isSPIRV())
735+
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
736+
Semantic->getAttrName()->getName(),
737+
/* BuiltIn::FragCoord */ 15);
738+
if (CGM.getTarget().getTriple().isDXIL())
739+
return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
740+
}
741+
742+
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Vertex) {
743+
return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
744+
}
737745
}
738746

739747
llvm_unreachable("non-handled system semantic. FIXME.");
@@ -759,11 +767,14 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
759767
std::optional<unsigned> Index) {
760768

761769
std::string SemanticName = Semantic->getAttrName()->getName().upper();
762-
if (SemanticName == "SV_POSITION")
763-
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
764-
Semantic->getAttrName()->getName(),
765-
/* BuiltIn::Position */ 0);
766-
else
770+
if (SemanticName == "SV_POSITION") {
771+
if (CGM.getTarget().getTriple().isDXIL())
772+
emitDXILUserSemanticStore(B, Source, Semantic, Index);
773+
else if (CGM.getTarget().getTriple().isSPIRV())
774+
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
775+
Semantic->getAttrName()->getName(),
776+
/* BuiltIn::Position */ 0);
777+
} else
767778
llvm_unreachable("non-handled system semantic. FIXME.");
768779
}
769780

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -771,9 +771,12 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
771771
}
772772
}
773773

774-
bool SemaHLSL::determineActiveSemanticOnScalar(
775-
FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D,
776-
SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) {
774+
bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
775+
DeclaratorDecl *OutputDecl,
776+
DeclaratorDecl *D,
777+
SemanticInfo &ActiveSemantic,
778+
llvm::StringSet<> &UsedSemantics,
779+
bool IsInput) {
777780
if (ActiveSemantic.Semantic == nullptr) {
778781
ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
779782
if (ActiveSemantic.Semantic)
@@ -792,7 +795,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar(
792795
if (!A)
793796
return false;
794797

795-
checkSemanticAnnotation(FD, D, A);
798+
checkSemanticAnnotation(FD, D, A, IsInput);
796799
OutputDecl->addAttr(A);
797800

798801
unsigned Location = ActiveSemantic.Index.value_or(0);
@@ -820,7 +823,8 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
820823
DeclaratorDecl *OutputDecl,
821824
DeclaratorDecl *D,
822825
SemanticInfo &ActiveSemantic,
823-
llvm::StringSet<> &UsedSemantics) {
826+
llvm::StringSet<> &UsedSemantics,
827+
bool IsInput) {
824828
if (ActiveSemantic.Semantic == nullptr) {
825829
ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
826830
if (ActiveSemantic.Semantic)
@@ -833,12 +837,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
833837
const RecordType *RT = dyn_cast<RecordType>(T);
834838
if (!RT)
835839
return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic,
836-
UsedSemantics);
840+
UsedSemantics, IsInput);
837841

838842
const RecordDecl *RD = RT->getDecl();
839843
for (FieldDecl *Field : RD->fields()) {
840844
SemanticInfo Info = ActiveSemantic;
841-
if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) {
845+
if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics,
846+
IsInput)) {
842847
Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
843848
return false;
844849
}
@@ -920,7 +925,7 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
920925

921926
// FIXME: Verify output semantics in parameters.
922927
if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic,
923-
ActiveInputSemantics)) {
928+
ActiveInputSemantics, /* IsInput= */ true)) {
924929
Diag(Param->getLocation(), diag::note_previous_decl) << Param;
925930
FD->setInvalidDecl();
926931
}
@@ -932,12 +937,13 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
932937
if (ActiveSemantic.Semantic)
933938
ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
934939
if (!FD->getReturnType()->isVoidType())
935-
determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics);
940+
determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics,
941+
/* IsInput= */ false);
936942
}
937943

938944
void SemaHLSL::checkSemanticAnnotation(
939945
FunctionDecl *EntryPoint, const Decl *Param,
940-
const HLSLAppliedSemanticAttr *SemanticAttr) {
946+
const HLSLAppliedSemanticAttr *SemanticAttr, bool IsInput) {
941947
auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
942948
assert(ShaderAttr && "Entry point has no shader attribute");
943949
llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
@@ -961,11 +967,14 @@ void SemaHLSL::checkSemanticAnnotation(
961967
}
962968

963969
if (SemanticName == "SV_POSITION") {
964-
// TODO(#143523): allow use on other shader types & output once the overall
965-
// semantic logic is implemented.
966-
if (ST == llvm::Triple::Pixel)
970+
// SV_Position can is I/O for vertex shaders.
971+
// For pixel shaders, only valid as input.
972+
// Note: for SPIR-V, not backed by a builtin when used as input in a vertex
973+
// shaders.
974+
if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput))
967975
return;
968-
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
976+
DiagnoseAttrStageMismatch(SemanticAttr, ST,
977+
{llvm::Triple::Pixel, llvm::Triple::Vertex});
969978
return;
970979
}
971980

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
1+
// 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
2+
// 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
23

3-
// CHECK: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
4+
// CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
45

56
// CHECK: define void @main() {{.*}} {
67
float4 main(float4 p : SV_Position) : A {
7-
// CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 16
8-
// CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
9-
// CHECK: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16
8+
// CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 16
9+
// CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
10+
// CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16
11+
12+
// CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
13+
// CHECK-DXIL: %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
14+
// CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
1015
return p;
1116
}
17+
18+
// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]]}
19+
// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 15}
20+
// | `-> BuiltIn Position
21+
// `-> SPIR-V decoration 'FragCoord'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// 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
2+
// 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
3+
4+
// CHECK-SPIRV: @SV_Position0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
5+
// CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_2:]]
6+
7+
// CHECK: define void @main() {{.*}} {
8+
float4 main(float4 p : SV_Position) : SV_Position {
9+
// CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position0, align 16
10+
// CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
11+
// CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @SV_Position, align 16
12+
13+
// CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
14+
// CHECK-DXIL: %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
15+
// CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
16+
return p;
17+
}
18+
19+
// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]]}
20+
// CHECK-SPIRV-DAG: ![[#MD_2]] = !{![[#MD_3:]]}
21+
// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 30, i32 0}
22+
// | `-> Location 0
23+
// `-> SPIR-V decoration 'Location'
24+
// CHECK-SPIRV-DAG: ![[#MD_3]] = !{i32 11, i32 0}
25+
// | `-> BuiltIn Position
26+
// `-> SPIR-V decoration 'BuiltIn'
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel -finclude-default-header -x hlsl -verify -o - %s
2+
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -x hlsl -verify -o - %s
23

3-
// FIXME(Keenuts): change output semantic to something valid for pixels shaders
4-
float4 main(float4 a : SV_Position2) : A {
5-
// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)'
6-
// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 'float4':'vector<float, 4>'
7-
// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
8-
// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
9-
10-
// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <line:4:40> "A" 0
11-
// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:40> "A" 0
4+
float4 main(float4 a : A) : SV_Position {
5+
// expected-error@-1 {{attribute 'SV_Position' is unsupported in 'pixel' shaders, requires one of the following: pixel, vertex}}
126
return a;
137
}

clang/test/SemaHLSL/Semantics/position.vs.hlsl

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-DAG: OpDecorate %[[#INPUT:]] BuiltIn FragCoord
5+
; CHECK-DAG: OpDecorate %[[#OUTPUT:]] Location 0
6+
7+
; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
8+
; CHECK-DAG: %[[#v4:]] = OpTypeVector %[[#float]] 4
9+
; CHECK-DAG: %[[#ptr_i:]] = OpTypePointer Input %[[#v4]]
10+
; CHECK-DAG: %[[#ptr_o:]] = OpTypePointer Output %[[#v4]]
11+
12+
; CHECK-DAG: %[[#INPUT]] = OpVariable %[[#ptr_i]] Input
13+
; CHECK-DAG: %[[#OUTPUT]] = OpVariable %[[#ptr_o]] Output
14+
15+
@SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
16+
@A0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !2
17+
18+
define void @main() #1 {
19+
entry:
20+
%0 = load <4 x float>, ptr addrspace(7) @SV_Position, align 16
21+
store <4 x float> %0, ptr addrspace(8) @A0, align 16
22+
ret void
23+
24+
; CHECK: %[[#TMP:]] = OpLoad %[[#v4]] %[[#INPUT]] Aligned 16
25+
; CHECK: OpStore %[[#OUTPUT]] %[[#TMP]] Aligned 16
26+
}
27+
28+
!0 = !{!1}
29+
!1 = !{i32 11, i32 15}
30+
!2 = !{!3}
31+
!3 = !{i32 30, i32 0}
32+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK-DAG: OpDecorate %[[#INPUT:]] Location 0
5+
; CHECK-DAG: OpDecorate %[[#OUTPUT:]] BuiltIn Position
6+
7+
; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
8+
; CHECK-DAG: %[[#v4:]] = OpTypeVector %[[#float]] 4
9+
; CHECK-DAG: %[[#ptr_i:]] = OpTypePointer Input %[[#v4]]
10+
; CHECK-DAG: %[[#ptr_o:]] = OpTypePointer Output %[[#v4]]
11+
12+
; CHECK-DAG: %[[#INPUT]] = OpVariable %[[#ptr_i]] Input
13+
; CHECK-DAG: %[[#OUTPUT]] = OpVariable %[[#ptr_o]] Output
14+
15+
@SV_Position0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
16+
@SV_Position = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !2
17+
18+
define void @main() #1 {
19+
entry:
20+
%0 = load <4 x float>, ptr addrspace(7) @SV_Position0, align 16
21+
store <4 x float> %0, ptr addrspace(8) @SV_Position, align 16
22+
ret void
23+
24+
; CHECK: %[[#TMP:]] = OpLoad %[[#v4]] %[[#INPUT]] Aligned 16
25+
; CHECK: OpStore %[[#OUTPUT]] %[[#TMP]] Aligned 16
26+
}
27+
28+
!0 = !{!1}
29+
!1 = !{i32 30, i32 0}
30+
!2 = !{!3}
31+
!3 = !{i32 11, i32 0}

0 commit comments

Comments
 (0)