Skip to content

Commit a625bc6

Browse files
authored
[HLSL][SPIR-V] Add hlsl_private address space for SPIR-V (#133464)
This is an alternative to #122103 In SPIR-V, private global variables have the Private storage class. This PR adds a new address space which allows frontend to emit variable with this storage class when targeting this backend. This is covered in this proposal: llvm/wg-hlsl@4c9e11a This PR will cause addrspacecast to show up in several cases, like class member functions or assignment. Those will have to be handled in the backend later on, particularly to fixup pointer storage classes in some functions. Before this change, global variable were emitted with the 'Function' storage class, which was wrong.
1 parent 344a491 commit a625bc6

26 files changed

+186
-28
lines changed

clang/include/clang/Basic/AddressSpaces.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ enum class LangAS : unsigned {
5959
// HLSL specific address spaces.
6060
hlsl_groupshared,
6161
hlsl_constant,
62+
hlsl_private,
6263

6364
// Wasm specific address spaces.
6465
wasm_funcref,

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,6 +4328,7 @@ class Sema final : public SemaBase {
43284328
NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);
43294329

43304330
void deduceOpenCLAddressSpace(ValueDecl *decl);
4331+
void deduceHLSLAddressSpace(VarDecl *decl);
43314332

43324333
/// Adjust the \c DeclContext for a function or variable that might be a
43334334
/// function-local external declaration.

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class SemaHLSL : public SemaBase {
154154
bool TransformInitList(const InitializedEntity &Entity,
155155
const InitializationKind &Kind, InitListExpr *Init);
156156

157+
void deduceAddressSpace(VarDecl *Decl);
158+
157159
private:
158160
// HLSL resource type attributes need to be processed all at once.
159161
// This is a list to collect them.

clang/lib/AST/Type.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
9494
(A == LangAS::Default &&
9595
(B == LangAS::cuda_constant || B == LangAS::cuda_device ||
9696
B == LangAS::cuda_shared)) ||
97+
// `this` overloading depending on address space is not ready,
98+
// so this is a hack to allow generating addrspacecasts.
99+
// IR legalization will be required when this address space is used.
100+
(A == LangAS::Default && B == LangAS::hlsl_private) ||
97101
// Conversions from target specific address spaces may be legal
98102
// depending on the target information.
99103
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);

clang/lib/AST/TypePrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,6 +2581,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
25812581
return "groupshared";
25822582
case LangAS::hlsl_constant:
25832583
return "hlsl_constant";
2584+
case LangAS::hlsl_private:
2585+
return "hlsl_private";
25842586
case LangAS::wasm_funcref:
25852587
return "__funcref";
25862588
default:

clang/lib/Basic/TargetInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ static const LangASMap FakeAddrSpaceMap = {
4747
11, // ptr32_uptr
4848
12, // ptr64
4949
13, // hlsl_groupshared
50+
14, // hlsl_constant
51+
15, // hlsl_private
5052
20, // wasm_funcref
5153
};
5254

clang/lib/Basic/Targets/AArch64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static const unsigned ARM64AddrSpaceMap[] = {
4545
static_cast<unsigned>(AArch64AddrSpace::ptr64),
4646
0, // hlsl_groupshared
4747
0, // hlsl_constant
48+
0, // hlsl_private
4849
// Wasm address space values for this target are dummy values,
4950
// as it is only enabled for Wasm targets.
5051
20, // wasm_funcref

clang/lib/Basic/Targets/AMDGPU.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
6060
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
6161
llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
6262
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
63+
// FIXME(pr/122103): hlsl_private -> PRIVATE is wrong, but at least this
64+
// will break loudly.
65+
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
6366
};
6467

6568
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -85,6 +88,7 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
8588
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
8689
llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
8790
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
91+
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
8892
};
8993
} // namespace targets
9094
} // namespace clang

