[clang] [llvm] [HLSL][SPIR-V] Implement vk::location for inputs (PR #169479)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 25 02:23:09 PST 2025
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/169479 at github.com>
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Nathan Gauër (Keenuts)
<details>
<summary>Changes</summary>
This commit adds the support for vk::location attribute which can be applied to input and output variables.
As in/inout parameters are not supported yet, vk::location on such parameters is not tested.
As implemented in DXC, vk::location has the following rules:
- input and outputs are handled independently.
- input/output lowered to a SPIR-V builtins are not using the assigned vk::location and thus ignored.
- input/output lowered to a Location decoration must either all have explicit locations, or none. Mixing is not allowed (except with builtins).
---
Patch is 33.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169479.diff
21 Files Affected:
- (modified) clang/include/clang/Basic/Attr.td (+8)
- (modified) clang/include/clang/Basic/AttrDocs.td (+12)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6)
- (modified) clang/include/clang/Sema/SemaHLSL.h (+22-3)
- (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+18-7)
- (modified) clang/lib/CodeGen/CGHLSLRuntime.h (+2)
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+3)
- (modified) clang/lib/Sema/SemaHLSL.cpp (+109-8)
- (added) clang/test/CodeGenHLSL/semantics/SV_Target.ps.hlsl (+19)
- (added) clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl (+37)
- (added) clang/test/CodeGenHLSL/semantics/semantic.explicit-location.hlsl (+19)
- (added) clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin.hlsl (+39)
- (modified) clang/test/Misc/pragma-attribute-supported-attributes-list.test (+1)
- (modified) clang/test/SemaHLSL/Semantics/position.ps.hlsl (+1-1)
- (added) clang/test/SemaHLSL/Semantics/semantic.explicit-mix-builtin-vs.hlsl (+16)
- (added) clang/test/SemaHLSL/Semantics/semantic.explicit-mix-location-2.hlsl (+15)
- (added) clang/test/SemaHLSL/Semantics/semantic.explicit-mix-location.hlsl (+15)
- (added) clang/test/SemaHLSL/Semantics/target.ps.input.hlsl (+7)
- (added) clang/test/SemaHLSL/Semantics/target.vs.input.hlsl (+8)
- (added) clang/test/SemaHLSL/Semantics/target.vs.output.hlsl (+7)
- (added) llvm/test/CodeGen/SPIRV/semantics/target.ps.ll (+33)
``````````diff
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 8e5f7ef0bb82d..9e7dc200bc6cf 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5172,6 +5172,14 @@ def HLSLVkConstantId : InheritableAttr {
let Documentation = [VkConstantIdDocs];
}
+def HLSLVkLocation : HLSLAnnotationAttr {
+ let Spellings = [CXX11<"vk", "location">];
+ let Args = [IntArgument<"Location">];
+ let Subjects = SubjectList<[ParmVar, Field, Function], ErrorDiag>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLVkLocationDocs];
+}
+
def RandomizeLayout : InheritableAttr {
let Spellings = [GCC<"randomize_layout">];
let Subjects = SubjectList<[Record]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index c1b1510f363d4..fa365da3ed9aa 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8981,6 +8981,18 @@ The descriptor set is optional and defaults to 0 if not provided.
}];
}
+def HLSLVkLocationDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+Attribute used for specifying the location number for the stage input/output
+variables. Allowed on function parameters, function returns, and struct
+fields. This parameter has no effect when used outside of an entrypoint
+parameter/parameter field/return value.
+
+This attribute maps to the 'Location' SPIR-V decoration.
+ }];
+}
+
def WebAssemblyFuncrefDocs : Documentation {
let Category = DocCatType;
let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 53aa86a7dabde..04812bd78d9b4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13231,6 +13231,12 @@ 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 err_hlsl_semantic_partial_explicit_indexing
+ : Error<"partial explicit stage input location assignment via "
+ "vk::location(X) unsupported">;
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">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 15edb7e77a22b..cac89f6e51cae 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<llvm::Triple::EnvironmentType> AllowedStages);
QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS,
QualType LHSType, QualType RHSType,
@@ -171,6 +168,7 @@ class SemaHLSL : public SemaBase {
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
void handleVkBindingAttr(Decl *D, const ParsedAttr &AL);
+ void handleVkLocationAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
@@ -243,6 +241,19 @@ class SemaHLSL : public SemaBase {
HLSLParsedSemanticAttr *Semantic;
std::optional<uint32_t> Index;
};
+ std::optional<bool> InputUsesExplicitVkLocations = std::nullopt;
+ std::optional<bool> OutputUsesExplicitVkLocations = std::nullopt;
+
+ enum IOType {
+ In = 0b01,
+ Out = 0b10,
+ InOut = 0b11,
+ };
+
+ struct SemanticStageInfo {
+ llvm::Triple::EnvironmentType Stage;
+ IOType AllowedIOTypesMask;
+ };
private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
@@ -269,6 +280,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++;
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f5c07fe2e33ff..913d80b7e5c25 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -582,20 +582,22 @@ static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
return B.CreateLoad(Ty, GV);
}
-llvm::Value *
-CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
- HLSLAppliedSemanticAttr *Semantic,
- std::optional<unsigned> Index) {
+llvm::Value *CGHLSLRuntime::emitSPIRVUserSemanticLoad(
+ llvm::IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
+ HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
Twine BaseName = Twine(Semantic->getAttrName()->getName());
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
unsigned Location = SPIRVLastAssignedInputSemanticLocation;
+ if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
+ Location = L->getLocation();
// DXC completely ignores the semantic/index pair. Location are assigned from
// the first semantic to the last.
llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
unsigned ElementCount = AT ? AT->getNumElements() : 1;
SPIRVLastAssignedInputSemanticLocation += ElementCount;
+
return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
VariableName.str());
}
@@ -616,10 +618,14 @@ static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
void CGHLSLRuntime::emitSPIRVUserSemanticStore(
llvm::IRBuilder<> &B, llvm::Value *Source,
- HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
+ const clang::DeclaratorDecl *Decl, HLSLAppliedSemanticAttr *Semantic,
+ std::optional<unsigned> Index) {
Twine BaseName = Twine(Semantic->getAttrName()->getName());
Twine VariableName = BaseName.concat(Twine(Index.value_or(0)));
+
unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
+ if (auto *L = Decl->getAttr<HLSLVkLocationAttr>())
+ Location = L->getLocation();
// DXC completely ignores the semantic/index pair. Location are assigned from
// the first semantic to the last.
@@ -671,7 +677,7 @@ llvm::Value *CGHLSLRuntime::emitUserSemanticLoad(
IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic, std::optional<unsigned> Index) {
if (CGM.getTarget().getTriple().isSPIRV())
- return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index);
+ return emitSPIRVUserSemanticLoad(B, Type, Decl, Semantic, Index);
if (CGM.getTarget().getTriple().isDXIL())
return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
@@ -684,7 +690,7 @@ void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index) {
if (CGM.getTarget().getTriple().isSPIRV())
- return emitSPIRVUserSemanticStore(B, Source, Semantic, Index);
+ return emitSPIRVUserSemanticStore(B, Source, Decl, Semantic, Index);
if (CGM.getTarget().getTriple().isDXIL())
return emitDXILUserSemanticStore(B, Source, Semantic, Index);
@@ -783,6 +789,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/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index c883282a8d9c8..d057add2db222 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -278,6 +278,7 @@ class CGHLSLRuntime {
HLSLResourceBindingAttr *RBA);
llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index);
llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
@@ -289,6 +290,7 @@ class CGHLSLRuntime {
std::optional<unsigned> Index);
void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
HLSLAppliedSemanticAttr *Semantic,
std::optional<unsigned> Index);
void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Source,
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index e3af5023c74d0..c9d1ee76a2e52 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7703,6 +7703,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLUnparsedSemantic:
S.HLSL().handleSemanticAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLVkLocation:
+ S.HLSL().handleVkLocationAttr(D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index ecab3946b58c7..2a69703d0d1e9 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -771,6 +771,22 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
}
}
+static bool isPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD,
+ HLSLAppliedSemanticAttr *Semantic) {
+ if (AstContext.getTargetInfo().getTriple().getOS() != llvm::Triple::Vulkan)
+ return false;
+
+ const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
+ assert(ShaderAttr && "Entry point has no shader attribute");
+ llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
+ auto SemanticName = Semantic->getSemanticName().upper();
+
+ if (ST == llvm::Triple::Pixel && SemanticName == "SV_POSITION")
+ return true;
+
+ return false;
+}
+
bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
DeclaratorDecl *OutputDecl,
DeclaratorDecl *D,
@@ -800,6 +816,22 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD,
unsigned Location = ActiveSemantic.Index.value_or(0);
+ if (!isPipelineBuiltin(getASTContext(), FD, A)) {
+ bool HasVkLocation = false;
+ if (auto *A = D->getAttr<HLSLVkLocationAttr>()) {
+ HasVkLocation = true;
+ Location = A->getLocation();
+ }
+
+ auto &UsesExplicitVkLocations =
+ IsInput ? InputUsesExplicitVkLocations : OutputUsesExplicitVkLocations;
+ if (UsesExplicitVkLocations.value_or(HasVkLocation) != HasVkLocation) {
+ Diag(D->getLocation(), diag::err_hlsl_semantic_partial_explicit_indexing);
+ return false;
+ }
+ UsesExplicitVkLocations = HasVkLocation;
+ }
+
const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType());
unsigned ElementCount = AT ? AT->getZExtSize() : 1;
ActiveSemantic.Index = Location + ElementCount;
@@ -873,14 +905,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});
@@ -954,7 +986,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 +1002,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 +1020,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;
@@ -996,6 +1034,50 @@ 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) {
+ SmallVector<std::string, 2> 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<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>())
@@ -1707,6 +1789,15 @@ void SemaHLSL::handleVkBindingAttr(Decl *D, const ParsedAttr &AL) {
HLSLVkBindingAttr(getASTContext(), AL, Binding, Set));
}
+void SemaHLSL::handleVkLocationAttr(Decl *D, const ParsedAttr &AL) {
+ uint32_t Location;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
+ return;
+
+ D->addAttr(::new (getASTContext())
+ HLSLVkLocationAttr(getASTContext(), AL, Location));
+}
+
bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
const auto *VT = T->getAs<VectorType>();
@@ -1797,6 +1888,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;
}
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/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
new file mode 100644
index 0000000000000..c5d86637fb4ea
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-location-output-struct.hlsl
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,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-prefixes=CHECK,CHECK-DXIL
+
+// CHECK-SPIRV: @SV_Positi...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/169479
More information about the llvm-commits
mailing list