Skip to content

[HLSL][SPIR-V] Add hlsl_private address space for SPIR-V #133464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/AddressSpaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum class LangAS : unsigned {
// HLSL specific address spaces.
hlsl_groupshared,
hlsl_constant,
hlsl_private,

// Wasm specific address spaces.
wasm_funcref,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4328,6 +4328,7 @@ class Sema final : public SemaBase {
NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);

void deduceOpenCLAddressSpace(ValueDecl *decl);
void deduceHLSLAddressSpace(VarDecl *decl);

/// Adjust the \c DeclContext for a function or variable that might be a
/// function-local external declaration.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
(A == LangAS::Default &&
(B == LangAS::cuda_constant || B == LangAS::cuda_device ||
B == LangAS::cuda_shared)) ||
// `this` overloading depending on address space is not ready,
// so this is a hack to allow generating addrspacecasts.
// IR legalization will be required when this address space is used.
(A == LangAS::Default && B == LangAS::hlsl_private) ||
// Conversions from target specific address spaces may be legal
// depending on the target information.
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2581,6 +2581,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
return "groupshared";
case LangAS::hlsl_constant:
return "hlsl_constant";
case LangAS::hlsl_private:
return "hlsl_private";
case LangAS::wasm_funcref:
return "__funcref";
default:
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static const LangASMap FakeAddrSpaceMap = {
11, // ptr32_uptr
12, // ptr64
13, // hlsl_groupshared
14, // hlsl_constant
15, // hlsl_private
20, // wasm_funcref
};

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
static_cast<unsigned>(AArch64AddrSpace::ptr64),
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
// FIXME(pr/122103): hlsl_private -> PRIVATE is wrong, but at least this
// will break loudly.
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
};

const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
Expand All @@ -85,6 +88,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
};
} // namespace targets
} // namespace clang
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/DirectX.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const unsigned DirectXAddrSpaceMap[] = {
0, // ptr64
3, // hlsl_groupshared
2, // hlsl_constant
0, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/NVPTX.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static const unsigned NVPTXAddrSpaceMap[] = {
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down
48 changes: 25 additions & 23 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,17 @@ static const unsigned SPIRDefIsPrivMap[] = {
0, // cuda_constant
0, // cuda_shared
// SYCL address space values for this map are dummy
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
2, // hlsl_constant
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
2, // hlsl_constant
10, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand All @@ -70,18 +71,19 @@ static const unsigned SPIRDefIsGenMap[] = {
// cuda_constant pointer can be casted to default/"flat" pointer, but in
// SPIR-V casts between constant and generic pointers are not allowed. For
// this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.
1, // cuda_constant
3, // cuda_shared
1, // sycl_global
5, // sycl_global_device
6, // sycl_global_host
3, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
1, // cuda_constant
3, // cuda_shared
1, // sycl_global
5, // sycl_global_device
6, // sycl_global_host
3, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
10, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down Expand Up @@ -315,7 +317,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
// SPIR-V IDs are represented with a single 32-bit word.
SizeType = TargetInfo::UnsignedInt;
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"
"v256:256-v512:512-v1024:1024-n8:16:32:64-G1");
"v256:256-v512:512-v1024:1024-n8:16:32:64-G10");
}

llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const unsigned ZOSAddressMap[] = {
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
0 // wasm_funcref
};

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/TCE.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
20, // wasm_funcref
};

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static const unsigned X86AddrSpaceMap[] = {
272, // ptr64
0, // hlsl_groupshared
0, // hlsl_constant
0, // hlsl_private
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,8 +1157,22 @@ void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
CGM.getCXXABI().useSinitAndSterm() &&
"Arg could not be nullptr unless using sinit and sterm functions.");
CI = Builder.CreateCall(CalleeTy, Callee);
} else
} else {
// If the object lives in a different address space, the `this` pointer
// address space won't match the dtor `this` param. An addrspacecast is
// required.
assert(Arg->getType()->isPointerTy());
assert(CalleeTy->getParamType(0)->isPointerTy());
unsigned ActualAddrSpace = Arg->getType()->getPointerAddressSpace();
unsigned ExpectedAddrSpace =
CalleeTy->getParamType(0)->getPointerAddressSpace();
if (ActualAddrSpace != ExpectedAddrSpace) {
llvm::PointerType *PTy =
llvm::PointerType::get(getLLVMContext(), ExpectedAddrSpace);
Arg = llvm::ConstantExpr::getAddrSpaceCast(Arg, PTy);
}
CI = Builder.CreateCall(CalleeTy, Callee, Arg);
}

// Make sure the call and the callee agree on calling convention.
if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,12 +371,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(DeferredDeactivationCleanupStack.empty() &&
"mismatched activate/deactivate of cleanups!");

if (CGM.shouldEmitConvergenceTokens()) {
ConvergenceTokenStack.pop_back();
assert(ConvergenceTokenStack.empty() &&
"mismatched push/pop in convergence stack!");
}

bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
&& NumSimpleReturnExprs == NumReturnExprs
&& ReturnBlock.getBlock()->use_empty();
Expand Down Expand Up @@ -564,6 +558,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
ReturnValue = Address::invalid();
}
}

if (CGM.shouldEmitConvergenceTokens()) {
ConvergenceTokenStack.pop_back();
assert(ConvergenceTokenStack.empty() &&
"mismatched push/pop in convergence stack!");
}
}