clang/lib/Basic/Targets/DirectX.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static const unsigned DirectXAddrSpaceMap[] = {
4343
0, // ptr64
4444
3, // hlsl_groupshared
4545
2, // hlsl_constant
46+
0, // hlsl_private
4647
// Wasm address space values for this target are dummy values,
4748
// as it is only enabled for Wasm targets.
4849
20, // wasm_funcref

clang/lib/Basic/Targets/NVPTX.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static const unsigned NVPTXAddrSpaceMap[] = {
4747
0, // ptr64
4848
0, // hlsl_groupshared
4949
0, // hlsl_constant
50+
0, // hlsl_private
5051
// Wasm address space values for this target are dummy values,
5152
// as it is only enabled for Wasm targets.
5253
20, // wasm_funcref

clang/lib/Basic/Targets/SPIR.h

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ static const unsigned SPIRDefIsPrivMap[] = {
3838
0, // cuda_constant
3939
0, // cuda_shared
4040
// SYCL address space values for this map are dummy
41-
0, // sycl_global
42-
0, // sycl_global_device
43-
0, // sycl_global_host
44-
0, // sycl_local
45-
0, // sycl_private
46-
0, // ptr32_sptr
47-
0, // ptr32_uptr
48-
0, // ptr64
49-
0, // hlsl_groupshared
50-
2, // hlsl_constant
41+
0, // sycl_global
42+
0, // sycl_global_device
43+
0, // sycl_global_host
44+
0, // sycl_local
45+
0, // sycl_private
46+
0, // ptr32_sptr
47+
0, // ptr32_uptr
48+
0, // ptr64
49+
0, // hlsl_groupshared
50+
2, // hlsl_constant
51+
10, // hlsl_private
5152
// Wasm address space values for this target are dummy values,
5253
// as it is only enabled for Wasm targets.
5354
20, // wasm_funcref
@@ -70,18 +71,19 @@ static const unsigned SPIRDefIsGenMap[] = {
7071
// cuda_constant pointer can be casted to default/"flat" pointer, but in
7172
// SPIR-V casts between constant and generic pointers are not allowed. For
7273
// this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.
73-
1, // cuda_constant
74-
3, // cuda_shared
75-
1, // sycl_global
76-
5, // sycl_global_device
77-
6, // sycl_global_host
78-
3, // sycl_local
79-
0, // sycl_private
80-
0, // ptr32_sptr
81-
0, // ptr32_uptr
82-
0, // ptr64
83-
0, // hlsl_groupshared
84-
0, // hlsl_constant
74+
1, // cuda_constant
75+
3, // cuda_shared
76+
1, // sycl_global
77+
5, // sycl_global_device
78+
6, // sycl_global_host
79+
3, // sycl_local
80+
0, // sycl_private
81+
0, // ptr32_sptr
82+
0, // ptr32_uptr
83+
0, // ptr64
84+
0, // hlsl_groupshared
85+
0, // hlsl_constant
86+
10, // hlsl_private
8587
// Wasm address space values for this target are dummy values,
8688
// as it is only enabled for Wasm targets.
8789
20, // wasm_funcref
@@ -315,7 +317,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo {
315317
// SPIR-V IDs are represented with a single 32-bit word.
316318
SizeType = TargetInfo::UnsignedInt;
317319
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-"
318-
"v256:256-v512:512-v1024:1024-n8:16:32:64-G1");
320+
"v256:256-v512:512-v1024:1024-n8:16:32:64-G10");
319321
}
320322

321323
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;

clang/lib/Basic/Targets/SystemZ.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static const unsigned ZOSAddressMap[] = {
4343
0, // ptr64
4444
0, // hlsl_groupshared
4545
0, // hlsl_constant
46+
0, // hlsl_private
4647
0 // wasm_funcref
4748
};
4849

clang/lib/Basic/Targets/TCE.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
5252
0, // ptr64
5353
0, // hlsl_groupshared
5454
0, // hlsl_constant
55+
0, // hlsl_private
5556
// Wasm address space values for this target are dummy values,
5657
// as it is only enabled for Wasm targets.
5758
20, // wasm_funcref

clang/lib/Basic/Targets/WebAssembly.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static const unsigned WebAssemblyAddrSpaceMap[] = {
4343
0, // ptr64
4444
0, // hlsl_groupshared
4545
0, // hlsl_constant
46+
0, // hlsl_private
4647
20, // wasm_funcref
4748
};
4849

clang/lib/Basic/Targets/X86.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static const unsigned X86AddrSpaceMap[] = {
4747
272, // ptr64
4848
0, // hlsl_groupshared
4949
0, // hlsl_constant
50+
0, // hlsl_private
5051
// Wasm address space values for this target are dummy values,
5152
// as it is only enabled for Wasm targets.
5253
20, // wasm_funcref

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,8 +1157,22 @@ void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
11571157
CGM.getCXXABI().useSinitAndSterm() &&
11581158
"Arg could not be nullptr unless using sinit and sterm functions.");
11591159
CI = Builder.CreateCall(CalleeTy, Callee);
1160-
} else
1160+
} else {
1161+
// If the object lives in a different address space, the `this` pointer
1162+
// address space won't match the dtor `this` param. An addrspacecast is
1163+
// required.
1164+
assert(Arg->getType()->isPointerTy());
1165+
assert(CalleeTy->getParamType(0)->isPointerTy());
1166+
unsigned ActualAddrSpace = Arg->getType()->getPointerAddressSpace();
1167+
unsigned ExpectedAddrSpace =
1168+
CalleeTy->getParamType(0)->getPointerAddressSpace();
1169+
if (ActualAddrSpace != ExpectedAddrSpace) {
1170+
llvm::PointerType *PTy =
1171+
llvm::PointerType::get(getLLVMContext(), ExpectedAddrSpace);
1172+
Arg = llvm::ConstantExpr::getAddrSpaceCast(Arg, PTy);
1173+
}
11611174
CI = Builder.CreateCall(CalleeTy, Callee, Arg);
1175+
}
11621176

