Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][Dialect] Make addrspace in pointer types to model LangAS #692

Merged
merged 17 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,18 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return mlir::cir::IntType::get(getContext(), N, true);
}

mlir::cir::PointerType getPointerTo(mlir::Type ty,
unsigned addressSpace = 0) {
assert(!addressSpace && "address space is NYI");
return mlir::cir::PointerType::get(getContext(), ty);
mlir::cir::PointerType
getPointerTo(mlir::Type ty, clang::LangAS langAS = clang::LangAS::Default) {
mlir::cir::AddressSpaceAttr addrSpaceAttr;
if (langAS != clang::LangAS::Default)
addrSpaceAttr = mlir::cir::AddressSpaceAttr::get(getContext(), langAS);

return mlir::cir::PointerType::get(getContext(), ty, addrSpaceAttr);
}

mlir::cir::PointerType getVoidPtrTy(unsigned addressSpace = 0) {
return getPointerTo(::mlir::cir::VoidType::get(getContext()), addressSpace);
mlir::cir::PointerType
getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) {
return getPointerTo(::mlir::cir::VoidType::get(getContext()), langAS);
}

mlir::Value createLoad(mlir::Location loc, mlir::Value ptr,
Expand Down
137 changes: 137 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,143 @@ def DynamicCastInfoAttr
}];
}

//===----------------------------------------------------------------------===//
// AddressSpaceAttr
//===----------------------------------------------------------------------===//

// TODO: other CIR AS cases
def AS_Target : I32EnumAttrCase<"target", 21>;

def AddressSpaceAttr : CIR_Attr<"AddressSpace", "addrspace"> {

let summary = "Address space attribute for pointer types";
let description = [{
The address space attribute models `clang::LangAS` rather than the LLVM
address space, which means it's not yet converted by the address space map
to carry target-specific semantics.

The representation is one-to-one except for `LangAS::Default`, which
corresponds to a null attribute instead.
}];

let parameters = (ins "int32_t":$value);

let assemblyFormat = [{
`<` $value `>`
}];

let builders = [
AttrBuilder<(ins "clang::LangAS":$langAS), [{
assert(langAS != clang::LangAS::Default &&
"Default address space is encoded as null attribute");
return $_get($_ctxt, getValueFromLangAS(langAS).value());
}]>
];

let cppNamespace = "::mlir::cir";

// The following codes implement these conversions:
// clang::LangAS -> int32_t <-> text-form CIR

// CIR_PointerType manipulates the parse- and stringify- methods to provide
// simplified assembly format `custom<PointerAddrSpace>`.

list<I32EnumAttrCase> langASCases = [
// TODO: includes all non-target CIR AS cases here
];

I32EnumAttrCase targetASCase = AS_Target;

let extraClassDeclaration = [{
static constexpr char kTargetKeyword[] = "}]#targetASCase.symbol#[{";
static constexpr int32_t kFirstTargetASValue = }]#targetASCase.value#[{;

bool isLang() const;
bool isTarget() const;
unsigned getTargetValue() const;

static std::optional<int32_t> parseValueFromString(llvm::StringRef s);
static std::optional<int32_t> getValueFromLangAS(clang::LangAS v);
static std::optional<llvm::StringRef> stringifyValue(int32_t v);
}];

let extraClassDefinition = [{
bool $cppClass::isLang() const {
return !isTarget();
}

bool $cppClass::isTarget() const {
return getValue() >= kFirstTargetASValue;
}

unsigned $cppClass::getTargetValue() const {
assert(isTarget() && "Not a target address space");
return getValue() - kFirstTargetASValue;
}

std::optional<int32_t>
$cppClass::parseValueFromString(llvm::StringRef str) {
return llvm::StringSwitch<::std::optional<int32_t>>(str)
}]
#
!interleave(
!foreach(case, langASCases,
".Case(\""#case.symbol# "\", "#case.value # ")\n"
),
"\n"
)
#
[{
// Target address spaces are not parsed here
.Default(std::nullopt);
}

std::optional<llvm::StringRef>
$cppClass::stringifyValue(int32_t value) {
switch (value) {
}]
#
!interleave(
!foreach(case, langASCases,
"case "#case.value
# ": return \""#case.symbol # "\";" ),
"\n"
)
#
[{
default:
// Target address spaces are not processed here
return std::nullopt;
}
}

std::optional<int32_t>
$cppClass::getValueFromLangAS(clang::LangAS langAS) {
assert((langAS == clang::LangAS::Default ||
clang::isTargetAddressSpace(langAS)) &&
"Language-specific address spaces are not supported");
switch (langAS) {
}]
#
!interleave(
!foreach(case, langASCases,
"case clang::LangAS::"#case.symbol
# [{: llvm_unreachable("Not Yet Supported");}] ),
"\n"
)
#
[{
case clang::LangAS::Default:
// Default address space should be encoded as a null attribute.
return std::nullopt;
default:
// Target address space offset arithmetics
return clang::toTargetAddressSpace(langAS) + kFirstTargetASValue;
}
}
}];
}

//===----------------------------------------------------------------------===//
// AST Wrappers
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"

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

//===----------------------------------------------------------------------===//
// CIR StructType
//
Expand Down
26 changes: 18 additions & 8 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -208,24 +208,34 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr",
`CIR.ptr` is a type returned by any op generating a pointer in C++.
}];

