[clang] [CIR] Upstream `AddressSpace` support for `PointerType` (PR #161028)
David Rivera via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 27 21:53:35 PDT 2025
https://github.com/RiverDave updated https://github.com/llvm/llvm-project/pull/161028
>From 42940a5ebddba0ed3030d8b63285f79d21bcfdc1 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Sat, 27 Sep 2025 19:14:52 -0400
Subject: [PATCH] [CIR] Upstream `AddressSpace` support for `PointerType`
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 16 ++-
clang/include/clang/CIR/Dialect/IR/CIRAttrs.h | 1 +
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 41 ++++++
.../clang/CIR/Dialect/IR/CIREnumAttr.td | 24 ++++
clang/include/clang/CIR/Dialect/IR/CIRTypes.h | 38 +++++
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 62 +++++---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 +-
clang/lib/CIR/CodeGen/CIRGenTypeCache.h | 6 +
clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 2 +-
clang/lib/CIR/CodeGen/TargetInfo.h | 2 +
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 9 ++
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 133 +++++++++++++++---
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 19 ++-
clang/test/CIR/IR/invalid-addrspace.cir | 36 +++++
clang/test/CIR/address-space.c | 22 +++
15 files changed, 370 insertions(+), 44 deletions(-)
create mode 100644 clang/test/CIR/IR/invalid-addrspace.cir
create mode 100644 clang/test/CIR/address-space.c
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index a3f167e3cde2c..cef8624e65d57 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -129,8 +129,20 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::PointerType::get(ty);
}
- cir::PointerType getVoidPtrTy() {
- return getPointerTo(cir::VoidType::get(getContext()));
+ cir::PointerType getPointerTo(mlir::Type ty, cir::AddressSpace as) {
+ return cir::PointerType::get(ty, as);
+ }
+
+ cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) {
+ return getPointerTo(ty, cir::toCIRAddressSpace(langAS));
+ }
+
+ cir::PointerType getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) {
+ return getPointerTo(cir::VoidType::get(getContext()), langAS);
+ }
+
+ cir::PointerType getVoidPtrTy(cir::AddressSpace as) {
+ return getPointerTo(cir::VoidType::get(getContext()), as);
}
cir::BoolAttr getCIRBoolAttr(bool state) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
index 925a9a87e267f..03a6a97dc8c2e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.h
@@ -15,6 +15,7 @@
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributeInterfaces.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index f8358de9a1eb9..01dd2106136ab 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -601,6 +601,47 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
}];
}
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_AddressSpaceAttr : CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
+ let builders = [AttrBuilder<(ins "clang::LangAS":$langAS), [{
+ return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
+ }]>];
+
+ let assemblyFormat = [{
+ `` custom<AddressSpaceValue>($value)
+ }];
+
+ let defaultValue = "cir::AddressSpace::Default";
+
+ let extraClassDeclaration = [{
+ bool isLang() const;
+ bool isTarget() const;
+ unsigned getTargetValue() const;
+ unsigned getAsUnsignedValue() const;
+ }];
+
+ let extraClassDefinition = [{
+ unsigned $cppClass::getAsUnsignedValue() const {
+ return static_cast<unsigned>(getValue());
+ }
+
+ bool $cppClass::isLang() const {
+ return cir::isLangAddressSpace(getValue());
+ }
+
+ bool $cppClass::isTarget() const {
+ return cir::isTargetAddressSpace(getValue());
+ }
+
+ unsigned $cppClass::getTargetValue() const {
+ return cir::getTargetAddressSpaceValue(getValue());
+ }
+ }];
+}
+
//===----------------------------------------------------------------------===//
// ConstComplexAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 98b8a31d2a18a..6566b8e771a75 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,4 +35,28 @@ class CIR_DefaultValuedEnumParameter<EnumAttrInfo info, string value = "">
let defaultValue = value;
}
+def CIR_AddressSpace
+ : CIR_I32EnumAttr<
+ "AddressSpace", "address space kind",
+ [I32EnumAttrCase<"Default", 0, "default">,
+ I32EnumAttrCase<"OffloadPrivate", 1, "offload_private">,
+ I32EnumAttrCase<"OffloadLocal", 2, "offload_local">,
+ I32EnumAttrCase<"OffloadGlobal", 3, "offload_global">,
+ I32EnumAttrCase<"OffloadConstant", 4, "offload_constant">,
+ I32EnumAttrCase<"OffloadGeneric", 5, "offload_generic">,
+ I32EnumAttrCase<"Target", 6, "target">]> {
+ let description = [{
+ The `address_space` attribute is used to represent address spaces for
+ pointer types in CIR. It provides a unified model on top of `clang::LangAS`
+ and simplifies the representation of address spaces.
+
+ The `value` parameter is an extensible enum, which encodes target address
+ space as an offset to the last language address space. For that reason, the
+ attribute is implemented as custom AddressSpaceAttr, which provides custom
+ printer and parser for the `value` parameter.
+ }];
+
+ let genSpecializedAttr = 0;
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index bfa165cdd945e..6a2b02ce46cd6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -16,6 +16,8 @@
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/Types.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
namespace cir {
@@ -35,6 +37,42 @@ bool isValidFundamentalIntWidth(unsigned width);
/// void, or abstract types.
bool isSized(mlir::Type ty);
+//===----------------------------------------------------------------------===//
+// AddressSpace helpers
+//===----------------------------------------------------------------------===//
+
+cir::AddressSpace toCIRAddressSpace(clang::LangAS langAS);
+
+constexpr unsigned getAsUnsignedValue(cir::AddressSpace as) {
+ return static_cast<unsigned>(as);
+}
+
+inline constexpr unsigned targetAddressSpaceOffset =
+ cir::getMaxEnumValForAddressSpace();
+
+// Target address space is used for target-specific address spaces that are not
+// part of the enum. Its value is represented as an offset from the maximum
+// value of the enum. Make sure that it is always the last enum value.
+static_assert(getAsUnsignedValue(cir::AddressSpace::Target) ==
+ cir::getMaxEnumValForAddressSpace(),
+ "Target address space must be the last enum value");
+
+constexpr bool isTargetAddressSpace(cir::AddressSpace as) {
+ return getAsUnsignedValue(as) >= cir::getMaxEnumValForAddressSpace();
+}
+
+constexpr bool isLangAddressSpace(cir::AddressSpace as) {
+ return !isTargetAddressSpace(as);
+}
+
+constexpr unsigned getTargetAddressSpaceValue(cir::AddressSpace as) {
+ assert(isTargetAddressSpace(as) && "expected target address space");
+ return getAsUnsignedValue(as) - targetAddressSpaceOffset;
+}
+
+constexpr cir::AddressSpace computeTargetAddressSpace(unsigned v) {
+ return static_cast<cir::AddressSpace>(v + targetAddressSpaceOffset);
+}
} // namespace cir
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 4eec34cb299ab..13edfc5143650 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -14,10 +14,12 @@
#define CLANG_CIR_DIALECT_IR_CIRTYPES_TD
include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "clang/CIR/Dialect/IR/CIREnumAttr.td"
include "clang/CIR/Dialect/IR/CIRTypeConstraints.td"
include "clang/CIR/Interfaces/CIRTypeInterfaces.td"
include "mlir/Interfaces/DataLayoutInterfaces.td"
include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
//===----------------------------------------------------------------------===//
// CIR Types
@@ -226,31 +228,57 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
]> {
let summary = "CIR pointer type";
let description = [{
- The `!cir.ptr` type represents C and C++ pointer types and C++ reference
- types, other than pointers-to-members. The `pointee` type is the type
- pointed to.
+ The `!cir.ptr` type is a typed pointer type. It is used to represent
+ pointers to objects in C/C++. The type of the pointed-to object is given by
+ the `pointee` parameter. The `addrSpace` parameter is an optional address
+ space attribute that specifies the address space of the pointer. If not
+ specified, the pointer is assumed to be in the default address space.
- TODO(CIR): The address space attribute is not yet implemented.
- }];
+ The `!cir.ptr` type can point to any type, including fundamental types,
+ records, arrays, vectors, functions, and other pointers. It can also point
+ to incomplete types, such as incomplete records.
- let parameters = (ins "mlir::Type":$pointee);
+ Note: Data-member pointers and method pointers are represented by
+ `!cir.data_member` and `!cir.method` types, respectively not by
+ `!cir.ptr` type.
- let builders = [
- TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{
- return $_get(pointee.getContext(), pointee);
- }]>,
- TypeBuilder<(ins "mlir::Type":$pointee), [{
- return $_get($_ctxt, pointee);
- }]>
- ];
+ Examples:
- let assemblyFormat = [{
- `<` $pointee `>`
+ ```mlir
+ !cir.ptr<!cir.int<u, 8>>
+ !cir.ptr<!cir.float>
+ !cir.ptr<!cir.record<struct "MyStruct">>
+ !cir.ptr<!cir.record<struct "MyStruct">, addrspace(offload_private)>
+ !cir.ptr<!cir.int<u, 8>, addrspace(target<1>)>
+ ```
}];
- let genVerifyDecl = 1;
+ let parameters = (ins "mlir::Type":$pointee,
+ CIR_DefaultValuedEnumParameter<CIR_AddressSpace,
+ "cir::AddressSpace::Default">:$addrSpace);
let skipDefaultBuilders = 1;
+ let builders = [TypeBuilderWithInferredContext<
+ (ins "mlir::Type":$pointee,
+ CArg<"cir::AddressSpace",
+ "cir::AddressSpace::Default">:$addrSpace),
+ [{
+ return $_get(pointee.getContext(), pointee, addrSpace);
+ }]>,
+ TypeBuilder<
+ (ins "mlir::Type":$pointee,
+ CArg<"cir::AddressSpace",
+ "cir::AddressSpace::Default">:$addrSpace),
+ [{
+ return $_get($_ctxt, pointee, addrSpace);
+ }]>];
+
+ let assemblyFormat = [{
+ `<`
+ $pointee
+ ( `,` `addrspace` `(` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+ `>`
+ }];
let extraClassDeclaration = [{
template <typename ...Types>
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index fa68ad931ba74..44626bbdd1dfa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,8 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
// layout like original CodeGen. The data layout awareness should be done in
// the lowering pass instead.
assert(!cir::MissingFeatures::addressSpace());
- cir::PointerType localVarPtrTy = builder.getPointerTo(ty);
+ cir::PointerType localVarPtrTy =
+ builder.getPointerTo(ty, getCIRAllocaAddressSpace());
mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index cc3ce09be4f95..b95f0404eb8d9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -73,6 +73,8 @@ struct CIRGenTypeCache {
/// The alignment of size_t.
unsigned char SizeAlignInBytes;
+ cir::AddressSpace cirAllocaAddressSpace;
+
clang::CharUnits getSizeAlign() const {
return clang::CharUnits::fromQuantity(SizeAlignInBytes);
}
@@ -80,6 +82,10 @@ struct CIRGenTypeCache {
clang::CharUnits getPointerAlign() const {
return clang::CharUnits::fromQuantity(PointerAlignInBytes);
}
+
+ cir::AddressSpace getCIRAllocaAddressSpace() const {
+ return cirAllocaAddressSpace;
+ }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index bb24933a22ed7..e65896a9ff109 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -417,7 +417,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
mlir::Type pointeeType = convertType(elemTy);
- resultType = builder.getPointerTo(pointeeType);
+ resultType = builder.getPointerTo(pointeeType, elemTy.getAddressSpace());
break;
}
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index a5c548aa2c7c4..1c3ba0b9971b3 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -32,6 +32,8 @@ bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd);
/// if the [[no_unique_address]] attribute would have made them empty.
bool isEmptyRecordForLayout(const ASTContext &context, QualType t);
+class CIRGenFunction;
+
class TargetCIRGenInfo {
std::unique_ptr<ABIInfo> info;
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 95faad6746955..ac3e08c880614 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -43,6 +43,15 @@ parseFloatLiteral(mlir::AsmParser &parser,
mlir::FailureOr<llvm::APFloat> &value,
cir::FPTypeInterface fpType);
+//===----------------------------------------------------------------------===//
+// AddressSpaceAttr
+//===----------------------------------------------------------------------===//
+
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+ cir::AddressSpace &addrSpace);
+
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
mlir::IntegerAttr &value);
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 35b4513c5789f..32254fb1e21c1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -38,6 +38,26 @@ parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> ¶ms,
static void printFuncTypeParams(mlir::AsmPrinter &p,
mlir::ArrayRef<mlir::Type> params,
bool isVarArg);
+//===----------------------------------------------------------------------===//
+// CIR Custom Parser/Printer Signatures
+//===----------------------------------------------------------------------===//
+
+static mlir::ParseResult
+parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> ¶ms,
+ bool &isVarArg);
+
+static void printFuncTypeParams(mlir::AsmPrinter &p,
+ mlir::ArrayRef<mlir::Type> params,
+ bool isVarArg);
+
+//===----------------------------------------------------------------------===//
+// AddressSpace
+//===----------------------------------------------------------------------===//
+
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+ cir::AddressSpace &addrSpace);
+
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
//===----------------------------------------------------------------------===//
// Get autogenerated stuff
@@ -297,6 +317,20 @@ bool RecordType::isLayoutIdentical(const RecordType &other) {
// Data Layout information for types
//===----------------------------------------------------------------------===//
+llvm::TypeSize
+PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
+ ::mlir::DataLayoutEntryListRef params) const {
+ // FIXME: improve this in face of address spaces
+ return llvm::TypeSize::getFixed(64);
+}
+
+uint64_t
+PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
+ ::mlir::DataLayoutEntryListRef params) const {
+ // FIXME: improve this in face of address spaces
+ return 8;
+}
+
llvm::TypeSize
RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
@@ -766,30 +800,93 @@ mlir::LogicalResult cir::VectorType::verify(
}
//===----------------------------------------------------------------------===//
-// PointerType Definitions
-//===----------------------------------------------------------------------===//
-
-llvm::TypeSize
-PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
- ::mlir::DataLayoutEntryListRef params) const {
- // FIXME: improve this in face of address spaces
- return llvm::TypeSize::getFixed(64);
+// AddressSpace definitions
+//===----------------------------------------------------------------------===//
+
+cir::AddressSpace cir::toCIRAddressSpace(clang::LangAS langAS) {
+ using clang::LangAS;
+ switch (langAS) {
+ case LangAS::Default:
+ return AddressSpace::Default;
+ case LangAS::opencl_global:
+ return AddressSpace::OffloadGlobal;
+ case LangAS::opencl_local:
+ case LangAS::cuda_shared:
+ // Local means local among the work-group (OpenCL) or block (CUDA).
+ // All threads inside the kernel can access local memory.
+ return AddressSpace::OffloadLocal;
+ case LangAS::cuda_device:
+ return AddressSpace::OffloadGlobal;
+ case LangAS::opencl_constant:
+ case LangAS::cuda_constant:
+ return AddressSpace::OffloadConstant;
+ case LangAS::opencl_private:
+ return AddressSpace::OffloadPrivate;
+ case LangAS::opencl_generic:
+ return AddressSpace::OffloadGeneric;
+ case LangAS::opencl_global_device:
+ case LangAS::opencl_global_host:
+ case LangAS::sycl_global:
+ case LangAS::sycl_global_device:
+ case LangAS::sycl_global_host:
+ case LangAS::sycl_local:
+ case LangAS::sycl_private:
+ case LangAS::ptr32_sptr:
+ case LangAS::ptr32_uptr:
+ case LangAS::ptr64:
+ case LangAS::hlsl_groupshared:
+ case LangAS::wasm_funcref:
+ llvm_unreachable("NYI");
+ default:
+ // Target address space offset arithmetics
+ return static_cast<cir::AddressSpace>(clang::toTargetAddressSpace(langAS) +
+ cir::getMaxEnumValForAddressSpace());
+ }
}
-uint64_t
-PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
- ::mlir::DataLayoutEntryListRef params) const {
- // FIXME: improve this in face of address spaces
- return 8;
-}
+mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
+ cir::AddressSpace &addrSpace) {
+ llvm::SMLoc loc = p.getCurrentLocation();
+ mlir::FailureOr<cir::AddressSpace> result =
+ mlir::FieldParser<cir::AddressSpace>::parse(p);
+ if (mlir::failed(result))
+ return p.emitError(loc, "expected address space keyword");
+
+ // Address space is either a target address space or a regular one.
+ // - If it is a target address space, we expect a value to follow in the form
+ // of `<value>`, where value is an integer that represents the target address
+ // space value. This value is kept in the address space enum as an offset
+ // from the maximum address space value, which is defined in
+ // `cir::getMaxEnumValForAddressSpace()`. This allows us to use
+ // the same enum for both regular and target address spaces.
+ // - Otherwise, we just use the parsed value.
+ if (cir::isTargetAddressSpace(result.value())) {
+ if (p.parseLess())
+ return p.emitError(loc, "expected '<' after target address space");
+
+ int64_t targetValue;
+ if (p.parseInteger(targetValue) || p.parseGreater())
+ return p.emitError(loc, "expected target address space value");
+
+ addrSpace = cir::computeTargetAddressSpace(targetValue);
+ } else {
+ addrSpace = result.value();
+ }
-mlir::LogicalResult
-PointerType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
- mlir::Type pointee) {
- // TODO(CIR): Verification of the address space goes here.
return mlir::success();
}
+// Prints the address space value in the form of:
+// - `target<value>` for target address spaces
+// - or just the address space name for regular address spaces.
+void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace) {
+ if (cir::isTargetAddressSpace(addrSpace))
+ p << cir::stringifyEnum(cir::AddressSpace::Target) << '<'
+ << cir::getTargetAddressSpaceValue(addrSpace) << '>';
+ else
+ p << cir::stringifyEnum(addrSpace);
+}
+
//===----------------------------------------------------------------------===//
// CIR Dialect
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 876948d53010b..5c674a71d1569 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2298,14 +2298,23 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
return mlir::success();
}
+static unsigned
+getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace) {
+ if (addrSpace == cir::AddressSpace::Default)
+ return 0; // Default address space is always 0 in LLVM.
+
+ if (cir::isTargetAddressSpace(addrSpace))
+ return cir::getTargetAddressSpaceValue(addrSpace);
+
+ llvm_unreachable("CIR AS map is not available");
+}
+
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
mlir::DataLayout &dataLayout) {
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
- // Drop pointee type since LLVM dialect only allows opaque pointers.
- assert(!cir::MissingFeatures::addressSpace());
- unsigned targetAS = 0;
-
- return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
+ unsigned addrSpace =
+ getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace());
+ return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
});
converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
assert(!cir::MissingFeatures::addressSpace());
diff --git a/clang/test/CIR/IR/invalid-addrspace.cir b/clang/test/CIR/IR/invalid-addrspace.cir
new file mode 100644
index 0000000000000..d65599a770bb7
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-addrspace.cir
@@ -0,0 +1,36 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error at below {{expected address space keyword}}
+// expected-error at below {{expected keyword for address space kind}}
+cir.func @address_space1(%p : !cir.ptr<!u64i, addrspace()>) {
+ cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error at below {{expected target address space value}}
+// expected-error at below {{expected integer value}}
+cir.func @address_space2(%p : !cir.ptr<!u64i, addrspace(target<>)>) {
+ cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error at below {{expected '<'}}
+cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) {
+ cir.return
+}
+
+// -----
+
+!u64i = !cir.int<u, 64>
+// expected-error at below {{expected one of [default, offload_private, offload_local, offload_global, offload_constant, offload_generic, target] for address space kind, got: foobar}}
+// expected-error at below {{expected address space keyword}}
+cir.func @address_space4(%p : !cir.ptr<!u64i, addrspace(foobar)>) {
+ cir.return
+}
\ No newline at end of file
diff --git a/clang/test/CIR/address-space.c b/clang/test/CIR/address-space.c
new file mode 100644
index 0000000000000..d131fb84d98dc
--- /dev/null
+++ b/clang/test/CIR/address-space.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+// CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<1>)>
+// LLVM: define dso_local void @foo(ptr addrspace(1) %0)
+void foo(int __attribute__((address_space(1))) *arg) {
+ return;
+}
+
+// CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<0>)>
+// LLVM: define dso_local void @bar(ptr %0)
+void bar(int __attribute__((address_space(0))) *arg) {
+ return;
+}
+
+// CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
+// LLVM: define dso_local void @baz(ptr %0)
+void baz(int *arg) {
+ return;
+}
More information about the cfe-commits
mailing list