Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -13213,6 +13213,8 @@ 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_direction_for_stage
: Error<"semantic %0 is unsupported as %1 for stage %2">;

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
33 changes: 27 additions & 6 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,26 +241,50 @@ class SemaHLSL : public SemaBase {
std::optional<uint32_t> Index;
};

enum IOType {
In = 0b01,
Out = 0b10,
InOut = 0b11,
};

struct SemanticStageInfo {
llvm::Triple::EnvironmentType Stage;
IOType Direction;
};

private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
const RecordType *RT);

void checkSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAppliedSemanticAttr *SemanticAttr);
const HLSLAppliedSemanticAttr *SemanticAttr,
bool IsInput);

bool determineActiveSemanticOnScalar(FunctionDecl *FD,
DeclaratorDecl *OutputDecl,
DeclaratorDecl *D,
SemanticInfo &ActiveSemantic,
llvm::StringSet<> &ActiveInputSemantics);
llvm::StringSet<> &ActiveSemantics,
bool IsInput);

bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *OutputDecl,
DeclaratorDecl *D, SemanticInfo &ActiveSemantic,
llvm::StringSet<> &ActiveInputSemantics);
llvm::StringSet<> &ActiveSemantics,
bool IsInput);

void processExplicitBindingsOnDecl(VarDecl *D);

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
31 changes: 22 additions & 9 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,10 +730,18 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
}

if (SemanticName == "SV_POSITION") {
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
Semantic->getAttrName()->getName(),
/* BuiltIn::FragCoord */ 15);
if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel) {
if (CGM.getTarget().getTriple().isSPIRV())
return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
Semantic->getAttrName()->getName(),
/* BuiltIn::FragCoord */ 15);
if (CGM.getTarget().getTriple().isDXIL())
return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
}

if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Vertex) {
return emitUserSemanticLoad(B, Type, Decl, Semantic, Index);
}
}

llvm_unreachable("non-handled system semantic. FIXME.");
Expand All @@ -759,11 +767,16 @@ void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
std::optional<unsigned> Index) {

std::string SemanticName = Semantic->getAttrName()->getName().upper();
if (SemanticName == "SV_POSITION")
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
Semantic->getAttrName()->getName(),
/* BuiltIn::Position */ 0);
else
if (SemanticName == "SV_POSITION") {
if (CGM.getTarget().getTriple().isDXIL())
emitDXILUserSemanticStore(B, Source, Semantic, Index);
else if (CGM.getTarget().getTriple().isSPIRV())
createSPIRVBuiltinStore(B, CGM.getModule(), Source,
Semantic->getAttrName()->getName(),
/* BuiltIn::Position */ 0);
} else if (SemanticName == "SV_TARGET") {
emitUserSemanticStore(B, Source, Decl, Semantic, Index);
} else
llvm_unreachable("non-handled system semantic. FIXME.");
}

Expand Down
90 changes: 71 additions & 19 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,12 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
}
}

