diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 45bd1a8ebb8f..cb404205f019 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -93,27 +93,24 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return cir::IntType::get(getContext(), N, true); } - cir::AddressSpaceAttr getAddrSpaceAttr(clang::LangAS langAS) { - if (langAS == clang::LangAS::Default) - return {}; - return cir::AddressSpaceAttr::get(getContext(), langAS); + cir::PointerType getPointerTo(mlir::Type ty) { + return cir::PointerType::get(ty); } - cir::PointerType getPointerTo(mlir::Type ty, - cir::AddressSpaceAttr cirAS = {}) { - return cir::PointerType::get(ty, cirAS); + 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, getAddrSpaceAttr(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::AddressSpaceAttr cirAS) { - return getPointerTo(cir::VoidType::get(getContext()), cirAS); + cir::PointerType getVoidPtrTy(cir::AddressSpace as) { + return getPointerTo(cir::VoidType::get(getContext()), as); } cir::MethodAttr getMethodAttr(cir::MethodType ty, cir::FuncOp methodFuncOp) { @@ -396,7 +393,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global, bool threadLocal = false) { return create( - loc, getPointerTo(global.getSymType(), global.getAddrSpaceAttr()), + loc, getPointerTo(global.getSymType(), global.getAddrSpace()), global.getName(), threadLocal); } @@ -774,9 +771,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { auto methodFuncInputTypes = methodFuncTy.getInputs(); auto objectPtrTy = mlir::cast(objectPtr.getType()); - auto objectPtrAddrSpace = mlir::cast_if_present( - objectPtrTy.getAddrSpace()); - auto adjustedThisTy = getVoidPtrTy(objectPtrAddrSpace); + auto adjustedThisTy = getVoidPtrTy(objectPtrTy.getAddrSpace()); llvm::SmallVector calleeFuncInputTypes{adjustedThisTy}; calleeFuncInputTypes.insert(calleeFuncInputTypes.end(), diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 0def5436f7b9..5ea69e8db0b3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -14,7 +14,7 @@ #define MLIR_CIR_DIALECT_CIR_ATTRS include "mlir/IR/BuiltinAttributeInterfaces.td" -include "mlir/IR/EnumAttr.td" +include "clang/CIR/Dialect/IR/CIREnumAttr.td" include "clang/CIR/Dialect/IR/CIRDialect.td" include "clang/CIR/Dialect/IR/CIRAttrConstraints.td" @@ -45,21 +45,6 @@ class CIR_TypedAttr traits = []> let assemblyFormat = [{}]; } -class CIR_I32EnumAttr cases> - : I32EnumAttr { - let cppNamespace = "::cir"; -} - -class CIR_I64EnumAttr cases> - : I64EnumAttr { - let cppNamespace = "::cir"; -} - -class CIR_EnumAttr traits = []> - : EnumAttr { - let assemblyFormat = "`<` $value `>`"; -} - class CIRUnitAttr traits = []> : CIR_Attr { let returnType = "bool"; @@ -972,133 +957,41 @@ def DynamicCastInfoAttr // AddressSpaceAttr //===----------------------------------------------------------------------===// -def AS_OffloadPrivate : I32EnumAttrCase<"offload_private", 1>; -def AS_OffloadLocal : I32EnumAttrCase<"offload_local", 2>; -def AS_OffloadGlobal : I32EnumAttrCase<"offload_global", 3>; -def AS_OffloadConstant : I32EnumAttrCase<"offload_constant", 4>; -def AS_OffloadGeneric : I32EnumAttrCase<"offload_generic", 5>; -def AS_Target : I32EnumAttrCase<"target", 6>; - -def AddressSpaceAttr : CIR_Attr<"AddressSpace", "addrspace"> { - - let summary = "Address space attribute for pointer types"; - let description = [{ - The address space attribute is used in pointer types. It essentially - provides a unified model on top of `clang::LangAS`, rather than LLVM address - spaces. - - The representation is further simplified: `LangAS::Default` is encoded as - a null attribute; many address spaces from different offloading languages - are unified as `offload_*`; etc. - - The meaning of `value` parameter is defined as an extensible enum `Kind`, - which encodes target AS as offset to the last language AS. - }]; - - let parameters = (ins "int32_t":$value); - - let assemblyFormat = [{ - `<` $value `>` - }]; - +def CIR_AddressSpaceAttr : CIR_EnumAttr { let builders = [ AttrBuilder<(ins "clang::LangAS":$langAS), [{ - assert(langAS != clang::LangAS::Default && - "Default address space is encoded as null attribute"); - return $_get($_ctxt, getValueFromLangAS(langAS).value()); + return $_get($_ctxt, cir::toCIRAddressSpace(langAS)); }]> ]; - let cppNamespace = "::cir"; - - // The following codes implement these conversions: - // clang::LangAS -> int32_t <-> text-form CIR - - // CIR_PointerType manipulates the parse- and stringify- methods to provide - // simplified assembly format `custom`. - - list langASCases = [ - AS_OffloadPrivate, AS_OffloadLocal, AS_OffloadGlobal, AS_OffloadConstant, - AS_OffloadGeneric - ]; + let assemblyFormat = [{ + `` custom($value) + }]; - I32EnumAttrCase targetASCase = AS_Target; + let defaultValue = "cir::AddressSpace::Default"; let extraClassDeclaration = [{ - static constexpr char kTargetKeyword[] = "}]#targetASCase.symbol#[{"; - static constexpr int32_t kFirstTargetASValue = }]#targetASCase.value#[{; - bool isLang() const; bool isTarget() const; unsigned getTargetValue() const; - - /// Convert a clang LangAS to its corresponding CIR AS storage value. This - /// helper does not perform any language-specific mappings (e.g. determining - /// the default AS for offloading languages), so these must be handled in - /// the caller. - static std::optional getValueFromLangAS(clang::LangAS v); - - /// Helper methods for the assembly format `custom`. - static std::optional parseValueFromString(llvm::StringRef s); - static std::optional stringifyValue(int32_t v); - - struct Kind { - }]#!interleave( - !foreach(case, langASCases, - "static constexpr int32_t "#case.symbol#" = "#case.value#";" - ), "\n" - )#[{ - }; + unsigned getAsUnsignedValue() const; }]; let extraClassDefinition = [{ + unsigned $cppClass::getAsUnsignedValue() const { + return static_cast(getValue()); + } + bool $cppClass::isLang() const { - return !isTarget(); + return cir::isLangAddressSpace(getValue()); } bool $cppClass::isTarget() const { - return getValue() >= kFirstTargetASValue; + return cir::isTargetAddressSpace(getValue()); } unsigned $cppClass::getTargetValue() const { - assert(isTarget() && "Not a target address space"); - return getValue() - kFirstTargetASValue; - } - - std::optional - $cppClass::parseValueFromString(llvm::StringRef str) { - return llvm::StringSwitch<::std::optional>(str) - }] - # - !interleave( - !foreach(case, langASCases, - ".Case(\""#case.symbol# "\", "#case.value # ")\n" - ), - "\n" - ) - # - [{ - // Target address spaces are not parsed here - .Default(std::nullopt); - } - - std::optional - $cppClass::stringifyValue(int32_t value) { - switch (value) { - }] - # - !interleave( - !foreach(case, langASCases, - "case "#case.value - # ": return \""#case.symbol # "\";" ), - "\n" - ) - # - [{ - default: - // Target address spaces are not processed here - return std::nullopt; - } + return cir::getTargetAddressSpaceValue(getValue()); } }]; } diff --git a/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td new file mode 100644 index 000000000000..98b8a31d2a18 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIREnumAttr.td @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the CIR dialect enum base classes +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD +#define CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD + +include "mlir/IR/EnumAttr.td" + +class CIR_I32EnumAttr cases> + : I32EnumAttr { + let cppNamespace = "::cir"; +} + +class CIR_I64EnumAttr cases> + : I64EnumAttr { + let cppNamespace = "::cir"; +} + +class CIR_EnumAttr traits = []> + : EnumAttr { + let assemblyFormat = "`<` $value `>`"; +} + +class CIR_DefaultValuedEnumParameter + : EnumParameter { + let defaultValue = value; +} + +#endif // CLANG_CIR_DIALECT_IR_CIRENUMATTR_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 81a45d148453..a2b2e2f5a4fb 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2347,7 +2347,6 @@ def ForOp : CIR_Op<"for", [CIR_LoopOpInterface, NoRegionArguments]> { // currently handy as part of forwarding appropriate linkage types for LLVM // lowering, specially useful for C++ support. - /// An enumeration for the kinds of linkage for global values. def CIR_GlobalLinkageKind : CIR_I32EnumAttr< "GlobalLinkageKind", "linkage kind", [ @@ -2396,10 +2395,11 @@ def CIR_TLSModel : CIR_I32EnumAttr<"TLS_Model", "TLS model", [ I32EnumAttrCase<"LocalExec", 3, "tls_local_exec"> ]>; -def GlobalOp : CIR_Op<"global", - [DeclareOpInterfaceMethods, - DeclareOpInterfaceMethods, - NoRegionArguments]> { +def CIR_GlobalOp : CIR_Op<"global", [ + DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods, + NoRegionArguments +]> { let summary = "Declares or defines a global variable"; let description = [{ The `cir.global` operation declares or defines a named global variable. @@ -2431,26 +2431,33 @@ def GlobalOp : CIR_Op<"global", // Note that both sym_name and sym_visibility are tied to Symbol trait. // TODO: sym_visibility can possibly be represented by implementing the // necessary Symbol's interface in terms of linkage instead. - let arguments = (ins SymbolNameAttr:$sym_name, - DefaultValuedAttr< - CIR_VisibilityAttr, - "VisibilityKind::Default" - >:$global_visibility, - OptionalAttr:$sym_visibility, - TypeAttr:$sym_type, - CIR_GlobalLinkageKind:$linkage, - OptionalAttr:$addr_space, - OptionalAttr:$tls_model, - // Note this can also be a FlatSymbolRefAttr - OptionalAttr:$initial_value, - UnitAttr:$comdat, - UnitAttr:$constant, - UnitAttr:$dso_local, - OptionalAttr:$alignment, - OptionalAttr:$ast, - OptionalAttr:$section, - OptionalAttr:$annotations); + let arguments = (ins + SymbolNameAttr:$sym_name, + DefaultValuedAttr< + CIR_VisibilityAttr, + "VisibilityKind::Default" + >:$global_visibility, + OptionalAttr:$sym_visibility, + TypeAttr:$sym_type, + CIR_GlobalLinkageKind:$linkage, + DefaultValuedAttr< + CIR_AddressSpaceAttr, + "AddressSpace::Default" + >:$addr_space, + OptionalAttr:$tls_model, + // Note this can also be a FlatSymbolRefAttr + OptionalAttr:$initial_value, + UnitAttr:$comdat, + UnitAttr:$constant, + UnitAttr:$dso_local, + OptionalAttr:$alignment, + OptionalAttr:$ast, + OptionalAttr:$section, + OptionalAttr:$annotations + ); + let regions = (region AnyRegion:$ctorRegion, AnyRegion:$dtorRegion); + let assemblyFormat = [{ ($sym_visibility^)? (`` $global_visibility^)? @@ -2459,7 +2466,7 @@ def GlobalOp : CIR_Op<"global", (`comdat` $comdat^)? ($tls_model^)? (`dso_local` $dso_local^)? - (`addrspace` `(` custom($addr_space)^ `)`)? + ( `addrspace` `(` $addr_space^ `)` )? $sym_name custom($sym_type, $initial_value, $ctorRegion, $dtorRegion) ($annotations^)? @@ -2483,7 +2490,7 @@ def GlobalOp : CIR_Op<"global", // CIR defaults to external linkage. CArg<"cir::GlobalLinkageKind", "cir::GlobalLinkageKind::ExternalLinkage">:$linkage, - CArg<"cir::AddressSpaceAttr", "{}">:$addrSpace, + CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace, CArg<"llvm::function_ref", "nullptr">:$ctorBuilder, CArg<"llvm::function_ref", diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h index 4a0fe7f40ff5..b7cf95d08ca8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#ifndef MLIR_DIALECT_CIR_IR_CIRTYPES_H_ -#define MLIR_DIALECT_CIR_IR_CIRTYPES_H_ +#ifndef CLANG_CIR_DIALECT_IR_CIRTYPES_H +#define CLANG_CIR_DIALECT_IR_CIRTYPES_H #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Types.h" @@ -30,12 +30,44 @@ bool isValidFundamentalIntWidth(unsigned width); // Returns true if the type is a CIR sized type. bool isSized(mlir::Type ty); -} // namespace cir +//===----------------------------------------------------------------------===// +// AddressSpace helpers +//===----------------------------------------------------------------------===// + +cir::AddressSpace toCIRAddressSpace(clang::LangAS langAS); + +constexpr unsigned getAsUnsignedValue(cir::AddressSpace as) { + return static_cast(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"); -mlir::ParseResult parseAddrSpaceAttribute(mlir::AsmParser &p, - mlir::Attribute &addrSpaceAttr); -void printAddrSpaceAttribute(mlir::AsmPrinter &p, - mlir::Attribute addrSpaceAttr); +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(v + TargetAddressSpaceOffset); +} + +} // namespace cir //===----------------------------------------------------------------------===// // CIR Dialect Tablegen'd Types @@ -45,9 +77,11 @@ namespace cir { #include "clang/CIR/Dialect/IR/CIRTypeConstraints.h.inc" +class AddressSpaceAttr; + } // namespace cir #define GET_TYPEDEF_CLASSES #include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc" -#endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_ +#endif // CLANG_CIR_DIALECT_IR_CIRTYPES_H diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index b09d477bab3e..47cb8a302465 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -14,6 +14,7 @@ #define MLIR_CIR_DIALECT_CIR_TYPES 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/ASTAttrInterfaces.td" include "clang/CIR/Interfaces/CIRTypeInterfaces.td" @@ -199,45 +200,90 @@ def CIR_ComplexType : CIR_Type<"Complex", "complex", [ // PointerType //===----------------------------------------------------------------------===// +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; +} + def CIR_PointerType : CIR_Type<"Pointer", "ptr", [ DeclareTypeInterfaceMethods, DeclareTypeInterfaceMethods ]> { let summary = "CIR pointer type"; let description = [{ - `CIR.ptr` is a type returned by any op generating a pointer in C++. + 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. + + 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. + + 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 + !cir.ptr> + !cir.ptr + !cir.ptr> + !cir.ptr, addrspace(offload_private)> + !cir.ptr, addrspace(target<1>)> + ``` }]; let parameters = (ins "mlir::Type":$pointee, - // FIXME(cir): Currently unable to directly use AddressSpaceAttr because of - // cyclic dep. Workaround with the top type and verifier. - OptionalParameter<"mlir::Attribute">:$addrSpace + CIR_DefaultValuedEnumParameter< + CIR_AddressSpace, + "cir::AddressSpace::Default" + >:$addrSpace ); + let skipDefaultBuilders = 1; let builders = [ TypeBuilderWithInferredContext<(ins "mlir::Type":$pointee, - CArg<"mlir::Attribute", "{}">:$addrSpace), [{ - return $_get(pointee.getContext(), pointee, addrSpace); + CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{ + return $_get(pointee.getContext(), pointee, addrSpace); }]>, TypeBuilder<(ins "mlir::Type":$pointee, - CArg<"mlir::Attribute", "{}">:$addrSpace), [{ - return $_get($_ctxt, pointee, addrSpace); + CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace), [{ + return $_get($_ctxt, pointee, addrSpace); }]> ]; let assemblyFormat = [{ - `<` $pointee ( `,` `addrspace` `(` - custom($addrSpace)^ - `)` )? `>` + `<` + $pointee + ( `,` `addrspace` `(` custom($addrSpace)^ `)` )? + `>` }]; - let genVerifyDecl = 1; - - let skipDefaultBuilders = 1; - let extraClassDeclaration = [{ template bool isPtrTo() const { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index 672bc4fa0717..437db1a7fdd8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -17,10 +17,8 @@ mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc, auto arrayTy = ::mlir::dyn_cast(arrayPtrTy.getPointee()); if (arrayTy) { - auto addrSpace = ::mlir::cast_if_present( - arrayPtrTy.getAddrSpace()); cir::PointerType flatPtrTy = - getPointerTo(arrayTy.getElementType(), addrSpace); + getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace()); return create(loc, flatPtrTy, cir::CastKind::array_to_ptrdecay, arrayPtr); } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index d83e04ec22b1..82f5e6fa2b9b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -745,7 +745,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { [[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp module, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConst, cir::GlobalLinkageKind linkage, - cir::AddressSpaceAttr addrSpace = {}) { + cir::AddressSpace addrSpace = cir::AddressSpace::Default) { mlir::OpBuilder::InsertionGuard guard(*this); setInsertionPointToStart(module.getBody()); return create(loc, name, type, isConst, linkage, addrSpace); @@ -754,11 +754,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { /// Creates a versioned global variable. If the symbol is already taken, an ID /// will be appended to the symbol. The returned global must always be queried /// for its name so it can be referenced correctly. - [[nodiscard]] cir::GlobalOp - createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, - mlir::StringRef name, mlir::Type type, bool isConst, - cir::GlobalLinkageKind linkage, - cir::AddressSpaceAttr addrSpace = {}) { + [[nodiscard]] cir::GlobalOp createVersionedGlobal( + mlir::ModuleOp module, mlir::Location loc, mlir::StringRef name, + mlir::Type type, bool isConst, cir::GlobalLinkageKind linkage, + cir::AddressSpace addrSpace = cir::AddressSpace::Default) { // Create a unique name if the given name is already taken. std::string uniqueName; if (unsigned version = GlobalsVersioning[name.str()]++) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 00d835f2360a..683a438e7a75 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -1652,8 +1652,8 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // the AST level this is handled within CreateTempAlloca et al., but for the // builtin / dynamic alloca we have to handle it here. assert(!cir::MissingFeatures::addressSpace()); - auto AAS = getCIRAllocaAddressSpace(); - auto EAS = builder.getAddrSpaceAttr( + cir::AddressSpace AAS = getCIRAllocaAddressSpace(); + cir::AddressSpace EAS = cir::toCIRAddressSpace( E->getType()->getPointeeType().getAddressSpace()); if (EAS != AAS) { assert(false && "Non-default address space for alloca NYI"); diff --git a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp index fbc34255c6a4..dba29d8cab83 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp @@ -314,7 +314,8 @@ mlir::Operation *CIRGenNVCUDARuntime::getKernelHandle(cir::FuncOp fn, fn->getLoc(), globalName, fn.getFunctionType(), [&] { return CIRGenModule::createGlobalOp( cgm, fn->getLoc(), globalName, - builder.getPointerTo(fn.getFunctionType()), true, /* addrSpace=*/{}, + builder.getPointerTo(fn.getFunctionType()), true, + cir::AddressSpace::Default, /*insertPoint=*/nullptr, fn.getLinkage()); }); diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index f04631e22aee..47293b081bf0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDataLayout.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" @@ -470,8 +471,7 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &D, Name = getStaticDeclName(*this, D); mlir::Type LTy = getTypes().convertTypeForMem(Ty); - cir::AddressSpaceAttr AS = - builder.getAddrSpaceAttr(getGlobalVarAddressSpace(&D)); + cir::AddressSpace AS = cir::toCIRAddressSpace(getGlobalVarAddressSpace(&D)); // OpenCL variables in local address space and CUDA shared // variables cannot have an initializer. @@ -586,7 +586,7 @@ cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( // Given those constraints, thread in the GetGlobalOp and update it // directly. GVAddr.getAddr().setType( - getBuilder().getPointerTo(Init.getType(), GV.getAddrSpaceAttr())); + getBuilder().getPointerTo(Init.getType(), GV.getAddrSpace())); } bool NeedsDtor = diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 2ab018aa82f6..fc7ad46937d4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/GlobalDecl.h" #include "clang/Basic/Builtins.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" @@ -921,9 +922,8 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &CGF, const Expr *E, auto V = CGF.CGM.getAddrOfGlobalVar(VD); auto RealVarTy = CGF.convertTypeForMem(VD->getType()); - cir::PointerType realPtrTy = CGF.getBuilder().getPointerTo( - RealVarTy, cast_if_present( - cast(V.getType()).getAddrSpace())); + cir::PointerType realPtrTy = cir::PointerType::get( + RealVarTy, cast(V.getType()).getAddrSpace()); if (realPtrTy != V.getType()) V = CGF.getBuilder().createBitcast(V.getLoc(), V, realPtrTy); @@ -2027,9 +2027,10 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *E) { case CK_AddressSpaceConversion: { LValue LV = emitLValue(E->getSubExpr()); QualType DestTy = getContext().getPointerType(E->getType()); - auto SrcAS = - builder.getAddrSpaceAttr(E->getSubExpr()->getType().getAddressSpace()); - auto DestAS = builder.getAddrSpaceAttr(E->getType().getAddressSpace()); + cir::AddressSpace SrcAS = + cir::toCIRAddressSpace(E->getSubExpr()->getType().getAddressSpace()); + cir::AddressSpace DestAS = + cir::toCIRAddressSpace(E->getType().getAddressSpace()); mlir::Value V = getTargetHooks().performAddrSpaceCast( *this, LV.getPointer(), SrcAS, DestAS, convertType(DestTy)); return makeAddrLValue(Address(V, convertTypeForMem(E->getType()), @@ -3080,8 +3081,7 @@ Address CIRGenFunction::CreateTempAlloca(mlir::Type Ty, CharUnits Align, // be different from the type defined by the language. For example, // in C++ the auto variables are in the default address space. Therefore // cast alloca to the default address space when necessary. - if (auto ASTAS = - builder.getAddrSpaceAttr(CGM.getLangTempAllocaAddressSpace()); + if (auto ASTAS = cir::toCIRAddressSpace(CGM.getLangTempAllocaAddressSpace()); getCIRAllocaAddressSpace() != ASTAS) { llvm_unreachable("Requires address space cast which is NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp index e16d169d19f5..cdd7a9a42408 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp @@ -426,10 +426,8 @@ void AggExprEmitter::emitArrayInit(Address DestPtr, cir::ArrayType AType, QualType elementPtrType = CGF.getContext().getPointerType(elementType); auto cirElementType = CGF.convertType(elementType); - auto cirAddrSpace = mlir::cast_if_present( - DestPtr.getType().getAddrSpace()); - auto cirElementPtrType = - CGF.getBuilder().getPointerTo(cirElementType, cirAddrSpace); + auto cirElementPtrType = CGF.getBuilder().getPointerTo( + cirElementType, DestPtr.getType().getAddrSpace()); auto loc = CGF.getLoc(ExprToVisit->getSourceRange()); // Cast from cir.ptr to cir.ptr diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 94606775c6b5..fcd169187704 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1659,10 +1659,10 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. - auto SrcAS = CGF.builder.getAddrSpaceAttr( + cir::AddressSpace SrcAS = cir::toCIRAddressSpace( E->getType()->getPointeeType().getAddressSpace()); - auto DestAS = CGF.builder.getAddrSpaceAttr( - DestTy->getPointeeType().getAddressSpace()); + cir::AddressSpace DestAS = + cir::toCIRAddressSpace(DestTy->getPointeeType().getAddressSpace()); return CGF.CGM.getTargetCIRGenInfo().performAddrSpaceCast( CGF, Visit(E), SrcAS, DestAS, convertType(DestTy)); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 09d2609cd7b3..701cc3a1ad46 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -825,7 +825,7 @@ mlir::Value CIRGenModule::getGlobalValue(const Decl *d) { cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm, mlir::Location loc, StringRef name, mlir::Type t, bool isConstant, - cir::AddressSpaceAttr addrSpace, + cir::AddressSpace addrSpace, mlir::Operation *insertPoint, cir::GlobalLinkageKind linkage) { cir::GlobalOp g; @@ -996,10 +996,8 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp oldSym, cir::GlobalOp newSym) { // If the types does not match, update all references to Old to the new type. auto oldTy = oldSym.getSymType(); auto newTy = newSym.getSymType(); - cir::AddressSpaceAttr oldAS = oldSym.getAddrSpaceAttr(); - cir::AddressSpaceAttr newAS = newSym.getAddrSpaceAttr(); // TODO(cir): If the AS differs, we should also update all references. - if (oldAS != newAS) { + if (oldSym.getAddrSpace() != newSym.getAddrSpace()) { llvm_unreachable("NYI"); } @@ -1098,9 +1096,9 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty, entry = dyn_cast_or_null(v); } - cir::AddressSpaceAttr cirAS = builder.getAddrSpaceAttr(langAS); + cir::AddressSpace cirAS = cir::toCIRAddressSpace(langAS); if (entry) { - auto entryCIRAS = entry.getAddrSpaceAttr(); + cir::AddressSpace entryCIRAS = entry.getAddrSpace(); if (WeakRefReferences.erase(entry)) { if (d && !d->hasAttr()) { auto lt = cir::GlobalLinkageKind::ExternalLinkage; @@ -1154,7 +1152,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty, return entry; } - auto declCIRAS = builder.getAddrSpaceAttr(getGlobalVarAddressSpace(d)); + auto declCIRAS = cir::toCIRAddressSpace(getGlobalVarAddressSpace(d)); // TODO(cir): do we need to strip pointer casts for Entry? auto loc = getLoc(d->getSourceRange()); @@ -1274,7 +1272,7 @@ mlir::Value CIRGenModule::getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty, bool tlsAccess = d->getTLSKind() != VarDecl::TLS_None; auto g = getOrCreateCIRGlobal(d, ty, isForDefinition); - auto ptrTy = builder.getPointerTo(g.getSymType(), g.getAddrSpaceAttr()); + auto ptrTy = builder.getPointerTo(g.getSymType(), g.getAddrSpace()); return builder.create(getLoc(d->getSourceRange()), ptrTy, g.getSymName(), tlsAccess); } @@ -1288,7 +1286,8 @@ CIRGenModule::getAddrOfGlobalVarAttr(const VarDecl *d, mlir::Type ty, ty = getTypes().convertTypeForMem(astTy); auto globalOp = getOrCreateCIRGlobal(d, ty, isForDefinition); - auto ptrTy = builder.getPointerTo(globalOp.getSymType()); + auto ptrTy = + builder.getPointerTo(globalOp.getSymType(), globalOp.getAddrSpace()); return builder.getGlobalViewAttr(ptrTy, globalOp); } @@ -1758,14 +1757,14 @@ static cir::GlobalOp generateStringLiteral(mlir::Location loc, mlir::TypedAttr c, cir::GlobalLinkageKind lt, CIRGenModule &cgm, StringRef globalName, CharUnits alignment) { - cir::AddressSpaceAttr addrSpaceAttr = - cgm.getBuilder().getAddrSpaceAttr(cgm.getGlobalConstantAddressSpace()); + cir::AddressSpace addrSpace = + cir::toCIRAddressSpace(cgm.getGlobalConstantAddressSpace()); // Create a global variable for this string // FIXME(cir): check for insertion point in module level. auto gv = CIRGenModule::createGlobalOp(cgm, loc, globalName, c.getType(), !cgm.getLangOpts().WritableStrings, - addrSpaceAttr); + addrSpace); // Set up extra information and add to the module gv.setAlignmentAttr(cgm.getSize(alignment)); @@ -1861,8 +1860,8 @@ CIRGenModule::getAddrOfConstantStringFromLiteral(const StringLiteral *s, auto gv = getGlobalForStringLiteral(s, name); auto arrayTy = mlir::dyn_cast(gv.getSymType()); assert(arrayTy && "String literal must be array"); - auto ptrTy = getBuilder().getPointerTo(arrayTy.getElementType(), - gv.getAddrSpaceAttr()); + auto ptrTy = + getBuilder().getPointerTo(arrayTy.getElementType(), gv.getAddrSpace()); return builder.getGlobalViewAttr(ptrTy, gv); } @@ -1972,7 +1971,7 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *expr, linkage = cir::GlobalLinkageKind::InternalLinkage; } } - auto targetAS = builder.getAddrSpaceAttr(addrSpace); + cir::AddressSpace targetAS = cir::toCIRAddressSpace(addrSpace); auto loc = getLoc(expr->getSourceRange()); auto gv = createGlobalOp(*this, loc, name, type, isConstant, targetAS, diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index e96220ea395a..50d8c3cda18c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -260,7 +260,8 @@ class CIRGenModule : public CIRGenTypeCache { static cir::GlobalOp createGlobalOp( CIRGenModule &cgm, mlir::Location loc, llvm::StringRef name, mlir::Type t, - bool isConstant = false, cir::AddressSpaceAttr addrSpace = {}, + bool isConstant = false, + cir::AddressSpace addrSpace = cir::AddressSpace::Default, mlir::Operation *insertPoint = nullptr, cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage); diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h index 551bc74861b6..c83d60673f23 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h @@ -106,7 +106,7 @@ struct CIRGenTypeCache { unsigned char SizeAlignInBytes; }; - cir::AddressSpaceAttr CIRAllocaAddressSpace; + cir::AddressSpace CIRAllocaAddressSpace; clang::CharUnits getSizeSize() const { return clang::CharUnits::fromQuantity(SizeSizeInBytes); @@ -121,7 +121,7 @@ struct CIRGenTypeCache { return clang::CharUnits::fromQuantity(PointerAlignInBytes); } - cir::AddressSpaceAttr getCIRAllocaAddressSpace() const { + cir::AddressSpace getCIRAllocaAddressSpace() const { return CIRAllocaAddressSpace; } }; diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 17129bb813fb..d7e57cfc5a87 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -266,10 +266,8 @@ class CommonSPIRTargetCIRGenInfo : public TargetCIRGenInfo { CommonSPIRTargetCIRGenInfo(std::unique_ptr ABIInfo) : TargetCIRGenInfo(std::move(ABIInfo)) {} - cir::AddressSpaceAttr getCIRAllocaAddressSpace() const override { - return cir::AddressSpaceAttr::get( - &getABIInfo().CGT.getMLIRContext(), - cir::AddressSpaceAttr::Kind::offload_private); + cir::AddressSpace getCIRAllocaAddressSpace() const override { + return cir::AddressSpace::OffloadPrivate; } cir::CallingConv getOpenCLKernelCallingConv() const override { @@ -664,8 +662,8 @@ TargetCIRGenInfo::getGlobalVarAddressSpace(CIRGenModule &CGM, } mlir::Value TargetCIRGenInfo::performAddrSpaceCast( - CIRGenFunction &CGF, mlir::Value Src, cir::AddressSpaceAttr SrcAddr, - cir::AddressSpaceAttr DestAddr, mlir::Type DestTy, bool IsNonNull) const { + CIRGenFunction &CGF, mlir::Value Src, cir::AddressSpace SrcAddr, + cir::AddressSpace DestAddr, mlir::Type DestTy, bool IsNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. if (auto globalOp = Src.getDefiningOp()) diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index b941cbb5742f..21f3b0a0637d 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -101,10 +101,8 @@ class TargetCIRGenInfo { const clang::VarDecl *D) const; /// Get the CIR address space for alloca. - virtual cir::AddressSpaceAttr getCIRAllocaAddressSpace() const { - // Return the null attribute, which means the target does not care about the - // alloca address space. - return {}; + virtual cir::AddressSpace getCIRAllocaAddressSpace() const { + return cir::AddressSpace::Default; } /// Perform address space cast of an expression of pointer type. @@ -114,8 +112,8 @@ class TargetCIRGenInfo { /// \param DestTy is the destination pointer type. /// \param IsNonNull is the flag indicating \p V is known to be non null. virtual mlir::Value performAddrSpaceCast(CIRGenFunction &CGF, mlir::Value V, - cir::AddressSpaceAttr SrcAddr, - cir::AddressSpaceAttr DestAddr, + cir::AddressSpace SrcAddr, + cir::AddressSpace DestAddr, mlir::Type DestTy, bool IsNonNull = false) const; diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 30cc71d7b234..e18676c23e4d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -72,6 +72,19 @@ static mlir::ParseResult parseConstPtr(mlir::AsmParser &parser, static void printConstPtr(mlir::AsmPrinter &p, mlir::IntegerAttr value); +//===----------------------------------------------------------------------===// +// AddressSpaceAttr +//===----------------------------------------------------------------------===// + +mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, + cir::AddressSpace &addrSpace); + +void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace); + +//===----------------------------------------------------------------------===// +// Tablegen defined attributes +//===----------------------------------------------------------------------===// + #define GET_ATTRDEF_CLASSES #include "clang/CIR/Dialect/IR/CIROpsAttributes.cpp.inc" @@ -562,52 +575,6 @@ LogicalResult DynamicCastInfoAttr::verify( return success(); } -//===----------------------------------------------------------------------===// -// AddressSpaceAttr definitions -//===----------------------------------------------------------------------===// - -std::optional -AddressSpaceAttr::getValueFromLangAS(clang::LangAS langAS) { - using clang::LangAS; - switch (langAS) { - case LangAS::Default: - // Default address space should be encoded as a null attribute. - return std::nullopt; - case LangAS::opencl_global: - return Kind::offload_global; - 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 Kind::offload_local; - case LangAS::cuda_device: - return Kind::offload_global; - case LangAS::opencl_constant: - case LangAS::cuda_constant: - return Kind::offload_constant; - case LangAS::opencl_private: - return Kind::offload_private; - case LangAS::opencl_generic: - return Kind::offload_generic; - 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 clang::toTargetAddressSpace(langAS) + kFirstTargetASValue; - } -} - //===----------------------------------------------------------------------===// // CIR Dialect //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index fe70e8c9236b..5f97a5de0c67 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2105,16 +2105,6 @@ static void printConstant(OpAsmPrinter &p, Attribute value) { p.printAttribute(value); } -static ParseResult -parseGlobalOpAddrSpace(OpAsmParser &p, cir::AddressSpaceAttr &addrSpaceAttr) { - return parseAddrSpaceAttribute(p, addrSpaceAttr); -} - -static void printGlobalOpAddrSpace(OpAsmPrinter &p, cir::GlobalOp op, - cir::AddressSpaceAttr addrSpaceAttr) { - printAddrSpaceAttribute(p, addrSpaceAttr); -} - static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op, TypeAttr type, Attribute initAttr, mlir::Region &ctorRegion, @@ -2287,7 +2277,7 @@ LogicalResult cir::GlobalOp::verify() { void cir::GlobalOp::build( OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name, Type sym_type, bool isConstant, cir::GlobalLinkageKind linkage, - cir::AddressSpaceAttr addrSpace, + cir::AddressSpace addrSpace, function_ref ctorBuilder, function_ref dtorBuilder) { odsState.addAttribute(getSymNameAttrName(odsState.name), @@ -2302,8 +2292,9 @@ void cir::GlobalOp::build( cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage); odsState.addAttribute(getLinkageAttrName(odsState.name), linkageAttr); - if (addrSpace) - odsState.addAttribute(getAddrSpaceAttrName(odsState.name), addrSpace); + odsState.addAttribute( + getAddrSpaceAttrName(odsState.name), + cir::AddressSpaceAttr::get(odsBuilder.getContext(), addrSpace)); Region *ctorRegion = odsState.addRegion(); if (ctorBuilder) { @@ -2366,10 +2357,10 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { << "' does not reference a valid cir.global or cir.func"; mlir::Type symTy; - cir::AddressSpaceAttr symAddrSpace{}; + cir::AddressSpace symAddrSpace{}; if (auto g = dyn_cast(op)) { symTy = g.getSymType(); - symAddrSpace = g.getAddrSpaceAttr(); + symAddrSpace = g.getAddrSpace(); // Verify that for thread local global access, the global needs to // be marked with tls bits. if (getTls() && !g.getTlsModel()) diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 4d35b4aebbf0..09ad0f3b9f51 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 "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypesDetails.h" #include "clang/CIR/MissingFeatures.h" @@ -61,10 +62,15 @@ parseFuncTypeParams(mlir::AsmParser &p, llvm::SmallVector ¶ms, static void printFuncTypeParams(mlir::AsmPrinter &p, mlir::ArrayRef params, bool isVarArg); -static mlir::ParseResult parsePointerAddrSpace(mlir::AsmParser &p, - mlir::Attribute &addrSpaceAttr); -static void printPointerAddrSpace(mlir::AsmPrinter &p, - mlir::Attribute addrSpaceAttr); + +//===----------------------------------------------------------------------===// +// AddressSpace +//===----------------------------------------------------------------------===// + +mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, + cir::AddressSpace &addrSpace); + +void printAddressSpaceValue(mlir::AsmPrinter &p, cir::AddressSpace addrSpace); //===----------------------------------------------------------------------===// // Get autogenerated stuff @@ -897,67 +903,91 @@ MethodType::getABIAlignment(const mlir::DataLayout &dataLayout, } //===----------------------------------------------------------------------===// -// PointerType Definitions +// AddressSpace definitions //===----------------------------------------------------------------------===// -mlir::LogicalResult -PointerType::verify(llvm::function_ref emitError, - mlir::Type pointee, mlir::Attribute addrSpace) { - if (addrSpace && !mlir::isa(addrSpace)) - return emitError() << "unexpected addrspace attribute type"; - return mlir::success(); -} - -mlir::ParseResult parseAddrSpaceAttribute(mlir::AsmParser &p, - mlir::Attribute &addrSpaceAttr) { - using cir::AddressSpaceAttr; - auto attrLoc = p.getCurrentLocation(); - - llvm::StringRef addrSpaceKind; - if (mlir::failed(p.parseOptionalKeyword(&addrSpaceKind))) - return p.emitError(attrLoc, "expected keyword for addrspace kind"); - - if (addrSpaceKind == AddressSpaceAttr::kTargetKeyword) { - int64_t targetValue = -1; - if (p.parseLess() || p.parseInteger(targetValue) || p.parseGreater()) { - return mlir::failure(); - } - addrSpaceAttr = AddressSpaceAttr::get( - p.getContext(), AddressSpaceAttr::kFirstTargetASValue + targetValue); - } else { - std::optional value = - AddressSpaceAttr::parseValueFromString(addrSpaceKind); - // not target AS, must be wrong keyword if no value - if (!value.has_value()) - return p.emitError(attrLoc, - "invalid addrspace kind keyword: " + addrSpaceKind); - - addrSpaceAttr = AddressSpaceAttr::get(p.getContext(), *value); +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(clang::toTargetAddressSpace(langAS) + + cir::getMaxEnumValForAddressSpace()); } - - return mlir::success(); } -void printAddrSpaceAttribute(mlir::AsmPrinter &p, - mlir::Attribute rawAddrSpaceAttr) { - using cir::AddressSpaceAttr; - auto addrSpaceAttr = mlir::cast(rawAddrSpaceAttr); - if (addrSpaceAttr.isTarget()) { - p << AddressSpaceAttr::kTargetKeyword << "<" - << addrSpaceAttr.getTargetValue() << ">"; +mlir::ParseResult parseAddressSpaceValue(mlir::AsmParser &p, + cir::AddressSpace &addrSpace) { + llvm::SMLoc loc = p.getCurrentLocation(); + mlir::FailureOr result = + mlir::FieldParser::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 ``, 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 { - p << AddressSpaceAttr::stringifyValue(addrSpaceAttr.getValue()); + addrSpace = result.value(); } -} -mlir::ParseResult parsePointerAddrSpace(mlir::AsmParser &p, - mlir::Attribute &addrSpaceAttr) { - return parseAddrSpaceAttribute(p, addrSpaceAttr); + return mlir::success(); } -void printPointerAddrSpace(mlir::AsmPrinter &p, - mlir::Attribute rawAddrSpaceAttr) { - printAddrSpaceAttribute(p, rawAddrSpaceAttr); +// Prints the address space value in the form of: +// - `target` 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); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp index ff9c9dc295b9..32f660024125 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp @@ -375,7 +375,7 @@ mlir::Value createCoercedNonFundamental(mlir::Value src, mlir::Type ty, auto oldAlloca = mlir::dyn_cast(addr.getDefiningOp()); auto alloca = bld.create( - src.getLoc(), bld.getType(ty), ty, + src.getLoc(), cir::PointerType::get(ty), ty, /*name=*/llvm::StringRef(""), oldAlloca.getAlignmentAttr()); auto tySize = LF.LM.getDataLayout().getTypeStoreSize(ty); @@ -582,7 +582,7 @@ llvm::LogicalResult LowerFunction::buildFunctionProlog( // FIXME(cir): Get the original name of the argument, as well as the // proper alignment for the given type being allocated. auto Alloca = rewriter.create( - Fn.getLoc(), rewriter.getType(Ty), Ty, + Fn.getLoc(), cir::PointerType::get(Ty), Ty, /*name=*/llvm::StringRef(""), /*alignment=*/rewriter.getI64IntegerAttr(4)); @@ -673,7 +673,7 @@ llvm::LogicalResult LowerFunction::buildFunctionProlog( cir_cconv_assert(!ArgI.getIndirectByVal() && "For truly ABI indirect arguments"); - auto ptrTy = rewriter.getType(Arg.getType()); + auto ptrTy = cir::PointerType::get(Arg.getType()); mlir::Value arg = SrcFn.getArgument(ArgNo); cir_cconv_assert(arg.hasOneUse()); auto *firstStore = *arg.user_begin(); @@ -683,7 +683,7 @@ llvm::LogicalResult LowerFunction::buildFunctionProlog( auto align = LM.getDataLayout().getABITypeAlign(ptrTy); auto alignAttr = rewriter.getI64IntegerAttr(align.value()); auto newAlloca = rewriter.create( - Fn.getLoc(), rewriter.getType(ptrTy), ptrTy, + Fn.getLoc(), cir::PointerType::get(ptrTy), ptrTy, /*name=*/llvm::StringRef(""), /*alignment=*/alignAttr); @@ -1008,7 +1008,7 @@ mlir::Value createAlloca(mlir::Location loc, mlir::Type type, auto align = CGF.LM.getDataLayout().getABITypeAlign(type); auto alignAttr = CGF.getRewriter().getI64IntegerAttr(align.value()); return CGF.getRewriter().create( - loc, CGF.getRewriter().getType(type), type, + loc, cir::PointerType::get(type), type, /*name=*/llvm::StringRef(""), alignAttr); } diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h index 8d33ef2e5dca..114d8cc0f697 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h @@ -31,8 +31,9 @@ class TargetLoweringInfo { virtual ~TargetLoweringInfo(); const ABIInfo &getABIInfo() const { return *Info; } - virtual unsigned getTargetAddrSpaceFromCIRAddrSpace( - cir::AddressSpaceAttr addressSpaceAttr) const = 0; + + virtual unsigned + getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace) const = 0; }; } // namespace cir diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp index 6751bd7d99a0..9a8edf39d738 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AArch64.cpp @@ -62,14 +62,13 @@ class AArch64TargetLoweringInfo : public TargetLoweringInfo { } unsigned getTargetAddrSpaceFromCIRAddrSpace( - cir::AddressSpaceAttr addressSpaceAttr) const override { - using Kind = cir::AddressSpaceAttr::Kind; - switch (addressSpaceAttr.getValue()) { - case Kind::offload_private: - case Kind::offload_local: - case Kind::offload_global: - case Kind::offload_constant: - case Kind::offload_generic: + cir::AddressSpace addrSpace) const override { + switch (addrSpace) { + case cir::AddressSpace::OffloadPrivate: + case cir::AddressSpace::OffloadLocal: + case cir::AddressSpace::OffloadGlobal: + case cir::AddressSpace::OffloadConstant: + case cir::AddressSpace::OffloadGeneric: return 0; default: cir_cconv_unreachable("Unknown CIR address space for this target"); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/NVPTX.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/NVPTX.cpp index 4f6a76dadabb..00f961d38666 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/NVPTX.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/NVPTX.cpp @@ -45,18 +45,17 @@ class NVPTXTargetLoweringInfo : public TargetLoweringInfo { : TargetLoweringInfo(std::make_unique(lt)) {} unsigned getTargetAddrSpaceFromCIRAddrSpace( - cir::AddressSpaceAttr addressSpaceAttr) const override { - using Kind = cir::AddressSpaceAttr::Kind; - switch (addressSpaceAttr.getValue()) { - case Kind::offload_private: + cir::AddressSpace addrSpace) const override { + switch (addrSpace) { + case cir::AddressSpace::OffloadPrivate: return 0; - case Kind::offload_local: + case cir::AddressSpace::OffloadLocal: return 3; - case Kind::offload_global: + case cir::AddressSpace::OffloadGlobal: return 1; - case Kind::offload_constant: + case cir::AddressSpace::OffloadConstant: return 4; - case Kind::offload_generic: + case cir::AddressSpace::OffloadGeneric: return 0; default: cir_cconv_unreachable("Unknown CIR address space for this target"); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/SPIR.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/SPIR.cpp index deffd8d27a05..0a4dc640decd 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/SPIR.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/SPIR.cpp @@ -42,18 +42,17 @@ class SPIRVTargetLoweringInfo : public TargetLoweringInfo { : TargetLoweringInfo(std::make_unique(LT)) {} unsigned getTargetAddrSpaceFromCIRAddrSpace( - cir::AddressSpaceAttr addressSpaceAttr) const override { - using Kind = cir::AddressSpaceAttr::Kind; - switch (addressSpaceAttr.getValue()) { - case Kind::offload_private: + cir::AddressSpace addrSpace) const override { + switch (addrSpace) { + case cir::AddressSpace::OffloadPrivate: return 0; - case Kind::offload_local: + case cir::AddressSpace::OffloadLocal: return 3; - case Kind::offload_global: + case cir::AddressSpace::OffloadGlobal: return 1; - case Kind::offload_constant: + case cir::AddressSpace::OffloadConstant: return 2; - case Kind::offload_generic: + case cir::AddressSpace::OffloadGeneric: return 4; default: cir_cconv_unreachable("Unknown CIR address space for this target"); diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp index 4a198dd6091f..ec8c880ef3ab 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/X86.cpp @@ -110,14 +110,13 @@ class X86_64TargetLoweringInfo : public TargetLoweringInfo { } unsigned getTargetAddrSpaceFromCIRAddrSpace( - cir::AddressSpaceAttr addressSpaceAttr) const override { - using Kind = cir::AddressSpaceAttr::Kind; - switch (addressSpaceAttr.getValue()) { - case Kind::offload_private: - case Kind::offload_local: - case Kind::offload_global: - case Kind::offload_constant: - case Kind::offload_generic: + cir::AddressSpace addrSpace) const override { + switch (addrSpace) { + case cir::AddressSpace::OffloadPrivate: + case cir::AddressSpace::OffloadLocal: + case cir::AddressSpace::OffloadGlobal: + case cir::AddressSpace::OffloadConstant: + case cir::AddressSpace::OffloadGeneric: return 0; default: cir_cconv_unreachable("Unknown CIR address space for this target"); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 0a42a90aa1d6..db53b1eea463 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -43,6 +43,7 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" @@ -349,7 +350,7 @@ unsigned getGlobalOpTargetAddrSpace(mlir::ConversionPatternRewriter &rewriter, const mlir::TypeConverter *converter, cir::GlobalOp op) { auto tempPtrTy = cir::PointerType::get(rewriter.getContext(), op.getSymType(), - op.getAddrSpaceAttr()); + op.getAddrSpace()); return cast(converter->convertType(tempPtrTy)) .getAddressSpace(); } @@ -4422,32 +4423,31 @@ std::unique_ptr prepareLowerModule(mlir::ModuleOp module) { return cir::createLowerModule(module, rewriter); } +static unsigned +getTargetAddrSpaceFromCIRAddrSpace(cir::AddressSpace addrSpace, + cir::LowerModule *lowerModule) { + if (addrSpace == cir::AddressSpace::Default) + return 0; // Default address space is always 0 in LLVM. + + if (cir::isTargetAddressSpace(addrSpace)) + return cir::getTargetAddressSpaceValue(addrSpace); + + assert(lowerModule && "CIR AS map is not available"); + return lowerModule->getTargetLoweringInfo() + .getTargetAddrSpaceFromCIRAddrSpace(addrSpace); +} + // FIXME: change the type of lowerModule to `LowerModule &` to have better // lambda capturing experience. Also blocked by makeTripleAlwaysPresent. void prepareTypeConverter(mlir::LLVMTypeConverter &converter, mlir::DataLayout &dataLayout, cir::LowerModule *lowerModule) { - converter.addConversion( - [&, lowerModule](cir::PointerType type) -> mlir::Type { - // Drop pointee type since LLVM dialect only allows opaque pointers. - - auto addrSpace = - mlir::cast_if_present(type.getAddrSpace()); - // Null addrspace attribute indicates the default addrspace. - if (!addrSpace) - return mlir::LLVM::LLVMPointerType::get(type.getContext()); - - assert(lowerModule && "CIR AS map is not available"); - // Pass through target addrspace and map CIR addrspace to LLVM addrspace - // by querying the target info. - unsigned targetAS = - addrSpace.isTarget() - ? addrSpace.getTargetValue() - : lowerModule->getTargetLoweringInfo() - .getTargetAddrSpaceFromCIRAddrSpace(addrSpace); - - return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS); - }); + converter.addConversion([&, + lowerModule](cir::PointerType type) -> mlir::Type { + unsigned addrSpace = + getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace(), lowerModule); + return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace); + }); converter.addConversion( [&, lowerModule](cir::DataMemberType type) -> mlir::Type { assert(lowerModule && "CXXABI is not available"); diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp index a1ef4a286464..1b826dfa7a36 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp @@ -464,7 +464,7 @@ class CIRWhileOpLowering : public mlir::OpConversionPattern { rewriter.setInsertionPointToStart(whileOp.getAfterBody()); auto boolTy = rewriter.getType(); - auto boolPtrTy = rewriter.getType(boolTy); + auto boolPtrTy = cir::PointerType::get(boolTy); auto alignment = rewriter.getI64IntegerAttr(4); auto condAlloca = rewriter.create(loc, boolPtrTy, boolTy, "condition", alignment); diff --git a/clang/test/CIR/IR/invalid.cir b/clang/test/CIR/IR/invalid.cir index 38ba656587a0..5f92c1a9d439 100644 --- a/clang/test/CIR/IR/invalid.cir +++ b/clang/test/CIR/IR/invalid.cir @@ -1232,28 +1232,35 @@ cir.func @bad_goto() -> () { // ----- !u64i = !cir.int -cir.func @address_space1(%p : !cir.ptr) { // expected-error {{expected keyword for addrspace kind}} +// expected-error@below {{expected address space keyword}} +// expected-error@below {{expected keyword for address space kind}} +cir.func @address_space1(%p : !cir.ptr) { cir.return } // ----- !u64i = !cir.int -cir.func @address_space2(%p : !cir.ptr)>) { // expected-error {{expected integer value}} +// expected-error@below {{expected target address space value}} +// expected-error@below {{expected integer value}} +cir.func @address_space2(%p : !cir.ptr)>) { cir.return } // ----- !u64i = !cir.int -cir.func @address_space3(%p : !cir.ptr) { // expected-error {{expected '<'}} +// expected-error@below {{expected '<'}} +cir.func @address_space3(%p : !cir.ptr) { cir.return } // ----- !u64i = !cir.int -cir.func @address_space4(%p : !cir.ptr) { // expected-error {{invalid addrspace kind keyword: foobar}} +// expected-error@below {{invalid address space kind specification: foobar}} +// expected-error@below {{expected address space keyword}} +cir.func @address_space4(%p : !cir.ptr) { cir.return }