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 <davidriv...@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@below {{expected address space keyword}} +// expected-error@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@below {{expected target address space value}} +// expected-error@below {{expected integer value}} +cir.func @address_space2(%p : !cir.ptr<!u64i, addrspace(target<>)>) { + cir.return +} + +// ----- + +!u64i = !cir.int<u, 64> +// expected-error@below {{expected '<'}} +cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) { + cir.return +} + +// ----- + +!u64i = !cir.int<u, 64> +// expected-error@below {{expected one of [default, offload_private, offload_local, offload_global, offload_constant, offload_generic, target] for address space kind, got: foobar}} +// expected-error@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 <davidriv...@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 <davidriv...@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 <davidriv...@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@below {{expected address space keyword}} -// expected-error@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@below {{expected target address space value}} -// expected-error@below {{expected integer value}} -cir.func @address_space2(%p : !cir.ptr<!u64i, addrspace(target<>)>) { +// expected-error@below {{expected '('}} +cir.func @address_space2(%p : !cir.ptr<!u64i, target_address_space>) { cir.return } // ----- !u64i = !cir.int<u, 64> -// expected-error@below {{expected '<'}} -cir.func @address_space3(%p : !cir.ptr<!u64i, addrspace(target)>) { +// expected-error@+2 {{expected integer value}} +// expected-error@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@below {{expected one of [default, offload_private, offload_local, offload_global, offload_constant, offload_generic, target] for address space kind, got: foobar}} -// expected-error@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 <davidriv...@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 6cf211b2276ee99b26cd34149d6be51bdb247c9c Mon Sep 17 00:00:00 2001 From: David Rivera <davidriv...@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 | 7 ------- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 3 ++- clang/test/CIR/CodeGen/address-space.c | 2 +- 10 files changed, 23 insertions(+), 30 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..070ce41403857 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"))) 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 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits