https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/141759
From 085154ddedf3b0789a3908231d04f997e9e66ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brio...@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?= <brio...@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?= <brio...@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 +@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?= <brio...@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?= <brio...@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?= <brio...@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 -@var = local_unnamed_addr addrspace(7) externally_initialized constant <3 x i32> undef, align 16, !spirv.Decorations !0 +@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?= <brio...@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@+1 {{'ext_builtin_input' attribute only applies to static const globals}} +[[vk::ext_builtin_input(/* WorkgroupId */ 26)]] +const uint3 groupid1; + +// expected-error@+1 {{'ext_builtin_input' attribute only applies to static const globals}} +[[vk::ext_builtin_input(/* WorkgroupId */ 26)]] +static uint3 groupid2; + +// expected-error@+1 {{'ext_builtin_input' attribute takes one argument}} +[[vk::ext_builtin_input()]] +// expected-error@+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@+1 {{'ext_builtin_input' attribute requires an integer constant}} +[[vk::ext_builtin_input(0.4f)]] +// expected-error@+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@+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 05cd38a877c7ad09ef5e0c98e2f19a712e26cf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brio...@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/Basic/AttrDocs.td | 14 +++++++ 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 + 13 files changed, 111 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..edbdf187af93d 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_PositionDocs]; +} + def HLSLPackOffset: HLSLAnnotationAttr { let Spellings = [HLSLAnnotation<"packoffset">]; let LangOpts = [HLSL]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 039a1808ffe40..d09500fe369c4 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8461,6 +8461,20 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo }]; } +def HLSLSV_PositionDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``SV_Position`` semantic, when applied to an input parameter in a pixel +shader, contains the location of the pixel center (x, y) in screen space. +This semantic can be applied to the parameter, or a field in a struct used +as input parameter. +This attribute is supported as input in pixel, hull, domain and mesh shaders. +This attribute is supported as output in vertex, geometry and domain shaders. + +The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics + }]; +} + def HLSLGroupSharedAddressSpaceDocs : Documentation { let Category = DocCatVariable; let Content = [{ 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@+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]>; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits