Skip to content

Commit 3fc3e29

Browse files
committed
[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 (See #168401). The layout issue being not only push-constant related, it's ignored for this PR. The frontend part of the implementation is straightforward: - adding a new attribute - when targeting vulkan/spirv, we process it - global variables with this attribute gets a new AS: hlsl_push_constant The IR has nothing specific, only some RO globals in this new AS. On the SPIR-V side, we not convert this AS into a PushConstant storage class. But this creates some issues: the variables in this storage class must have a specific set of decoration to define their layout. Current infra to create the SPIR-V types lacks the context required to make this decision: no indication on the AS or context around the type being created. Refactoring this would be a heavy task as it would require getting this information in every place using the GR for type creation. Instead, we do something similar to CBuffers: - find all globals with this address space, and change their type to a target-specific type. - insert a new intrinsic in place of every reference to this global variable. This allow the backend to handle both layout variables loads and type lowering independently. Type lowering has nothing specific: when we encounter a target extension type with spirv.PushConstant, we lower this to the correct SPIR-V type with the proper offset & block decorations. As for the intrinsic, it's mostly a no-op, but required since we have this target-specific type. Note: this implementation prevents the static declaration of multiple push constants in a single shader module. The actual specification is more relaxed: there can be only one **used** push constant block per entrypoint. To correctly implement this, we'd require to keep some additional state to determine the list of statically used resources per entrypoint. This shall be addressed as a follow-up (see #170310)
1 parent 87f4e80 commit 3fc3e29

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+559
-24
lines changed

clang/include/clang/Basic/AddressSpaces.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum class LangAS : unsigned {
6262
hlsl_private,
6363
hlsl_device,
6464
hlsl_input,
65+
hlsl_push_constant,
6566

6667
// Wasm specific address spaces.
6768
wasm_funcref,

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5164,6 +5164,14 @@ def HLSLVkExtBuiltinInput : InheritableAttr {
51645164
let Documentation = [HLSLVkExtBuiltinInputDocs];
51655165
}
51665166

5167+
def HLSLVkPushConstant : InheritableAttr {
5168+
let Spellings = [CXX11<"vk", "push_constant">];
5169+
let Args = [];
5170+
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
5171+
let LangOpts = [HLSL];
5172+
let Documentation = [HLSLVkPushConstantDocs];
5173+
}
5174+
51675175
def HLSLVkConstantId : InheritableAttr {
51685176
let Spellings = [CXX11<"vk", "constant_id">];
51695177
let Args = [IntArgument<"Id">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8794,6 +8794,22 @@ https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
87948794
}];
87958795
}
87968796

8797+
def HLSLVkPushConstantDocs : Documentation {
8798+
let Category = DocCatVariable;
8799+
let Content = [{
8800+
Vulkan shaders have `PushConstants`
8801+
8802+
The ``[[vk::push_constant]]`` attribute allows you to declare this
8803+
global variable as a push constant when targeting Vulkan.
8804+
This attribute is ignored otherwise.
8805+
8806+
This attribute must be applied to the variable, not underlying type.
8807+
The variable type must be a struct, per the requirements of Vulkan, "there
8808+
must be no more than one push constant block statically used per shader entry
8809+
point."
8810+
}];
8811+
}
8812+
87978813
def AnnotateTypeDocs : Documentation {
87988814
let Category = DocCatType;
87998815
let Heading = "annotate_type";

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13216,6 +13216,9 @@ def err_hlsl_attr_invalid_type : Error<
1321613216
"attribute %0 only applies to a field or parameter of type '%1'">;
1321713217
def err_hlsl_attr_invalid_ast_node : Error<
1321813218
"attribute %0 only applies to %1">;
13219+
def err_hlsl_attr_incompatible
13220+
: Error<"%0 attribute is not compatible with %1 attribute">;
13221+
1321913222
def err_hlsl_entry_shader_attr_mismatch : Error<
1322013223
"%0 attribute on entry function does not match the target profile">;
1322113224
def err_hlsl_numthreads_argument_oor : Error<"argument '%select{X|Y|Z}0' to numthreads attribute cannot exceed %1">;
@@ -13333,6 +13336,9 @@ def err_hlsl_incomplete_resource_array_in_function_param: Error<
1333313336
def err_hlsl_assign_to_global_resource: Error<
1333413337
"assignment to global resource variable %0 is not allowed">;
1333513338

13339+
def err_hlsl_push_constant_unique
13340+
: Error<"cannot have more than one push constant block">;
13341+
1333613342
// Layout randomization diagnostics.
1333713343
def err_non_designated_init_used : Error<
1333813344
"a randomized struct can only be initialized with a designated initializer">;

clang/include/clang/Basic/HLSLRuntime.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef CLANG_BASIC_HLSLRUNTIME_H
1515
#define CLANG_BASIC_HLSLRUNTIME_H
1616

17+
#include "clang/Basic/AddressSpaces.h"
1718
#include "clang/Basic/LangOptions.h"
1819
#include <cstdint>
1920

@@ -30,6 +31,10 @@ getStageFromEnvironment(const llvm::Triple::EnvironmentType &E) {
3031
return static_cast<ShaderStage>(Pipeline);
3132
}
3233

34+
constexpr bool isInitializedByPipeline(LangAS AS) {
35+
return AS == LangAS::hlsl_input || AS == LangAS::hlsl_push_constant;
36+
}
37+
3338
#define ENUM_COMPARE_ASSERT(Value) \
3439
static_assert( \
3540
getStageFromEnvironment(llvm::Triple::Value) == ShaderStage::Value, \

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class SemaHLSL : public SemaBase {
188188
void handleSemanticAttr(Decl *D, const ParsedAttr &AL);
189189

190190
void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
191+
void handleVkPushConstantAttr(Decl *D, const ParsedAttr &AL);
191192

192193
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
193194
QualType ProcessResourceTypeAttributes(QualType Wrapped);
@@ -237,6 +238,8 @@ class SemaHLSL : public SemaBase {
237238

238239
IdentifierInfo *RootSigOverrideIdent = nullptr;
239240

241+
bool HasDeclaredAPushConstant = false;
242+
240243
// Information about the current subtree being flattened.
241244
struct SemanticInfo {
242245
HLSLParsedSemanticAttr *Semantic;

clang/lib/AST/Type.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
101101
(A == LangAS::Default && B == LangAS::hlsl_private) ||
102102
(A == LangAS::Default && B == LangAS::hlsl_device) ||
103103
(A == LangAS::Default && B == LangAS::hlsl_input) ||
104+
(A == LangAS::Default && B == LangAS::hlsl_push_constant) ||
104105
// Conversions from target specific address spaces may be legal
105106
// depending on the target information.
106107
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);

clang/lib/AST/TypePrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2694,6 +2694,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
26942694
return "hlsl_device";
26952695
case LangAS::hlsl_input:
26962696
return "hlsl_input";
2697+
case LangAS::hlsl_push_constant:
2698+
return "hlsl_push_constant";
26972699
case LangAS::wasm_funcref:
26982700
return "__funcref";
26992701
default:

clang/lib/Basic/TargetInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static const LangASMap FakeAddrSpaceMap = {
5252
15, // hlsl_private
5353
16, // hlsl_device
5454
17, // hlsl_input
55+
18, // hlsl_push_constant
5556
20, // wasm_funcref
5657
};
5758

clang/lib/Basic/Targets/AArch64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
4848
0, // hlsl_private
4949
0, // hlsl_device
5050
0, // hlsl_input
51+
0, // hlsl_push_constant
5152
// Wasm address space values for this target are dummy values,
5253
// as it is only enabled for Wasm targets.
5354
20, // wasm_funcref

0 commit comments

Comments
 (0)