[clang] [llvm] [HLSL][SPIR-V] Handle SV_Postion builtin in PS (PR #141759)
Nathan Gauër via cfe-commits
cfe-commits at lists.llvm.org
Wed May 28 06:25:46 PDT 2025
https://github.com/Keenuts created https://github.com/llvm/llvm-project/pull/141759
This PR goes on top of #138530
This commit is using the same mechanism as vk::ext_builtin_input to
implement the SV_Position semantic input.
The HLSL signature is not yet ready for DXIL, hence this commit only
implements the SPIR-V side.
This is incomplete as it doesn't allow the semantic on hull/domain and
other shaders, but it's a first step to validate the overall input/output
semantic logic.
>From 085154ddedf3b0789a3908231d04f997e9e66ac4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Wed, 30 Apr 2025 11:06:55 +0200
Subject: [PATCH 1/8] [HLSL] Implement vk::ext_builtin_input attribute
This variable attribute is used in HLSL to add Vulkan specific builtins
in a shader.
The attribute is documented here:
https://github.com/microsoft/hlsl-specs/blob/17727e88fd1cb09013cb3a144110826af05f4dd5/proposals/0011-inline-spirv.md
Those variable, even if marked as `static` are externally initialized by
the pipeline/driver/GPU. This is handled by moving them to a specific
address space `hlsl_input`, also added by this commit.
The design for input variables in Clang can be found here:
https://github.com/llvm/wg-hlsl/blob/355771361ef69259fef39a65caef8bff9cb4046d/proposals/0019-spirv-input-builtin.md
Related to #136920
---
clang/include/clang/Basic/AddressSpaces.h | 1 +
clang/include/clang/Basic/Attr.td | 13 +++++++++++
clang/include/clang/Basic/AttrDocs.td | 22 +++++++++++++++++++
.../include/clang/Basic/AttributeCommonInfo.h | 2 +-
clang/include/clang/Sema/SemaHLSL.h | 2 ++
clang/lib/AST/Type.cpp | 1 +
clang/lib/AST/TypePrinter.cpp | 2 ++
clang/lib/Basic/Attributes.cpp | 1 +
clang/lib/Basic/TargetInfo.cpp | 2 ++
clang/lib/Basic/Targets/AArch64.h | 1 +
clang/lib/Basic/Targets/AMDGPU.cpp | 2 ++
clang/lib/Basic/Targets/DirectX.h | 1 +
clang/lib/Basic/Targets/NVPTX.h | 1 +
clang/lib/Basic/Targets/SPIR.h | 2 ++
clang/lib/Basic/Targets/SystemZ.h | 1 +
clang/lib/Basic/Targets/TCE.h | 1 +
clang/lib/Basic/Targets/WebAssembly.h | 1 +
clang/lib/Basic/Targets/X86.h | 1 +
clang/lib/CodeGen/CGHLSLRuntime.cpp | 11 ++++++++++
clang/lib/CodeGen/CGHLSLRuntime.h | 1 +
clang/lib/CodeGen/CodeGenModule.cpp | 17 ++++++++++++++
clang/lib/Sema/SemaDecl.cpp | 6 +++++
clang/lib/Sema/SemaDeclAttr.cpp | 3 +++
clang/lib/Sema/SemaHLSL.cpp | 14 ++++++++++++
clang/test/CodeGenHLSL/vk-input-builtin.hlsl | 14 ++++++++++++
.../SemaTemplate/address_space-dependent.cpp | 4 ++--
26 files changed, 124 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/vk-input-builtin.hlsl
diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h
index 519d959bb636c..48e4a1c61fe02 100644
--- a/clang/include/clang/Basic/AddressSpaces.h
+++ b/clang/include/clang/Basic/AddressSpaces.h
@@ -61,6 +61,7 @@ enum class LangAS : unsigned {
hlsl_constant,
hlsl_private,
hlsl_device,
+ hlsl_input,
// Wasm specific address spaces.
wasm_funcref,
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index df7bba094fce6..6b043160bd3bc 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -140,6 +140,11 @@ def SharedVar : SubsetSubject<Var,
[{S->hasGlobalStorage() && !S->getTLSKind()}],
"global variables">;
+def HLSLInputBuiltin : SubsetSubject<Var, [{S->hasGlobalStorage() &&
+ S->getStorageClass()==StorageClass::SC_Static &&
+ S->getType().isConstQualified()}],
+ "input builtin">;
+
def GlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage()}], "global variables">;
@@ -4908,6 +4913,14 @@ def HLSLWaveSize: InheritableAttr {
let Documentation = [WaveSizeDocs];
}
+def HLSLVkExtBuiltinInput : InheritableAttr {
+ let Spellings = [CXX11<"vk", "ext_builtin_input">];
+ let Args = [IntArgument<"BuiltIn">];
+ let Subjects = SubjectList<[HLSLInputBuiltin], ErrorDiag>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLVkExtBuiltinInputDocs];
+}
+
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 cbb397cb31dfb..9fc5ee24bf02f 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8497,6 +8497,28 @@ and copied back to the argument after the callee returns.
}];
}
+def HLSLVkExtBuiltinInputDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+Vulkan shaders have `Input` builtins. Those variables are externally
+initialized by the driver/pipeline, but each copy is private to the current
+lane.
+
+Those builtins can be declared using the `[[vk::ext_builtin_input]]` attribute
+like follows:
+
+.. code-block:: c++
+ [[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
+ static const uint3 groupid;
+
+This variable will be lowered into a module-level variable, with the `Input`
+storage class, and the `BuiltIn 26` decoration.
+
+The full documentation for this inline SPIR-V attribute can be found here:
+https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
+ }];
+}
+
def AnnotateTypeDocs : Documentation {
let Category = DocCatType;
let Heading = "annotate_type";
diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index 4af5a8fd1852c..dda37eadee277 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -67,7 +67,7 @@ class AttributeCommonInfo {
IgnoredAttribute,
UnknownAttribute,
};
- enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
+ enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, VK, GSL, RISCV };
enum class AttrArgsInfo {
None,
Optional,
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 5d260acf92abb..5d9f7e59b1349 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -130,6 +130,8 @@ class SemaHLSL : public SemaBase {
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL);
+ void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
+
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
QualType ProcessResourceTypeAttributes(QualType Wrapped);
HLSLAttributedResourceLocInfo
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 52b922e2138fd..52a1f10172d1c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -100,6 +100,7 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
// address spaces to default to work around this problem.
(A == LangAS::Default && B == LangAS::hlsl_private) ||
(A == LangAS::Default && B == LangAS::hlsl_device) ||
+ (A == LangAS::Default && B == LangAS::hlsl_input) ||
// Conversions from target specific address spaces may be legal
// depending on the target information.
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index cba1a2d98d660..6423ee49c11f4 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2619,6 +2619,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
return "hlsl_private";
case LangAS::hlsl_device:
return "hlsl_device";
+ case LangAS::hlsl_input:
+ return "hlsl_input";
case LangAS::wasm_funcref:
return "__funcref";
default:
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 6a070a99c8d96..67256142ad29c 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -189,6 +189,7 @@ getScopeFromNormalizedScopeName(StringRef ScopeName) {
.Case("gnu", AttributeCommonInfo::Scope::GNU)
.Case("gsl", AttributeCommonInfo::Scope::GSL)
.Case("hlsl", AttributeCommonInfo::Scope::HLSL)
+ .Case("vk", AttributeCommonInfo::Scope::VK)
.Case("msvc", AttributeCommonInfo::Scope::MSVC)
.Case("omp", AttributeCommonInfo::Scope::OMP)
.Case("riscv", AttributeCommonInfo::Scope::RISCV);
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index ab13c32f6943e..a6744c6c8931b 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -49,6 +49,8 @@ static const LangASMap FakeAddrSpaceMap = {
13, // hlsl_groupshared
14, // hlsl_constant
15, // hlsl_private
+ 16, // hlsl_device
+ 17, // hlsl_input
20, // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 2fab88cfca901..0c2135fb3862c 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -47,6 +47,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index c368200f3f739..13b76911bee47 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -64,6 +64,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
// will break loudly.
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_device
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -91,6 +92,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_device
+ llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
};
} // namespace targets
} // namespace clang
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 566acd6bb3cf3..1729a014c2dec 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -45,6 +45,7 @@ static const unsigned DirectXAddrSpaceMap[] = {
2, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index dc1ecc30980b7..6a54195b30452 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -49,6 +49,7 @@ static const unsigned NVPTXAddrSpaceMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..7c91840d1defa 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -50,6 +50,7 @@ static const unsigned SPIRDefIsPrivMap[] = {
2, // hlsl_constant
10, // hlsl_private
11, // hlsl_device
+ 12, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
@@ -85,6 +86,7 @@ static const unsigned SPIRDefIsGenMap[] = {
0, // hlsl_constant
10, // hlsl_private
11, // hlsl_device
+ 12, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 1f69530c4757f..6431be0b505ce 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -45,6 +45,7 @@ static const unsigned ZOSAddressMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
0 // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h
index f6e582120447f..005cab9819472 100644
--- a/clang/lib/Basic/Targets/TCE.h
+++ b/clang/lib/Basic/Targets/TCE.h
@@ -54,6 +54,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 04f0cb5df4601..d5aee5c0bd0eb 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -45,6 +45,7 @@ static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
20, // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 2f6fb33a7b597..a9287de51e82d 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -49,6 +49,7 @@ static const unsigned X86AddrSpaceMap[] = {
0, // hlsl_constant
0, // hlsl_private
0, // hlsl_device
+ 0, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f6608faaa7309..99e7b7f412559 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -554,6 +554,17 @@ static void initializeBufferFromBinding(CodeGenModule &CGM,
Args);
}
+void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
+ llvm::GlobalVariable *GV) {
+ if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) {
+ LLVMContext &Ctx = GV->getContext();
+ IRBuilder<> B(GV->getContext());
+ MDNode *Val = MDNode::get(
+ Ctx, {ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))});
+ GV->addMetadata("spv.builtin", *Val);
+ }
+}
+
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
if (!CGM.shouldEmitConvergenceTokens())
return nullptr;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 4d6db3f5d9f3e..68151c0f0ea24 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -150,6 +150,7 @@ class CGHLSLRuntime {
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
+ void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b36e078a51f97..68367c34fa514 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5636,6 +5636,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
else if (D->hasAttr<LoaderUninitializedAttr>())
Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
+ else if (GetGlobalVarAddressSpace(D) == LangAS::hlsl_input)
+ Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
else if (!InitExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
@@ -5759,9 +5761,18 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().internalizeDeviceSideVar(D, Linkage);
}
getCUDARuntime().handleVarRegistration(D, *GV);
+ } else if (LangOpts.HLSL &&
+ GetGlobalVarAddressSpace(D) == LangAS::hlsl_input) {
+ // HLSL Input variables are considered to be set by the driver/pipeline, but
+ // only visible to a single thread/wave.
+ GV->setExternallyInitialized(true);
}
GV->setInitializer(Init);
+
+ if (LangOpts.HLSL)
+ getHLSLRuntime().handleGlobalVarDefinition(D, GV);
+
if (emitter)
emitter->finalize(GV);
@@ -5804,6 +5815,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
!D->hasAttr<ConstInitAttr>())
Linkage = llvm::GlobalValue::InternalLinkage;
+ // HLSL variables in the input address space maps like memory-mapped
+ // variables. Even if they are 'static', they are externally initialized and
+ // read/write by the hardware/driver/pipeline.
+ if (LangOpts.HLSL && GetGlobalVarAddressSpace(D) == LangAS::hlsl_input)
+ Linkage = llvm::GlobalValue::ExternalLinkage;
+
GV->setLinkage(Linkage);
if (D->hasAttr<DLLImportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6b561d7bfc6e7..d5eb765fa4a56 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14412,6 +14412,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (getLangOpts().HLSL && HLSL().ActOnUninitializedVarDecl(Var))
return;
+ // HLSL input variables are expected to be externally initialized, even
+ // when marked `static`.
+ if (getLangOpts().HLSL &&
+ Var->getType().getAddressSpace() == LangAS::hlsl_input)
+ return;
+
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index bfb3ee9dcbd16..6094b41d89a4d 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7483,6 +7483,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLWaveSize:
S.HLSL().handleWaveSizeAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLVkExtBuiltinInput:
+ S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
+ break;
case ParsedAttr::AT_HLSLSV_GroupThreadID:
S.HLSL().handleSV_GroupThreadIDAttr(D, AL);
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 70aacaa2aadbe..55ac07f7f866a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1069,6 +1069,12 @@ void SemaHLSL::handleWaveSizeAttr(Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
+void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
+ IntegerLiteral *IL = cast<IntegerLiteral>(AL.getArgAsExpr(0));
+ D->addAttr(::new (getASTContext()) HLSLVkExtBuiltinInputAttr(
+ getASTContext(), AL, IL->getValue().getZExtValue()));
+}
+
bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
const auto *VT = T->getAs<VectorType>();
@@ -3190,6 +3196,14 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
return;
QualType Type = Decl->getType();
+
+ if (Decl->hasAttr<HLSLVkExtBuiltinInputAttr>()) {
+ LangAS ImplAS = LangAS::hlsl_input;
+ Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
+ Decl->setType(Type);
+ return;
+ }
+
if (Type->isSamplerT() || Type->isVoidType())
return;
diff --git a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
new file mode 100644
index 0000000000000..108aaaf9d78b9
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: spirv-unknown-vulkan1.3-compute %s -emit-llvm -O3 -o - | FileCheck %s
+
+[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
+static const uint3 groupid;
+// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(12) externally_initialized constant <3 x i32> undef, align 16, !spv.builtin [[META0:![0-9]+]]
+
+RWStructuredBuffer<int> output : register(u1, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+ output[0] = groupid;
+}
+// CHECK: [[META0]] = !{i32 26}
diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp
index 4eabcfa0fcf21..e17bf60e6a200 100644
--- a/clang/test/SemaTemplate/address_space-dependent.cpp
+++ b/clang/test/SemaTemplate/address_space-dependent.cpp
@@ -43,7 +43,7 @@ void neg() {
template <long int I>
void tooBig() {
- __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388583)}}
+ __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388582)}}
}
template <long int I>
@@ -101,7 +101,7 @@ int main() {
car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}}
HasASTemplateFields<1> HASTF;
neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
- correct<0x7FFFE7>();
+ correct<0x7FFFE6>();
tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}}
__attribute__((address_space(1))) char *x;
>From 9f2b07d4b3e7aac5866f91e0cf64e84d31d7946c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 5 May 2025 15:44:59 +0200
Subject: [PATCH 2/8] fix address space mapping for SPIR
---
clang/lib/Basic/Targets/SPIR.h | 4 ++--
clang/test/CodeGenHLSL/vk-input-builtin.hlsl | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 7c91840d1defa..7d73c8504c5b9 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -50,7 +50,7 @@ static const unsigned SPIRDefIsPrivMap[] = {
2, // hlsl_constant
10, // hlsl_private
11, // hlsl_device
- 12, // hlsl_input
+ 7, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
@@ -86,7 +86,7 @@ static const unsigned SPIRDefIsGenMap[] = {
0, // hlsl_constant
10, // hlsl_private
11, // hlsl_device
- 12, // hlsl_input
+ 7, // hlsl_input
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
diff --git a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
index 108aaaf9d78b9..2e8a854956100 100644
--- a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
+++ b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
@@ -3,7 +3,7 @@
[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
static const uint3 groupid;
-// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(12) externally_initialized constant <3 x i32> undef, align 16, !spv.builtin [[META0:![0-9]+]]
+// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spv.builtin [[META0:![0-9]+]]
RWStructuredBuffer<int> output : register(u1, space0);
>From 8f07d0bdd2c556ad580a40a304976fa2deddd837 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 5 May 2025 15:58:33 +0200
Subject: [PATCH 3/8] reuse spirv.Decorations metadata
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 8 +++---
clang/test/CodeGenHLSL/vk-input-builtin.hlsl | 5 ++--
.../hlsl-intrinsics/vk-ext-builtin-input.ll | 26 +++++++++++++++++++
3 files changed, 34 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 99e7b7f412559..7b2de217530c2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -559,9 +559,11 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) {
LLVMContext &Ctx = GV->getContext();
IRBuilder<> B(GV->getContext());
- MDNode *Val = MDNode::get(
- Ctx, {ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))});
- GV->addMetadata("spv.builtin", *Val);
+ MDNode *Operands = MDNode::get(
+ Ctx, {ConstantAsMetadata::get(B.getInt32(11)),
+ ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))});
+ MDNode *Decoration = MDNode::get(Ctx, {Operands});
+ GV->addMetadata("spirv.Decorations", *Decoration);
}
}
diff --git a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
index 2e8a854956100..ff31005bc1bf3 100644
--- a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
+++ b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
@@ -3,7 +3,7 @@
[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
static const uint3 groupid;
-// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spv.builtin [[META0:![0-9]+]]
+// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spirv.Decorations [[META0:![0-9]+]]
RWStructuredBuffer<int> output : register(u1, space0);
@@ -11,4 +11,5 @@ RWStructuredBuffer<int> output : register(u1, space0);
void main() {
output[0] = groupid;
}
-// CHECK: [[META0]] = !{i32 26}
+// CHECK: [[META0]] = !{[[META1:![0-9]+]]}
+// CHECK: [[META1]] = !{i32 11, i32 26}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
new file mode 100644
index 0000000000000..4387dc191cd12
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
@@ -0,0 +1,26 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
+
+; FIXME(138268): Alignment decoration is emitted.
+; NO-RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: OpDecorate %[[#WorkgroupId:]] BuiltIn WorkgroupId
+
+; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#uint_0:]] = OpConstant %[[#uint]] 0
+; CHECK-DAG: %[[#v3uint:]] = OpTypeVector %[[#uint]] 3
+; CHECK-DAG: %[[#ptr_Input_uint:]] = OpTypePointer Input %[[#uint]]
+; CHECK-DAG: %[[#ptr_Input_v3uint:]] = OpTypePointer Input %[[#v3uint]]
+; CHECK-DAG: %[[#WorkgroupId:]] = OpVariable %[[#ptr_Input_v3uint]] Input
+ at var = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spirv.Decorations !0
+
+define i32 @foo() {
+entry:
+; CHECK: %[[#ptr:]] = OpAccessChain %[[#ptr_Input_uint]] %[[#WorkgroupId]] %[[#uint_0]]
+; CHECK: %[[#res:]] = OpLoad %[[#uint]] %[[#ptr]] Aligned 16
+; CHECK: OpReturnValue %[[#res]]
+ %0 = load i32, ptr addrspace(7) @var, align 16
+ ret i32 %0
+}
+
+!0 = !{!1}
+!1 = !{i32 11, i32 26}
>From bab63962c0cb59c12022c59a1714a118d7e3cea3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 5 May 2025 16:15:47 +0200
Subject: [PATCH 4/8] fix docs
---
clang/include/clang/Basic/AttrDocs.td | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 9fc5ee24bf02f..039a1808ffe40 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8508,6 +8508,7 @@ Those builtins can be declared using the `[[vk::ext_builtin_input]]` attribute
like follows:
.. code-block:: c++
+
[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
static const uint3 groupid;
>From 941140eced6d80a56414732f1a979187e3cd8d47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 5 May 2025 17:16:39 +0200
Subject: [PATCH 5/8] change run prefix for failure
---
llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
index 4387dc191cd12..131c3aba182b5 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
@@ -1,7 +1,7 @@
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
; FIXME(138268): Alignment decoration is emitted.
-; NO-RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
+; FIXME: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-DAG: OpDecorate %[[#WorkgroupId:]] BuiltIn WorkgroupId
>From 2c2c670f9262d75d626b55b3e7095d583fdcaaa3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 6 May 2025 16:46:39 +0200
Subject: [PATCH 6/8] remove undef usage
---
clang/lib/CodeGen/CodeGenModule.cpp | 11 +++++------
clang/test/CodeGenHLSL/vk-input-builtin.hlsl | 2 +-
.../SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll | 2 +-
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 68367c34fa514..4f4c01f52fdb4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5636,8 +5636,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
else if (D->hasAttr<LoaderUninitializedAttr>())
Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
- else if (GetGlobalVarAddressSpace(D) == LangAS::hlsl_input)
- Init = llvm::UndefValue::get(getTypes().ConvertTypeForMem(ASTTy));
else if (!InitExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
@@ -5761,15 +5759,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().internalizeDeviceSideVar(D, Linkage);
}
getCUDARuntime().handleVarRegistration(D, *GV);
- } else if (LangOpts.HLSL &&
- GetGlobalVarAddressSpace(D) == LangAS::hlsl_input) {
+ }
+
+ if (LangOpts.HLSL && GetGlobalVarAddressSpace(D) == LangAS::hlsl_input) {
// HLSL Input variables are considered to be set by the driver/pipeline, but
// only visible to a single thread/wave.
GV->setExternallyInitialized(true);
+ } else {
+ GV->setInitializer(Init);
}
- GV->setInitializer(Init);
-
if (LangOpts.HLSL)
getHLSLRuntime().handleGlobalVarDefinition(D, GV);
diff --git a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
index ff31005bc1bf3..1cc7963c0e289 100644
--- a/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
+++ b/clang/test/CodeGenHLSL/vk-input-builtin.hlsl
@@ -3,7 +3,7 @@
[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
static const uint3 groupid;
-// CHECK: @_ZL7groupid = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spirv.Decorations [[META0:![0-9]+]]
+// CHECK: @_ZL7groupid = external local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32>, align 16, !spirv.Decorations [[META0:![0-9]+]]
RWStructuredBuffer<int> output : register(u1, space0);
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
index 131c3aba182b5..2253b9761d5bd 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/vk-ext-builtin-input.ll
@@ -11,7 +11,7 @@
; CHECK-DAG: %[[#ptr_Input_uint:]] = OpTypePointer Input %[[#uint]]
; CHECK-DAG: %[[#ptr_Input_v3uint:]] = OpTypePointer Input %[[#v3uint]]
; CHECK-DAG: %[[#WorkgroupId:]] = OpVariable %[[#ptr_Input_v3uint]] Input
- at var = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spirv.Decorations !0
+ at var = external local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32>, align 16, !spirv.Decorations !0
define i32 @foo() {
entry:
>From 981ccf98be2a2d58243c5abe0bb5a5c1caa54405 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 6 May 2025 17:22:40 +0200
Subject: [PATCH 7/8] add sema tests
---
clang/include/clang/Basic/Attr.td | 4 +--
clang/lib/Sema/SemaHLSL.cpp | 8 +++--
clang/test/SemaHLSL/vk-ext-input-builtin.hlsl | 29 +++++++++++++++++++
3 files changed, 36 insertions(+), 5 deletions(-)
create mode 100644 clang/test/SemaHLSL/vk-ext-input-builtin.hlsl
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 6b043160bd3bc..bb9302bdb21c3 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -143,7 +143,7 @@ def SharedVar : SubsetSubject<Var,
def HLSLInputBuiltin : SubsetSubject<Var, [{S->hasGlobalStorage() &&
S->getStorageClass()==StorageClass::SC_Static &&
S->getType().isConstQualified()}],
- "input builtin">;
+ "static const globals">;
def GlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage()}], "global variables">;
@@ -4915,7 +4915,7 @@ def HLSLWaveSize: InheritableAttr {
def HLSLVkExtBuiltinInput : InheritableAttr {
let Spellings = [CXX11<"vk", "ext_builtin_input">];
- let Args = [IntArgument<"BuiltIn">];
+ let Args = [UnsignedArgument<"BuiltIn">];
let Subjects = SubjectList<[HLSLInputBuiltin], ErrorDiag>;
let LangOpts = [HLSL];
let Documentation = [HLSLVkExtBuiltinInputDocs];
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 55ac07f7f866a..4bf7387b5d8cd 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1070,9 +1070,11 @@ void SemaHLSL::handleWaveSizeAttr(Decl *D, const ParsedAttr &AL) {
}
void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
- IntegerLiteral *IL = cast<IntegerLiteral>(AL.getArgAsExpr(0));
- D->addAttr(::new (getASTContext()) HLSLVkExtBuiltinInputAttr(
- getASTContext(), AL, IL->getValue().getZExtValue()));
+ uint32_t ID;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), ID))
+ return;
+ D->addAttr(::new (getASTContext())
+ HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
}
bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
diff --git a/clang/test/SemaHLSL/vk-ext-input-builtin.hlsl b/clang/test/SemaHLSL/vk-ext-input-builtin.hlsl
new file mode 100644
index 0000000000000..e636e146cf68a
--- /dev/null
+++ b/clang/test/SemaHLSL/vk-ext-input-builtin.hlsl
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple spirv-unkown-vulkan1.3-compute -x hlsl -hlsl-entry foo -finclude-default-header -o - %s -verify
+
+// expected-error at +1 {{'ext_builtin_input' attribute only applies to static const globals}}
+[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
+const uint3 groupid1;
+
+// expected-error at +1 {{'ext_builtin_input' attribute only applies to static const globals}}
+[[vk::ext_builtin_input(/* WorkgroupId */ 26)]]
+static uint3 groupid2;
+
+// expected-error at +1 {{'ext_builtin_input' attribute takes one argument}}
+[[vk::ext_builtin_input()]]
+// expected-error at +1 {{default initialization of an object of const type 'const hlsl_private uint3' (aka 'const hlsl_private vector<uint, 3>')}}
+static const uint3 groupid3;
+
+// expected-error at +1 {{'ext_builtin_input' attribute requires an integer constant}}
+[[vk::ext_builtin_input(0.4f)]]
+// expected-error at +1 {{default initialization of an object of const type 'const hlsl_private uint3' (aka 'const hlsl_private vector<uint, 3>')}}
+static const uint3 groupid4;
+
+// expected-error at +1 {{'ext_builtin_input' attribute only applies to static const globals}}
+[[vk::ext_builtin_input(1)]]
+void some_function() {
+}
+
+[numthreads(1,1,1)]
+void foo() {
+}
+
>From d270224a83e27f349b78b473ee4df1b3e945a263 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 5 May 2025 18:01:17 +0200
Subject: [PATCH 8/8] [HLSL][SPIR-V] Handle SV_Postion builtin in PS
This commit is using the same mechanism as vk::ext_builtin_input to
implement the SV_Position semantic input.
The HLSL signature is not yet ready for DXIL, hence this commit only
implements the SPIR-V side.
This is incomplete as it doesn't allow the semantic on hull/domain and
other shaders, but it's a first step to validate the overall input/output
semantic logic.
---
clang/include/clang/Basic/Attr.td | 7 ++++
clang/include/clang/Sema/SemaHLSL.h | 2 +
clang/lib/CodeGen/CGHLSLRuntime.cpp | 40 ++++++++++++++-----
clang/lib/CodeGen/CGHLSLRuntime.h | 1 +
clang/lib/Parse/ParseHLSL.cpp | 1 +
clang/lib/Sema/SemaDeclAttr.cpp | 3 ++
clang/lib/Sema/SemaHLSL.cpp | 25 ++++++++++++
.../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 10 +++++
.../test/SemaHLSL/Semantics/position.ps.hlsl | 7 ++++
.../test/SemaHLSL/Semantics/position.vs.hlsl | 6 +++
llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 +
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 +
12 files changed, 97 insertions(+), 9 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
create mode 100644 clang/test/SemaHLSL/Semantics/position.ps.hlsl
create mode 100644 clang/test/SemaHLSL/Semantics/position.vs.hlsl
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index bb9302bdb21c3..1d10e11fb79b1 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4807,6 +4807,13 @@ def HLSLResourceBinding: InheritableAttr {
}];
}
+def HLSLSV_Position : HLSLAnnotationAttr {
+ let Spellings = [HLSLAnnotation<"sv_position">];
+ let Subjects = SubjectList<[ParmVar, Field]>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLSV_DispatchThreadIDDocs];
+}
+
def HLSLPackOffset: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"packoffset">];
let LangOpts = [HLSL];
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 5d9f7e59b1349..b013bc20fe0d6 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -124,6 +124,7 @@ class SemaHLSL : public SemaBase {
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
+ void handleSV_PositionAttr(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);
@@ -145,6 +146,7 @@ class SemaHLSL : public SemaBase {
// Diagnose whether the input ID is uint/unit2/uint3 type.
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL);
+ bool diagnosePositionType(QualType T, const ParsedAttr &AL);
bool CanPerformScalarCast(QualType SrcTy, QualType DestTy);
bool ContainsBitField(QualType BaseTy);
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 7b2de217530c2..c073a72208562 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -345,6 +345,28 @@ static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
return B.CreateCall(F, {B.getInt32(0)});
}
+static void addBuiltinDecoration(llvm::GlobalVariable *GV, unsigned BuiltIn) {
+ LLVMContext &Ctx = GV->getContext();
+ IRBuilder<> B(GV->getContext());
+ MDNode *Operands =
+ MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(11)),
+ ConstantAsMetadata::get(B.getInt32(BuiltIn))});
+ MDNode *Decoration = MDNode::get(Ctx, {Operands});
+ GV->addMetadata("spirv.Decorations", *Decoration);
+}
+
+static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
+ llvm::Type *Ty, const Twine &Name,
+ unsigned BuiltInID) {
+ auto *GV = new llvm::GlobalVariable(
+ M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
+ /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
+ llvm::GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
+ addBuiltinDecoration(GV, BuiltInID);
+ return B.CreateLoad(Ty, GV);
+}
+
llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
const ParmVarDecl &D,
llvm::Type *Ty) {
@@ -368,6 +390,13 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic());
return buildVectorInput(B, GroupIDIntrinsic, Ty);
}
+ if (D.hasAttr<HLSLSV_PositionAttr>()) {
+ if (getArch() == llvm::Triple::spirv)
+ return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position",
+ /* BuiltIn::Position */ 0);
+ llvm_unreachable(
+ "Shader signature for semantics not implemented for DXIL.");
+ }
assert(false && "Unhandled parameter attribute");
return nullptr;
}
@@ -556,15 +585,8 @@ static void initializeBufferFromBinding(CodeGenModule &CGM,
void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *GV) {
- if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>()) {
- LLVMContext &Ctx = GV->getContext();
- IRBuilder<> B(GV->getContext());
- MDNode *Operands = MDNode::get(
- Ctx, {ConstantAsMetadata::get(B.getInt32(11)),
- ConstantAsMetadata::get(B.getInt32(Attr->getBuiltIn()))});
- MDNode *Decoration = MDNode::get(Ctx, {Operands});
- GV->addMetadata("spirv.Decorations", *Decoration);
- }
+ if (auto Attr = VD->getAttr<HLSLVkExtBuiltinInputAttr>())
+ addBuiltinDecoration(GV, Attr->getBuiltIn());
}
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 68151c0f0ea24..7b37218afc5ab 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -96,6 +96,7 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(Step, step)
GENERATE_HLSL_INTRINSIC_FUNCTION(Radians, radians)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(Position, position)
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupThreadId, thread_id_in_group)
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupId, group_id)
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index 5569605c287b1..53d46465e3362 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -289,6 +289,7 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
case ParsedAttr::AT_HLSLSV_GroupID:
case ParsedAttr::AT_HLSLSV_GroupIndex:
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ case ParsedAttr::AT_HLSLSV_Position:
break;
default:
llvm_unreachable("invalid HLSL Annotation");
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 6094b41d89a4d..080377ab2a45d 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7483,6 +7483,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLWaveSize:
S.HLSL().handleWaveSizeAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLSV_Position:
+ S.HLSL().handleSV_PositionAttr(D, AL);
+ break;
case ParsedAttr::AT_HLSLVkExtBuiltinInput:
S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4bf7387b5d8cd..63d99ef37262b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -743,6 +743,11 @@ void SemaHLSL::CheckSemanticAnnotation(
return;
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
break;
+ case attr::HLSLSV_Position:
+ if (ST == llvm::Triple::Pixel)
+ return;
+ DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel});
+ break;
default:
llvm_unreachable("Unknown HLSLAnnotationAttr");
}
@@ -1099,6 +1104,26 @@ void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
}
+bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) {
+ const auto *VT = T->getAs<VectorType>();
+
+ if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
+ Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
+ << AL << "float/float1/float2/float3";
+ return false;
+ }
+
+ return true;
+}
+
+void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) {
+ auto *VD = cast<ValueDecl>(D);
+ if (!diagnosePositionType(VD->getType(), AL))
+ return;
+
+ D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL));
+}
+
void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) {
auto *VD = cast<ValueDecl>(D);
if (!diagnoseInputIDType(VD->getType(), AL))
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
new file mode 100644
index 0000000000000..58b91fc9264dd
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+// CHECK: @sv_position = external thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
+
+// CHECK: define void @main() {{.*}} {
+float4 main(float4 p : SV_Position) {
+ // 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]])
+ return p;
+}
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.hlsl
new file mode 100644
index 0000000000000..32bc5f55b2abd
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/position.ps.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -finclude-default-header -o - %s -ast-dump | FileCheck %s
+
+float4 main(float4 a : SV_Position) {
+// CHECK: FunctionDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-1]]:8 main 'float4 (float4)'
+// CHECK-NEXT: ParmVarDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:20 a 'float4':'vector<float, 4>'
+// CHECK-NEXT: HLSLSV_PositionAttr 0x{{[0-9a-fA-F]+}} <{{.*}}>
+}
diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
new file mode 100644
index 0000000000000..19f781fa3757c
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify
+
+// expected-error at +1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}}
+float4 main(float4 a : SV_Position) {
+ return a;
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index b1a27311e2a9c..0bfba1b1a80bd 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -16,6 +16,8 @@ def int_dx_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrW
def int_dx_group_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
def int_dx_thread_id_in_group : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
def int_dx_flattened_thread_id_in_group : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrWillReturn]>;
+def int_dx_position
+ : Intrinsic<[llvm_v4f32_ty], [], [IntrNoMem, IntrWillReturn]>;
// Create resource handle given binding information. Returns a `target("dx.")`
// type appropriate for the kind of resource given a register space ID, lower
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 404467781b4d0..aa44b1e682244 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -63,6 +63,8 @@ let TargetPrefix = "spv" in {
def int_spv_thread_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
def int_spv_group_id : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
def int_spv_thread_id_in_group : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrWillReturn]>;
+ def int_spv_position
+ : Intrinsic<[llvm_v4f32_ty], [], [IntrNoMem, IntrWillReturn]>;
def int_spv_flattened_thread_id_in_group : Intrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrWillReturn]>;
def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
More information about the cfe-commits
mailing list