Skip to content

Commit 0288170

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 ee2d404 commit 0288170

File tree

10 files changed

+153
-16
lines changed

10 files changed

+153
-16
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13213,6 +13213,8 @@ def err_hlsl_semantic_indexing_not_supported
1321313213
def err_hlsl_init_priority_unsupported : Error<
1321413214
"initializer priorities are not supported in HLSL">;
1321513215
def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
13216+
def err_hlsl_semantic_unsupported_direction_for_stage
13217+
: Error<"semantic %0 is unsupported as %1 for stage %2">;
1321613218

1321713219
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>;
1321813220
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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,8 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
774774
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
775775
Semantic->getAttrName()->getName(),
776776
/* BuiltIn::Position */ 0);
777+
} else if (SemanticName == "SV_TARGET") {
778+
emitUserSemanticStore(B, Source, Decl, Semantic, Index);
777779
} else
778780
llvm_unreachable("non-handled system semantic. FIXME.");
779781
}

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 55 additions & 12 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 =
@@ -967,14 +968,15 @@ void SemaHLSL::checkSemanticAnnotation(
967968
}
968969

969970
if (SemanticName == "SV_POSITION") {
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))
975-
return;
976-
DiagnoseAttrStageMismatch(SemanticAttr, ST,
977-
{llvm::Triple::Pixel, llvm::Triple::Vertex});
971+
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
972+
{{llvm::Triple::Vertex, IOType::InOut},
973+
{llvm::Triple::Pixel, IOType::In}});
974+
return;
975+
}
976+
977+
if (SemanticName == "SV_TARGET") {
978+
diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput,
979+
{{llvm::Triple::Pixel, IOType::Out}});
978980
return;
979981
}
980982

@@ -984,7 +986,7 @@ void SemaHLSL::checkSemanticAnnotation(
984986
llvm_unreachable("Unknown SemanticAttr");
985987
}
986988

987-
void SemaHLSL::DiagnoseAttrStageMismatch(
989+
void SemaHLSL::diagnoseAttrStageMismatch(
988990
const Attr *A, llvm::Triple::EnvironmentType Stage,
989991
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
990992
SmallVector<StringRef, 8> StageStrings;
@@ -998,6 +1000,37 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
9981000
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
9991001
}
10001002

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

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

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)