Skip to content

Commit 8305fe2

Browse files
committed
[HLSL][SPIR-V] Add support for SV_Target semantic
This PR adds the support for the SV_Target semantic and improved the diagnostics when the stage is correct, but the direction is disallowed.
1 parent e575539 commit 8305fe2

File tree

10 files changed

+154
-12
lines changed

10 files changed

+154
-12
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13231,6 +13231,8 @@ def err_hlsl_semantic_indexing_not_supported
1323113231
def err_hlsl_init_priority_unsupported : Error<
1323213232
"initializer priorities are not supported in HLSL">;
1323313233
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
13234+
def err_hlsl_semantic_unsupported_direction_for_stage
13235+
: Error<"semantic %0 is unsupported as %1 for stage %2">;
1323413236

1323513237
def warn_hlsl_user_defined_type_missing_member: Warning<"binding type '%select{t|u|b|s|c}0' only applies to types containing %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric types}0">, InGroup<LegacyConstantRegisterBinding>;
1323613238
def err_hlsl_binding_type_mismatch: Error<"binding type '%select{t|u|b|s|c}0' only applies to %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric variables in the global scope}0">;

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ class SemaHLSL : public SemaBase {
134134
void CheckEntryPoint(FunctionDecl *FD);
135135
bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr,
136136
SourceLocation Loc);
137-
void DiagnoseAttrStageMismatch(
138-
const Attr *A, llvm::Triple::EnvironmentType Stage,
139-
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
140137

141138
QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
142139
QualType LHSType, QualType RHSType,
@@ -244,6 +241,17 @@ class SemaHLSL : public SemaBase {
244241
std::optional<uint32_t> Index;
245242
};
246243

244+
enum IOType {
245+
In = 0b01,
246+
Out = 0b10,
247+
InOut = 0b11,
248+
};
249+
250+
struct SemanticStageInfo {
251+
llvm::Triple::EnvironmentType Stage;
252+
IOType Direction;
253+
};
254+
247255
private:
248256
void collectResourceBindingsOnVarDecl(VarDecl *D);
249257
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
@@ -269,6 +277,14 @@ class SemaHLSL : public SemaBase {
269277

270278
void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
271279

280+
void diagnoseAttrStageMismatch(
281+
const Attr *A, llvm::Triple::EnvironmentType Stage,
282+
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);
283+
284+
void diagnoseSemanticStageMismatch(
285+
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
286+
std::initializer_list<SemanticStageInfo> AllowedStages);
287+
272288
uint32_t getNextImplicitBindingOrderID() {
273289
return ImplicitBindingNextOrderID++;
274290
}

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,9 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
783783
}
784784
}
785785

786+
if (SemanticName == "SV_TARGET")
787+
emitUserSemanticStore(B, Source, Decl, Semantic, Index);
788+
786789
llvm_unreachable(
787790
"Store hasn't been implemented yet for this system semantic. FIXME");
788791
}

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -873,14 +873,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
873873
case llvm::Triple::Miss:
874874
case llvm::Triple::Callable:
875875
if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
876-
DiagnoseAttrStageMismatch(NT, ST,
876+
diagnoseAttrStageMismatch(NT, ST,
877877
{llvm::Triple::Compute,
878878
llvm::Triple::Amplification,
879879
llvm::Triple::Mesh});
880880
FD->setInvalidDecl();
881881
}
882882
if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
883-
DiagnoseAttrStageMismatch(WS, ST,
883+
diagnoseAttrStageMismatch(WS, ST,
884884
{llvm::Triple::Compute,
885885
llvm::Triple::Amplification,
886886
llvm::Triple::Mesh});
@@ -954,7 +954,8 @@ void SemaHLSL::checkSemanticAnnotation(
954954
SemanticName == "SV_GROUPID") {
955955

956956
if (ST != llvm::Triple::Compute)
957-
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute});
957+
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
958+
{{llvm::Triple::Compute, IOType::In}});
958959

959960
if (SemanticAttr->getSemanticIndex() != 0) {
960961
std::string PrettyName =
@@ -969,10 +970,15 @@ void SemaHLSL::checkSemanticAnnotation(
969970
if (SemanticName == "SV_POSITION") {
970971
// SV_Position can be an input or output in vertex shaders,
971972
// but only an input in pixel shaders.
972-
if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput))
973-
return;
974-
DiagnoseAttrStageMismatch(SemanticAttr, ST,
975-
{llvm::Triple::Pixel, llvm::Triple::Vertex});
973+
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
974+
{{llvm::Triple::Vertex, IOType::InOut},
975+
{llvm::Triple::Pixel, IOType::In}});
976+
return;
977+
}
978+
979+
if (SemanticName == "SV_TARGET") {
980+
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
981+
{{llvm::Triple::Pixel, IOType::Out}});
976982
return;
977983
}
978984

