Skip to content

Commit c3f3d51

Browse files
committed
[SPIR-V] Add hlsl_private address space for SPIR-V
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 8fdfe3f commit c3f3d51

24 files changed

+169
-37
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
@@ -4321,6 +4321,7 @@ class Sema final : public SemaBase {
43214321
NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name);
43224322

43234323
void deduceOpenCLAddressSpace(ValueDecl *decl);
4324+
void deduceHLSLAddressSpace(VarDecl *decl);
43244325

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

clang/lib/AST/Type.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ 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+
// Default is a superset of HLSL private.
98+
(A == LangAS::Default && B == LangAS::hlsl_private) ||
9799
// Conversions from target specific address spaces may be legal
98100
// depending on the target information.
99101
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);
@@ -5150,6 +5152,9 @@ bool Type::isHLSLIntangibleType() const {
51505152
CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
51515153
assert(RD != nullptr &&
51525154
"all HLSL structs and classes should be CXXRecordDecl");
5155+
5156+
if (!RD->isCompleteDefinition())
5157+
return false;
51535158
assert(RD->isCompleteDefinition() && "expecting complete type");
51545159
return RD->isHLSLIntangible();
51555160
}

clang/lib/AST/TypePrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
25792579
return "groupshared";
25802580
case LangAS::hlsl_constant:
25812581
return "hlsl_constant";
2582+
case LangAS::hlsl_private:
2583+
return "hlsl_private";
25822584
case LangAS::wasm_funcref:
25832585
return "__funcref";
25842586
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
@@ -1158,8 +1158,22 @@ void CodeGenFunction::GenerateCXXGlobalCleanUpFunc(
11581158
CGM.getCXXABI().useSinitAndSterm() &&
11591159
"Arg could not be nullptr unless using sinit and sterm functions.");
11601160
CI = Builder.CreateCall(CalleeTy, Callee);
1161-
} else
1161+
} else {
1162+
// If the object lives in a different address space, the `this` pointer
1163+
// address space won't match the dtor `this` param. An addrspacecast is
1164+
// required.
1165+
assert(Arg->getType()->isPointerTy());
1166+
assert(CalleeTy->getParamType(0)->isPointerTy());
1167+
unsigned ActualAddrSpace = Arg->getType()->getPointerAddressSpace();
1168+
unsigned ExpectedAddrSpace =
1169+
CalleeTy->getParamType(0)->getPointerAddressSpace();
1170+
if (ActualAddrSpace != ExpectedAddrSpace) {
1171+
llvm::PointerType *PTy =
1172+
llvm::PointerType::get(getLLVMContext(), ExpectedAddrSpace);
1173+
Arg = llvm::ConstantExpr::getAddrSpaceCast(Arg, PTy);
1174+
}
11621175
CI = Builder.CreateCall(CalleeTy, Callee, Arg);
1176+
}
11631177

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

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
371371
assert(DeferredDeactivationCleanupStack.empty() &&
372372
"mismatched activate/deactivate of cleanups!");
373373

374-
if (CGM.shouldEmitConvergenceTokens()) {
375-
ConvergenceTokenStack.pop_back();
376-
assert(ConvergenceTokenStack.empty() &&
377-
"mismatched push/pop in convergence stack!");
378-
}
379-
380374
bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
381375
&& NumSimpleReturnExprs == NumReturnExprs
382376
&& ReturnBlock.getBlock()->use_empty();
@@ -564,6 +558,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
564558
ReturnValue = Address::invalid();
565559
}
566560
}
561+
562+
if (CGM.shouldEmitConvergenceTokens()) {
563+
ConvergenceTokenStack.pop_back();
564+
assert(ConvergenceTokenStack.empty() &&
565+
"mismatched push/pop in convergence stack!");
566+
}
567567
}
568568

569569
/// ShouldInstrumentFunction - Return true if the current function should be

