Skip to content

Commit 74f5548

Browse files
authored
[HLSL][SPIR-V] Implements SV_Position for VS/PS I/O (#168735)
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 72bfa28 commit 74f5548

File tree

15 files changed

+271
-49
lines changed

15 files changed

+271
-49
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: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -731,13 +731,22 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
731731
}
732732

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

740-
llvm_unreachable("non-handled system semantic. FIXME.");
748+
llvm_unreachable(
749+
"Load hasn't been implemented yet for this system semantic. FIXME");
741750
}
742751

743752
static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
@@ -760,12 +769,22 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
760769
std::optional<unsigned> Index) {
761770

762771
std::string SemanticName = Semantic->getAttrName()->getName().upper();
763-
if (SemanticName == "SV_POSITION")
764-
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
765-
Semantic->getAttrName()->getName(),
766-
/* BuiltIn::Position */ 0);
767-
else
768-
llvm_unreachable("non-handled system semantic. FIXME.");
772+
if (SemanticName == "SV_POSITION") {
773+
if (CGM.getTarget().getTriple().isDXIL()) {
774+
emitDXILUserSemanticStore(B, Source, Semantic, Index);
775+
return;
776+
}
777+
778+
if (CGM.getTarget().getTriple().isSPIRV()) {
779+
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
780+
Semantic->getAttrName()->getName(),
781+
/* BuiltIn::Position */ 0);
782+
return;
783+
}
784+
}
785+
786+
llvm_unreachable(
787+
"Store hasn't been implemented yet for this system semantic. FIXME");
769788
}
770789

771790
llvm::Value *CGHLSLRuntime::handleScalarSemanticLoad(

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 21 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,12 @@ 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 be an input or output in vertex shaders,
971+
// but only an input in pixel shaders.
972+
if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput))
967973
return;
968-
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
974+
DiagnoseAttrStageMismatch(SemanticAttr, ST,
975+
{llvm::Triple::Pixel, llvm::Triple::Vertex});
969976
return;
970977
}
971978

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
5+
// CHECK: CXXRecordDecl {{.*}} referenced struct S definition
6+
// CHECK: FieldDecl {{.*}} field1 'int'
7+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0
8+
// CHECK: FieldDecl {{.*}} field2 'int'
9+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4
10+
11+
struct S {
12+
int field1 : A;
13+
int field2 : B4;
14+
};
15+
16+
// CHECK: FunctionDecl {{.*}} main 'void (S)'
17+
// CHECK-NEXT: ParmVarDecl {{.*}} s 'S'
18+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "C" 0
19+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "C" 0
20+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "C" 1
21+
void main(S s : C) {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
5+
// CHECK: CXXRecordDecl {{.*}} referenced struct S definition
6+
// CHECK: FieldDecl {{.*}} field1 'int'
7+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0
8+
// CHECK: FieldDecl {{.*}} field2 'int'
9+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4
10+
11+
struct S {
12+
int field1 : A;
13+
int field2 : B4;
14+
};
15+
16+
// CHECK: FunctionDecl {{.*}} main 'void (S)'
17+
// CHECK-NEXT: ParmVarDecl {{.*}} s 'S'
18+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "A" 0
19+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "B" 4
20+
void main(S s) {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
// CHECK: ParmVarDecl {{.*}} a 'float4':'vector<float, 4>'
5+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "ABC" 0
6+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "ABC" 0
7+
8+
void main(float4 a : ABC) {
9+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
5+
// CHECK: CXXRecordDecl {{.*}} referenced struct S definition
6+
// CHECK: FieldDecl {{.*}} referenced field1 'int'
7+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0
8+
// CHECK: FieldDecl {{.*}} referenced field2 'int'
9+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4
10+
11+
struct S {
12+
int field1 : A;
13+
int field2 : B4;
14+
};
15+
16+
// CHECK: FunctionDecl {{.*}} main 'S ()'
17+
// CHECK: HLSLParsedSemanticAttr {{.*}} "DEF" 0
18+
// CHECK: HLSLAppliedSemanticAttr {{.*}} "DEF" 0
19+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "DEF" 1
20+
S main() : DEF {
21+
S tmp;
22+
return tmp;
23+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
5+
// CHECK: CXXRecordDecl {{.*}} referenced struct S definition
6+
// CHECK: FieldDecl {{.*}} referenced field1 'int'
7+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "A" 0
8+
// CHECK: FieldDecl {{.*}} referenced field2 'int'
9+
// CHECK-NEXT: HLSLParsedSemanticAttr {{.*}} "B" 4
10+
11+
struct S {
12+
int field1 : A;
13+
int field2 : B4;
14+
};
15+
16+
// CHECK: FunctionDecl {{.*}} main 'S ()'
17+
// CHECK: HLSLAppliedSemanticAttr {{.*}} "A" 0
18+
// CHECK-NEXT: HLSLAppliedSemanticAttr {{.*}} "B" 4
19+
S main() {
20+
S tmp;
21+
return tmp;
22+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.8-vertex -finclude-default-header -ast-dump -o - %s | FileCheck %s
3+
4+
// CHECK: FunctionDecl {{.*}} main 'uint ()'
5+
// CHECK: HLSLParsedSemanticAttr {{.*}} "ABC" 0
6+
// CHECK: HLSLAppliedSemanticAttr {{.*}} "ABC" 0
7+
uint main() : ABC {
8+
return 0;
9+
}
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'

0 commit comments

Comments
 (0)