11631177
// Make sure the call and the callee agree on calling convention.
11641178
if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7977,6 +7977,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
79777977

79787978
if (getLangOpts().HLSL)
79797979
HLSL().ActOnVariableDeclarator(NewVD);
7980+
79807981
if (getLangOpts().OpenACC)
79817982
OpenACC().ActOnVariableDeclarator(NewVD);
79827983

@@ -13131,6 +13132,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
1313113132
if (getLangOpts().OpenCL)
1313213133
deduceOpenCLAddressSpace(VDecl);
1313313134

13135+
if (getLangOpts().HLSL)
13136+
HLSL().deduceAddressSpace(VDecl);
13137+
1313413138
// If this is a redeclaration, check that the type we just deduced matches
1313513139
// the previously declared type.
1313613140
if (VarDecl *Old = VDecl->getPreviousDecl()) {

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3138,6 +3138,32 @@ static bool IsDefaultBufferConstantDecl(VarDecl *VD) {
31383138
!isInvalidConstantBufferLeafElementType(QT.getTypePtr());
31393139
}
31403140

3141+
void SemaHLSL::deduceAddressSpace(VarDecl *Decl) {
3142+
// The variable already has an address space (groupshared for ex).
3143+
if (Decl->getType().hasAddressSpace())
3144+
return;
3145+
3146+
if (Decl->getType()->isDependentType())
3147+
return;
3148+
3149+
QualType Type = Decl->getType();
3150+
if (Type->isSamplerT() || Type->isVoidType())
3151+
return;
3152+
3153+
// Resource handles.
3154+
if (isResourceRecordTypeOrArrayOf(Type->getUnqualifiedDesugaredType()))
3155+
return;
3156+
3157+
// Only static globals belong to the Private address space.
3158+
// Non-static globals belongs to the cbuffer.
3159+
if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
3160+
return;
3161+
3162+
LangAS ImplAS = LangAS::hlsl_private;
3163+
Type = SemaRef.getASTContext().getAddrSpaceQualType(Type, ImplAS);
3164+
Decl->setType(Type);
3165+
}
3166+
31413167
void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
31423168
if (VD->hasGlobalStorage()) {
31433169
// make sure the declaration has a complete type
@@ -3146,6 +3172,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
31463172
SemaRef.getASTContext().getBaseElementType(VD->getType()),
31473173
diag::err_typecheck_decl_incomplete_type)) {
31483174
VD->setInvalidDecl();
3175+
deduceAddressSpace(VD);
31493176
return;
31503177
}
31513178

@@ -3177,6 +3204,8 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
31773204
// process explicit bindings
31783205
processExplicitBindingsOnDecl(VD);
31793206
}
3207+
3208+
deduceAddressSpace(VD);
31803209
}
31813210

31823211
// Walks though the global variable declaration, collects all resource binding

