================ @@ -424,6 +455,1006 @@ void CIRGenItaniumCXXABI::emitVirtualInheritanceTables( vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd); } +namespace { +class CIRGenItaniumRTTIBuilder { + CIRGenModule &cgm; // Per-module state. + const CIRGenItaniumCXXABI &cxxABI; // Per-module state. + + /// The fields of the RTTI descriptor currently being built. + SmallVector<mlir::Attribute, 16> fields; + + // Returns the mangled type name of the given type. + cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty, + cir::GlobalLinkageKind linkage); + + /// descriptor of the given type. + mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc, + QualType ty); + + /// Build the vtable pointer for the given type. + void buildVTablePointer(mlir::Location loc, const Type *ty); + + /// Build an abi::__si_class_type_info, used for single inheritance, according + /// to the Itanium C++ ABI, 2.9.5p6b. + void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd); + + /// Build an abi::__vmi_class_type_info, used for + /// classes with bases that do not satisfy the abi::__si_class_type_info + /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. + void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd); + +public: + CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &_cgm) + : cgm(_cgm), cxxABI(abi) {} + + /// Build the RTTI type info struct for the given type, or + /// link to an existing RTTI descriptor if one already exists. + mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty); + + /// Build the RTTI type info struct for the given type. + mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty, + cir::GlobalLinkageKind linkage, + mlir::SymbolTable::Visibility visibility); +}; +} // namespace + +// TODO(cir): Will be removed after sharing them with the classical codegen +namespace { + +// Pointer type info flags. +enum { + /// PTI_Const - Type has const qualifier. + PTI_Const = 0x1, + + /// PTI_Volatile - Type has volatile qualifier. + PTI_Volatile = 0x2, + + /// PTI_Restrict - Type has restrict qualifier. + PTI_Restrict = 0x4, + + /// PTI_Incomplete - Type is incomplete. + PTI_Incomplete = 0x8, + + /// PTI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + PTI_ContainingClassIncomplete = 0x10, + + /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS). + // PTI_TransactionSafe = 0x20, + + /// PTI_Noexcept - Pointee is noexcept function (C++1z). + PTI_Noexcept = 0x40, +}; + +// VMI type info flags. +enum { + /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance. + VMI_NonDiamondRepeat = 0x1, + + /// VMI_DiamondShaped - Class is diamond shaped. + VMI_DiamondShaped = 0x2 +}; + +// Base class type info flags. +enum { + /// BCTI_Virtual - Base class is virtual. + BCTI_Virtual = 0x1, + + /// BCTI_Public - Base class is public. + BCTI_Public = 0x2 +}; + +/// Given a builtin type, returns whether the type +/// info for that type is defined in the standard library. +/// TODO(cir): this can unified with LLVM codegen +static bool TypeInfoIsInStandardLibrary(const BuiltinType *ty) { + // Itanium C++ ABI 2.9.2: + // Basic type information (e.g. for "int", "bool", etc.) will be kept in + // the run-time support library. Specifically, the run-time support + // library should contain type_info objects for the types X, X* and + // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char, + // unsigned char, signed char, short, unsigned short, int, unsigned int, + // long, unsigned long, long long, unsigned long long, float, double, + // long double, char16_t, char32_t, and the IEEE 754r decimal and + // half-precision floating point types. + // + // GCC also emits RTTI for __int128. + // FIXME: We do not emit RTTI information for decimal types here. + + // Types added here must also be added to EmitFundamentalRTTIDescriptors. + switch (ty->getKind()) { + case BuiltinType::WasmExternRef: + case BuiltinType::HLSLResource: + llvm_unreachable("NYI"); + case BuiltinType::Void: + case BuiltinType::NullPtr: + case BuiltinType::Bool: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char_U: + case BuiltinType::Char_S: + case BuiltinType::UChar: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + case BuiltinType::Half: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + case BuiltinType::Float16: + case BuiltinType::Float128: + case BuiltinType::Ibm128: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Int128: + case BuiltinType::UInt128: + return true; + +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id: +#include "clang/Basic/OpenCLExtensionTypes.def" + case BuiltinType::OCLSampler: + case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLReserveID: +#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/AArch64ACLETypes.def" +#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id: +#include "clang/Basic/PPCTypes.def" +#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/RISCVVTypes.def" +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: +#include "clang/Basic/AMDGPUTypes.def" + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: + case BuiltinType::BFloat16: + return false; + + case BuiltinType::Dependent: +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + llvm_unreachable("asking for RRTI for a placeholder type!"); + + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + llvm_unreachable("FIXME: Objective-C types are unsupported!"); + } + + llvm_unreachable("Invalid BuiltinType Kind!"); +} + +static bool TypeInfoIsInStandardLibrary(const PointerType *pointerTy) { + QualType pointeeTy = pointerTy->getPointeeType(); + const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy); + if (!builtinTy) + return false; + + // Check the qualifiers. + Qualifiers quals = pointeeTy.getQualifiers(); + quals.removeConst(); + + if (!quals.empty()) + return false; + + return TypeInfoIsInStandardLibrary(builtinTy); +} + +/// IsStandardLibraryRTTIDescriptor - Returns whether the type +/// information for the given type exists in the standard library. +static bool IsStandardLibraryRTTIDescriptor(QualType ty) { + // Type info for builtin types is defined in the standard library. + if (const auto *builtinTy = dyn_cast<BuiltinType>(ty)) + return TypeInfoIsInStandardLibrary(builtinTy); + + // Type info for some pointer types to builtin types is defined in the + // standard library. + if (const auto *pointerTy = dyn_cast<PointerType>(ty)) + return TypeInfoIsInStandardLibrary(pointerTy); + + return false; +} + +/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for +/// the given type exists somewhere else, and that we should not emit the type +/// information in this translation unit. Assumes that it is not a +/// standard-library type. +static bool ShouldUseExternalRTTIDescriptor(CIRGenModule &cgm, QualType ty) { + ASTContext &context = cgm.getASTContext(); + + // If RTTI is disabled, assume it might be disabled in the + // translation unit that defines any potential key function, too. + if (!context.getLangOpts().RTTI) + return false; + + if (const auto *recordTy = dyn_cast<RecordType>(ty)) { + const CXXRecordDecl *rd = + cast<CXXRecordDecl>(recordTy->getOriginalDecl())->getDefinitionOrSelf(); + if (!rd->hasDefinition()) + return false; + + if (!rd->isDynamicClass()) + return false; + + // FIXME: this may need to be reconsidered if the key function + // changes. + // N.B. We must always emit the RTTI data ourselves if there exists a key + // function. + bool isDLLImport = rd->hasAttr<DLLImportAttr>(); + + // Don't import the RTTI but emit it locally. + if (cgm.getTriple().isOSCygMing()) + return false; + + if (cgm.getVTables().isVTableExternal(rd)) { + if (cgm.getTarget().hasPS4DLLImportExport()) + return true; + + return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment(); + } + + if (isDLLImport) + return true; + } + + return false; +} + +/// Contains virtual and non-virtual bases seen when traversing a class +/// hierarchy. +struct SeenBases { + llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases; + llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases; +}; + +/// Compute the value of the flags member in abi::__vmi_class_type_info. +/// +static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *base, + SeenBases &bases) { + + unsigned flags = 0; + auto *baseDecl = base->getType()->castAsCXXRecordDecl(); + + if (base->isVirtual()) { + // Mark the virtual base as seen. + if (!bases.virtualBases.insert(baseDecl).second) { + // If this virtual base has been seen before, then the class is diamond + // shaped. + flags |= VMI_DiamondShaped; + } else { + if (bases.nonVirtualBases.count(baseDecl)) + flags |= VMI_NonDiamondRepeat; + } + } else { + // Mark the non-virtual base as seen. + if (!bases.nonVirtualBases.insert(baseDecl).second) { + // If this non-virtual base has been seen before, then the class has non- + // diamond shaped repeated inheritance. + flags |= VMI_NonDiamondRepeat; + } else { + if (bases.virtualBases.count(baseDecl)) + flags |= VMI_NonDiamondRepeat; + } + } + + // Walk all bases. + for (const auto &bs : baseDecl->bases()) + flags |= ComputeVMIClassTypeInfoFlags(&bs, bases); + + return flags; +} + +static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *rd) { + unsigned flags = 0; + SeenBases bases; + + // Walk all bases. + for (const auto &bs : rd->bases()) + flags |= ComputeVMIClassTypeInfoFlags(&bs, bases); + + return flags; +} + +// Return whether the given record decl has a "single, +// public, non-virtual base at offset zero (i.e. the derived class is dynamic +// iff the base is)", according to Itanium C++ ABI, 2.95p6b. +// TODO(cir): this can unified with LLVM codegen +static bool CanUseSingleInheritance(const CXXRecordDecl *rd) { + // Check the number of bases. + if (rd->getNumBases() != 1) + return false; + + // Get the base. + CXXRecordDecl::base_class_const_iterator base = rd->bases_begin(); + + // Check that the base is not virtual. + if (base->isVirtual()) + return false; + + // Check that the base is public. + if (base->getAccessSpecifier() != AS_public) + return false; + + // Check that the class is dynamic iff the base is. + auto *baseDecl = base->getType()->castAsCXXRecordDecl(); + return baseDecl->isEmpty() || + baseDecl->isDynamicClass() == rd->isDynamicClass(); +} + +/// IsIncompleteClassType - Returns whether the given record type is incomplete. +static bool IsIncompleteClassType(const RecordType *recordTy) { + return !recordTy->getOriginalDecl() + ->getDefinitionOrSelf() + ->isCompleteDefinition(); +} + +/// Returns whether the given type contains an +/// incomplete class type. This is true if +/// +/// * The given type is an incomplete class type. +/// * The given type is a pointer type whose pointee type contains an +/// incomplete class type. +/// * The given type is a member pointer type whose class is an incomplete +/// class type. +/// * The given type is a member pointer type whoise pointee type contains an +/// incomplete class type. +/// is an indirect or direct pointer to an incomplete class type. +static bool ContainsIncompleteClassType(QualType ty) { + if (const auto *recordTy = dyn_cast<RecordType>(ty)) { + if (IsIncompleteClassType(recordTy)) + return true; + } + + if (const auto *pointerTy = dyn_cast<PointerType>(ty)) + return ContainsIncompleteClassType(pointerTy->getPointeeType()); + + if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) { + // Check if the class type is incomplete. + if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition()) + return true; + + return ContainsIncompleteClassType(memberPointerTy->getPointeeType()); + } + + return false; +} + +/// Return the linkage that the type info and type info name constants +/// should have for the given type. +static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm, + QualType ty) { + // In addition, it and all of the intermediate abi::__pointer_type_info + // structs in the chain down to the abi::__class_type_info for the + // incomplete class type must be prevented from resolving to the + // corresponding type_info structs for the complete class type, possibly + // by making them local static objects. Finally, a dummy class RTTI is + // generated for the incomplete type that will not resolve to the final + // complete class RTTI (because the latter need not exist), possibly by + // making it a local static object. + if (ContainsIncompleteClassType(ty)) + return cir::GlobalLinkageKind::InternalLinkage; + + switch (ty->getLinkage()) { + case Linkage::Invalid: + llvm_unreachable("Linkage hasn't been computed!"); + + case Linkage::None: + case Linkage::Internal: + case Linkage::UniqueExternal: + return cir::GlobalLinkageKind::InternalLinkage; + + case Linkage::VisibleNone: + case Linkage::Module: + case Linkage::External: + // RTTI is not enabled, which means that this type info struct is going + // to be used for exception handling. Give it linkonce_odr linkage. + if (!cgm.getLangOpts().RTTI) + return cir::GlobalLinkageKind::LinkOnceODRLinkage; + + if (const RecordType *record = dyn_cast<RecordType>(ty)) { + const CXXRecordDecl *rd = + cast<CXXRecordDecl>(record->getOriginalDecl())->getDefinitionOrSelf(); + if (rd->hasAttr<WeakAttr>()) + return cir::GlobalLinkageKind::WeakODRLinkage; + + if (cgm.getTriple().isWindowsItaniumEnvironment()) + if (rd->hasAttr<DLLImportAttr>() && + ShouldUseExternalRTTIDescriptor(cgm, ty)) + return cir::GlobalLinkageKind::ExternalLinkage; + + // MinGW always uses LinkOnceODRLinkage for type info. + if (rd->isDynamicClass() && !cgm.getASTContext() + .getTargetInfo() + .getTriple() + .isWindowsGNUEnvironment()) + return cgm.getVTableLinkage(rd); + } + + return cir::GlobalLinkageKind::LinkOnceODRLinkage; + } + + llvm_unreachable("Invalid linkage!"); +} +} // namespace + +// FIXME: Check please +cir::GlobalOp +CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty, + cir::GlobalLinkageKind linkage) { + auto &builder = cgm.getBuilder(); + SmallString<256> name; + llvm::raw_svector_ostream out(name); + cgm.getCXXABI().getMangleContext().mangleCXXRTTIName(ty, out); + + // We know that the mangled name of the type starts at index 4 of the + // mangled name of the typename, so we can just index into it in order to + // get the mangled name of the type. + mlir::Attribute init = builder.getString( + name.substr(4), cgm.convertType(cgm.getASTContext().CharTy), + std::nullopt); + + CharUnits align = + cgm.getASTContext().getTypeAlignInChars(cgm.getASTContext().CharTy); + + // builder.getString can return a #cir.zero if the string given to it only + // contains null bytes. However, type names cannot be full of null bytes. + // So cast Init to a ConstArrayAttr should be safe. + auto initStr = cast<cir::ConstArrayAttr>(init); + + cir::GlobalOp gv = cgm.createOrReplaceCXXRuntimeVariable( + loc, name, initStr.getType(), linkage, align); + CIRGenModule::setInitializer(gv, init); + return gv; +} + +mlir::Attribute +CIRGenItaniumRTTIBuilder::getAddrOfExternalRTTIDescriptor(mlir::Location loc, + QualType ty) { + // Mangle the RTTI name. + SmallString<256> name; + llvm::raw_svector_ostream out(name); + cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out); + CIRGenBuilderTy &builder = cgm.getBuilder(); + + // Look for an existing global. + cir::GlobalOp gv = dyn_cast_or_null<cir::GlobalOp>( + mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name)); + + if (!gv) { + // Create a new global variable. + // From LLVM codegen => Note for the future: If we would ever like to do + // deferred emission of RTTI, check if emitting vtables opportunistically + // need any adjustment. + gv = CIRGenModule::createGlobalOp(cgm, loc, name, builder.getUInt8PtrTy(), + /*isConstant=*/true); + const CXXRecordDecl *rd = ty->getAsCXXRecordDecl(); + cgm.setGVProperties(gv, rd); + + // Import the typeinfo symbol when all non-inline virtual methods are + // imported. + if (cgm.getTarget().hasPS4DLLImportExport()) + llvm_unreachable("NYI"); + } + + return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv); +} + +// FIXME: Split this function +void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc, + const Type *ty) { + auto &builder = cgm.getBuilder(); + + // abi::__class_type_info. + static const char *const ClassTypeInfo = ---------------- AmrDeveloper wrote:
I forgot to split this part. I do that, it should be moved into a `VTableClassNameForType` https://github.com/llvm/llvm-project/pull/160002 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits