Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<LegacyConstantRegisterBinding>;
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">;
Expand Down
22 changes: 19 additions & 3 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<llvm::Triple::EnvironmentType> AllowedStages);

QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
QualType LHSType, QualType RHSType,
Expand Down Expand Up @@ -244,6 +241,17 @@ class SemaHLSL : public SemaBase {
std::optional<uint32_t> 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,
Expand All @@ -269,6 +277,14 @@ class SemaHLSL : public SemaBase {

void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);

void diagnoseAttrStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage,
std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages);

void diagnoseSemanticStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
std::initializer_list<SemanticStageInfo> AllowedStages);

uint32_t getNextImplicitBindingOrderID() {
return ImplicitBindingNextOrderID++;
}
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
75 changes: 67 additions & 8 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,14 +873,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
case llvm::Triple::Miss:
case llvm::Triple::Callable:
if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
DiagnoseAttrStageMismatch(NT, ST,
diagnoseAttrStageMismatch(NT, ST,
{llvm::Triple::Compute,
llvm::Triple::Amplification,
llvm::Triple::Mesh});
FD->setInvalidDecl();
}
if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
DiagnoseAttrStageMismatch(WS, ST,
diagnoseAttrStageMismatch(WS, ST,
{llvm::Triple::Compute,
llvm::Triple::Amplification,
llvm::Triple::Mesh});
Expand Down Expand Up @@ -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 =
Expand All @@ -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;
}

Expand All @@ -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<llvm::Triple::EnvironmentType> AllowedStages) {
SmallVector<StringRef, 8> StageStrings;
Expand All @@ -996,6 +1002,49 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}

void SemaHLSL::diagnoseSemanticStageMismatch(
const Attr *A, llvm::Triple::EnvironmentType Stage, bool IsInput,
std::initializer_list<SemanticStageInfo> 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<std::string, 8> ValidCases;
llvm::transform(
Allowed, std::back_inserter(ValidCases), [](SemanticStageInfo Case) {
std::string Type =
Case.AllowedIOTypesMask == IOType::InOut
? " inout"
: (Case.AllowedIOTypesMask & IOType::In ? " in" : " out");
return std::string(
HLSLShaderAttr::ConvertEnvironmentTypeToStr(Case.Stage)) +
Type;
});
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<StringRef, 8> 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 <CastKind Kind>
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
if (const auto *VTy = Ty->getAs<VectorType>())
Expand Down Expand Up @@ -1797,6 +1846,16 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
return;
}

if (SemanticName == "SV_TARGET") {
const auto *VT = ValueType->getAs<VectorType>();
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<HLSLParsedSemanticAttr>(AL, Index));
return;
}

Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
}

Expand Down
19 changes: 19 additions & 0 deletions clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl
Original file line number Diff line number Diff line change
@@ -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'
2 changes: 1 addition & 1 deletion clang/test/SemaHLSL/Semantics/position.ps.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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 inout, pixel in}}
return a;
}
7 changes: 7 additions & 0 deletions clang/test/SemaHLSL/Semantics/target.ps.input.hlsl
Original file line number Diff line number Diff line change
@@ -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;
}
8 changes: 8 additions & 0 deletions clang/test/SemaHLSL/Semantics/target.vs.input.hlsl
Original file line number Diff line number Diff line change
@@ -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;
}

7 changes: 7 additions & 0 deletions clang/test/SemaHLSL/Semantics/target.vs.output.hlsl
Original file line number Diff line number Diff line change
@@ -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;
}
33 changes: 33 additions & 0 deletions llvm/test/CodeGen/SPIRV/semantics/target.ps.ll
Original file line number Diff line number Diff line change
@@ -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}