/// ShouldInstrumentFunction - Return true if the current function should be
Expand Down
44 changes: 43 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6888,6 +6888,42 @@ static void SetNestedNameSpecifier(Sema &S, DeclaratorDecl *DD, Declarator &D) {
DD->setQualifierInfo(SS.getWithLocInContext(S.Context));
}

void Sema::deduceHLSLAddressSpace(VarDecl *Decl) {
// The variable already has an address space (groupshared for ex).
if (Decl->getType().hasAddressSpace())
return;

if (Decl->getType()->isDependentType())
return;

QualType Type = Decl->getType();
if (Type->isSamplerT() || Type->isVoidType())
return;

// Template instantiations can lack definition. In such case,
// we cannot deduce the AS.
// FIXME: figure out why RWBuffer<float> yields such declaration.
if (const RecordType *RT =
dyn_cast<RecordType>(Type->getUnqualifiedDesugaredType())) {
CXXRecordDecl *RD = Type->getAsCXXRecordDecl();
if (RD && !RD->isCompleteDefinition())
return;
}

// Resource handles.
if (Type->isHLSLIntangibleType())
return;

// Only static globals belong to the Private address space.
// Non-static globals belongs to the cbuffer.
if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
return;

LangAS ImplAS = LangAS::hlsl_private;
Type = Context.getAddrSpaceQualType(Type, ImplAS);
Decl->setType(Type);
}

void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) {
if (Decl->getType().hasAddressSpace())
return;
Expand Down Expand Up @@ -7975,8 +8011,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);

if (getLangOpts().HLSL)
if (getLangOpts().HLSL) {
HLSL().ActOnVariableDeclarator(NewVD);
deduceHLSLAddressSpace(NewVD);
}

if (getLangOpts().OpenACC)
OpenACC().ActOnVariableDeclarator(NewVD);

Expand Down Expand Up @@ -13131,6 +13170,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
if (getLangOpts().OpenCL)
deduceOpenCLAddressSpace(VDecl);

if (getLangOpts().HLSL)
deduceHLSLAddressSpace(VDecl);

// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/HLSL/cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblay
cbuffer CB {
// CHECK: FunctionDecl {{.*}} f 'void ()'
void f() {}
// CHECK: VarDecl {{.*}} SV 'float' static
// CHECK: VarDecl {{.*}} SV 'hlsl_private float' static
static float SV;
// CHECK: VarDecl {{.*}} s7 'EmptyStruct' callinit
EmptyStruct s7;
Expand Down
34 changes: 34 additions & 0 deletions clang/test/AST/HLSL/private.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | FileCheck %s

// CHECK: VarDecl {{.*}} global_scalar 'hlsl_private int' static cinit
static int global_scalar = 0;

// CHECK: VarDecl {{.*}} global_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit
RWBuffer<float> global_buffer;

class A {
// CHECK: VarDecl {{.*}} a 'hlsl_private int' static
static int a;
};

class B {
// CHECK: VarDecl {{.*}} b 'hlsl_private int' static
static int b;
};

// CHECK: VarDecl {{.*}} b 'hlsl_private int' cinit
int B::b = 0;

export void foo() {
// CHECK: VarDecl {{.*}} local_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' cinit
RWBuffer<float> local_buffer = global_buffer;

// CHECK: VarDecl {{.*}} static_local_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' static cinit
static RWBuffer<float> static_local_buffer = global_buffer;

// CHECK: VarDecl {{.*}} local_scalar 'int' cinit
int local_scalar = global_scalar;

// CHECK: VarDecl {{.*}} static_scalar 'hlsl_private int' static cinit
static int static_scalar = 0;
}
15 changes: 11 additions & 4 deletions clang/test/CodeGenHLSL/GlobalConstructors.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,DXIL

RWBuffer<float> Buffer;

Expand All @@ -10,7 +11,13 @@ void main(unsigned GI : SV_GroupIndex) {}
// CHECK-NOT:@llvm.global_dtors
//CHECK: define void @main()
//CHECK-NEXT: entry:
//CHECK-NEXT: call void @_GLOBAL__sub_I_GlobalConstructors.hlsl()
//CHECK-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
//CHECK-NEXT: call void @_Z4mainj(i32 %0)

//SPIRV-NEXT: %0 = call token @llvm.experimental.convergence.entry()
//SPIRV-NEXT: call spir_func void @_GLOBAL__sub_I_GlobalConstructors.hlsl() [ "convergencectrl"(token %0) ]
//SPIRV-NEXT: %1 = call i32 @llvm.spv.flattened.thread.id.in.group()
//SPIRV-NEXT: call spir_func void @_Z4mainj(i32 %1) [ "convergencectrl"(token %0) ]

//DXIL-NEXT: call void @_GLOBAL__sub_I_GlobalConstructors.hlsl()
//DXIL-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
//DXIL-NEXT: call void @_Z4mainj(i32 %0)
//CHECK-NEXT: ret void
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ cbuffer B {

// CHECK: define {{.*}} float @_Z3foov() #0 {
// CHECK: load float, ptr addrspace(2) @a, align 4
// CHECK: load float, ptr @_ZL1b, align 4

extern float bar() {
return foo();
Expand Down
Loading
Loading