@@ -982,7 +988,7 @@ void SemaHLSL::checkSemanticAnnotation(
982988
llvm_unreachable("Unknown SemanticAttr");
983989
}
984990

985-
void SemaHLSL::DiagnoseAttrStageMismatch(
991+
void SemaHLSL::diagnoseAttrStageMismatch(
986992
const Attr *A, llvm::Triple::EnvironmentType Stage,
987993
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
988994
SmallVector<StringRef, 8> StageStrings;
@@ -996,6 +1002,37 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
9961002
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
9971003
}
9981004

1005+
void SemaHLSL::diagnoseSemanticStageMismatch(
1006+
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
1007+
std::initializer_list<SemanticStageInfo> Allowed) {
1008+
1009+
for (auto &Case : Allowed) {
1010+
if (Case.Stage != Stage)
1011+
continue;
1012+
1013+
if (IsInput && Case.Direction & IOType::In)
1014+
return;
1015+
if (!IsInput && Case.Direction & IOType::Out)
1016+
return;
1017+
1018+
Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_direction_for_stage)
1019+
<< A->getAttrName() << (IsInput ? "input" : "output")
1020+
<< llvm::Triple::getEnvironmentTypeName(Case.Stage);
1021+
return;
1022+
}
1023+
1024+
SmallVector<StringRef, 8> StageStrings;
1025+
llvm::transform(
1026+
Allowed, std::back_inserter(StageStrings), [](SemanticStageInfo Case) {
1027+
return StringRef(
1028+
HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage));
1029+
});
1030+
1031+
Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
1032+
<< A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage)
1033+
<< (Allowed.size() != 1) << join(StageStrings, ", ");
1034+
}
1035+
9991036
template <CastKind Kind>
10001037
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
10011038
if (const auto *VTy = Ty->getAs<VectorType>())
@@ -1797,6 +1834,16 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
17971834
return;
17981835
}
17991836

1837+
if (SemanticName == "SV_TARGET") {
1838+
const auto *VT = ValueType->getAs<VectorType>();
1839+
if (!ValueType->hasFloatingRepresentation() ||
1840+
(VT && VT->getNumElements() > 4))
1841+
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
1842+
<< AL << "float/float1/float2/float3/float4";
1843+
D->addAttr(createSemanticAttr<HLSLParsedSemanticAttr>(AL, Index));
1844+
return;
1845+
}
1846+
18001847
Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
18011848
}
18021849

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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
3+
4+
// CHECK-SPIRV: @SV_Target0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_2:]]
5+
6+
// CHECK: define void @main() {{.*}} {
7+
float4 main(float4 p : SV_Position) : SV_Target {
8+
// CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#]])
9+
// CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 16
10+
11+
// CHECK-DXIL: %[[#TMP:]] = call <4 x float> @_Z4mainDv4_f(<4 x float> %SV_Position0)
12+
// CHECK-DXIL: call void @llvm.dx.store.output.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison, <4 x float> %[[#TMP]])
13+
return p;
14+
}
15+
16+
// CHECK-SPIRV-DAG: ![[#MD_2]] = !{![[#MD_3:]]}
17+
// CHECK-SPIRV-DAG: ![[#MD_3]] = !{i32 30, i32 0}
18+
// | `-> Location index
19+
// `-> SPIR-V decoration 'Location'

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -x hlsl -verify -o - %s
33

44
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}}
5+
// expected-error@-1 {{semantic 'SV_Position' is unsupported as output for stage pixel}}
66
return a;
77
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
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
3+
4+
float4 main(float4 a : SV_Target) : A {
5+
// expected-error@-1 {{semantic 'SV_Target' is unsupported as input for stage pixel}}
6+
return a;
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s
2+
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s
3+
4+
float4 main(float4 a : SV_Target) : A {
5+
// expected-error@-1 {{attribute 'SV_Target' is unsupported in 'vertex' shaders, requires pixel}}
6+
return a;
7+
}
8+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s
2+
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s
3+
4+
float4 main(float4 a : SV_Position) : SV_Target {
5+
// expected-error@-1 {{attribute 'SV_Target' is unsupported in 'vertex' shaders, requires pixel}}
6+
return a;
7+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
@SV_Target0 = 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) @SV_Target0, 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+
33+

0 commit comments

Comments
 (0)