bool SemaHLSL::determineActiveSemanticOnScalar(
FunctionDecl *FD, DeclaratorDecl *OutputDecl, DeclaratorDecl *D,
SemanticInfo &ActiveSemantic, llvm::StringSet<> &UsedSemantics) {
bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
DeclaratorDecl *OutputDecl,
DeclaratorDecl *D,
SemanticInfo &ActiveSemantic,
llvm::StringSet<> &UsedSemantics,
bool IsInput) {
if (ActiveSemantic.Semantic == nullptr) {
ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
if (ActiveSemantic.Semantic)
Expand All @@ -792,7 +795,7 @@ bool SemaHLSL::determineActiveSemanticOnScalar(
if (!A)
return false;

checkSemanticAnnotation(FD, D, A);
checkSemanticAnnotation(FD, D, A, IsInput);
OutputDecl->addAttr(A);

unsigned Location = ActiveSemantic.Index.value_or(0);
Expand Down Expand Up @@ -820,7 +823,8 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
DeclaratorDecl *OutputDecl,
DeclaratorDecl *D,
SemanticInfo &ActiveSemantic,
llvm::StringSet<> &UsedSemantics) {
llvm::StringSet<> &UsedSemantics,
bool IsInput) {
if (ActiveSemantic.Semantic == nullptr) {
ActiveSemantic.Semantic = D->getAttr<HLSLParsedSemanticAttr>();
if (ActiveSemantic.Semantic)
Expand All @@ -833,12 +837,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD,
const RecordType *RT = dyn_cast<RecordType>(T);
if (!RT)
return determineActiveSemanticOnScalar(FD, OutputDecl, D, ActiveSemantic,
UsedSemantics);
UsedSemantics, IsInput);

const RecordDecl *RD = RT->getDecl();
for (FieldDecl *Field : RD->fields()) {
SemanticInfo Info = ActiveSemantic;
if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics)) {
if (!determineActiveSemantic(FD, OutputDecl, Field, Info, UsedSemantics,
IsInput)) {
Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field;
return false;
}
Expand Down Expand Up @@ -868,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 @@ -920,7 +925,7 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {

// FIXME: Verify output semantics in parameters.
if (!determineActiveSemantic(FD, Param, Param, ActiveSemantic,
ActiveInputSemantics)) {
ActiveInputSemantics, /* IsInput= */ true)) {
Diag(Param->getLocation(), diag::note_previous_decl) << Param;
FD->setInvalidDecl();
}
Expand All @@ -932,12 +937,13 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
if (ActiveSemantic.Semantic)
ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
if (!FD->getReturnType()->isVoidType())
determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics);
determineActiveSemantic(FD, FD, FD, ActiveSemantic, ActiveOutputSemantics,
/* IsInput= */ false);
}

void SemaHLSL::checkSemanticAnnotation(
FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAppliedSemanticAttr *SemanticAttr) {
const HLSLAppliedSemanticAttr *SemanticAttr, bool IsInput) {
auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
Expand All @@ -948,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 @@ -961,11 +968,15 @@ void SemaHLSL::checkSemanticAnnotation(
}

if (SemanticName == "SV_POSITION") {
// TODO(#143523): allow use on other shader types & output once the overall
// semantic logic is implemented.
if (ST == llvm::Triple::Pixel)
return;
DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel});
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 @@ -975,7 +986,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 @@ -989,6 +1000,37 @@ 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.Direction & IOType::In)
return;
if (!IsInput && Case.Direction & IOType::Out)
return;

Diag(A->getLoc(), diag::err_hlsl_semantic_unsupported_direction_for_stage)
<< A->getAttrName() << (IsInput ? "input" : "output")
<< llvm::Triple::getEnvironmentTypeName(Case.Stage);
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 @@ -1790,6 +1832,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
20 changes: 15 additions & 5 deletions clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
// 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: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
// CHECK-SPIRV: @SV_Position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]

// CHECK: define void @main() {{.*}} {
float4 main(float4 p : SV_Position) : A {
// CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 16
// CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
// CHECK: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16
// CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position, align 16
// CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
// CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @A0, align 16

// CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
// 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_0]] = !{![[#MD_1:]]}
// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 15}
// | `-> BuiltIn Position
// `-> SPIR-V decoration 'FragCoord'
26 changes: 26 additions & 0 deletions clang/test/CodeGenHLSL/semantics/SV_Position.vs.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.8-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-DXIL %s
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-SPIRV %s

// CHECK-SPIRV: @SV_Position0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
// CHECK-SPIRV: @SV_Position = 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_Position {
// CHECK-SPIRV: %[[#P:]] = load <4 x float>, ptr addrspace(7) @SV_Position0, align 16
// CHECK-SPIRV: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
// CHECK-SPIRV: store <4 x float> %[[#R]], ptr addrspace(8) @SV_Position, align 16

// CHECK-DXIL: %SV_Position0 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
// 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_0]] = !{![[#MD_1:]]}
// CHECK-SPIRV-DAG: ![[#MD_2]] = !{![[#MD_3:]]}
// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 30, i32 0}
// | `-> Location 0
// `-> SPIR-V decoration 'Location'
// CHECK-SPIRV-DAG: ![[#MD_3]] = !{i32 11, i32 0}
// | `-> BuiltIn Position
// `-> SPIR-V decoration 'BuiltIn'
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'
14 changes: 4 additions & 10 deletions clang/test/SemaHLSL/Semantics/position.ps.hlsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s
// 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

// FIXME(Keenuts): change output semantic to something valid for pixels shaders
float4 main(float4 a : SV_Position2) : A {
// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 used a 'float4':'vector<float, 4>'
// CHECK-NEXT: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2
// CHECK-NEXT: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:24> "SV_Position" 2

// CHECK: HLSLParsedSemanticAttr 0x{{[0-9a-f]+}} <line:4:40> "A" 0
// CHECK: HLSLAppliedSemanticAttr 0x{{[0-9a-f]+}} <col:40> "A" 0
float4 main(float4 a : A) : SV_Position {
// expected-error@-1 {{semantic 'SV_Position' is unsupported as output for stage pixel}}
return a;
}
Loading