let parameters = (ins "mlir::Type":$pointee,
DefaultValuedParameter<"unsigned", "0">:$addrSpace);
let parameters = (ins
"mlir::Type":$pointee,
// FIXME(cir): Currently unable to directly use AddressSpaceAttr because of
// cyclic dep. Workaround with the top type and verifier.
OptionalParameter<"mlir::Attribute">:$addrSpace
);

let builders = [
TypeBuilderWithInferredContext<(ins
"mlir::Type":$pointee, CArg<"unsigned", "0">:$addrSpace), [{
return Base::get(pointee.getContext(), pointee, addrSpace);
"mlir::Type":$pointee,
CArg<"mlir::Attribute", "{}">:$addrSpace), [{
return $_get(pointee.getContext(), pointee, addrSpace);
}]>,
TypeBuilder<(ins
"mlir::Type":$pointee, CArg<"unsigned", "0">:$addrSpace), [{
return Base::get($_ctxt, pointee, addrSpace);
}]>,
"mlir::Type":$pointee,
CArg<"mlir::Attribute", "{}">:$addrSpace), [{
return $_get($_ctxt, pointee, addrSpace);
}]>
];

let assemblyFormat = [{
`<` $pointee ( `,` `addrspace` `(` $addrSpace^ `)` )? `>`
`<` $pointee ( `,` `addrspace` `(`
custom<PointerAddrSpace>($addrSpace)^
`)` )? `>`
}];

let genVerifyDecl = 1;

let skipDefaultBuilders = 1;

