Skip to content

Commit

Permalink
[CIR][CodeGen] Set address space for OpenCL static and local-qualifie…
Browse files Browse the repository at this point in the history
…d variables (llvm#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.
  • Loading branch information
seven-mile authored and smeenai committed Oct 9, 2024
1 parent 128e7c0 commit 624beb6
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 8 deletions.
17 changes: 9 additions & 8 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ void CIRGenFunction::buildVarDecl(const VarDecl &D) {
}

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

assert(D.hasLocalStorage());

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

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

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

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

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

// Ensure that the static local gets initialized by making sure the parent
// function gets emitted eventually.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
builder.getContext(), astCtx.getTargetInfo().getMaxPointerWidth(),
/*isSigned=*/true);

if (langOpts.OpenCL) {
createOpenCLRuntime();
}

mlir::cir::sob::SignedOverflowBehavior sob;
switch (langOpts.getSignedOverflowBehavior()) {
case clang::LangOptions::SignedOverflowBehaviorTy::SOB_Defined:
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "CIRGenBuilder.h"
#include "CIRGenCall.h"
#include "CIRGenOpenCLRuntime.h"
#include "CIRGenTypeCache.h"
#include "CIRGenTypes.h"
#include "CIRGenVTables.h"
Expand Down Expand Up @@ -102,6 +103,9 @@ class CIRGenModule : public CIRGenTypeCache {
/// Holds information about C++ vtables.
CIRGenVTables VTables;

/// Holds the OpenCL runtime
std::unique_ptr<CIRGenOpenCLRuntime> openCLRuntime;

/// Holds the OpenMP runtime
std::unique_ptr<CIRGenOpenMPRuntime> openMPRuntime;

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

/// Return a reference to the configured OpenMP runtime.
CIRGenOpenCLRuntime &getOpenCLRuntime() {
assert(openCLRuntime != nullptr);
return *openCLRuntime;
}

void createOpenCLRuntime() {
openCLRuntime.reset(new CIRGenOpenCLRuntime(*this));
}

/// Return a reference to the configured OpenMP runtime.
CIRGenOpenMPRuntime &getOpenMPRuntime() {
assert(openMPRuntime != nullptr);
Expand Down
29 changes: 29 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===-- CIRGenOpenCLRuntime.cpp - Interface to OpenCL Runtimes ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for OpenCL CIR generation. Concrete
// subclasses of this implement code generation for specific OpenCL
// runtime libraries.
//
//===----------------------------------------------------------------------===//

#include "CIRGenOpenCLRuntime.h"
#include "CIRGenFunction.h"

#include "clang/CIR/Dialect/IR/CIROpsEnums.h"

using namespace clang;
using namespace cir;

CIRGenOpenCLRuntime::~CIRGenOpenCLRuntime() {}

void CIRGenOpenCLRuntime::buildWorkGroupLocalVarDecl(CIRGenFunction &CGF,
const VarDecl &D) {
return CGF.buildStaticVarDecl(D,
mlir::cir::GlobalLinkageKind::InternalLinkage);
}
46 changes: 46 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- CIRGenOpenCLRuntime.h - Interface to OpenCL Runtimes -----*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for OpenCL CIR generation. Concrete
// subclasses of this implement code generation for specific OpenCL
// runtime libraries.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H
#define LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H

namespace clang {

class VarDecl;

} // namespace clang

namespace cir {

class CIRGenFunction;
class CIRGenModule;

class CIRGenOpenCLRuntime {
protected:
CIRGenModule &CGM;

public:
CIRGenOpenCLRuntime(CIRGenModule &CGM) : CGM(CGM) {}
virtual ~CIRGenOpenCLRuntime();

/// Emit the IR required for a work-group-local variable declaration, and add
/// an entry to CGF's LocalDeclMap for D. The base class does this using
/// CIRGenFunction::EmitStaticVarDecl to emit an internal global for D.
virtual void buildWorkGroupLocalVarDecl(CIRGenFunction &CGF,
const clang::VarDecl &D);
};

} // namespace cir

#endif // LLVM_CLANG_LIB_CIR_CIRGENOPENCLRUNTIME_H
1 change: 1 addition & 0 deletions clang/lib/CIR/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_clang_library(clangCIR
CIRGenFunction.cpp
CIRGenItaniumCXXABI.cpp
CIRGenModule.cpp
CIRGenOpenCLRuntime.cpp
CIRGenOpenCL.cpp
CIRGenOpenMPRuntime.cpp
CIRGenStmt.cpp
Expand Down
24 changes: 24 additions & 0 deletions clang/test/CIR/CodeGen/OpenCL/static-vardecl.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-cir -triple spirv64-unknown-unknown %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM

kernel void test_static(int i) {
static global int b = 15;
// CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_global) @test_static.b = #cir.int<15> : !s32i {alignment = 4 : i64}
// LLVM-DAG: @test_static.b = internal addrspace(1) global i32 15

local int c;
// CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_local) @test_static.c : !s32i {alignment = 4 : i64}
// LLVM-DAG: @test_static.c = internal addrspace(3) global i32 undef

// CIR-DAG: %[[#ADDRB:]] = cir.get_global @test_static.b : !cir.ptr<!s32i, addrspace(offload_global)>
// CIR-DAG: %[[#ADDRC:]] = cir.get_global @test_static.c : !cir.ptr<!s32i, addrspace(offload_local)>

c = b;
// CIR: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr<!s32i, addrspace(offload_global)>, !s32i
// CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRC]] : !s32i, !cir.ptr<!s32i, addrspace(offload_local)>

// LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @test_static.b, align 4
// LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(3) @test_static.c, align 4
}

0 comments on commit 624beb6

Please sign in to comment.