Skip to content

Commit 548458f

Browse files
authoredAug 15, 2024··
[CIR][CodeGen] Set address space for OpenCL static and local-qualified variables (#792)
In OpenCL, `local`-qualified variables are implicitly considered as static. In order to support it, this PR unblocks code paths related to OpenCL static declarations in `CIRGenDecl.cpp`. Following the approach of LLVM CodeGen, a new class `CIRGenOpenCLRuntime` is added to handle the language hook of creating `local`-qualified variables. The default behavior of this hook is quite simple. It forwards the call to `CGF.buildStaticVarDecl`. So in CIR, the OpenCL local memory representation is equivalent to the one defined by SPIR-LLVM convention: a `cir.global` with `addrspace(local)` and *without initializer*, which corresponds to LLVM `undef` initializer. See check lines in test for more details. A `static global`-qualified variable is also added in the test to exercise the static code path itself.

File tree

7 files changed

+127
-8
lines changed

7 files changed

+127
-8
lines changed
 

‎clang/lib/CIR/CodeGen/CIRGenDecl.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ void CIRGenFunction::buildVarDecl(const VarDecl &D) {
411411
}
412412

413413
if (D.getType().getAddressSpace() == LangAS::opencl_local)
414-
llvm_unreachable("OpenCL and address space are NYI");
414+
return CGM.getOpenCLRuntime().buildWorkGroupLocalVarDecl(*this, D);
415415

416416
assert(D.hasLocalStorage());
417417

@@ -465,19 +465,19 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &D,
465465
Name = getStaticDeclName(*this, D);
466466

467467
mlir::Type LTy = getTypes().convertTypeForMem(Ty);
468-
assert(!MissingFeatures::addressSpace());
468+
mlir::cir::AddressSpaceAttr AS =
469+
builder.getAddrSpaceAttr(getGlobalVarAddressSpace(&D));
469470

470471
// OpenCL variables in local address space and CUDA shared
471472
// variables cannot have an initializer.
472473
mlir::Attribute Init = nullptr;
473-
if (Ty.getAddressSpace() == LangAS::opencl_local ||
474-
D.hasAttr<CUDASharedAttr>() || D.hasAttr<LoaderUninitializedAttr>())
475-
llvm_unreachable("OpenCL & CUDA are NYI");
476-
else
474+
if (D.hasAttr<CUDASharedAttr>() || D.hasAttr<LoaderUninitializedAttr>())
475+
llvm_unreachable("CUDA is NYI");
476+
else if (Ty.getAddressSpace() != LangAS::opencl_local)
477477
Init = builder.getZeroInitAttr(getTypes().ConvertType(Ty));
478478

479479
mlir::cir::GlobalOp GV = builder.createVersionedGlobal(
480-
getModule(), getLoc(D.getLocation()), Name, LTy, false, Linkage);
480+
getModule(), getLoc(D.getLocation()), Name, LTy, false, Linkage, AS);
481481
// TODO(cir): infer visibility from linkage in global op builder.
482482
GV.setVisibility(getMLIRVisibilityFromCIRLinkage(Linkage));
483483
GV.setInitialValueAttr(Init);
@@ -492,7 +492,8 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &D,
492492
setGVProperties(GV, &D);
493493

494494
// Make sure the result is of the correct type.
495-
assert(!MissingFeatures::addressSpace());
495+
if (AS != builder.getAddrSpaceAttr(Ty.getAddressSpace()))
496+
llvm_unreachable("address space cast NYI");
496497

497498
// Ensure that the static local gets initialized by making sure the parent
498499
// function gets emitted eventually.

‎clang/lib/CIR/CodeGen/CIRGenModule.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
165165
builder.getContext(), astCtx.getTargetInfo().getMaxPointerWidth(),
166166
/*isSigned=*/true);
167167

168+
if (langOpts.OpenCL) {
169+
createOpenCLRuntime();
170+
}
171+
168172
mlir::cir::sob::SignedOverflowBehavior sob;
169173
switch (langOpts.getSignedOverflowBehavior()) {
170174
case clang::LangOptions::SignedOverflowBehaviorTy::SOB_Defined:

‎clang/lib/CIR/CodeGen/CIRGenModule.h

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "CIRGenBuilder.h"
1717
#include "CIRGenCall.h"
18+
#include "CIRGenOpenCLRuntime.h"
1819
#include "CIRGenTypeCache.h"
1920
#include "CIRGenTypes.h"
2021
#include "CIRGenVTables.h"
@@ -102,6 +103,9 @@ class CIRGenModule : public CIRGenTypeCache {
102103
/// Holds information about C++ vtables.
103104
CIRGenVTables VTables;
104105

106+
/// Holds the OpenCL runtime
107+
std::unique_ptr<CIRGenOpenCLRuntime> openCLRuntime;
108+
105109
/// Holds the OpenMP runtime
106110
std::unique_ptr<CIRGenOpenMPRuntime> openMPRuntime;
107111

@@ -700,6 +704,16 @@ class CIRGenModule : public CIRGenTypeCache {
700704
/// Print out an error that codegen doesn't support the specified decl yet.
701705
void ErrorUnsupported(const Decl *D, const char *Type);
702706

707+
/// Return a reference to the configured OpenMP runtime.
708+
CIRGenOpenCLRuntime &getOpenCLRuntime() {
709+
assert(openCLRuntime != nullptr);
710+
return *openCLRuntime;
711+
}
712+
713+
void createOpenCLRuntime() {
714+
openCLRuntime.reset(new CIRGenOpenCLRuntime(*this));
715+
}
716+
703717
/// Return a reference to the configured OpenMP runtime.
704718
CIRGenOpenMPRuntime &getOpenMPRuntime() {
705719
assert(openMPRuntime != nullptr);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- CIRGenOpenCLRuntime.cpp - Interface to OpenCL Runtimes ------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This provides an abstract class for OpenCL CIR generation. Concrete
10+
// subclasses of this implement code generation for specific OpenCL
11+
// runtime libraries.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "CIRGenOpenCLRuntime.h"
16+
#include "CIRGenFunction.h"
17+
18+
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
19+
20+
using namespace clang;
21+
using namespace cir;
22+
23+
CIRGenOpenCLRuntime::~CIRGenOpenCLRuntime() {}
24+
25+
void CIRGenOpenCLRuntime::buildWorkGroupLocalVarDecl(CIRGenFunction &CGF,
26+
const VarDecl &D) {
27+
return CGF.buildStaticVarDecl(D,
28+
mlir::cir::GlobalLinkageKind::InternalLinkage);
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===-- CIRGenOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This provides an abstract class for OpenCL CIR generation. Concrete
10+
// subclasses of this implement code generation for specific OpenCL
11+
// runtime libraries.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H
16+
#define LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H
17+
18+
namespace clang {
19+
20+
class VarDecl;
21+
22+
} // namespace clang
23+
24+
namespace cir {
25+
26+
class CIRGenFunction;
27+
class CIRGenModule;
28+
29+
class CIRGenOpenCLRuntime {
30+
protected:
31+
CIRGenModule &CGM;
32+
33+
public:
34+
CIRGenOpenCLRuntime(CIRGenModule &CGM) : CGM(CGM) {}
35+
virtual ~CIRGenOpenCLRuntime();
36+
37+
/// Emit the IR required for a work-group-local variable declaration, and add
38+
/// an entry to CGF's LocalDeclMap for D. The base class does this using
39+
/// CIRGenFunction::EmitStaticVarDecl to emit an internal global for D.
40+
virtual void buildWorkGroupLocalVarDecl(CIRGenFunction &CGF,
41+
const clang::VarDecl &D);
42+
};
43+
44+
} // namespace cir
45+
46+
#endif // LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H

‎clang/lib/CIR/CodeGen/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ add_clang_library(clangCIR
3131
CIRGenFunction.cpp
3232
CIRGenItaniumCXXABI.cpp
3333
CIRGenModule.cpp
34+
CIRGenOpenCLRuntime.cpp
3435
CIRGenOpenCL.cpp
3536
CIRGenOpenMPRuntime.cpp
3637
CIRGenStmt.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
kernel void test_static(int i) {
7+
static global int b = 15;
8+
// CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_global) @test_static.b = #cir.int<15> : !s32i {alignment = 4 : i64}
9+
// LLVM-DAG: @test_static.b = internal addrspace(1) global i32 15
10+
11+
local int c;
12+
// CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_local) @test_static.c : !s32i {alignment = 4 : i64}
13+
// LLVM-DAG: @test_static.c = internal addrspace(3) global i32 undef
14+
15+
// CIR-DAG: %[[#ADDRB:]] = cir.get_global @test_static.b : !cir.ptr<!s32i, addrspace(offload_global)>
16+
// CIR-DAG: %[[#ADDRC:]] = cir.get_global @test_static.c : !cir.ptr<!s32i, addrspace(offload_local)>
17+
18+
c = b;
19+
// CIR: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr<!s32i, addrspace(offload_global)>, !s32i
20+
// CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRC]] : !s32i, !cir.ptr<!s32i, addrspace(offload_local)>
21+
22+
// LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @test_static.b, align 4
23+
// LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(3) @test_static.c, align 4
24+
}

0 commit comments

Comments
 (0)
Please sign in to comment.