let extraClassDeclaration = [{
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ struct MissingFeatures {
static bool constantFoldsToSimpleInteger() { return false; }
static bool checkFunctionCallABI() { return false; }
static bool zeroInitializer() { return false; }
static bool targetLoweringInfoAddressSpaceMap() { return false; }
static bool targetCodeGenInfoIsProtoCallVariadic() { return false; }
static bool targetCodeGenInfoGetNullPointer() { return false; }
static bool operandBundles() { return false; }
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,9 +605,7 @@ mlir::Type CIRGenTypes::ConvertType(QualType T) {
const ReferenceType *RTy = cast<ReferenceType>(Ty);
QualType ETy = RTy->getPointeeType();
auto PointeeType = convertTypeForMem(ETy);
ResultType = ::mlir::cir::PointerType::get(
Builder.getContext(), PointeeType,
Context.getTargetAddressSpace(ETy.getAddressSpace()));
ResultType = Builder.getPointerTo(PointeeType, ETy.getAddressSpace());
assert(ResultType && "Cannot get pointer type?");
break;
}
Expand All @@ -622,9 +620,7 @@ mlir::Type CIRGenTypes::ConvertType(QualType T) {
// if (PointeeType->isVoidTy())
// PointeeType = Builder.getI8Type();

ResultType = ::mlir::cir::PointerType::get(
Builder.getContext(), PointeeType,
Context.getTargetAddressSpace(ETy.getAddressSpace()));
ResultType = Builder.getPointerTo(PointeeType, ETy.getAddressSpace());
assert(ResultType && "Cannot get pointer type?");
break;
}
Expand Down
64 changes: 64 additions & 0 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
static void printFuncTypeArgs(mlir::AsmPrinter &p,
mlir::ArrayRef<mlir::Type> params, bool isVarArg);

static mlir::ParseResult parsePointerAddrSpace(mlir::AsmParser &p,
mlir::Attribute &addrSpaceAttr);
static void printPointerAddrSpace(mlir::AsmPrinter &p,
mlir::Attribute addrSpaceAttr);

//===----------------------------------------------------------------------===//
// Get autogenerated stuff
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -873,6 +878,65 @@ llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {

bool FuncType::isVoid() const { return mlir::isa<VoidType>(getReturnType()); }

//===----------------------------------------------------------------------===//
// PointerType Definitions
//===----------------------------------------------------------------------===//

mlir::LogicalResult
PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
mlir::Type pointee, mlir::Attribute addrSpace) {
if (addrSpace && !mlir::isa<mlir::cir::AddressSpaceAttr>(addrSpace)) {
emitError() << "unexpected addrspace attribute type";
return mlir::failure();
}
return mlir::success();
}

mlir::ParseResult parsePointerAddrSpace(mlir::AsmParser &p,
mlir::Attribute &addrSpaceAttr) {
using mlir::cir::AddressSpaceAttr;
auto attrLoc = p.getCurrentLocation();

llvm::StringRef addrSpaceKind;
if (mlir::failed(p.parseOptionalKeyword(&addrSpaceKind))) {
p.emitError(attrLoc, "expected keyword for addrspace kind");
return mlir::failure();
}

if (addrSpaceKind == AddressSpaceAttr::kTargetKeyword) {
int64_t targetValue = -1;
if (p.parseLess() || p.parseInteger(targetValue) || p.parseGreater()) {
return mlir::failure();
}
addrSpaceAttr = AddressSpaceAttr::get(
p.getContext(), AddressSpaceAttr::kFirstTargetASValue + targetValue);
} else {
std::optional<int64_t> value =
AddressSpaceAttr::parseValueFromString(addrSpaceKind);
// not target AS, must be wrong keyword if no value
if (!value.has_value()) {
p.emitError(attrLoc, "invalid addrspace kind keyword: " + addrSpaceKind);
return mlir::failure();
}

addrSpaceAttr = AddressSpaceAttr::get(p.getContext(), *value);
}

return mlir::success();
}

void printPointerAddrSpace(mlir::AsmPrinter &p,
mlir::Attribute rawAddrSpaceAttr) {
using mlir::cir::AddressSpaceAttr;
auto addrSpaceAttr = mlir::cast<AddressSpaceAttr>(rawAddrSpaceAttr);
if (addrSpaceAttr.isTarget()) {
p << AddressSpaceAttr::kTargetKeyword << "<"
<< addrSpaceAttr.getTargetValue() << ">";
} else {
p << AddressSpaceAttr::stringifyValue(addrSpaceAttr.getValue());
}
}

//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3335,8 +3335,20 @@ void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
mlir::DataLayout &dataLayout) {
converter.addConversion([&](mlir::cir::PointerType type) -> mlir::Type {
// Drop pointee type since LLVM dialect only allows opaque pointers.

auto addrSpace =
mlir::cast_if_present<mlir::cir::AddressSpaceAttr>(type.getAddrSpace());
// null addrspace attribute indicates the default addrspace
if (!addrSpace)
return mlir::LLVM::LLVMPointerType::get(type.getContext());

// TODO(cir): Query the target-specific address space map to lower other ASs
// like `opencl_private`.
assert(!MissingFeatures::targetLoweringInfoAddressSpaceMap());
assert(addrSpace.isTarget() && "NYI");

return mlir::LLVM::LLVMPointerType::get(type.getContext(),
type.getAddrSpace());
addrSpace.getTargetValue());
});
converter.addConversion([&](mlir::cir::DataMemberType type) -> mlir::Type {
return mlir::IntegerType::get(type.getContext(),
Expand Down
11 changes: 7 additions & 4 deletions clang/test/CIR/CodeGen/OpenCL/addrspace-alloca.cl
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
// 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

// CIR: cir.func @func(%arg0: !cir.ptr<!s32i, addrspace(3)>
// Lowering of language-specific AS not supported
// XFAIL: *

// CIR: cir.func @func(%arg0: !cir.ptr<!s32i, addrspace(target<3>)>
// LLVM: @func(ptr addrspace(3)
kernel void func(local int *p) {
// CIR-NEXT: %[[#ALLOCA_P:]] = cir.alloca !cir.ptr<!s32i, addrspace(3)>, !cir.ptr<!cir.ptr<!s32i, addrspace(3)>>, ["p", init] {alignment = 8 : i64}
// 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}
// LLVM-NEXT: %[[#ALLOCA_P:]] = alloca ptr addrspace(3), i64 1, align 8

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

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

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

return;
Expand Down
3 changes: 3 additions & 0 deletions clang/test/CIR/CodeGen/OpenCL/spirv-target.cl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
// RUN: %clang_cc1 -cl-std=CL3.0 -fclangir -emit-llvm -triple spirv64-unknown-unknown %s -o %t_64.ll
// RUN: FileCheck --input-file=%t_64.ll %s --check-prefix=LLVM-SPIRV64

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

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

Expand Down
Loading
Loading