[clang] [llvm] [HLSL][SPIR-V] Implement vk::push_constant (PR #166793)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 18 04:52:28 PST 2025
https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/166793
>From fb3dec4a74a7ad8f3aceda851a9c6268a734296f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Wed, 5 Nov 2025 16:37:37 +0100
Subject: [PATCH 1/5] [HLSL][SPIR-V] Implement vk::push_constant
Implements initial support for vk::push_constant.
As is, this allows handling simple push constants, but has one
main issue: layout can be incorrect.
The old fix would be to use target specific types, but this is
actively being reworked on for cbuffers (#147352). So for now, this
part is marked as XFAIL.
---
clang/include/clang/Basic/AddressSpaces.h | 1 +
clang/include/clang/Basic/Attr.td | 8 +++++
clang/include/clang/Basic/AttrDocs.td | 5 +++
.../clang/Basic/DiagnosticSemaKinds.td | 6 ++++
clang/include/clang/Basic/HLSLRuntime.h | 5 +++
clang/include/clang/Sema/SemaHLSL.h | 3 ++
clang/lib/AST/Type.cpp | 1 +
clang/lib/AST/TypePrinter.cpp | 2 ++
clang/lib/Basic/TargetInfo.cpp | 1 +
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/CodeGenModule.cpp | 15 +++++----
clang/lib/Sema/SemaDecl.cpp | 7 ++--
clang/lib/Sema/SemaDeclAttr.cpp | 3 ++
clang/lib/Sema/SemaHLSL.cpp | 32 ++++++++++++++++---
.../vk.pushconstant.access.bitfield.hlsl | 20 ++++++++++++
.../vk.pushconstant.anon-struct.hlsl | 17 ++++++++++
.../vk-features/vk.pushconstant.invalid.hlsl | 13 ++++++++
.../vk-features/vk.pushconstant.layout.hlsl | 31 ++++++++++++++++++
.../vk-features/vk.pushconstant.multiple.hlsl | 13 ++++++++
.../vk-features/vk.pushconstant.static.hlsl | 25 +++++++++++++++
...a-attribute-supported-attributes-list.test | 1 +
.../SemaTemplate/address_space-dependent.cpp | 4 +--
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 17 +++++-----
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 2 ++
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 ++
33 files changed, 222 insertions(+), 23 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.bitfield.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.anon-struct.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.layout.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.static.hlsl
diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h
index 48e4a1c61fe02..7280b8fc923d2 100644
--- a/clang/include/clang/Basic/AddressSpaces.h
+++ b/clang/include/clang/Basic/AddressSpaces.h
@@ -62,6 +62,7 @@ enum class LangAS : unsigned {
hlsl_private,
hlsl_device,
hlsl_input,
+ hlsl_push_constant,
// Wasm specific address spaces.
wasm_funcref,
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 8dfe4bc08c48e..e00765a57cb23 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5146,6 +5146,14 @@ def HLSLVkExtBuiltinInput : InheritableAttr {
let Documentation = [HLSLVkExtBuiltinInputDocs];
}
+def HLSLVkPushConstant : InheritableAttr {
+ let Spellings = [CXX11<"vk", "push_constant">];
+ let Args = [];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLVkPushConstantDocs];
+}
+
def HLSLVkConstantId : InheritableAttr {
let Spellings = [CXX11<"vk", "constant_id">];
let Args = [IntArgument<"Id">];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 4813191d2d602..3938c624c9d0c 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8777,6 +8777,11 @@ https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
}];
}
+def HLSLVkPushConstantDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{ FIXME }];
+}
+
def AnnotateTypeDocs : Documentation {
let Category = DocCatType;
let Heading = "annotate_type";
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a6e60fe4692ee..c9d128d77c90f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13183,6 +13183,9 @@ def err_hlsl_attr_invalid_type : Error<
"attribute %0 only applies to a field or parameter of type '%1'">;
def err_hlsl_attr_invalid_ast_node : Error<
"attribute %0 only applies to %1">;
+def err_hlsl_attr_incompatible
+ : Error<"%0 attribute is not compatible with %1 attribute">;
+
def err_hlsl_entry_shader_attr_mismatch : Error<
"%0 attribute on entry function does not match the target profile">;
def err_hlsl_numthreads_argument_oor : Error<"argument '%select{X|Y|Z}0' to numthreads attribute cannot exceed %1">;
@@ -13294,6 +13297,9 @@ def err_hlsl_incomplete_resource_array_in_function_param: Error<
def err_hlsl_assign_to_global_resource: Error<
"assignment to global resource variable %0 is not allowed">;
+def err_hlsl_push_constant_unique
+ : Error<"cannot have more than one push constant block">;
+
// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
"a randomized struct can only be initialized with a designated initializer">;
diff --git a/clang/include/clang/Basic/HLSLRuntime.h b/clang/include/clang/Basic/HLSLRuntime.h
index 03166805daa6a..f6a1cf9636467 100644
--- a/clang/include/clang/Basic/HLSLRuntime.h
+++ b/clang/include/clang/Basic/HLSLRuntime.h
@@ -14,6 +14,7 @@
#ifndef CLANG_BASIC_HLSLRUNTIME_H
#define CLANG_BASIC_HLSLRUNTIME_H
+#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/LangOptions.h"
#include <cstdint>
@@ -30,6 +31,10 @@ getStageFromEnvironment(const llvm::Triple::EnvironmentType &E) {
return static_cast<ShaderStage>(Pipeline);
}
+constexpr bool isInitializedByPipeline(LangAS AS) {
+ return AS == LangAS::hlsl_input || AS == LangAS::hlsl_push_constant;
+}
+
#define ENUM_COMPARE_ASSERT(Value) \
static_assert( \
getStageFromEnvironment(llvm::Triple::Value) == ShaderStage::Value, \
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 86da323892f98..2fcac237eba1c 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -190,6 +190,7 @@ class SemaHLSL : public SemaBase {
void handleSemanticAttr(Decl *D, const ParsedAttr &AL);
void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
+ void handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL);
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
QualType ProcessResourceTypeAttributes(QualType Wrapped);
@@ -239,6 +240,8 @@ class SemaHLSL : public SemaBase {
IdentifierInfo *RootSigOverrideIdent = nullptr;
+ bool HasDeclaredAPushConstant = false;
+
struct SemanticInfo {
HLSLParsedSemanticAttr *Semantic;
std::optional<uint32_t> Index;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4548af17e37f2..53082bcf78f6a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -101,6 +101,7 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
(A == LangAS::Default && B == LangAS::hlsl_private) ||
(A == LangAS::Default && B == LangAS::hlsl_device) ||
(A == LangAS::Default && B == LangAS::hlsl_input) ||
+ (A == LangAS::Default && B == LangAS::hlsl_push_constant) ||
// 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 c18b2eafc722c..8448dd3748e28 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2749,6 +2749,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
return "hlsl_device";
case LangAS::hlsl_input:
return "hlsl_input";
+ case LangAS::hlsl_push_constant:
+ return "hlsl_push_constant";
case LangAS::wasm_funcref:
return "__funcref";
default:
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index ffaf98bf9c366..92ca7a66a9593 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -52,6 +52,7 @@ static const LangASMap FakeAddrSpaceMap = {
15, // hlsl_private
16, // hlsl_device
17, // hlsl_input
+ 18, // hlsl_push_constant
20, // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 1a7aa658e9d87..8e8d8e6ae86b5 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -48,6 +48,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
// 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 d4d696b8456b6..993a73a89c9e9 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -63,6 +63,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_device
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_push_constant
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -91,6 +92,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_device
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
+ llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_push_constant
};
} // namespace targets
} // namespace clang
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index a21a593365773..c0799a6f7610f 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -46,6 +46,7 @@ static const unsigned DirectXAddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
// 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 f5c8396f398aa..6338a4f2f9036 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -50,6 +50,7 @@ static const unsigned NVPTXAddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
// 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 22b2799518dd0..94449231efb94 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -51,6 +51,7 @@ static const unsigned SPIRDefIsPrivMap[] = {
10, // hlsl_private
11, // hlsl_device
7, // hlsl_input
+ 13, // hlsl_push_constant
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
@@ -87,6 +88,7 @@ static const unsigned SPIRDefIsGenMap[] = {
10, // hlsl_private
11, // hlsl_device
7, // hlsl_input
+ 13, // hlsl_push_constant
// 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 4e15d5af1cde6..4ce515b31a001 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -46,6 +46,7 @@ static const unsigned ZOSAddressMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
0 // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h
index 005cab9819472..161025378c471 100644
--- a/clang/lib/Basic/Targets/TCE.h
+++ b/clang/lib/Basic/Targets/TCE.h
@@ -55,6 +55,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
// 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 4de6ce6bb5a21..c8065843aeb42 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -46,6 +46,7 @@ static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
20, // wasm_funcref
};
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index e7da2622e78b5..7b88ac70e234f 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -50,6 +50,7 @@ static const unsigned X86AddrSpaceMap[] = {
0, // hlsl_private
0, // hlsl_device
0, // hlsl_input
+ 0, // hlsl_push_constant
// 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/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 3eeb1718e455a..c3b536c7a267f 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -6049,9 +6049,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().handleVarRegistration(D, *GV);
}
- if (LangOpts.HLSL && GetGlobalVarAddressSpace(D) == LangAS::hlsl_input) {
+ if (LangOpts.HLSL &&
+ hlsl::isInitializedByPipeline(GetGlobalVarAddressSpace(D))) {
// HLSL Input variables are considered to be set by the driver/pipeline, but
- // only visible to a single thread/wave.
+ // only visible to a single thread/wave. Push constants are also externally
+ // initialized, but constant, hence cross-wave visibility is not relevant.
GV->setExternallyInitialized(true);
} else {
GV->setInitializer(Init);
@@ -6102,10 +6104,11 @@ 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)
+ // HLSL variables in the input or push-constant address space maps are like
+ // memory-mapped variables. Even if they are 'static', they are externally
+ // initialized and read/write by the hardware/driver/pipeline.
+ if (LangOpts.HLSL &&
+ hlsl::isInitializedByPipeline(GetGlobalVarAddressSpace(D)))
Linkage = llvm::GlobalValue::ExternalLinkage;
GV->setLinkage(Linkage);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 25b89d65847ad..5c29bf5e77414 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticComment.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -14559,10 +14560,10 @@ 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`.
+ // HLSL input & push-constant variables are expected to be externally
+ // initialized, even when marked `static`.
if (getLangOpts().HLSL &&
- Var->getType().getAddressSpace() == LangAS::hlsl_input)
+ hlsl::isInitializedByPipeline(Var->getType().getAddressSpace()))
return;
// C++03 [dcl.init]p9:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index a9e7b44ac9d73..0396155bd6a9d 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7614,6 +7614,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLVkExtBuiltinInput:
S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLVkPushConstant:
+ S.HLSL().handleVkPushConstantAttr(D, AL);
+ break;
case ParsedAttr::AT_HLSLVkConstantId:
S.HLSL().handleVkConstantIdAttr(D, AL);
break;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2b9b3abbd5360..1831584c88697 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1667,6 +1667,11 @@ void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
}
+void SemaHLSL::handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL) {
+ D->addAttr(::new (getASTContext())
+ HLSLVkPushConstantAttr(getASTContext(), AL));
+}
+
void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) {
uint32_t Id;
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
@@ -3837,12 +3842,15 @@ QualType SemaHLSL::getInoutParameterType(QualType Ty) {
return Ty;
}
-static bool IsDefaultBufferConstantDecl(VarDecl *VD) {
+static bool IsDefaultBufferConstantDecl(const ASTContext &Ctx, VarDecl *VD) {
+ bool IsVulkan =
+ Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::Vulkan;
+ bool IsVKPushConstant = IsVulkan && VD->hasAttr<HLSLVkPushConstantAttr>();
QualType QT = VD->getType();
return VD->getDeclContext()->isTranslationUnit() &&
QT.getAddressSpace() == LangAS::Default &&
VD->getStorageClass() != SC_Static &&
- !VD->hasAttr<HLSLVkConstantIdAttr>() &&
+ !VD->hasAttr<HLSLVkConstantIdAttr>() && !IsVKPushConstant &&
!isInvalidConstantBufferLeafElementType(QT.getTypePtr());
}
@@ -3863,6 +3871,19 @@ void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
return;
}
+ bool IsVulkan = getASTContext().getTargetInfo().getTriple().getOS() ==
+ llvm::Triple::Vulkan;
+ if (IsVulkan && Decl->hasAttr<HLSLVkPushConstantAttr>()) {
+ if (HasDeclaredAPushConstant)
+ SemaRef.Diag(Decl->getLocation(), diag::err_hlsl_push_constant_unique);
+
+ LangAS ImplAS = LangAS::hlsl_push_constant;
+ Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
+ Decl->setType(Type);
+ HasDeclaredAPushConstant = true;
+ return;
+ }
+
if (Type->isSamplerT() || Type->isVoidType())
return;
@@ -3895,7 +3916,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
// Global variables outside a cbuffer block that are not a resource, static,
// groupshared, or an empty array or struct belong to the default constant
// buffer $Globals (to be created at the end of the translation unit).
- if (IsDefaultBufferConstantDecl(VD)) {
+ if (IsDefaultBufferConstantDecl(getASTContext(), VD)) {
// update address space to hlsl_constant
QualType NewTy = getASTContext().getAddrSpaceQualType(
VD->getType(), LangAS::hlsl_constant);
@@ -4196,8 +4217,11 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
bool HasBinding = false;
for (Attr *A : VD->attrs()) {
- if (isa<HLSLVkBindingAttr>(A))
+ if (isa<HLSLVkBindingAttr>(A)) {
HasBinding = true;
+ if (auto PA = VD->getAttr<HLSLVkPushConstantAttr>())
+ Diag(PA->getLoc(), diag::err_hlsl_attr_incompatible) << A << PA;
+ }
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
if (!RBA || !RBA->hasRegisterSlot())
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.bitfield.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.bitfield.hlsl
new file mode 100644
index 0000000000000..412ec4dffc572
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.bitfield.hlsl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S {
+ uint32_t a : 1;
+ uint32_t b : 1;
+};
+// CHECK: %struct.S = type { i8 }
+
+[[vk::push_constant]] S buffer;
+// CHECK: @buffer = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+
+[numthreads(1, 1, 1)]
+void main() {
+ uint32_t v = buffer.b;
+// CHECK: %bf.load = load i8, ptr addrspace(13) @buffer, align 1
+// CHECK: %bf.lshr = lshr i8 %bf.load, 1
+// CHECK: %bf.clear = and i8 %bf.lshr, 1
+// CHECK: %bf.cast = zext i8 %bf.clear to i32
+// CHECK: store i32 %bf.cast
+}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.anon-struct.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.anon-struct.hlsl
new file mode 100644
index 0000000000000..2b2e9d09c7ab0
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.anon-struct.hlsl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+[[vk::push_constant]]
+struct {
+ int a;
+ float b;
+ float3 c;
+}
+PushConstants;
+
+// CHECK: %struct.anon = type <{ i32, float, <3 x float> }>
+// CHECK: @PushConstants = external hidden addrspace(13) externally_initialized global %struct.anon, align 1
+
+[numthreads(1, 1, 1)]
+void main() {
+ float tmp = PushConstants.b;
+}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl
new file mode 100644
index 0000000000000..6b58decfa5188
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify
+
+struct S {
+ float f;
+};
+
+// expected-error at +1 {{'vk::binding' attribute is not compatible with 'vk::push_constant' attribute}}
+[[vk::push_constant, vk::binding(5)]]
+S pcs;
+
+[numthreads(1, 1, 1)]
+void main() {
+}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.layout.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.layout.hlsl
new file mode 100644
index 0000000000000..c671e6effe3e4
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.layout.hlsl
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct T {
+ float2 f1[3];
+ // FIXME(): matrix support.
+ // column_major float3x2 f2[2];
+ // row_major int3x2 f4[2];
+ // row_major float3x2 f3[2];
+};
+// %struct.T = type { [3 x <2 x float>] }
+
+struct S {
+ float f1;
+ float3 f2;
+ T f4;
+ // FIXME(): matrix support.
+ // row_major int2x3 f5;
+ // row_major float2x3 f3;
+};
+// %struct.S = type <{ float, <3 x float>, %struct.T }>
+
+[[vk::push_constant]]
+S pcs;
+// CHECK: @pcs = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+
+[numthreads(1, 1, 1)]
+void main() {
+ float a = pcs.f1;
+// CHECK: %[[#TMP:]] = load float, ptr addrspace(13) @pcs, align 1
+// CHECK: store float %[[#TMP]], ptr %a, align 4
+}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl
new file mode 100644
index 0000000000000..9a2ae1266e69c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-compute -x hlsl -emit-llvm -disable-llvm-passes -o - -hlsl-entry main %s -verify
+
+struct S {
+ float f;
+};
+
+[[vk::push_constant]] S a;
+
+// expected-error at +1 {{cannot have more than one push constant block}}
+[[vk::push_constant]] S b;
+
+[numthreads(1, 1, 1)]
+void main() {}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.static.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.static.hlsl
new file mode 100644
index 0000000000000..ca05fda1d0ee1
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.static.hlsl
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S
+{
+ const static uint a = 1;
+ uint b;
+};
+// CHECK: %struct.S = type { i32 }
+
+[[vk::push_constant]] S s;
+// CHECK: @s = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+
+[numthreads(1,1,1)]
+void main()
+{
+ uint32_t v = s.b;
+ // CHECK: %[[#TMP:]] = load i32, ptr addrspace(13) @s, align 1
+ // CHECK: store i32 %[[#TMP]], ptr %v, align 4
+
+ uint32_t w = S::a;
+ // CHECK: store i32 1, ptr %w, align 4
+
+ uint32_t x = s.a;
+ // CHECK: store i32 1, ptr %x, align 4
+}
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index ab4153a64f028..e39ba6db5ae61 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -89,6 +89,7 @@
// CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function)
// CHECK-NEXT: GNUInline (SubjectMatchRule_function)
// CHECK-NEXT: HIPManaged (SubjectMatchRule_variable)
+// CHECK-NEXT: HLSLVkPushConstant (SubjectMatchRule_variable_is_global)
// CHECK-NEXT: Hot (SubjectMatchRule_function)
// CHECK-NEXT: HybridPatchable (SubjectMatchRule_function)
// CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp
index e17bf60e6a200..cba21b416bb48 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 (8388582)}}
+ __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388581)}}
}
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<0x7FFFE6>();
+ correct<0x7FFFE5>();
tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}}
__attribute__((address_space(1))) char *x;
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 53074ea3b2597..38be5b450f998 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -87,14 +87,15 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
const LLT p10 = LLT::pointer(10, PSize); // Private
const LLT p11 = LLT::pointer(11, PSize); // StorageBuffer
const LLT p12 = LLT::pointer(12, PSize); // Uniform
+ const LLT p13 = LLT::pointer(13, PSize); // PushConstant
// TODO: remove copy-pasting here by using concatenation in some way.
auto allPtrsScalarsAndVectors = {
- p0, p1, p2, p3, p4, p5, p6, p7, p8,
- p10, p11, p12, s1, s8, s16, s32, s64, v2s1,
- v2s8, v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
- v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16, v8s32,
- v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
+ p0, p1, p2, p3, p4, p5, p6, p7, p8,
+ p10, p11, p12, p13, s1, s8, s16, s32, s64,
+ v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32,
+ v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
+ v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
@@ -121,10 +122,10 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
- auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1, p2, p3,
- p4, p5, p6, p7, p8, p10, p11, p12};
+ auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1, p2, p3, p4,
+ p5, p6, p7, p8, p10, p11, p12, p13};
- auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p10, p11, p12};
+ auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p10, p11, p12, p13};
bool IsExtendedInts =
ST.canUseExtension(
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 8f2fc01da476f..8202db2380a68 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -290,6 +290,8 @@ addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
return SPIRV::StorageClass::StorageBuffer;
case 12:
return SPIRV::StorageClass::Uniform;
+ case 13:
+ return SPIRV::StorageClass::PushConstant;
default:
report_fatal_error("Unknown address space");
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 99d9d403ea70c..32e744c18a5f7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -264,6 +264,8 @@ storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
return 11;
case SPIRV::StorageClass::Uniform:
return 12;
+ case SPIRV::StorageClass::PushConstant:
+ return 13;
default:
report_fatal_error("Unable to get address space id");
}
>From a8001b71bab8bd70c7ffe7991a801fb99774d0b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 18 Nov 2025 13:35:24 +0100
Subject: [PATCH 2/5] move tests to Sema
---
.../vk-features => SemaHLSL}/vk.pushconstant.invalid.hlsl | 0
.../vk-features => SemaHLSL}/vk.pushconstant.multiple.hlsl | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename clang/test/{CodeGenHLSL/vk-features => SemaHLSL}/vk.pushconstant.invalid.hlsl (100%)
rename clang/test/{CodeGenHLSL/vk-features => SemaHLSL}/vk.pushconstant.multiple.hlsl (100%)
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl b/clang/test/SemaHLSL/vk.pushconstant.invalid.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/vk-features/vk.pushconstant.invalid.hlsl
rename to clang/test/SemaHLSL/vk.pushconstant.invalid.hlsl
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl b/clang/test/SemaHLSL/vk.pushconstant.multiple.hlsl
similarity index 100%
rename from clang/test/CodeGenHLSL/vk-features/vk.pushconstant.multiple.hlsl
rename to clang/test/SemaHLSL/vk.pushconstant.multiple.hlsl
>From 8d4c31a5befb3d05b8592539851049aafa18b804 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 18 Nov 2025 13:40:09 +0100
Subject: [PATCH 3/5] add AST test
---
clang/test/AST/HLSL/vk.pushconstant.hlsl | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 clang/test/AST/HLSL/vk.pushconstant.hlsl
diff --git a/clang/test/AST/HLSL/vk.pushconstant.hlsl b/clang/test/AST/HLSL/vk.pushconstant.hlsl
new file mode 100644
index 0000000000000..b07eb633f5402
--- /dev/null
+++ b/clang/test/AST/HLSL/vk.pushconstant.hlsl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -ast-dump -o - %s | FileCheck %s
+
+struct S {
+ int value;
+};
+
+[[vk::push_constant]] S PC;
+// CHECK: VarDecl 0x[[A:[0-9a-f]+]] <line:7:23, col:25> col:25 PC 'hlsl_push_constant S'
+// CHECK-NEXT: HLSLVkPushConstantAttr 0x[[A:[0-9a-f]+]] <col:3, col:7>
+
+[numthreads(1, 1, 1)]
+void main() { }
>From cb477ce6d61e014f3d62faf43f1e722f2c4f6826 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 18 Nov 2025 13:46:36 +0100
Subject: [PATCH 4/5] add DXIL & basic access tests
---
.../vk-features/vk.pushconstant.access.hlsl | 16 ++++++++++++++++
.../vk-features/vk.pushconstant.dxil.hlsl | 18 ++++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.hlsl
create mode 100644 clang/test/CodeGenHLSL/vk-features/vk.pushconstant.dxil.hlsl
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.hlsl
new file mode 100644
index 0000000000000..59974b8cdf969
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.access.hlsl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S {
+ uint value;
+};
+// CHECK: %struct.S = type { i32 }
+
+[[vk::push_constant]] S buffer;
+// CHECK: @buffer = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+
+[numthreads(1, 1, 1)]
+void main() {
+ uint32_t v = buffer.value;
+// CHECK: %[[#REG:]] = load i32, ptr addrspace(13) @buffer, align 1
+// CHECK: store i32 %[[#REG]], ptr %v, align 4
+}
diff --git a/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.dxil.hlsl b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.dxil.hlsl
new file mode 100644
index 0000000000000..448af1904890b
--- /dev/null
+++ b/clang/test/CodeGenHLSL/vk-features/vk.pushconstant.dxil.hlsl
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
+
+struct S {
+ uint value;
+};
+// CHECK: %struct.S = type { i32 }
+
+[[vk::push_constant]] S buffer;
+// When targeting DXIL, the attribute is ignored, meaning this variable
+// is part of the implicit cbuffer.
+// CHECK: @buffer = external hidden addrspace(2) global %struct.S, align 1
+
+[numthreads(1, 1, 1)]
+void main() {
+ uint32_t v = buffer.value;
+// CHECK: %[[#REG:]] = load i32, ptr addrspace(2) @buffer, align 1
+// CHECK: store i32 %[[#REG]], ptr %v, align 4
+}
>From 8d82a7f8cda090853d04a97b3fc1c6826e69dde7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 18 Nov 2025 13:51:44 +0100
Subject: [PATCH 5/5] add SPIR-V codegen tests
---
.../CodeGen/SPIRV/vk-pushconstant-access.ll | 32 +++++++++++++++
.../CodeGen/SPIRV/vk-pushconstant-layout.ll | 40 +++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/vk-pushconstant-access.ll
create mode 100644 llvm/test/CodeGen/SPIRV/vk-pushconstant-layout.ll
diff --git a/llvm/test/CodeGen/SPIRV/vk-pushconstant-access.ll b/llvm/test/CodeGen/SPIRV/vk-pushconstant-access.ll
new file mode 100644
index 0000000000000..dca97218792c3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/vk-pushconstant-access.ll
@@ -0,0 +1,32 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
+
+%struct.S = type <{ float }>
+
+; CHECK-DAG: %[[#PTR_PCS:]] = OpTypePointer PushConstant %[[#S_S:]]
+
+; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#UINT:]] = OpTypeInt 32 0
+
+; CHECK-DAG: %[[#S_S]] = OpTypeStruct %[[#F32]]
+
+; CHECK-DAG: OpMemberDecorate %[[#S_S]] 0 Offset 0
+; CHECK-DAG: OpDecorate %[[#S_S]] Block
+
+
+ at pcs = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+; CHECK: %[[#PCS:]] = OpVariable %[[#PTR_PCS]] PushConstant
+
+define void @main() #1 {
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ %1 = alloca float, align 4
+ %2 = load float, ptr addrspace(13) @pcs, align 1
+ store float %2, ptr %1
+ ret void
+}
+
+declare token @llvm.experimental.convergence.entry() #2
+
+attributes #1 = { convergent noinline norecurse optnone "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #2 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
+
diff --git a/llvm/test/CodeGen/SPIRV/vk-pushconstant-layout.ll b/llvm/test/CodeGen/SPIRV/vk-pushconstant-layout.ll
new file mode 100644
index 0000000000000..3c5391b532fd1
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/vk-pushconstant-layout.ll
@@ -0,0 +1,40 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
+; XFAIL: *
+; FIXME(168401): fix the offset of last struct S field.
+
+%struct.T = type { [3 x <2 x float>] }
+%struct.S = type <{ float, <3 x float>, %struct.T }>
+
+; CHECK-DAG: %[[#PTR_PCS:]] = OpTypePointer PushConstant %[[#S_S:]]
+
+; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#V3F32:]] = OpTypeVector %[[#F32]] 3
+; CHECK-DAG: %[[#V2F32:]] = OpTypeVector %[[#F32]] 2
+; CHECK-DAG: %[[#UINT:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#UINT_3:]] = OpConstant %[[#UINT]] 3
+
+; CHECK-DAG: %[[#S_S]] = OpTypeStruct %[[#F32]] %[[#V3F32]] %[[#S_T:]]
+; CHECK-DAG: %[[#S_T]] = OpTypeStruct %[[#ARR:]]
+; CHECK-DAG: %[[#ARR]] = OpTypeArray %[[#V2F32]] %[[#UINT_3]]
+
+; CHECK-DAG: OpMemberDecorate %[[#S_T]] 0 Offset 0
+; CHECK-DAG: OpMemberDecorate %[[#S_S]] 0 Offset 0
+; CHECK-DAG: OpMemberDecorate %[[#S_S]] 1 Offset 4
+; CHECK-DAG: OpMemberDecorate %[[#S_S]] 2 Offset 16
+; CHECK-DAG: OpDecorate %[[#S_S]] Block
+; CHECK-DAG: OpDecorate %[[#ARR]] ArrayStride 8
+
+
+ at pcs = external hidden addrspace(13) externally_initialized global %struct.S, align 1
+; CHECK: %[[#PCS:]] = OpVariable %[[#PTR_PCS]] PushConstant
+
+define void @main() #1 {
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ ret void
+}
+
+declare token @llvm.experimental.convergence.entry() #2
+
+attributes #1 = { convergent noinline norecurse optnone "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #2 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
More information about the llvm-commits
mailing list