Skip to content

Commit 4cc61c4

Browse files
authored
[CIR][CodeGen] Set address space for OpenCL globals (#788)
This PR sets proper address space when creating `cir.global` and `cir.get_global`. Different languages use different ways to encode the address space in AST constructs (i.e. VarDecl *). OpenCL and SYCL use an address space qualifier on the type of `VarDecl`, while CUDA uses separate AST attributes like `CUDASharedAttr`. Similarily, some targets may want to use special address space for global variables. So a per-language + per-target hook is needed to provide this customization point. In the LLVM CodeGen, it's the helper method `getGlobalVarAddressSpace` that takes on the role. For OpenCL C + SPIR-V combination, OpenCL C converts the address space qualifier to corresponding LangAS, but SPIR-V does not require any action. This PR implements `global` qualifier in OpenCL C, but does not include `constant` qualifier. Although the modified part works for `constant`, CIRGen is not yet able to set constant attribute for global ops (there is a TODO line). Static variable decl and `local` qualifier work in a similar way and come in later patches.
1 parent 45c7bf4 commit 4cc61c4

File tree

7 files changed

+104
-19
lines changed

7 files changed

+104
-19
lines changed

clang/lib/CIR/CodeGen/CIRGenBuilder.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -674,9 +674,10 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
674674

675675
mlir::Value createGetGlobal(mlir::cir::GlobalOp global,
676676
bool threadLocal = false) {
677-
return create<mlir::cir::GetGlobalOp>(global.getLoc(),
678-
getPointerTo(global.getSymType()),
679-
global.getName(), threadLocal);
677+
return create<mlir::cir::GetGlobalOp>(
678+
global.getLoc(),
679+
getPointerTo(global.getSymType(), global.getAddrSpaceAttr()),
680+
global.getName(), threadLocal);
680681
}
681682

682683
mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,9 @@ static LValue buildGlobalVarDeclLValue(CIRGenFunction &CGF, const Expr *E,
895895
auto V = CGF.CGM.getAddrOfGlobalVar(VD);
896896

897897
auto RealVarTy = CGF.getTypes().convertTypeForMem(VD->getType());
898-
auto realPtrTy = CGF.getBuilder().getPointerTo(RealVarTy);
898+
mlir::cir::PointerType realPtrTy = CGF.getBuilder().getPointerTo(
899+
RealVarTy, cast_if_present<mlir::cir::AddressSpaceAttr>(
900+
cast<mlir::cir::PointerType>(V.getType()).getAddrSpace()));
899901
if (realPtrTy != V.getType())
900902
V = CGF.getBuilder().createBitcast(V.getLoc(), V, realPtrTy);
901903

clang/lib/CIR/CodeGen/CIRGenModule.cpp

+47-15
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,11 @@ mlir::Value CIRGenModule::getGlobalValue(const Decl *D) {
636636
return CurCGF->symbolTable.lookup(D);
637637
}
638638

639-
mlir::cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &CGM,
640-
mlir::Location loc,
641-
StringRef name, mlir::Type t,
642-
bool isCst,
643-
mlir::Operation *insertPoint) {
639+
mlir::cir::GlobalOp
640+
CIRGenModule::createGlobalOp(CIRGenModule &CGM, mlir::Location loc,
641+
StringRef name, mlir::Type t, bool isCst,
642+
mlir::cir::AddressSpaceAttr addrSpace,
643+
mlir::Operation *insertPoint) {
644644
mlir::cir::GlobalOp g;
645645
auto &builder = CGM.getBuilder();
646646
{
@@ -654,7 +654,8 @@ mlir::cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &CGM,
654654
if (curCGF)
655655
builder.setInsertionPoint(curCGF->CurFn);
656656

657-
g = builder.create<mlir::cir::GlobalOp>(loc, name, t, isCst);
657+
g = builder.create<mlir::cir::GlobalOp>(
658+
loc, name, t, isCst, GlobalLinkageKind::ExternalLinkage, addrSpace);
658659
if (!curCGF) {
659660
if (insertPoint)
660661
CGM.getModule().insert(insertPoint, g);
@@ -741,6 +742,12 @@ void CIRGenModule::replaceGlobal(mlir::cir::GlobalOp Old,
741742
// If the types does not match, update all references to Old to the new type.
742743
auto OldTy = Old.getSymType();
743744
auto NewTy = New.getSymType();
745+
mlir::cir::AddressSpaceAttr oldAS = Old.getAddrSpaceAttr();
746+
mlir::cir::AddressSpaceAttr newAS = New.getAddrSpaceAttr();
747+
// TODO(cir): If the AS differs, we should also update all references.
748+
if (oldAS != newAS) {
749+
llvm_unreachable("NYI");
750+
}
744751
if (OldTy != NewTy) {
745752
auto OldSymUses = Old.getSymbolUses(theModule.getOperation());
746753
if (OldSymUses.has_value()) {
@@ -808,7 +815,7 @@ void CIRGenModule::setTLSMode(mlir::Operation *Op, const VarDecl &D) const {
808815
/// mangled name but some other type.
809816
mlir::cir::GlobalOp
810817
CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
811-
LangAS AddrSpace, const VarDecl *D,
818+
LangAS langAS, const VarDecl *D,
812819
ForDefinition_t IsForDefinition) {
813820
// Lookup the entry, lazily creating it if necessary.
814821
mlir::cir::GlobalOp Entry;
@@ -817,8 +824,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
817824
Entry = dyn_cast_or_null<mlir::cir::GlobalOp>(V);
818825
}
819826

820-
// unsigned TargetAS = astCtx.getTargetAddressSpace(AddrSpace);
827+
mlir::cir::AddressSpaceAttr cirAS = builder.getAddrSpaceAttr(langAS);
821828
if (Entry) {
829+
auto entryCIRAS = Entry.getAddrSpaceAttr();
822830
if (WeakRefReferences.erase(Entry)) {
823831
if (D && !D->hasAttr<WeakAttr>()) {
824832
auto LT = mlir::cir::GlobalLinkageKind::ExternalLinkage;
@@ -836,8 +844,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
836844
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
837845
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);
838846

839-
// TODO(cir): check TargetAS matches Entry address space
840-
if (Entry.getSymType() == Ty && !MissingFeatures::addressSpaceInGlobalVar())
847+
if (Entry.getSymType() == Ty && entryCIRAS == cirAS)
841848
return Entry;
842849

843850
// If there are two attempts to define the same mangled name, issue an
@@ -866,14 +873,16 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
866873

867874
// TODO(cir): LLVM codegen makes sure the result is of the correct type
868875
// by issuing a address space cast.
876+
if (entryCIRAS != cirAS)
877+
llvm_unreachable("NYI");
869878

870879
// (If global is requested for a definition, we always need to create a new
871880
// global, not just return a bitcast.)
872881
if (!IsForDefinition)
873882
return Entry;
874883
}
875884

876-
// TODO(cir): auto DAddrSpace = GetGlobalVarAddressSpace(D);
885+
auto declCIRAS = builder.getAddrSpaceAttr(getGlobalVarAddressSpace(D));
877886
// TODO(cir): do we need to strip pointer casts for Entry?
878887

879888
auto loc = getLoc(D->getSourceRange());
@@ -882,6 +891,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
882891
// mark it as such.
883892
auto GV = CIRGenModule::createGlobalOp(*this, loc, MangledName, Ty,
884893
/*isConstant=*/false,
894+
/*addrSpace=*/declCIRAS,
885895
/*insertPoint=*/Entry.getOperation());
886896

887897
// If we already created a global with the same mangled name (but different
@@ -991,8 +1001,7 @@ mlir::Value CIRGenModule::getAddrOfGlobalVar(const VarDecl *D, mlir::Type Ty,
9911001

9921002
bool tlsAccess = D->getTLSKind() != VarDecl::TLS_None;
9931003
auto g = buildGlobal(D, Ty, IsForDefinition);
994-
auto ptrTy =
995-
mlir::cir::PointerType::get(builder.getContext(), g.getSymType());
1004+
auto ptrTy = builder.getPointerTo(g.getSymType(), g.getAddrSpaceAttr());
9961005
return builder.create<mlir::cir::GetGlobalOp>(
9971006
getLoc(D->getSourceRange()), ptrTy, g.getSymName(), tlsAccess);
9981007
}
@@ -1075,7 +1084,8 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
10751084
// If this is OpenMP device, check if it is legal to emit this global
10761085
// normally.
10771086
QualType ASTTy = D->getType();
1078-
if (getLangOpts().OpenCL || getLangOpts().OpenMPIsTargetDevice)
1087+
if ((getLangOpts().OpenCL && ASTTy->isSamplerT()) ||
1088+
getLangOpts().OpenMPIsTargetDevice)
10791089
llvm_unreachable("not implemented");
10801090

10811091
// TODO(cir): LLVM's codegen uses a llvm::TrackingVH here. Is that
@@ -1408,7 +1418,7 @@ LangAS CIRGenModule::getLangTempAllocaAddressSpace() const {
14081418
if (getLangOpts().OpenCL)
14091419
return LangAS::opencl_private;
14101420
if (getLangOpts().SYCLIsDevice || getLangOpts().CUDAIsDevice ||
1411-
(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice))
1421+
(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice))
14121422
llvm_unreachable("NYI");
14131423
return LangAS::Default;
14141424
}
@@ -3099,3 +3109,25 @@ mlir::cir::SourceLanguage CIRGenModule::getCIRSourceLanguage() {
30993109
// TODO(cir): support remaining source languages.
31003110
llvm_unreachable("CIR does not yet support the given source language");
31013111
}
3112+
3113+
LangAS CIRGenModule::getGlobalVarAddressSpace(const VarDecl *D) {
3114+
if (langOpts.OpenCL) {
3115+
LangAS AS = D ? D->getType().getAddressSpace() : LangAS::opencl_global;
3116+
assert(AS == LangAS::opencl_global || AS == LangAS::opencl_global_device ||
3117+
AS == LangAS::opencl_global_host || AS == LangAS::opencl_constant ||
3118+
AS == LangAS::opencl_local || AS >= LangAS::FirstTargetAddressSpace);
3119+
return AS;
3120+
}
3121+
3122+
if (langOpts.SYCLIsDevice &&
3123+
(!D || D->getType().getAddressSpace() == LangAS::Default))
3124+
llvm_unreachable("NYI");
3125+
3126+
if (langOpts.CUDA && langOpts.CUDAIsDevice)
3127+
llvm_unreachable("NYI");
3128+
3129+
if (langOpts.OpenMP)
3130+
llvm_unreachable("NYI");
3131+
3132+
return getTargetCIRGenInfo().getGlobalVarAddressSpace(*this, D);
3133+
}

clang/lib/CIR/CodeGen/CIRGenModule.h

+11
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ class CIRGenModule : public CIRGenTypeCache {
226226
static mlir::cir::GlobalOp
227227
createGlobalOp(CIRGenModule &CGM, mlir::Location loc, StringRef name,
228228
mlir::Type t, bool isCst = false,
229+
mlir::cir::AddressSpaceAttr addrSpace = {},
229230
mlir::Operation *insertPoint = nullptr);
230231

231232
// FIXME: Hardcoding priority here is gross.
@@ -328,6 +329,16 @@ class CIRGenModule : public CIRGenTypeCache {
328329
return (Twine(".compoundLiteral.") + Twine(CompoundLitaralCnt++)).str();
329330
}
330331

332+
/// Return the AST address space of the underlying global variable for D, as
333+
/// determined by its declaration. Normally this is the same as the address
334+
/// space of D's type, but in CUDA, address spaces are associated with
335+
/// declarations, not types. If D is nullptr, return the default address
336+
/// space for global variable.
337+
///
338+
/// For languages without explicit address spaces, if D has default address
339+
/// space, target-specific global or constant address space may be returned.
340+
LangAS getGlobalVarAddressSpace(const VarDecl *D);
341+
331342
/// Return the AST address space of constant literal, which is used to emit
332343
/// the constant literal as global variable in LLVM IR.
333344
/// Note: This is not necessarily the address space of the constant literal

clang/lib/CIR/CodeGen/TargetInfo.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,15 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy) const {
552552
return ABIArgInfo::getDirect(ResType);
553553
}
554554

555+
clang::LangAS
556+
TargetCIRGenInfo::getGlobalVarAddressSpace(cir::CIRGenModule &CGM,
557+
const clang::VarDecl *D) const {
558+
assert(!CGM.getLangOpts().OpenCL &&
559+
!(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
560+
"Address space agnostic languages only");
561+
return D ? D->getType().getAddressSpace() : LangAS::Default;
562+
}
563+
555564
mlir::Value TargetCIRGenInfo::performAddrSpaceCast(
556565
CIRGenFunction &CGF, mlir::Value Src, mlir::cir::AddressSpaceAttr SrcAddr,
557566
mlir::cir::AddressSpaceAttr DestAddr, mlir::Type DestTy,

clang/lib/CIR/CodeGen/TargetInfo.h

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ class TargetCIRGenInfo {
6262
std::vector<LValue> &ResultRegDests,
6363
std::string &AsmString, unsigned NumOutputs) const {}
6464

65+
/// Get target favored AST address space of a global variable for languages
66+
/// other than OpenCL and CUDA.
67+
/// If \p D is nullptr, returns the default target favored address space
68+
/// for global variable.
69+
virtual clang::LangAS getGlobalVarAddressSpace(CIRGenModule &CGM,
70+
const clang::VarDecl *D) const;
71+
6572
/// Get the CIR address space for alloca.
6673
virtual mlir::cir::AddressSpaceAttr getCIRAllocaAddressSpace() const {
6774
// Return the null attribute, which means the target does not care about the
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-cir -triple spirv64-unknown-unknown %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
5+
6+
global int a = 13;
7+
// CIR-DAG: cir.global external addrspace(offload_global) @a = #cir.int<13> : !s32i
8+
// LLVM-DAG: @a = addrspace(1) global i32 13
9+
10+
global int b = 15;
11+
// CIR-DAG: cir.global external addrspace(offload_global) @b = #cir.int<15> : !s32i
12+
// LLVM-DAG: @b = addrspace(1) global i32 15
13+
14+
kernel void test_get_global() {
15+
a = b;
16+
// CIR: %[[#ADDRB:]] = cir.get_global @b : !cir.ptr<!s32i, addrspace(offload_global)>
17+
// CIR-NEXT: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr<!s32i, addrspace(offload_global)>, !s32i
18+
// CIR-NEXT: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr<!s32i, addrspace(offload_global)>
19+
// CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRA]] : !s32i, !cir.ptr<!s32i, addrspace(offload_global)>
20+
21+
// LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @b, align 4
22+
// LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(1) @a, align 4
23+
}

0 commit comments

Comments
 (0)