clang/test/AST/HLSL/cbuffer.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ _Static_assert(__builtin_hlsl_is_scalarized_layout_compatible(TwoFloats, __cblay
149149
cbuffer CB {
150150
// CHECK: FunctionDecl {{.*}} f 'void ()'
151151
void f() {}
152-
// CHECK: VarDecl {{.*}} SV 'float' static
152+
// CHECK: VarDecl {{.*}} SV 'hlsl_private float' static
153153
static float SV;
154154
// CHECK: VarDecl {{.*}} s7 'EmptyStruct' callinit
155155
EmptyStruct s7;

clang/test/AST/HLSL/private.hlsl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | FileCheck %s
2+
3+
// CHECK: VarDecl {{.*}} global_scalar 'hlsl_private int' static cinit
4+
static int global_scalar = 0;
5+
6+
// CHECK: VarDecl {{.*}} global_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit
7+
RWBuffer<float> global_buffer;
8+
9+
class A {
10+
// CHECK: VarDecl {{.*}} a 'hlsl_private int' static
11+
static int a;
12+
};
13+
14+
class B {
15+
// CHECK: VarDecl {{.*}} b 'hlsl_private int' static
16+
static int b;
17+
};
18+
19+
// CHECK: VarDecl {{.*}} b 'hlsl_private int' cinit
20+
int B::b = 0;
21+
22+
export void foo() {
23+
// CHECK: VarDecl {{.*}} local_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' cinit
24+
RWBuffer<float> local_buffer = global_buffer;
25+
26+
// CHECK: VarDecl {{.*}} static_local_buffer 'RWBuffer<float>':'hlsl::RWBuffer<float>' static cinit
27+
static RWBuffer<float> static_local_buffer = global_buffer;
28+
29+
// CHECK: VarDecl {{.*}} local_scalar 'int' cinit
30+
int local_scalar = global_scalar;
31+
32+
// CHECK: VarDecl {{.*}} static_scalar 'hlsl_private int' static cinit
33+
static int static_scalar = 0;
34+
}

clang/test/CodeGenHLSL/GlobalDestructors.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void main(unsigned GI : SV_GroupIndex) {
8787
// NOINLINE-SPIRV: define internal spir_func void @_GLOBAL__D_a() [[IntAttr:\#[0-9]+]]
8888
// NOINLINE-SPIRV-NEXT: entry:
8989
// NOINLINE-SPIRV-NEXT: %0 = call token @llvm.experimental.convergence.entry()
90-
// NOINLINE-SPIRV-NEXT: call spir_func void @_ZN4TailD1Ev(ptr @_ZZ3WagvE1T) [ "convergencectrl"(token %0) ]
90+
// NOINLINE-SPIRV-NEXT: call spir_func void @_ZN4TailD1Ev(ptr addrspacecast (ptr addrspace(10) @_ZZ3WagvE1T to ptr)) [ "convergencectrl"(token %0) ]
9191
// NOINLINE-SPIRV-NEXT: call spir_func void @_ZN6PupperD1Ev(ptr @GlobalPup) [ "convergencectrl"(token %0) ]
9292
// NOINLINE-SPIRV-NEXT: ret void
9393

clang/test/CodeGenHLSL/cbuffer_with_static_global_and_function.hlsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ cbuffer B {
2020

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

2425
extern float bar() {
2526
return foo();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -o - -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,DXIL
2+
// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-compute -std=hlsl202x -emit-llvm -o - -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,SPIRV
3+
4+
struct S {
5+
static int Value;
6+
};
7+
8+
int S::Value = 1;
9+
// DXIL: @_ZN1S5ValueE = global i32 1, align 4
10+
// SPIRV: @_ZN1S5ValueE = addrspace(10) global i32 1, align 4
11+
12+
[shader("compute")]
13+
[numthreads(1,1,1)]
14+
void main() {
15+
S s;
16+
int value1, value2;
17+
// CHECK: %s = alloca %struct.S, align 1
18+
// CHECK: %value1 = alloca i32, align 4
19+
// CHECK: %value2 = alloca i32, align 4
20+
21+
// DXIL: [[tmp:%.*]] = load i32, ptr @_ZN1S5ValueE, align 4
22+
// SPIRV: [[tmp:%.*]] = load i32, ptr addrspace(10) @_ZN1S5ValueE, align 4
23+
// CHECK: store i32 [[tmp]], ptr %value1, align 4
24+
value1 = S::Value;
25+
26+
// DXIL: [[tmp:%.*]] = load i32, ptr @_ZN1S5ValueE, align 4
27+
// SPIRV: [[tmp:%.*]] = load i32, ptr addrspace(10) @_ZN1S5ValueE, align 4
28+
// CHECK: store i32 [[tmp]], ptr %value2, align 4
29+
value2 = s.Value;
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
2+
// RUN: spirv-unknown-vulkan1.3-library %s \
3+
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=SPIRV
4+
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
5+
// RUN: dxil-pc-shadermodel6.3-library %s \
6+
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefix=DXIL
7+
8+
// DXIL: @_ZL1g = internal global float 0.000000e+00, align 4
9+
// SPIRV: @_ZL1g = internal addrspace(10) global float 0.000000e+00, align 4
10+
11+
static float g = 0;
12+
13+
[numthreads(8,8,1)]
14+
void main() {
15+
// DXIL: {{.*}} = load float, ptr @_ZL1g, align 4
16+
// SPIRV: {{.*}} = load float, ptr addrspace(10) @_ZL1g, align 4
17+
float l = g;
18+
}

0 commit comments

Comments
 (0)