Skip to content

Commit 171b53c

Browse files
seven-milelanza
authored andcommittedNov 3, 2024
[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.

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
@@ -637,11 +637,11 @@ mlir::Value CIRGenModule::getGlobalValue(const Decl *D) {
637637
return CurCGF->symbolTable.lookup(D);
638638
}
639639

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

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

821-
// unsigned TargetAS = astCtx.getTargetAddressSpace(AddrSpace);
828+
mlir::cir::AddressSpaceAttr cirAS = builder.getAddrSpaceAttr(langAS);
822829
if (Entry) {
830+
auto entryCIRAS = Entry.getAddrSpaceAttr();
823831
if (WeakRefReferences.erase(Entry)) {
824832
if (D && !D->hasAttr<WeakAttr>()) {
825833
auto LT = mlir::cir::GlobalLinkageKind::ExternalLinkage;
@@ -837,8 +845,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
837845
if (langOpts.OpenMP && !langOpts.OpenMPSimd && D)
838846
getOpenMPRuntime().registerTargetGlobalVariable(D, Entry);
839847

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

844851
// If there are two attempts to define the same mangled name, issue an
@@ -867,14 +874,16 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
867874

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

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

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

880889
auto loc = getLoc(D->getSourceRange());
@@ -883,6 +892,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
883892
// mark it as such.
884893
auto GV = CIRGenModule::createGlobalOp(*this, loc, MangledName, Ty,
885894
/*isConstant=*/false,
895+
/*addrSpace=*/declCIRAS,
886896
/*insertPoint=*/Entry.getOperation());
887897

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

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

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

‎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)
Please sign in to comment.