[clang] [CIR] Upstream `AddressSpace` support for `PointerType` (PR #161028)
David Rivera via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 2 05:41:14 PDT 2025
https://github.com/RiverDave updated https://github.com/llvm/llvm-project/pull/161028
>From 8c38500340087d2954be7068d8899d6db9090039 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 1/6] [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 3f83c302176c0..6206628a9213c 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 22f069d9cead0..9a1b85a9e8790 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2305,14 +2305,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..369c7c0a45388
--- /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
+}
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;
+}
>From feff1350baae490feb0cba502c2bbcfebbaa3740 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Sun, 28 Sep 2025 17:17:17 -0400
Subject: [PATCH 2/6] Fix formatting on td files
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 10 +++---
.../clang/CIR/Dialect/IR/CIREnumAttr.td | 20 ++++++------
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 32 ++++++++++---------
3 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 01dd2106136ab..69b4dd2143449 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -605,13 +605,15 @@ 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), [{
+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)
+ `(` custom<AddressSpaceValue>($value) `)`
}];
let defaultValue = "cir::AddressSpace::Default";
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 6566b8e771a75..01b2a34c1e663 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,16 +35,16 @@ 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">]> {
+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`
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 13edfc5143650..55f452bd4c27d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -253,30 +253,32 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
```
}];
- let parameters = (ins "mlir::Type":$pointee,
- CIR_DefaultValuedEnumParameter<CIR_AddressSpace,
- "cir::AddressSpace::Default">:$addrSpace);
+ 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),
- [{
+ 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),
- [{
+ TypeBuilder<(ins
+ "mlir::Type":$pointee,
+ CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
return $_get($_ctxt, pointee, addrSpace);
- }]>];
+ }]>
+ ];
let assemblyFormat = [{
`<`
$pointee
- ( `,` `addrspace` `(` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+ ( `,` `addrspace` `(` `` custom<AddressSpaceValue>($addrSpace)^ `)` )?
`>`
}];
>From dce6d6153a7c4c1e638bc0de6390b738433a65bc Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Tue, 30 Sep 2025 13:44:51 -0400
Subject: [PATCH 3/6] Address first round of comments
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 32 +++++++++++++++++++
.../clang/CIR/Dialect/IR/CIREnumAttr.td | 5 ---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 1 -
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 1 +
clang/lib/CIR/CodeGen/TargetInfo.h | 7 ++--
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 4 +--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +-
clang/test/CIR/{ => CodeGen}/address-space.c | 8 +++++
8 files changed, 49 insertions(+), 11 deletions(-)
rename clang/test/CIR/{ => CodeGen}/address-space.c (65%)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 69b4dd2143449..786158411fb10 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -606,6 +606,38 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
//===----------------------------------------------------------------------===//
def CIR_AddressSpaceAttr : CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
+ let summary = "Attribute representing memory address spaces";
+ let description = [{
+ Represents different memory address spaces for pointer types.
+ Address spaces distinguish between different types of memory regions,
+ such as global, local, or constant memory.
+
+ 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.
+
+ CIR supports two categories:
+ - Language address spaces: Predefined spaces like `offload_global`,
+ `offload_constant`, `offload_private` for offload programming models
+ - Target address spaces: Numeric spaces `target<N>` for target-specific
+ memory regions, where N is the address space number
+
+ Examples:
+ ```mlir
+ // Default address space (implicit)
+ !cir.ptr<!s32i>
+
+ // Language-defined offload address spaces
+ !cir.ptr<!s32i, addrspace(offload_global)>
+ !cir.ptr<!s32i, addrspace(offload_constant)>
+ !cir.ptr<!s32i, addrspace(offload_private)>
+
+ // Target-specific numeric address spaces
+ !cir.ptr<!s32i, addrspace(target<1>)>
+ !cir.ptr<!s32i, addrspace(target<10>)>
+ ```
+ }];
let builders = [
AttrBuilder<(ins "clang::LangAS":$langAS), [{
return $_get($_ctxt, cir::toCIRAddressSpace(langAS));
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 01b2a34c1e663..93ad8781a079a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -49,11 +49,6 @@ def CIR_AddressSpace : CIR_I32EnumAttr<
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;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 44626bbdd1dfa..158f1617a46db 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2052,7 +2052,6 @@ mlir::Value CIRGenFunction::emitAlloca(StringRef name, mlir::Type ty,
// CIR uses its own alloca address space rather than follow the target data
// 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, getCIRAllocaAddressSpace());
mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 2bd2729f0b0fb..dc615316dd634 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,6 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
UInt8PtrTy = cir::PointerType::get(UInt8Ty);
+ cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index 1c3ba0b9971b3..180dfa329cba4 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -32,8 +32,6 @@ 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;
@@ -45,6 +43,11 @@ class TargetCIRGenInfo {
/// Returns ABI info helper for the target.
const ABIInfo &getABIInfo() const { return *info; }
+ /// Get the CIR address space for alloca.
+ virtual cir::AddressSpace getCIRAllocaAddressSpace() const {
+ return cir::AddressSpace::Default;
+ }
+
/// Determine whether a call to an unprototyped functions under
/// the given calling convention should use the variadic
/// convention or the non-variadic convention.
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 32254fb1e21c1..b5cec89a51966 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -852,13 +852,13 @@ mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &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.
+ // Address space is either a target address space or a language-specific 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.
+ // the same enum for both language-specific and target address spaces.
// - Otherwise, we just use the parsed value.
if (cir::isTargetAddressSpace(result.value())) {
if (p.parseLess())
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9a1b85a9e8790..2b157856e744f 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2313,7 +2313,7 @@ getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace) {
if (cir::isTargetAddressSpace(addrSpace))
return cir::getTargetAddressSpaceValue(addrSpace);
- llvm_unreachable("CIR AS map is not available");
+ llvm_unreachable("CIR target lowering is NYI");
}
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
diff --git a/clang/test/CIR/address-space.c b/clang/test/CIR/CodeGen/address-space.c
similarity index 65%
rename from clang/test/CIR/address-space.c
rename to clang/test/CIR/CodeGen/address-space.c
index d131fb84d98dc..c67640eb5051a 100644
--- a/clang/test/CIR/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -2,21 +2,29 @@
// 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
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// Test address space 1
// CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<1>)>
// LLVM: define dso_local void @foo(ptr addrspace(1) %0)
+// OGCG: define dso_local void @foo(ptr addrspace(1) noundef %arg)
void foo(int __attribute__((address_space(1))) *arg) {
return;
}
+// Test explicit address space 0 (should be same as default)
// CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<0>)>
// LLVM: define dso_local void @bar(ptr %0)
+// OGCG: define dso_local void @bar(ptr noundef %arg)
void bar(int __attribute__((address_space(0))) *arg) {
return;
}
+// Test default address space (no attribute)
// CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
// LLVM: define dso_local void @baz(ptr %0)
+// OGCG: define dso_local void @baz(ptr noundef %arg)
void baz(int *arg) {
return;
}
>From 89366183451ad93cf558aa5680a82426040d79a4 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Wed, 1 Oct 2025 16:41:59 -0400
Subject: [PATCH 4/6] Refactor address space handling to use
TargetAddressSpaceAttr and update related functionality
---
.../CIR/Dialect/Builder/CIRBaseBuilder.h | 17 ++-
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 69 ++--------
.../clang/CIR/Dialect/IR/CIREnumAttr.td | 19 ---
clang/include/clang/CIR/Dialect/IR/CIRTypes.h | 34 +----
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 15 +--
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenTypeCache.h | 7 +-
clang/lib/CIR/CodeGen/TargetInfo.h | 7 +-
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 7 +-
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 120 ++++++------------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 15 +--
clang/test/CIR/CodeGen/address-space.c | 8 +-
clang/test/CIR/IR/invalid-addrspace.cir | 23 +---
14 files changed, 95 insertions(+), 250 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 6206628a9213c..b875fac9b7969 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
#include "clang/AST/CharUnits.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -129,19 +130,29 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return cir::PointerType::get(ty);
}
- cir::PointerType getPointerTo(mlir::Type ty, cir::AddressSpace as) {
+ cir::PointerType getPointerTo(mlir::Type ty, cir::TargetAddressSpaceAttr as) {
return cir::PointerType::get(ty, as);
}
cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS langAS) {
- return getPointerTo(ty, cir::toCIRAddressSpace(langAS));
+ if (langAS == clang::LangAS::Default) // Default address space.
+ return getPointerTo(ty);
+
+ if (clang::isTargetAddressSpace(langAS)) {
+ unsigned addrSpace = clang::toTargetAddressSpace(langAS);
+ auto asAttr = cir::TargetAddressSpaceAttr::get(
+ getContext(), getUI32IntegerAttr(addrSpace));
+ return getPointerTo(ty, asAttr);
+ }
+
+ llvm_unreachable("language-specific address spaces NYI");
}
cir::PointerType getVoidPtrTy(clang::LangAS langAS = clang::LangAS::Default) {
return getPointerTo(cir::VoidType::get(getContext()), langAS);
}
- cir::PointerType getVoidPtrTy(cir::AddressSpace as) {
+ cir::PointerType getVoidPtrTy(cir::TargetAddressSpaceAttr as) {
return getPointerTo(cir::VoidType::get(getContext()), as);
}
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 786158411fb10..6a0a2bde7368a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -602,78 +602,25 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
}
//===----------------------------------------------------------------------===//
-// AddressSpaceAttr
+// TargetAddressSpaceAttr
//===----------------------------------------------------------------------===//
-def CIR_AddressSpaceAttr : CIR_EnumAttr<CIR_AddressSpace, "address_space"> {
- let summary = "Attribute representing memory address spaces";
+def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
+ "target_address_space"> {
+ let summary = "Attribute representing a target-specific numeric address space";
let description = [{
- Represents different memory address spaces for pointer types.
- Address spaces distinguish between different types of memory regions,
- such as global, local, or constant memory.
+ Represents a target-specific numeric address space for pointer types.
- 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.
-
- CIR supports two categories:
- - Language address spaces: Predefined spaces like `offload_global`,
- `offload_constant`, `offload_private` for offload programming models
- - Target address spaces: Numeric spaces `target<N>` for target-specific
- memory regions, where N is the address space number
-
- Examples:
+ Example:
```mlir
- // Default address space (implicit)
- !cir.ptr<!s32i>
-
- // Language-defined offload address spaces
- !cir.ptr<!s32i, addrspace(offload_global)>
- !cir.ptr<!s32i, addrspace(offload_constant)>
- !cir.ptr<!s32i, addrspace(offload_private)>
-
// Target-specific numeric address spaces
!cir.ptr<!s32i, addrspace(target<1>)>
!cir.ptr<!s32i, addrspace(target<10>)>
```
}];
- 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());
- }
- }];
+ let parameters = (ins "mlir::IntegerAttr":$value);
+ let assemblyFormat = "`<` `target` `<` $value `>` `>`";
}
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
index 93ad8781a079a..98b8a31d2a18a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td
@@ -35,23 +35,4 @@ 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.
- }];
-
- 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 6a2b02ce46cd6..c1a063875f480 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -17,6 +17,7 @@
#include "mlir/IR/Types.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "clang/Basic/AddressSpaces.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Interfaces/CIRTypeInterfaces.h"
@@ -41,38 +42,9 @@ bool isSized(mlir::Type ty);
// AddressSpace helpers
//===----------------------------------------------------------------------===//
-cir::AddressSpace toCIRAddressSpace(clang::LangAS langAS);
+/// Returns the integer value of a CIR address space for LLVM.
+unsigned getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr);
-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 55f452bd4c27d..e2f64f84d266f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -248,16 +248,15 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
!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>)>
+ !cir.ptr<!cir.int<u, 8>, target_address_space(1)>
+ !cir.ptr<!cir.record<struct "MyStruct">, target_address_space(5)>
```
}];
let parameters = (ins
"mlir::Type":$pointee,
- CIR_DefaultValuedEnumParameter<
- CIR_AddressSpace,
- "cir::AddressSpace::Default"
+ OptionalParameter<
+ "cir::TargetAddressSpaceAttr"
>:$addrSpace
);
@@ -265,12 +264,12 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
let builders = [
TypeBuilderWithInferredContext<(ins
"mlir::Type":$pointee,
- CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
+ CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{
return $_get(pointee.getContext(), pointee, addrSpace);
}]>,
TypeBuilder<(ins
"mlir::Type":$pointee,
- CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{
+ CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{
return $_get($_ctxt, pointee, addrSpace);
}]>
];
@@ -278,7 +277,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
let assemblyFormat = [{
`<`
$pointee
- ( `,` `addrspace` `(` `` custom<AddressSpaceValue>($addrSpace)^ `)` )?
+ ( `,` ` ` custom<TargetAddressSpace>($addrSpace)^ )?
`>`
}];
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 158f1617a46db..16cfc96022497 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,7 @@ 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.
cir::PointerType localVarPtrTy =
- builder.getPointerTo(ty, getCIRAllocaAddressSpace());
+ builder.getPointerTo(ty, getASTAllocaAddressSpace());
mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index dc615316dd634..fc26d1f2e1f63 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,7 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
UInt8PtrTy = cir::PointerType::get(UInt8Ty);
- cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
+ ASTAllocaAddressSpace = getTargetCIRGenInfo().getASTAllocaAddressSpace();
UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index b95f0404eb8d9..3e261c4b82fb4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
#include "clang/AST/CharUnits.h"
+#include "clang/Basic/AddressSpaces.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
namespace clang::CIRGen {
@@ -73,7 +74,7 @@ struct CIRGenTypeCache {
/// The alignment of size_t.
unsigned char SizeAlignInBytes;
- cir::AddressSpace cirAllocaAddressSpace;
+ LangAS ASTAllocaAddressSpace;
clang::CharUnits getSizeAlign() const {
return clang::CharUnits::fromQuantity(SizeAlignInBytes);
@@ -83,9 +84,7 @@ struct CIRGenTypeCache {
return clang::CharUnits::fromQuantity(PointerAlignInBytes);
}
- cir::AddressSpace getCIRAllocaAddressSpace() const {
- return cirAllocaAddressSpace;
- }
+ LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index 180dfa329cba4..b23b0581b5c14 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -16,6 +16,7 @@
#include "ABIInfo.h"
#include "CIRGenTypes.h"
+#include "clang/Basic/AddressSpaces.h"
#include <memory>
#include <utility>
@@ -43,10 +44,8 @@ class TargetCIRGenInfo {
/// Returns ABI info helper for the target.
const ABIInfo &getABIInfo() const { return *info; }
- /// Get the CIR address space for alloca.
- virtual cir::AddressSpace getCIRAllocaAddressSpace() const {
- return cir::AddressSpace::Default;
- }
+ /// Get the AST address space for alloca.
+ virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
/// Determine whether a call to an unprototyped functions under
/// the given calling convention should use the variadic
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index ac3e08c880614..5ba05a04a56b1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -47,10 +47,11 @@ parseFloatLiteral(mlir::AsmParser &parser,
// AddressSpaceAttr
//===----------------------------------------------------------------------===//
-mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
- cir::AddressSpace &addrSpace);
+mlir::ParseResult
+parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr);
-void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+ cir::TargetAddressSpaceAttr attr);
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 b5cec89a51966..b37fb9b0db18c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -13,6 +13,7 @@
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "mlir/IR/DialectImplementation.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypesDetails.h"
#include "clang/CIR/MissingFeatures.h"
@@ -54,10 +55,11 @@ static void printFuncTypeParams(mlir::AsmPrinter &p,
// AddressSpace
//===----------------------------------------------------------------------===//
-mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p,
- cir::AddressSpace &addrSpace);
+mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+ cir::TargetAddressSpaceAttr &attr);
-void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace);
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+ cir::TargetAddressSpaceAttr attr);
//===----------------------------------------------------------------------===//
// Get autogenerated stuff
@@ -800,91 +802,45 @@ mlir::LogicalResult cir::VectorType::verify(
}
//===----------------------------------------------------------------------===//
-// 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());
- }
+// TargetAddressSpace definitions
+//===----------------------------------------------------------------------===//
+
+// Convert from TargetAddressSpaceAttr to the actual integer address space.
+unsigned cir::getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr) {
+ if (!attr)
+ return 0; // Default address space is 0 in LLVM.
+ return attr.getValue().getUInt();
}
-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 language-specific 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 language-specific 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::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+ cir::TargetAddressSpaceAttr &attr) {
+ if (failed(p.parseKeyword("target_address_space")))
+ return mlir::failure();
+
+ if (failed(p.parseLParen()))
+ return mlir::failure();
+
+ int64_t targetValue;
+ if (failed(p.parseInteger(targetValue)))
+ return p.emitError(p.getCurrentLocation(),
+ "expected integer address space value");
+
+ if (failed(p.parseRParen()))
+ return p.emitError(p.getCurrentLocation(),
+ "expected ')' after address space value");
+ mlir::MLIRContext *context = p.getBuilder().getContext();
+ auto intTy = mlir::IntegerType::get(context, 32);
+ attr = cir::TargetAddressSpaceAttr::get(
+ context, mlir::IntegerAttr::get(intTy, targetValue));
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);
+// The custom printer for the `addrspace` parameter in `!cir.ptr`.
+// in the format of `target_address_space(N)`.
+void printTargetAddressSpace(mlir::AsmPrinter &p,
+ cir::TargetAddressSpaceAttr attr) {
+ p << "target_address_space(" << attr.getValue().getUInt() << ")";
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 2b157856e744f..82521f6567dc3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -32,6 +32,7 @@
#include "mlir/Transforms/DialectConversion.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/LoweringHelpers.h"
#include "clang/CIR/MissingFeatures.h"
@@ -2305,22 +2306,10 @@ 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 target lowering is NYI");
-}
-
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
mlir::DataLayout &dataLayout) {
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
- unsigned addrSpace =
- getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace());
+ unsigned addrSpace = cir::getTargetAddrSpaceFromAttr(type.getAddrSpace());
return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
});
converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
diff --git a/clang/test/CIR/CodeGen/address-space.c b/clang/test/CIR/CodeGen/address-space.c
index c67640eb5051a..ebb53df7305a6 100644
--- a/clang/test/CIR/CodeGen/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -6,7 +6,7 @@
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
// Test address space 1
-// CIR: cir.func dso_local {{@.*foo.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<1>)>
+// CIR: cir.func dso_local @foo(%arg0: !cir.ptr<!s32i, target_address_space(1)>
// LLVM: define dso_local void @foo(ptr addrspace(1) %0)
// OGCG: define dso_local void @foo(ptr addrspace(1) noundef %arg)
void foo(int __attribute__((address_space(1))) *arg) {
@@ -14,7 +14,7 @@ void foo(int __attribute__((address_space(1))) *arg) {
}
// Test explicit address space 0 (should be same as default)
-// CIR: cir.func dso_local {{@.*bar.*}}(%arg0: !cir.ptr<!s32i, addrspace(target<0>)>
+// CIR: cir.func dso_local @bar(%arg0: !cir.ptr<!s32i, target_address_space(0)>
// LLVM: define dso_local void @bar(ptr %0)
// OGCG: define dso_local void @bar(ptr noundef %arg)
void bar(int __attribute__((address_space(0))) *arg) {
@@ -22,9 +22,9 @@ void bar(int __attribute__((address_space(0))) *arg) {
}
// Test default address space (no attribute)
-// CIR: cir.func dso_local {{@.*baz.*}}(%arg0: !cir.ptr<!s32i>
+// CIR: cir.func dso_local @baz(%arg0: !cir.ptr<!s32i>
// LLVM: define dso_local void @baz(ptr %0)
// OGCG: define dso_local void @baz(ptr noundef %arg)
void baz(int *arg) {
return;
-}
+}
\ No newline at end of file
diff --git a/clang/test/CIR/IR/invalid-addrspace.cir b/clang/test/CIR/IR/invalid-addrspace.cir
index 369c7c0a45388..8f188b840bdec 100644
--- a/clang/test/CIR/IR/invalid-addrspace.cir
+++ b/clang/test/CIR/IR/invalid-addrspace.cir
@@ -3,34 +3,25 @@
// -----
!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()>) {
+// expected-error @below {{expected 'target_address_space'}}
+cir.func @address_space1(%p : !cir.ptr<!u64i, foobar>) {
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<>)>) {
+// expected-error at below {{expected '('}}
+cir.func @address_space2(%p : !cir.ptr<!u64i, target_address_space>) {
cir.return
}
// -----
!u64i = !cir.int<u, 64>
-// expected-error at below {{expected '<'}}
-cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) {
+// expected-error at +2 {{expected integer value}}
+// expected-error at below {{expected integer address space value}}
+cir.func @address_space3(%p : !cir.ptr<!u64i, target_address_space()>) {
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
-}
>From b5180ef0c6b9a9cb242773c464cc293e90c02572 Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Wed, 1 Oct 2025 17:06:43 -0400
Subject: [PATCH 5/6] fix formatting once again.
---
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 5ba05a04a56b1..3484c59df4ece 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -47,11 +47,11 @@ parseFloatLiteral(mlir::AsmParser &parser,
// AddressSpaceAttr
//===----------------------------------------------------------------------===//
-mlir::ParseResult
-parseTargetAddressSpace(mlir::AsmParser &p, cir::TargetAddressSpaceAttr &attr);
+mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
+ cir::TargetAddressSpaceAttr &attr);
void printTargetAddressSpace(mlir::AsmPrinter &p,
- cir::TargetAddressSpaceAttr attr);
+ cir::TargetAddressSpaceAttr attr);
static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser,
mlir::IntegerAttr &value);
>From 9cd2c5476d0ff413e7fa45dc31315acaba05f84e Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Thu, 2 Oct 2025 08:27:17 -0400
Subject: [PATCH 6/6] Apply 2nd round of suggestions
---
clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 9 +++++++--
clang/include/clang/CIR/Dialect/IR/CIRTypes.h | 7 -------
clang/include/clang/CIR/Dialect/IR/CIRTypes.td | 7 +------
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenTypeCache.h | 6 ++++--
clang/lib/CIR/CodeGen/TargetInfo.h | 8 ++++++--
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 12 ++----------
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 3 ++-
clang/test/CIR/CodeGen/address-space.c | 2 +-
10 files changed, 25 insertions(+), 33 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 6a0a2bde7368a..7714750a53d44 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -607,9 +607,14 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
"target_address_space"> {
- let summary = "Attribute representing a target-specific numeric address space";
+ let summary = "Represents a target-specific numeric address space";
let description = [{
- Represents a target-specific numeric address space for pointer types.
+ The TargetAddressSpaceAttr represents a target-specific numeric address space,
+ corresponding to the LLVM IR `addressspace` qualifier and the clang
+ `address_space` attribute.
+
+ A value of zero represents the default address space. The semantics of non-zero
+ address spaces are target-specific.
Example:
```mlir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
index c1a063875f480..45f646f1c9dfa 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -38,13 +38,6 @@ bool isValidFundamentalIntWidth(unsigned width);
/// void, or abstract types.
bool isSized(mlir::Type ty);
-//===----------------------------------------------------------------------===//
-// AddressSpace helpers
-//===----------------------------------------------------------------------===//
-
-/// Returns the integer value of a CIR address space for LLVM.
-unsigned getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr);
-
} // namespace cir
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index e2f64f84d266f..313184764f536 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -238,10 +238,6 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
records, arrays, vectors, functions, and other pointers. It can also point
to incomplete types, such as incomplete records.
- Note: Data-member pointers and method pointers are represented by
- `!cir.data_member` and `!cir.method` types, respectively not by
- `!cir.ptr` type.
-
Examples:
```mlir
@@ -256,8 +252,7 @@ def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
let parameters = (ins
"mlir::Type":$pointee,
OptionalParameter<
- "cir::TargetAddressSpaceAttr"
- >:$addrSpace
+ "cir::TargetAddressSpaceAttr">:$addrSpace
);
let skipDefaultBuilders = 1;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 16cfc96022497..158f1617a46db 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2053,7 +2053,7 @@ 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.
cir::PointerType localVarPtrTy =
- builder.getPointerTo(ty, getASTAllocaAddressSpace());
+ builder.getPointerTo(ty, getCIRAllocaAddressSpace());
mlir::IntegerAttr alignIntAttr = cgm.getSize(alignment);
mlir::Value addr;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index fc26d1f2e1f63..dc615316dd634 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -76,7 +76,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
SInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);
UInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);
UInt8PtrTy = cir::PointerType::get(UInt8Ty);
- ASTAllocaAddressSpace = getTargetCIRGenInfo().getASTAllocaAddressSpace();
+ cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();
UInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);
UInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);
UInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
index 3e261c4b82fb4..273ec7f06b4b5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -74,7 +74,7 @@ struct CIRGenTypeCache {
/// The alignment of size_t.
unsigned char SizeAlignInBytes;
- LangAS ASTAllocaAddressSpace;
+ cir::TargetAddressSpaceAttr cirAllocaAddressSpace;
clang::CharUnits getSizeAlign() const {
return clang::CharUnits::fromQuantity(SizeAlignInBytes);
@@ -84,7 +84,9 @@ struct CIRGenTypeCache {
return clang::CharUnits::fromQuantity(PointerAlignInBytes);
}
- LangAS getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
+ cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const {
+ return cirAllocaAddressSpace;
+ }
};
} // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h
index b23b0581b5c14..91a5531208bbe 100644
--- a/clang/lib/CIR/CodeGen/TargetInfo.h
+++ b/clang/lib/CIR/CodeGen/TargetInfo.h
@@ -16,6 +16,8 @@
#include "ABIInfo.h"
#include "CIRGenTypes.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
#include "clang/Basic/AddressSpaces.h"
#include <memory>
@@ -44,8 +46,10 @@ class TargetCIRGenInfo {
/// Returns ABI info helper for the target.
const ABIInfo &getABIInfo() const { return *info; }
- /// Get the AST address space for alloca.
- virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; }
+ /// Get the address space for alloca.
+ virtual cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const {
+ return nullptr;
+ }
/// Determine whether a call to an unprototyped functions under
/// the given calling convention should use the variadic
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index b37fb9b0db18c..a3bafe8b6f380 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -805,13 +805,6 @@ mlir::LogicalResult cir::VectorType::verify(
// TargetAddressSpace definitions
//===----------------------------------------------------------------------===//
-// Convert from TargetAddressSpaceAttr to the actual integer address space.
-unsigned cir::getTargetAddrSpaceFromAttr(cir::TargetAddressSpaceAttr attr) {
- if (!attr)
- return 0; // Default address space is 0 in LLVM.
- return attr.getValue().getUInt();
-}
-
mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
cir::TargetAddressSpaceAttr &attr) {
if (failed(p.parseKeyword("target_address_space")))
@@ -820,7 +813,7 @@ mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
if (failed(p.parseLParen()))
return mlir::failure();
- int64_t targetValue;
+ int32_t targetValue;
if (failed(p.parseInteger(targetValue)))
return p.emitError(p.getCurrentLocation(),
"expected integer address space value");
@@ -830,9 +823,8 @@ mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p,
"expected ')' after address space value");
mlir::MLIRContext *context = p.getBuilder().getContext();
- auto intTy = mlir::IntegerType::get(context, 32);
attr = cir::TargetAddressSpaceAttr::get(
- context, mlir::IntegerAttr::get(intTy, targetValue));
+ context, p.getBuilder().getUI32IntegerAttr(targetValue));
return mlir::success();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 82521f6567dc3..0aa18c8c017bc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2309,7 +2309,8 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
mlir::DataLayout &dataLayout) {
converter.addConversion([&](cir::PointerType type) -> mlir::Type {
- unsigned addrSpace = cir::getTargetAddrSpaceFromAttr(type.getAddrSpace());
+ unsigned addrSpace =
+ type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0;
return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);
});
converter.addConversion([&](cir::VPtrType type) -> mlir::Type {
diff --git a/clang/test/CIR/CodeGen/address-space.c b/clang/test/CIR/CodeGen/address-space.c
index ebb53df7305a6..a334b8a2907e4 100644
--- a/clang/test/CIR/CodeGen/address-space.c
+++ b/clang/test/CIR/CodeGen/address-space.c
@@ -27,4 +27,4 @@ void bar(int __attribute__((address_space(0))) *arg) {
// OGCG: define dso_local void @baz(ptr noundef %arg)
void baz(int *arg) {
return;
-}
\ No newline at end of file
+}
More information about the cfe-commits
mailing list