Skip to content

Commit 1252466

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 dae0ef5 commit 1252466

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
@@ -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/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);
@@ -5168,6 +5170,9 @@ bool Type::isHLSLIntangibleType() const {
51685170
CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
51695171
assert(RD != nullptr &&
51705172
"all HLSL structs and classes should be CXXRecordDecl");
5173+
5174+
if (!RD->isCompleteDefinition())
5175+
return false;
51715176
assert(RD->isCompleteDefinition() && "expecting complete type");
51725177
return RD->isHLSLIntangible();
51735178
}

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/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;
@@ -7776,6 +7802,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77767802
NewVD = VarDecl::Create(Context, DC, D.getBeginLoc(),
77777803
D.getIdentifierLoc(), II, R, TInfo, SC);
77787804

7805+
if (getLangOpts().HLSL)
7806+
deduceHLSLAddressSpace(NewVD);
7807+
77797808
// If this is supposed to be a variable template, create it as such.
77807809
if (IsVariableTemplate) {
77817810
NewTemplate =
@@ -7960,6 +7989,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
79607989
}
79617990
}
79627991

7992+
if (getLangOpts().HLSL)
7993+
deduceHLSLAddressSpace(NewVD);
7994+
79637995
// WebAssembly tables are always in address space 1 (wasm_var). Don't apply
79647996
// address space if the table has local storage (semantic checks elsewhere
79657997
// will produce an error anyway).
@@ -13131,6 +13163,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
1313113163
if (getLangOpts().OpenCL)
1313213164
deduceOpenCLAddressSpace(VDecl);
1313313165

13166+
if (getLangOpts().HLSL)
13167+
deduceHLSLAddressSpace(VDecl);
13168+
1313413169
// If this is a redeclaration, check that the type we just deduced matches
1313513170
// the previously declared type.
1313613171
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)