clang/lib/Sema/SemaDecl.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6888,6 +6888,32 @@ static void SetNestedNameSpecifier(Sema &S, DeclaratorDecl *DD, Declarator &D) {
68886888
DD->setQualifierInfo(SS.getWithLocInContext(S.Context));
68896889
}
68906890

6891+
void Sema::deduceHLSLAddressSpace(VarDecl *Decl) {
6892+
// The variable already has an address space (groupshared for ex).
6893+
if (Decl->getType().hasAddressSpace())
6894+
return;
6895+
6896+
if (Decl->getType()->isDependentType())
6897+
return;
6898+
6899+
QualType Type = Decl->getType();
6900+
if (Type->isSamplerT() || Type->isVoidType())
6901+
return;
6902+
6903+
// Resource handles.
6904+
if (Type->isHLSLIntangibleType())
6905+
return;
6906+
6907+
// Only static globals belong to the Private address space.
6908+
// Non-static globals belongs to the cbuffer.
6909+
if (Decl->getStorageClass() != SC_Static && !Decl->isStaticDataMember())
6910+
return;
6911+
6912+
LangAS ImplAS = LangAS::hlsl_private;
6913+
Type = Context.getAddrSpaceQualType(Type, ImplAS);
6914+
Decl->setType(Type);
6915+
}
6916+
68916917
void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) {
68926918
if (Decl->getType().hasAddressSpace())
68936919
return;
@@ -7781,6 +7807,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77817807
NewVD = VarDecl::Create(Context, DC, D.getBeginLoc(),
77827808
D.getIdentifierLoc(), II, R, TInfo, SC);
77837809

7810+
if (getLangOpts().HLSL)
7811+
deduceHLSLAddressSpace(NewVD);
7812+
77847813
// If this is supposed to be a variable template, create it as such.
77857814
if (IsVariableTemplate) {
77867815
NewTemplate =
@@ -7966,6 +7995,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
79667995
}
79677996
}
79687997

7998+
if (getLangOpts().HLSL)
7999+
deduceHLSLAddressSpace(NewVD);
8000+
79698001
// WebAssembly tables are always in address space 1 (wasm_var). Don't apply
79708002
// address space if the table has local storage (semantic checks elsewhere
79718003
// will produce an error anyway).
@@ -13138,6 +13170,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
1313813170
if (getLangOpts().OpenCL)
1313913171
deduceOpenCLAddressSpace(VDecl);
1314013172

13173+
if (getLangOpts().HLSL)
13174+
deduceHLSLAddressSpace(VDecl);
13175+
1314113176
// If this is a redeclaration, check that the type we just deduced matches
1314213177
// the previously declared type.
1314313178
if (VarDecl *Old = VDecl->getPreviousDecl()) {

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;
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
1+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,SPIRV
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,DXIL
23

34
RWBuffer<float> Buffer;
45

@@ -10,7 +11,13 @@ void main(unsigned GI : SV_GroupIndex) {}
1011
// CHECK-NOT:@llvm.global_dtors
1112
//CHECK: define void @main()
1213
//CHECK-NEXT: entry:
13-
//CHECK-NEXT: call void @_GLOBAL__sub_I_GlobalConstructors.hlsl()
14-
//CHECK-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
15-
//CHECK-NEXT: call void @_Z4mainj(i32 %0)
14+
15+
//SPIRV-NEXT: %0 = call token @llvm.experimental.convergence.entry()
16+
//SPIRV-NEXT: call spir_func void @_GLOBAL__sub_I_GlobalConstructors.hlsl() [ "convergencectrl"(token %0) ]
17+
//SPIRV-NEXT: %1 = call i32 @llvm.spv.flattened.thread.id.in.group()
18+
//SPIRV-NEXT: call spir_func void @_Z4mainj(i32 %1) [ "convergencectrl"(token %0) ]
19+
20+
//DXIL-NEXT: call void @_GLOBAL__sub_I_GlobalConstructors.hlsl()
21+
//DXIL-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
22+
//DXIL-NEXT: call void @_Z4mainj(i32 %0)
1623
//CHECK-NEXT: ret void

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)