diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 53aa86a7dabde..48a17df95c1e6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13231,6 +13231,9 @@ def err_hlsl_semantic_indexing_not_supported def err_hlsl_init_priority_unsupported : Error< "initializer priorities are not supported in HLSL">; def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">; +def err_hlsl_semantic_unsupported_iotype_for_stage + : Error<"semantic %0 is unsupported in %2 shaders as %1, requires one of " + "the following: %3">; 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; 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">; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 15edb7e77a22b..fb18817f2177b 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -134,9 +134,6 @@ class SemaHLSL : public SemaBase { void CheckEntryPoint(FunctionDecl *FD); bool CheckResourceBinOp(BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr, SourceLocation Loc); - void DiagnoseAttrStageMismatch( - const Attr *A, llvm::Triple::EnvironmentType Stage, - std::initializer_list AllowedStages); QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, @@ -244,6 +241,17 @@ class SemaHLSL : public SemaBase { std::optional Index; }; + enum IOType { + In = 0b01, + Out = 0b10, + InOut = 0b11, + }; + + struct SemanticStageInfo { + llvm::Triple::EnvironmentType Stage; + IOType AllowedIOTypesMask; + }; + private: void collectResourceBindingsOnVarDecl(VarDecl *D); void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD, @@ -269,6 +277,14 @@ class SemaHLSL : public SemaBase { void diagnoseAvailabilityViolations(TranslationUnitDecl *TU); + void diagnoseAttrStageMismatch( + const Attr *A, llvm::Triple::EnvironmentType Stage, + std::initializer_list AllowedStages); + + void diagnoseSemanticStageMismatch( + const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput, + std::initializer_list AllowedStages); + uint32_t getNextImplicitBindingOrderID() { return ImplicitBindingNextOrderID++; } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index f5c07fe2e33ff..58a523b853647 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -783,6 +783,11 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source, } } + if (SemanticName == "SV_TARGET") { + emitUserSemanticStore(B, Source, Decl, Semantic, Index); + return; + } + llvm_unreachable( "Store hasn't been implemented yet for this system semantic. FIXME"); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index ecab3946b58c7..0cea7af6024d4 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -873,14 +873,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { case llvm::Triple::Miss: case llvm::Triple::Callable: if (const auto *NT = FD->getAttr()) { - DiagnoseAttrStageMismatch(NT, ST, + diagnoseAttrStageMismatch(NT, ST, {llvm::Triple::Compute, llvm::Triple::Amplification, llvm::Triple::Mesh}); FD->setInvalidDecl(); } if (const auto *WS = FD->getAttr()) { - DiagnoseAttrStageMismatch(WS, ST, + diagnoseAttrStageMismatch(WS, ST, {llvm::Triple::Compute, llvm::Triple::Amplification, llvm::Triple::Mesh}); @@ -954,7 +954,8 @@ void SemaHLSL::checkSemanticAnnotation( SemanticName == "SV_GROUPID") { if (ST != llvm::Triple::Compute) - DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Compute}); + diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput, + {{llvm::Triple::Compute, IOType::In}}); if (SemanticAttr->getSemanticIndex() != 0) { std::string PrettyName = @@ -969,10 +970,15 @@ void SemaHLSL::checkSemanticAnnotation( if (SemanticName == "SV_POSITION") { // SV_Position can be an input or output in vertex shaders, // but only an input in pixel shaders. - if (ST == llvm::Triple::Vertex || (ST == llvm::Triple::Pixel && IsInput)) - return; - DiagnoseAttrStageMismatch(SemanticAttr, ST, - {llvm::Triple::Pixel, llvm::Triple::Vertex}); + diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput, + {{llvm::Triple::Vertex, IOType::InOut}, + {llvm::Triple::Pixel, IOType::In}}); + return; + } + + if (SemanticName == "SV_TARGET") { + diagnoseSemanticStageMismatch(SemanticAttr, ST, IsInput, + {{llvm::Triple::Pixel, IOType::Out}}); return; } @@ -982,7 +988,7 @@ void SemaHLSL::checkSemanticAnnotation( llvm_unreachable("Unknown SemanticAttr"); } -void SemaHLSL::DiagnoseAttrStageMismatch( +void SemaHLSL::diagnoseAttrStageMismatch( const Attr *A, llvm::Triple::EnvironmentType Stage, std::initializer_list AllowedStages) { SmallVector StageStrings; @@ -996,6 +1002,50 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << (AllowedStages.size() != 1) << join(StageStrings, ", "); } +void SemaHLSL::diagnoseSemanticStageMismatch( + const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput, + std::initializer_list Allowed) { + + for (auto &Case : Allowed) { + if (Case.Stage != Stage) + continue; + + if (IsInput && Case.AllowedIOTypesMask & IOType::In) + return; + if (!IsInput && Case.AllowedIOTypesMask & IOType::Out) + return; + + SmallVector ValidCases; + llvm::transform( + Allowed, std::back_inserter(ValidCases), [](SemanticStageInfo Case) { + SmallVector ValidType; + if (Case.AllowedIOTypesMask & IOType::In) + ValidType.push_back("input"); + if (Case.AllowedIOTypesMask & IOType::Out) + ValidType.push_back("output"); + return std::string( + HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)) + + " " + join(ValidType, "/"); + }); + Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_iotype_for_stage) + << A->getAttrName() << (IsInput ? "input" : "output") + << llvm::Triple::getEnvironmentTypeName(Case.Stage) + << join(ValidCases, ", "); + return; + } + + SmallVector StageStrings; + llvm::transform( + Allowed, std::back_inserter(StageStrings), [](SemanticStageInfo Case) { + return StringRef( + HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)); + }); + + Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage) + << A->getAttrName() << llvm::Triple::getEnvironmentTypeName(Stage) + << (Allowed.size() != 1) << join(StageStrings, ", "); +} + template static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) { if (const auto *VTy = Ty->getAs()) @@ -1797,6 +1847,16 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL, return; } + if (SemanticName == "SV_TARGET") { + const auto *VT = ValueType->getAs(); + if (!ValueType->hasFloatingRepresentation() || + (VT && VT->getNumElements() > 4)) + Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "float/float1/float2/float3/float4"; + D->addAttr(createSemanticAttr(AL, Index)); + return; + } + Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; } diff --git a/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl new file mode 100644 index 0000000000000..4dc622a1eb6bb --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl @@ -0,0 +1,19 @@ +// 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-SPIRV: @SV_Target0 = 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_Target { + // CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#]]) + // CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @SV_Target0, align 16 + + // 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_2]] = !{![[#MD_3:]]} +// CHECK-SPIRV-DAG: ![[#MD_3]] = !{i32 30, i32 0} +// | `-> Location index +// `-> SPIR-V decoration 'Location' diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl index 47d07887911d6..d0fe19d1a5407 100644 --- a/clang/test/SemaHLSL/Semantics/position.ps.hlsl +++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl @@ -2,6 +2,6 @@ // RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -x hlsl -verify -o - %s 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}} +// expected-error@-1 {{semantic 'SV_Position' is unsupported in pixel shaders as output, requires one of the following: vertex input/output, pixel input}} return a; } diff --git a/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl b/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl new file mode 100644 index 0000000000000..a77b46c0e9f1a --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/target.ps.input.hlsl @@ -0,0 +1,7 @@ +// 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 + +float4 main(float4 a : SV_Target) : A { +// expected-error@-1 {{semantic 'SV_Target' is unsupported in pixel shaders as input, requires one of the following: pixel out}} + return a; +} diff --git a/clang/test/SemaHLSL/Semantics/target.vs.input.hlsl b/clang/test/SemaHLSL/Semantics/target.vs.input.hlsl new file mode 100644 index 0000000000000..add24732fc05a --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/target.vs.input.hlsl @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s + +float4 main(float4 a : SV_Target) : A { +// expected-error@-1 {{attribute 'SV_Target' is unsupported in 'vertex' shaders, requires pixel}} + return a; +} + diff --git a/clang/test/SemaHLSL/Semantics/target.vs.output.hlsl b/clang/test/SemaHLSL/Semantics/target.vs.output.hlsl new file mode 100644 index 0000000000000..0481bcdad0177 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/target.vs.output.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s +// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s + +float4 main(float4 a : SV_Position) : SV_Target { +// expected-error@-1 {{attribute 'SV_Target' is unsupported in 'vertex' shaders, requires pixel}} + return a; +} diff --git a/llvm/test/CodeGen/SPIRV/semantics/target.ps.ll b/llvm/test/CodeGen/SPIRV/semantics/target.ps.ll new file mode 100644 index 0000000000000..249ffc078f158 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/semantics/target.ps.ll @@ -0,0 +1,33 @@ +; 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 +@SV_Target0 = 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) @SV_Target0, 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} + +