diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 3f83c302176c0..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,8 +130,30 @@ 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::TargetAddressSpaceAttr as) { + return cir::PointerType::get(ty, as); + } + + cir::PointerType getPointerTo(mlir::Type ty, clang::LangAS 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::TargetAddressSpaceAttr 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..7714750a53d44 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -601,6 +601,33 @@ def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> { }]; } +//===----------------------------------------------------------------------===// +// TargetAddressSpaceAttr +//===----------------------------------------------------------------------===// + +def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace", + "target_address_space"> { + let summary = "Represents a target-specific numeric address space"; + let description = [{ + 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 + // Target-specific numeric address spaces + !cir.ptr)> + !cir.ptr)> + ``` + }]; + + let parameters = (ins "mlir::IntegerAttr":$value); + let assemblyFormat = "`<` `target` `<` $value `>` `>`"; +} + //===----------------------------------------------------------------------===// // ConstComplexAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index bfa165cdd945e..45f646f1c9dfa 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -16,6 +16,9 @@ #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/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Interfaces/CIRTypeInterfaces.h" namespace cir { diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 4eec34cb299ab..313184764f536 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,32 +228,54 @@ 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. + + Examples: + + ```mlir + !cir.ptr> + !cir.ptr + !cir.ptr> + !cir.ptr, target_address_space(1)> + !cir.ptr, target_address_space(5)> + ``` }]; - let parameters = (ins "mlir::Type":$pointee); + let parameters = (ins + "mlir::Type":$pointee, + OptionalParameter< + "cir::TargetAddressSpaceAttr">:$addrSpace + ); + let skipDefaultBuilders = 1; let builders = [ - TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee), [{ - return $_get(pointee.getContext(), pointee); + TypeBuilderWithInferredContext<(ins + "mlir::Type":$pointee, + CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{ + return $_get(pointee.getContext(), pointee, addrSpace); }]>, - TypeBuilder<(ins "mlir::Type":$pointee), [{ - return $_get($_ctxt, pointee); + TypeBuilder<(ins + "mlir::Type":$pointee, + CArg<"cir::TargetAddressSpaceAttr", "nullptr">:$addrSpace), [{ + return $_get($_ctxt, pointee, addrSpace); }]> ]; let assemblyFormat = [{ - `<` $pointee `>` + `<` + $pointee + ( `,` ` ` custom($addrSpace)^ )? + `>` }]; - let genVerifyDecl = 1; - - let skipDefaultBuilders = 1; - let extraClassDeclaration = [{ template bool isPtrTo() const { diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 7a6c084f51cd7..d8948a896586f 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -209,6 +209,7 @@ struct MissingFeatures { static bool dataLayoutTypeIsSized() { return false; } static bool dataLayoutTypeAllocSize() { return false; } static bool dataLayoutTypeStoreSize() { return false; } + static bool dataLayoutPtrHandlingBasedOnLangAS() { return false; } static bool deferredCXXGlobalInit() { return false; } static bool deleteArray() { return false; } static bool devirtualizeMemberFunction() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index fa68ad931ba74..158f1617a46db 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2052,8 +2052,8 @@ 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); + cir::PointerType localVarPtrTy = + 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 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/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index cc3ce09be4f95..273ec7f06b4b5 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,6 +74,8 @@ struct CIRGenTypeCache { /// The alignment of size_t. unsigned char SizeAlignInBytes; + cir::TargetAddressSpaceAttr cirAllocaAddressSpace; + clang::CharUnits getSizeAlign() const { return clang::CharUnits::fromQuantity(SizeAlignInBytes); } @@ -80,6 +83,10 @@ struct CIRGenTypeCache { clang::CharUnits getPointerAlign() const { return clang::CharUnits::fromQuantity(PointerAlignInBytes); } + + cir::TargetAddressSpaceAttr 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..dbb0312c76040 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 #include @@ -43,6 +44,11 @@ class TargetCIRGenInfo { /// Returns ABI info helper for the target. const ABIInfo &getABIInfo() const { return *info; } + /// Get the address space for alloca. + virtual cir::TargetAddressSpaceAttr getCIRAllocaAddressSpace() const { + return {}; + } + /// 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/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 95faad6746955..3484c59df4ece 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -43,6 +43,16 @@ parseFloatLiteral(mlir::AsmParser &parser, mlir::FailureOr &value, cir::FPTypeInterface fpType); +//===----------------------------------------------------------------------===// +// AddressSpaceAttr +//===----------------------------------------------------------------------===// + +mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, + cir::TargetAddressSpaceAttr &attr); + +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 35b4513c5789f..5897352829891 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" @@ -38,6 +39,27 @@ parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector ¶ms, static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef params, bool isVarArg); +//===----------------------------------------------------------------------===// +// CIR Custom Parser/Printer Signatures +//===----------------------------------------------------------------------===// + +static mlir::ParseResult +parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector ¶ms, + bool &isVarArg); + +static void printFuncTypeParams(mlir::AsmPrinter &p, + mlir::ArrayRef params, + bool isVarArg); + +//===----------------------------------------------------------------------===// +// AddressSpace +//===----------------------------------------------------------------------===// + +mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, + cir::TargetAddressSpaceAttr &attr); + +void printTargetAddressSpace(mlir::AsmPrinter &p, + cir::TargetAddressSpaceAttr attr); //===----------------------------------------------------------------------===// // Get autogenerated stuff @@ -297,6 +319,22 @@ 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 + assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS()); + 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 + assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS()); + return 8; +} + llvm::TypeSize RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, mlir::DataLayoutEntryListRef params) const { @@ -766,30 +804,39 @@ mlir::LogicalResult cir::VectorType::verify( } //===----------------------------------------------------------------------===// -// PointerType Definitions +// TargetAddressSpace 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); -} +mlir::ParseResult parseTargetAddressSpace(mlir::AsmParser &p, + cir::TargetAddressSpaceAttr &attr) { + if (failed(p.parseKeyword("target_address_space"))) + return mlir::failure(); -uint64_t -PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, - ::mlir::DataLayoutEntryListRef params) const { - // FIXME: improve this in face of address spaces - return 8; -} + if (failed(p.parseLParen())) + return mlir::failure(); -mlir::LogicalResult -PointerType::verify(llvm::function_ref emitError, - mlir::Type pointee) { - // TODO(CIR): Verification of the address space goes here. + int32_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(); + attr = cir::TargetAddressSpaceAttr::get( + context, p.getBuilder().getUI32IntegerAttr(targetValue)); return mlir::success(); } +// 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() << ")"; +} + //===----------------------------------------------------------------------===// // CIR Dialect //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 22f069d9cead0..0aa18c8c017bc 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" @@ -2308,11 +2309,9 @@ mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite( 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 = + type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0; + 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/CodeGen/address-space.c b/clang/test/CIR/CodeGen/address-space.c new file mode 100644 index 0000000000000..a334b8a2907e4 --- /dev/null +++ b/clang/test/CIR/CodeGen/address-space.c @@ -0,0 +1,30 @@ +// 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 +// 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 +// 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 +// 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 +// LLVM: define dso_local void @baz(ptr %0) +// OGCG: define dso_local void @baz(ptr noundef %arg) +void baz(int *arg) { + return; +} diff --git a/clang/test/CIR/IR/invalid-addrspace.cir b/clang/test/CIR/IR/invalid-addrspace.cir new file mode 100644 index 0000000000000..8f188b840bdec --- /dev/null +++ b/clang/test/CIR/IR/invalid-addrspace.cir @@ -0,0 +1,27 @@ +// RUN: cir-opt %s -verify-diagnostics -split-input-file + +// ----- + +!u64i = !cir.int +// expected-error @below {{expected 'target_address_space'}} +cir.func @address_space1(%p : !cir.ptr) { + cir.return +} + +// ----- + +!u64i = !cir.int +// expected-error@below {{expected '('}} +cir.func @address_space2(%p : !cir.ptr) { + cir.return +} + +// ----- + +!u64i = !cir.int +// expected-error@+2 {{expected integer value}} +// expected-error@below {{expected integer address space value}} +cir.func @address_space3(%p : !cir.ptr) { + cir.return +} +