Skip to content

Commit 491ab40

Browse files
seven-milelanza
authored andcommitted
[CIR][CodeGen][LowerToLLVM] End-to-end implementation of offload_* cases for OpenCL with SPIR-V target (llvm#724)
This PR implements `offload_*` cases discussed in [this thread](https://discourse.llvm.org/t/rfc-clangir-unified-address-space-design-in-clangir/79728). * Integrate target-specific CIR-to-LLVM address space map into `TargetLoweringInfo` * CIRGen: Implement these cases in `getValueFromLangAS` * Lowering: Extend the state of type converter with `LowerModule` When frontend provides a new LangAS like `opencl_generic`, it would be processed by CIRGenTypes and `Builder.getPointerTo()` and encoded as `offload_generic`. When we lower CIR to LLVM, * For pointer types without address space attribute, it's mapped to `ptr addrspace(0)` directly * For target cases `target<x>`, it's mapped to `ptr addrspace(x)` * For other defined cases, query the target info with a new virtual method `getTargetAddrSpaceFromCIRAddrSpace`. General targets like X86 and ARM64 map all known cases to 0. For SPIR-V target here, it maps `offload_generic` to `addrspace(4)`.
1 parent 4432e1d commit 491ab40

File tree

10 files changed

+119
-20
lines changed

10 files changed

+119
-20
lines changed

clang/include/clang/CIR/MissingFeatures.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ struct MissingFeatures {
161161
static bool constantFoldsToSimpleInteger() { return false; }
162162
static bool checkFunctionCallABI() { return false; }
163163
static bool zeroInitializer() { return false; }
164-
static bool targetLoweringInfoAddressSpaceMap() { return false; }
165164
static bool targetCodeGenInfoIsProtoCallVariadic() { return false; }
166165
static bool targetCodeGenInfoGetNullPointer() { return false; }
167166
static bool operandBundles() { return false; }
@@ -277,6 +276,10 @@ struct MissingFeatures {
277276
static bool returnValueDominatingStoreOptmiization() { return false; }
278277
// Globals (vars and functions) may have attributes that are target depedent.
279278
static bool setTargetAttributes() { return false; }
279+
280+
// CIR modules parsed from text form may not carry the triple or data layout
281+
// specs. We should make it always present.
282+
static bool makeTripleAlwaysPresent() { return false; }
280283
};
281284

282285
} // namespace cir

clang/lib/CIR/Dialect/IR/CIRAttrs.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,16 @@ AddressSpaceAttr::getValueFromLangAS(clang::LangAS langAS) {
566566
// Default address space should be encoded as a null attribute.
567567
return std::nullopt;
568568
case LangAS::opencl_global:
569+
return Kind::offload_global;
569570
case LangAS::opencl_local:
571+
return Kind::offload_local;
570572
case LangAS::opencl_constant:
573+
return Kind::offload_constant;
571574
case LangAS::opencl_private:
575+
return Kind::offload_private;
572576
case LangAS::opencl_generic:
577+
return Kind::offload_generic;
578+
573579
case LangAS::opencl_global_device:
574580
case LangAS::opencl_global_host:
575581
case LangAS::cuda_device:

clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "ABIInfo.h"
1919
#include <memory>
2020

21+
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
22+
2123
namespace mlir {
2224
namespace cir {
2325

@@ -30,6 +32,8 @@ class TargetLoweringInfo {
3032
virtual ~TargetLoweringInfo();
3133

3234
const ABIInfo &getABIInfo() const { return *Info; }
35+
virtual unsigned getTargetAddrSpaceFromCIRAddrSpace(
36+
mlir::cir::AddressSpaceAttr addressSpaceAttr) const = 0;
3337
};
3438

3539
} // namespace cir

clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ class AArch64TargetLoweringInfo : public TargetLoweringInfo {
6262
: TargetLoweringInfo(std::make_unique<AArch64ABIInfo>(LT, Kind)) {
6363
assert(!MissingFeature::swift());
6464
}
65+
66+
unsigned getTargetAddrSpaceFromCIRAddrSpace(
67+
mlir::cir::AddressSpaceAttr addressSpaceAttr) const override {
68+
using Kind = mlir::cir::AddressSpaceAttr::Kind;
69+
switch (addressSpaceAttr.getValue()) {
70+
case Kind::offload_private:
71+
case Kind::offload_local:
72+
case Kind::offload_global:
73+
case Kind::offload_constant:
74+
case Kind::offload_generic:
75+
return 0;
76+
default:
77+
llvm_unreachable("Unknown CIR address space for this target");
78+
}
79+
}
6580
};
6681

6782
} // namespace

clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/SPIR.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,25 @@ class SPIRVTargetLoweringInfo : public TargetLoweringInfo {
4141
public:
4242
SPIRVTargetLoweringInfo(LowerTypes &LT)
4343
: TargetLoweringInfo(std::make_unique<SPIRVABIInfo>(LT)) {}
44+
45+
unsigned getTargetAddrSpaceFromCIRAddrSpace(
46+
mlir::cir::AddressSpaceAttr addressSpaceAttr) const override {
47+
using Kind = mlir::cir::AddressSpaceAttr::Kind;
48+
switch (addressSpaceAttr.getValue()) {
49+
case Kind::offload_private:
50+
return 0;
51+
case Kind::offload_local:
52+
return 3;
53+
case Kind::offload_global:
54+
return 1;
55+
case Kind::offload_constant:
56+
return 2;
57+
case Kind::offload_generic:
58+
return 4;
59+
default:
60+
llvm_unreachable("Unknown CIR address space for this target");
61+
}
62+
}
4463
};
4564

4665
} // namespace

clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ class X86_64TargetLoweringInfo : public TargetLoweringInfo {
105105
: TargetLoweringInfo(std::make_unique<X86_64ABIInfo>(LM, AVXLevel)) {
106106
assert(!::cir::MissingFeatures::swift());
107107
}
108+
109+
unsigned getTargetAddrSpaceFromCIRAddrSpace(
110+
mlir::cir::AddressSpaceAttr addressSpaceAttr) const override {
111+
using Kind = mlir::cir::AddressSpaceAttr::Kind;
112+
switch (addressSpaceAttr.getValue()) {
113+
case Kind::offload_private:
114+
case Kind::offload_local:
115+
case Kind::offload_global:
116+
case Kind::offload_constant:
117+
case Kind::offload_generic:
118+
return 0;
119+
default:
120+
llvm_unreachable("Unknown CIR address space for this target");
121+
}
122+
}
108123
};
109124

110125
void X86_64ABIInfo::classify(Type Ty, uint64_t OffsetBase, Class &Lo, Class &Hi,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

+33-10
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969
#include <optional>
7070
#include <set>
7171

72+
#include "LowerModule.h"
73+
7274
using namespace cir;
7375
using namespace llvm;
7476

@@ -3482,24 +3484,43 @@ void populateCIRToLLVMConversionPatterns(mlir::RewritePatternSet &patterns,
34823484
}
34833485

34843486
namespace {
3487+
3488+
std::unique_ptr<mlir::cir::LowerModule>
3489+
prepareLowerModule(mlir::ModuleOp module) {
3490+
mlir::PatternRewriter rewriter{module->getContext()};
3491+
// If the triple is not present, e.g. CIR modules parsed from text, we
3492+
// cannot init LowerModule properly.
3493+
assert(!::cir::MissingFeatures::makeTripleAlwaysPresent());
3494+
if (!module->hasAttr("cir.triple"))
3495+
return {};
3496+
return mlir::cir::createLowerModule(module, rewriter);
3497+
}
3498+
3499+
// FIXME: change the type of lowerModule to `LowerModule &` to have better
3500+
// lambda capturing experience. Also blocked by makeTripleAlwaysPresent.
34853501
void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
3486-
mlir::DataLayout &dataLayout) {
3487-
converter.addConversion([&](mlir::cir::PointerType type) -> mlir::Type {
3502+
mlir::DataLayout &dataLayout,
3503+
mlir::cir::LowerModule *lowerModule) {
3504+
converter.addConversion([&, lowerModule](
3505+
mlir::cir::PointerType type) -> mlir::Type {
34883506
// Drop pointee type since LLVM dialect only allows opaque pointers.
34893507

34903508
auto addrSpace =
34913509
mlir::cast_if_present<mlir::cir::AddressSpaceAttr>(type.getAddrSpace());
3492-
// null addrspace attribute indicates the default addrspace
3510+
// Null addrspace attribute indicates the default addrspace.
34933511
if (!addrSpace)
34943512
return mlir::LLVM::LLVMPointerType::get(type.getContext());
34953513

3496-
// TODO(cir): Query the target-specific address space map to lower other ASs
3497-
// like `opencl_private`.
3498-
assert(!MissingFeatures::targetLoweringInfoAddressSpaceMap());
3499-
assert(addrSpace.isTarget() && "NYI");
3514+
assert(lowerModule && "CIR AS map is not available");
3515+
// Pass through target addrspace and map CIR addrspace to LLVM addrspace by
3516+
// querying the target info.
3517+
unsigned targetAS =
3518+
addrSpace.isTarget()
3519+
? addrSpace.getTargetValue()
3520+
: lowerModule->getTargetLoweringInfo()
3521+
.getTargetAddrSpaceFromCIRAddrSpace(addrSpace);
35003522

3501-
return mlir::LLVM::LLVMPointerType::get(type.getContext(),
3502-
addrSpace.getTargetValue());
3523+
return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
35033524
});
35043525
converter.addConversion([&](mlir::cir::DataMemberType type) -> mlir::Type {
35053526
return mlir::IntegerType::get(type.getContext(),
@@ -3724,7 +3745,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {
37243745
auto module = getOperation();
37253746
mlir::DataLayout dataLayout(module);
37263747
mlir::LLVMTypeConverter converter(&getContext());
3727-
prepareTypeConverter(converter, dataLayout);
3748+
std::unique_ptr<mlir::cir::LowerModule> lowerModule =
3749+
prepareLowerModule(module);
3750+
prepareTypeConverter(converter, dataLayout, lowerModule.get());
37283751

37293752
mlir::RewritePatternSet patterns(&getContext());
37303753

clang/test/CIR/CodeGen/OpenCL/addrspace-alloca.cl

+4-6
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,23 @@
33
// RUN: %clang_cc1 -cl-std=CL3.0 -O0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t.ll
44
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
55

6-
// Lowering of language-specific AS not supported
7-
// XFAIL: *
86

9-
// CIR: cir.func @func(%arg0: !cir.ptr<!s32i, addrspace(target<3>)>
7+
// CIR: cir.func @func(%arg0: !cir.ptr<!s32i, addrspace(offload_local)>
108
// LLVM: @func(ptr addrspace(3)
119
kernel void func(local int *p) {
12-
// CIR-NEXT: %[[#ALLOCA_P:]] = cir.alloca !cir.ptr<!s32i, addrspace(target<3>)>, !cir.ptr<!cir.ptr<!s32i, addrspace(target<3>)>>, ["p", init] {alignment = 8 : i64}
10+
// CIR-NEXT: %[[#ALLOCA_P:]] = cir.alloca !cir.ptr<!s32i, addrspace(offload_local)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_local)>>, ["p", init] {alignment = 8 : i64}
1311
// LLVM-NEXT: %[[#ALLOCA_P:]] = alloca ptr addrspace(3), i64 1, align 8
1412

1513
int x;
1614
// CIR-NEXT: %[[#ALLOCA_X:]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
1715
// LLVM-NEXT: %[[#ALLOCA_X:]] = alloca i32, i64 1, align 4
1816

1917
global char *b;
20-
// CIR-NEXT: %[[#ALLOCA_B:]] = cir.alloca !cir.ptr<!s8i, addrspace(target<1>)>, !cir.ptr<!cir.ptr<!s8i, addrspace(target<1>)>>, ["b"] {alignment = 8 : i64}
18+
// CIR-NEXT: %[[#ALLOCA_B:]] = cir.alloca !cir.ptr<!s8i, addrspace(offload_global)>, !cir.ptr<!cir.ptr<!s8i, addrspace(offload_global)>>, ["b"] {alignment = 8 : i64}
2119
// LLVM-NEXT: %[[#ALLOCA_B:]] = alloca ptr addrspace(1), i64 1, align 8
2220

2321
// Store of the argument `p`
24-
// CIR-NEXT: cir.store %arg0, %[[#ALLOCA_P]] : !cir.ptr<!s32i, addrspace(target<3>)>, !cir.ptr<!cir.ptr<!s32i, addrspace(target<3>)>>
22+
// CIR-NEXT: cir.store %arg0, %[[#ALLOCA_P]] : !cir.ptr<!s32i, addrspace(offload_local)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_local)>>
2523
// LLVM-NEXT: store ptr addrspace(3) %{{[0-9]+}}, ptr %[[#ALLOCA_P]], align 8
2624

2725
return;

clang/test/CIR/CodeGen/OpenCL/spirv-target.cl

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
// RUN: %clang_cc1 -cl-std=CL3.0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t_64.ll
55
// RUN: FileCheck --input-file=%t_64.ll %s --check-prefix=LLVM-SPIRV64
66

7-
// Lowering of language-specific AS not supported
8-
// XFAIL: *
97

108
// CIR-SPIRV64: cir.triple = "spirv64-unknown-unknown"
119
// LLVM-SPIRV64: target triple = "spirv64-unknown-unknown"

clang/test/CIR/Lowering/address-space.cir

+19-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
!s32i = !cir.int<s, 32>
55

6-
module {
6+
module attributes {
7+
cir.triple = "spirv64-unknown-unknown",
8+
llvm.data_layout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1"
9+
} {
710
// LLVM: define void @foo(ptr %0)
811
cir.func @foo(%arg0: !cir.ptr<!s32i>) {
912
// LLVM-NEXT: alloca ptr,
@@ -24,4 +27,19 @@ module {
2427
%0 = cir.alloca !cir.ptr<!s32i, addrspace(target<0>)>, !cir.ptr<!cir.ptr<!s32i, addrspace(target<0>)>>, ["arg", init] {alignment = 8 : i64}
2528
cir.return
2629
}
30+
31+
// LLVM: define void @test_lower_offload_as()
32+
cir.func @test_lower_offload_as() {
33+
%0 = cir.alloca !cir.ptr<!s32i, addrspace(offload_private)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_private)>>, ["arg0", init] {alignment = 8 : i64}
34+
// LLVM-NEXT: alloca ptr,
35+
%1 = cir.alloca !cir.ptr<!s32i, addrspace(offload_global)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_global)>>, ["arg1", init] {alignment = 8 : i64}
36+
// LLVM-NEXT: alloca ptr addrspace(1),
37+
%2 = cir.alloca !cir.ptr<!s32i, addrspace(offload_constant)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_constant)>>, ["arg2", init] {alignment = 8 : i64}
38+
// LLVM-NEXT: alloca ptr addrspace(2),
39+
%3 = cir.alloca !cir.ptr<!s32i, addrspace(offload_local)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_local)>>, ["arg3", init] {alignment = 8 : i64}
40+
// LLVM-NEXT: alloca ptr addrspace(3),
41+
%4 = cir.alloca !cir.ptr<!s32i, addrspace(offload_generic)>, !cir.ptr<!cir.ptr<!s32i, addrspace(offload_generic)>>, ["arg4", init] {alignment = 8 : i64}
42+
// LLVM-NEXT: alloca ptr addrspace(4),
43+
cir.return
44+
}
2745
}

0 commit comments

Comments
 (0)