From 0728a5fa8dc7c2c65fc760db1e6e64365750c5a4 Mon Sep 17 00:00:00 2001 From: seven-mile Date: Fri, 16 Aug 2024 00:23:44 +0800 Subject: [PATCH 1/4] [CIR][CodeGen] Support static OpenCL global with addrspace --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 8 +++++--- clang/test/CIR/CodeGen/OpenCL/global.cl | 10 ++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index d6e11e4516e2..466c4cbfabc2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -465,7 +465,8 @@ 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. @@ -477,7 +478,7 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &D, 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); @@ -492,7 +493,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. diff --git a/clang/test/CIR/CodeGen/OpenCL/global.cl b/clang/test/CIR/CodeGen/OpenCL/global.cl index cab7378fd102..051938ef14d6 100644 --- a/clang/test/CIR/CodeGen/OpenCL/global.cl +++ b/clang/test/CIR/CodeGen/OpenCL/global.cl @@ -21,3 +21,13 @@ kernel void test_get_global() { // LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @b, align 4 // LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(1) @a, align 4 } + +kernel void test_static(int i) { + static global int b = 15; + // CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_global) @func.b = #cir.int<15> : !s32i {alignment = 4 : i64} + a = b; + // CIR: %[[#ADDRB:]] = cir.get_global @func.b : !cir.ptr + // CIR-NEXT: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr, !s32i + // CIR-NEXT: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr + // CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRA]] : !s32i, !cir.ptr +} From bb56125c4a360bf939eed0f934a4f771e0bcb535 Mon Sep 17 00:00:00 2001 From: seven-mile Date: Fri, 2 Aug 2024 02:54:42 +0800 Subject: [PATCH 2/4] [CIR][CodeGen][NFC] Add skeleton of OpenCL Runtime --- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 4 ++ clang/lib/CIR/CodeGen/CIRGenModule.h | 14 ++++++ clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp | 29 ++++++++++++ clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h | 46 +++++++++++++++++++ clang/lib/CIR/CodeGen/CMakeLists.txt | 1 + 5 files changed, 94 insertions(+) create mode 100644 clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp create mode 100644 clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 5b3ca33cd24a..34a3a058d713 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -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: diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index b8ad57d788ae..b4d2f9dcbd00 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -15,6 +15,7 @@ #include "CIRGenBuilder.h" #include "CIRGenCall.h" +#include "CIRGenOpenCLRuntime.h" #include "CIRGenTypeCache.h" #include "CIRGenTypes.h" #include "CIRGenVTables.h" @@ -102,6 +103,9 @@ class CIRGenModule : public CIRGenTypeCache { /// Holds information about C++ vtables. CIRGenVTables VTables; + /// Holds the OpenCL runtime + std::unique_ptr openCLRuntime; + /// Holds the OpenMP runtime std::unique_ptr openMPRuntime; @@ -697,6 +701,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); diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp new file mode 100644 index 000000000000..863caf8629d2 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.cpp @@ -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); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h b/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h new file mode 100644 index 000000000000..891b5bb5fb79 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenOpenCLRuntime.h @@ -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 diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 552555779d46..97a8ad4f5ea8 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -31,6 +31,7 @@ add_clang_library(clangCIR CIRGenFunction.cpp CIRGenItaniumCXXABI.cpp CIRGenModule.cpp + CIRGenOpenCLRuntime.cpp CIRGenOpenCL.cpp CIRGenOpenMPRuntime.cpp CIRGenStmt.cpp From 7d70923bf1002a635b639d4112e8f98224ce711b Mon Sep 17 00:00:00 2001 From: seven-mile Date: Fri, 2 Aug 2024 03:18:59 +0800 Subject: [PATCH 3/4] [CIR][CodeGen] Local memory representation for OpenCL C --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 9 ++++----- clang/test/CIR/CodeGen/OpenCL/global.cl | 23 +++++++++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 466c4cbfabc2..b6e3beced986 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -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()); @@ -471,10 +471,9 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &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() || D.hasAttr()) - llvm_unreachable("OpenCL & CUDA are NYI"); - else + if (D.hasAttr() || D.hasAttr()) + llvm_unreachable("CUDA is NYI"); + else if (Ty.getAddressSpace() != LangAS::opencl_local) Init = builder.getZeroInitAttr(getTypes().ConvertType(Ty)); mlir::cir::GlobalOp GV = builder.createVersionedGlobal( diff --git a/clang/test/CIR/CodeGen/OpenCL/global.cl b/clang/test/CIR/CodeGen/OpenCL/global.cl index 051938ef14d6..5ca25d534cbc 100644 --- a/clang/test/CIR/CodeGen/OpenCL/global.cl +++ b/clang/test/CIR/CodeGen/OpenCL/global.cl @@ -25,9 +25,28 @@ kernel void test_get_global() { kernel void test_static(int i) { static global int b = 15; // CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_global) @func.b = #cir.int<15> : !s32i {alignment = 4 : i64} + // LLVM-DAG: @func.b = internal addrspace(1) global i32 15 + + local int c; + // CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_local) @func.c : !s32i {alignment = 4 : i64} + // LLVM-DAG: @func.c = internal addrspace(3) global i32 undef + + // CIR-DAG: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr + // CIR-DAG: %[[#ADDRB:]] = cir.get_global @func.b : !cir.ptr + // CIR-DAG: %[[#ADDRC:]] = cir.get_global @func.c : !cir.ptr + + c = a; + // CIR: %[[#LOADA:]] = cir.load %[[#ADDRA]] : !cir.ptr, !s32i + // CIR-NEXT: cir.store %[[#LOADA]], %[[#ADDRC]] : !s32i, !cir.ptr + + // LLVM: %[[#LOADA:]] = load i32, ptr addrspace(1) @a, align 4 + // LLVM-NEXT: store i32 %[[#LOADA]], ptr addrspace(3) @func.c, align 4 + a = b; - // CIR: %[[#ADDRB:]] = cir.get_global @func.b : !cir.ptr - // CIR-NEXT: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr, !s32i + // CIR: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr, !s32i // CIR-NEXT: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr // CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRA]] : !s32i, !cir.ptr + + // LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @func.b, align 4 + // LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(1) @a, align 4 } From 1c8103910c4c6326da313ad28bbef9f538448967 Mon Sep 17 00:00:00 2001 From: seven-mile Date: Fri, 16 Aug 2024 00:38:12 +0800 Subject: [PATCH 4/4] fix: move test away --- clang/test/CIR/CodeGen/OpenCL/global.cl | 29 ------------------- .../test/CIR/CodeGen/OpenCL/static-vardecl.cl | 24 +++++++++++++++ 2 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 clang/test/CIR/CodeGen/OpenCL/static-vardecl.cl diff --git a/clang/test/CIR/CodeGen/OpenCL/global.cl b/clang/test/CIR/CodeGen/OpenCL/global.cl index 5ca25d534cbc..cab7378fd102 100644 --- a/clang/test/CIR/CodeGen/OpenCL/global.cl +++ b/clang/test/CIR/CodeGen/OpenCL/global.cl @@ -21,32 +21,3 @@ kernel void test_get_global() { // LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @b, align 4 // LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(1) @a, align 4 } - -kernel void test_static(int i) { - static global int b = 15; - // CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_global) @func.b = #cir.int<15> : !s32i {alignment = 4 : i64} - // LLVM-DAG: @func.b = internal addrspace(1) global i32 15 - - local int c; - // CIR-DAG: cir.global "private" internal dsolocal addrspace(offload_local) @func.c : !s32i {alignment = 4 : i64} - // LLVM-DAG: @func.c = internal addrspace(3) global i32 undef - - // CIR-DAG: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr - // CIR-DAG: %[[#ADDRB:]] = cir.get_global @func.b : !cir.ptr - // CIR-DAG: %[[#ADDRC:]] = cir.get_global @func.c : !cir.ptr - - c = a; - // CIR: %[[#LOADA:]] = cir.load %[[#ADDRA]] : !cir.ptr, !s32i - // CIR-NEXT: cir.store %[[#LOADA]], %[[#ADDRC]] : !s32i, !cir.ptr - - // LLVM: %[[#LOADA:]] = load i32, ptr addrspace(1) @a, align 4 - // LLVM-NEXT: store i32 %[[#LOADA]], ptr addrspace(3) @func.c, align 4 - - a = b; - // CIR: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr, !s32i - // CIR-NEXT: %[[#ADDRA:]] = cir.get_global @a : !cir.ptr - // CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRA]] : !s32i, !cir.ptr - - // LLVM: %[[#LOADB:]] = load i32, ptr addrspace(1) @func.b, align 4 - // LLVM-NEXT: store i32 %[[#LOADB]], ptr addrspace(1) @a, align 4 -} diff --git a/clang/test/CIR/CodeGen/OpenCL/static-vardecl.cl b/clang/test/CIR/CodeGen/OpenCL/static-vardecl.cl new file mode 100644 index 000000000000..9ad8277012c4 --- /dev/null +++ b/clang/test/CIR/CodeGen/OpenCL/static-vardecl.cl @@ -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 + // CIR-DAG: %[[#ADDRC:]] = cir.get_global @test_static.c : !cir.ptr + + c = b; + // CIR: %[[#LOADB:]] = cir.load %[[#ADDRB]] : !cir.ptr, !s32i + // CIR-NEXT: cir.store %[[#LOADB]], %[[#ADDRC]] : !s32i, !cir.ptr + + // 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 +}