-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang][NFC] Create CodeGenShared component for shared code with ClangIR #157936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesIn this refactor, I moved functions that are used in ItaniumRTTIBuilder implementation and not using LLVM IR classes into the CodeGenShared library that will contain shared code between Clang classical CodeGen and ClangIR. Patch is 37.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157936.diff 6 Files Affected:
diff --git a/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h b/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h
new file mode 100644
index 0000000000000..0db0618d279d0
--- /dev/null
+++ b/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h
@@ -0,0 +1,117 @@
+//===--- ItaniumRTTIBuilder.h - LLVM Backend Utilities ----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H
+#define LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TypeBase.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+
+namespace CodeGenShared {
+
+// 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
+};
+
+/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty);
+
+bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy);
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+bool IsStandardLibraryRTTIDescriptor(QualType Ty);
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+bool IsIncompleteClassType(const RecordType *RecordTy);
+
+/// ContainsIncompleteClassType - 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.
+bool ContainsIncompleteClassType(QualType Ty);
+
+// CanUseSingleInheritance - 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.
+bool CanUseSingleInheritance(const CXXRecordDecl *RD);
+
+const char *VTableClassNameForType(const Type *Ty);
+
+/// Compute the flags for a __pbase_type_info, and remove the corresponding
+/// pieces from \p Type.
+unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type);
+
+/// SeenBases - 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;
+};
+
+/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
+/// abi::__vmi_class_type_info.
+unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
+ SeenBases &Bases);
+
+unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD);
+
+} // namespace CodeGenShared
+} // namespace clang
+
+#endif
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index 4f2218b583e41..5032c80943385 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(ASTMatchers)
add_subdirectory(CrossTU)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
+add_subdirectory(CodeGenShared)
add_subdirectory(Analysis)
add_subdirectory(Edit)
add_subdirectory(ExtractAPI)
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ad9ef91c781a8..9672cfac82c85 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -168,6 +168,7 @@ add_clang_library(clangCodeGen
clangAST
clangAnalysis
clangBasic
+ clangCodeGenShared
clangFrontend
clangLex
clangSerialization
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 7dc2eaf1e9f75..1b618532a379e 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -28,8 +28,8 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/Type.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGenShared/ItaniumRTTIBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
@@ -41,6 +41,7 @@
using namespace clang;
using namespace CodeGen;
+using namespace CodeGenShared;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
@@ -3544,49 +3545,6 @@ class ItaniumRTTIBuilder {
ItaniumRTTIBuilder(const ItaniumCXXABI &ABI)
: CGM(ABI.CGM), VMContext(CGM.getModule().getContext()), CXXABI(ABI) {}
- // 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
- };
-
/// BuildTypeInfo - Build the RTTI type info struct for the given type, or
/// link to an existing RTTI descriptor if one already exists.
llvm::Constant *BuildTypeInfo(QualType Ty);
@@ -3598,7 +3556,7 @@ class ItaniumRTTIBuilder {
llvm::GlobalValue::VisibilityTypes Visibility,
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass);
};
-}
+} // namespace
llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) {
@@ -3654,154 +3612,6 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
return GV;
}
-/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
-/// info for that type is defined in the standard library.
-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::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 WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
-#include "clang/Basic/WebAssemblyReferenceTypes.def"
-#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
-#include "clang/Basic/AMDGPUTypes.def"
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
-#include "clang/Basic/HLSLIntangibleTypes.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 BuiltinType *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 BuiltinType *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 PointerType *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
@@ -3848,195 +3658,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
return false;
}
-/// IsIncompleteClassType - Returns whether the given record type is incomplete.
-static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isCompleteDefinition();
-}
-
-/// ContainsIncompleteClassType - 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 RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- if (IsIncompleteClassType(RecordTy))
- return true;
- }
-
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return ContainsIncompleteClassType(PointerTy->getPointeeType());
-
- if (const MemberPointerType *MemberPointerTy =
- dyn_cast<MemberPointerType>(Ty)) {
- // Check if the class type is incomplete.
- if (!MemberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
- return true;
-
- return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
- }
-
- return false;
-}
-
-// CanUseSingleInheritance - 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.
-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();
- if (!BaseDecl->isEmpty() &&
- BaseDecl->isDynamicClass() != RD->isDynamicClass())
- return false;
-
- return true;
-}
-
void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty,
llvm::Constant *StorageAddress) {
- // abi::__class_type_info.
- static const char * const ClassTypeInfo =
- "_ZTVN10__cxxabiv117__class_type_infoE";
- // abi::__si_class_type_info.
- static const char * const SIClassTypeInfo =
- "_ZTVN10__cxxabiv120__si_class_type_infoE";
- // abi::__vmi_class_type_info.
- static const char * const VMIClassTypeInfo =
- "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
-
- const char *VTableName = nullptr;
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.inc"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("Undeduced type shouldn't get here");
-
- case Type::Pipe:
- llvm_unreachable("Pipe types shouldn't get here");
-
- case Type::ArrayParameter:
- llvm_unreachable("Array Parameter types should not get here.");
-
- case Type::Builtin:
- case Type::BitInt:
- // GCC treats vector and complex types as fundamental types.
- case Type::Vector:
- case Type::ExtVector:
- case Type::ConstantMatrix:
- case Type::Complex:
- case Type::Atomic:
- // FIXME: GCC treats block pointers as fundamental types?!
- case Type::BlockPointer:
- // abi::__fundamental_type_info.
- VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // abi::__array_type_info.
- VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // abi::__function_type_info.
- VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
- break;
-
- case Type::Enum:
- // abi::__enum_type_info.
- VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getOriginalDecl())
- ->getDefinitionOrSelf();
-
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- VTableName = ClassTypeInfo;
- } else if (CanUseSingleInheritance(RD)) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = VMIClassTypeInfo;
- }
-
- break;
- }
-
- case Type::ObjCObject:
- // Ignore protocol qualifiers.
- Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
-
- // Handle id and Class.
- if (isa<BuiltinType>(Ty)) {
- VTableName = ClassTypeInfo;
- break;
- }
-
- assert(isa<ObjCInterfaceType>(Ty));
- [[fallthrough]];
-
- case Type::ObjCInterface:
- if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = ClassTypeInfo;
- }
- break;
-
- case Type::ObjCObjectPointer:
- case Type::Pointer:
- // abi::__pointer_type_info.
- VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
- break;
-
- case Type::MemberPointer:
- // abi::__pointer_to_member_type_info.
- VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
-
- case Type::HLSLAttributedResource:
- case Type::HLSLInlineSpirv:
- llvm_unreachable("HLSL doesn't support virtual functions");
- }
-
+ const char *VTableName = VTableClassNameForType(Ty);
llvm::Constant *VTable = nullptr;
// Check if the alias exists. If it doesn't, then get or create the global.
@@ -4168,7 +3792,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass =
llvm::GlobalValue::DefaultStorageClass;
- if (auto RD = Ty->getAsCXXRecordDecl()) {
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
if ((CGM.getTriple().isWindowsItaniumEnvironment() &&
RD->hasAttr<DLLExportAttr>()) ||
(CGM.shouldMapVisibilityToDLLExport(RD) &&
@@ -4410,64 +4034,6 @@ void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
Fields.push_back(Ba...
[truncated]
|
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesIn this refactor, I moved functions that are used in ItaniumRTTIBuilder implementation and not using LLVM IR classes into the CodeGenShared library that will contain shared code between Clang classical CodeGen and ClangIR. Patch is 37.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/157936.diff 6 Files Affected:
diff --git a/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h b/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h
new file mode 100644
index 0000000000000..0db0618d279d0
--- /dev/null
+++ b/clang/include/clang/CodeGenShared/ItaniumRTTIBuilder.h
@@ -0,0 +1,117 @@
+//===--- ItaniumRTTIBuilder.h - LLVM Backend Utilities ----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H
+#define LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TypeBase.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+
+namespace CodeGenShared {
+
+// 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
+};
+
+/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty);
+
+bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy);
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+bool IsStandardLibraryRTTIDescriptor(QualType Ty);
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+bool IsIncompleteClassType(const RecordType *RecordTy);
+
+/// ContainsIncompleteClassType - 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.
+bool ContainsIncompleteClassType(QualType Ty);
+
+// CanUseSingleInheritance - 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.
+bool CanUseSingleInheritance(const CXXRecordDecl *RD);
+
+const char *VTableClassNameForType(const Type *Ty);
+
+/// Compute the flags for a __pbase_type_info, and remove the corresponding
+/// pieces from \p Type.
+unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type);
+
+/// SeenBases - 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;
+};
+
+/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
+/// abi::__vmi_class_type_info.
+unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
+ SeenBases &Bases);
+
+unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD);
+
+} // namespace CodeGenShared
+} // namespace clang
+
+#endif
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index 4f2218b583e41..5032c80943385 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(ASTMatchers)
add_subdirectory(CrossTU)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
+add_subdirectory(CodeGenShared)
add_subdirectory(Analysis)
add_subdirectory(Edit)
add_subdirectory(ExtractAPI)
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index ad9ef91c781a8..9672cfac82c85 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -168,6 +168,7 @@ add_clang_library(clangCodeGen
clangAST
clangAnalysis
clangBasic
+ clangCodeGenShared
clangFrontend
clangLex
clangSerialization
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 7dc2eaf1e9f75..1b618532a379e 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -28,8 +28,8 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/Type.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGenShared/ItaniumRTTIBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
@@ -41,6 +41,7 @@
using namespace clang;
using namespace CodeGen;
+using namespace CodeGenShared;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
@@ -3544,49 +3545,6 @@ class ItaniumRTTIBuilder {
ItaniumRTTIBuilder(const ItaniumCXXABI &ABI)
: CGM(ABI.CGM), VMContext(CGM.getModule().getContext()), CXXABI(ABI) {}
- // 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
- };
-
/// BuildTypeInfo - Build the RTTI type info struct for the given type, or
/// link to an existing RTTI descriptor if one already exists.
llvm::Constant *BuildTypeInfo(QualType Ty);
@@ -3598,7 +3556,7 @@ class ItaniumRTTIBuilder {
llvm::GlobalValue::VisibilityTypes Visibility,
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass);
};
-}
+} // namespace
llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) {
@@ -3654,154 +3612,6 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
return GV;
}
-/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
-/// info for that type is defined in the standard library.
-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::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 WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
-#include "clang/Basic/WebAssemblyReferenceTypes.def"
-#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
-#include "clang/Basic/AMDGPUTypes.def"
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
-#include "clang/Basic/HLSLIntangibleTypes.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 BuiltinType *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 BuiltinType *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 PointerType *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
@@ -3848,195 +3658,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
return false;
}
-/// IsIncompleteClassType - Returns whether the given record type is incomplete.
-static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isCompleteDefinition();
-}
-
-/// ContainsIncompleteClassType - 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 RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- if (IsIncompleteClassType(RecordTy))
- return true;
- }
-
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return ContainsIncompleteClassType(PointerTy->getPointeeType());
-
- if (const MemberPointerType *MemberPointerTy =
- dyn_cast<MemberPointerType>(Ty)) {
- // Check if the class type is incomplete.
- if (!MemberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
- return true;
-
- return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
- }
-
- return false;
-}
-
-// CanUseSingleInheritance - 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.
-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();
- if (!BaseDecl->isEmpty() &&
- BaseDecl->isDynamicClass() != RD->isDynamicClass())
- return false;
-
- return true;
-}
-
void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty,
llvm::Constant *StorageAddress) {
- // abi::__class_type_info.
- static const char * const ClassTypeInfo =
- "_ZTVN10__cxxabiv117__class_type_infoE";
- // abi::__si_class_type_info.
- static const char * const SIClassTypeInfo =
- "_ZTVN10__cxxabiv120__si_class_type_infoE";
- // abi::__vmi_class_type_info.
- static const char * const VMIClassTypeInfo =
- "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
-
- const char *VTableName = nullptr;
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.inc"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- case Type::DeducedTemplateSpecialization:
- llvm_unreachable("Undeduced type shouldn't get here");
-
- case Type::Pipe:
- llvm_unreachable("Pipe types shouldn't get here");
-
- case Type::ArrayParameter:
- llvm_unreachable("Array Parameter types should not get here.");
-
- case Type::Builtin:
- case Type::BitInt:
- // GCC treats vector and complex types as fundamental types.
- case Type::Vector:
- case Type::ExtVector:
- case Type::ConstantMatrix:
- case Type::Complex:
- case Type::Atomic:
- // FIXME: GCC treats block pointers as fundamental types?!
- case Type::BlockPointer:
- // abi::__fundamental_type_info.
- VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // abi::__array_type_info.
- VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // abi::__function_type_info.
- VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
- break;
-
- case Type::Enum:
- // abi::__enum_type_info.
- VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getOriginalDecl())
- ->getDefinitionOrSelf();
-
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- VTableName = ClassTypeInfo;
- } else if (CanUseSingleInheritance(RD)) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = VMIClassTypeInfo;
- }
-
- break;
- }
-
- case Type::ObjCObject:
- // Ignore protocol qualifiers.
- Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
-
- // Handle id and Class.
- if (isa<BuiltinType>(Ty)) {
- VTableName = ClassTypeInfo;
- break;
- }
-
- assert(isa<ObjCInterfaceType>(Ty));
- [[fallthrough]];
-
- case Type::ObjCInterface:
- if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = ClassTypeInfo;
- }
- break;
-
- case Type::ObjCObjectPointer:
- case Type::Pointer:
- // abi::__pointer_type_info.
- VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
- break;
-
- case Type::MemberPointer:
- // abi::__pointer_to_member_type_info.
- VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
-
- case Type::HLSLAttributedResource:
- case Type::HLSLInlineSpirv:
- llvm_unreachable("HLSL doesn't support virtual functions");
- }
-
+ const char *VTableName = VTableClassNameForType(Ty);
llvm::Constant *VTable = nullptr;
// Check if the alias exists. If it doesn't, then get or create the global.
@@ -4168,7 +3792,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass =
llvm::GlobalValue::DefaultStorageClass;
- if (auto RD = Ty->getAsCXXRecordDecl()) {
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
if ((CGM.getTriple().isWindowsItaniumEnvironment() &&
RD->hasAttr<DLLExportAttr>()) ||
(CGM.shouldMapVisibilityToDLLExport(RD) &&
@@ -4410,64 +4034,6 @@ void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
Fields.push_back(Ba...
[truncated]
|
#ifndef LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H | ||
#define LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifndef LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H | |
#define LLVM_CLANG_LIB_CODEGENSHARED_ITANIUMRTTIBUILDER_H | |
#ifndef CLANG_CODEGENSHARED_ITANIUMRTTIBUILDER_H | |
#define CLANG_CODEGENSHARED_ITANIUMRTTIBUILDER_H |
The overwhelming majority of current clang headers have LLVM_
as part of their header guard, but that's not consistent with what the coding standard says. I think it's best to follow the standard here, but if others prefer consistency, I can go along with that. Either way, this should not include _LIB
.
@asl @rjmccall @efriedma quic To give you a bit of context, as we have been upstreaming the ClangIR code, we have frequently come across pieces of code that would end up being extremely similar between the CIR codegen and the LLVM IR codegen. Up to now, we've mostly been just leaving TODO(cir)' comments in the code marking places that should be refactored for better code re-use. This PR marks the first step in a much larger effort to actually refactor the code in a way that makes more sharing possible. In #154905, @el-ev introduced a different sort of refactoring, wherein a bit of code was moved into an existing component where it could be called from either codegen. This PR is different in that it is breaking new ground to create a new component that will exist for the sole purpose of sharing code between the two codegens. I believe we will have much more to put here in the future, so we should discuss how best to do that. @AmrDeveloper has begun by simply refactoring this code in a way that allows common helper functions with no codegen specific implementation to be shared. The RTTI handling code lends itself to this approach, However, there are other places where the implementation will be structurally identical between CIR and LIVM IR codegen, but will include places where a function must be called in either CodeGenModule or CIRGenModule I have a vague idea for handling that by defining some abstract base class that both CodeGenModule and CIRGenModule derive from. The same will apply to "CodeGenFunction and CIRGenFunction In other cases the candidates for shared code will reference an IR-specific object, which may be The full discussion is beyond the scope of this PR, and I would like to see this PR move forward so we can get RTTI support going in CIR. However, I would also like us to start planning for a larger strategy for code sharing. Thanks. |
I guess the key question here is what exactly belongs in CodeGenShared, and not some other place? We have some things in clang/Basic and clang/AST which are mostly used by CodeGen, like clang/AST/VTableBuilder.h. Basically the only hard rule is that clang/Basic and clang/AST/ aren't allowed to depend on LLVM IR. So for example, if we wanted to add clang/AST/RTTIBuilder.h, that would be fine. It's a datastructure and algorithm which makes sense outside the context of LLVM IR, even if we don't have a specific idea for who else would use it. If you want to define helpers that are specifically only usable for codegen, like a template with callbacks to construct specific instructions, it probably makes sense to create a dedicated folder for that. |
Yes, the support in VTableBuilder is an excellent example, and it helped a lot with the VTable handling, but we still have a Given enough time, I would absolutely want to create a shared codegen component, and I hope we'll get there sooner rather than later. So I guess the question is whether we would rather have CodeGen-independent pieces, like the hypothetical In practical terms, my priority right now is to get a complete and functional CIR implementation at the cost of code duplication and defer most of the refactoring until later, but there was just so much code in RTTI that wasn't codegen-specific that I asked Amr to explore this direction. If you think that it makes sense to put a |
My take is that most of these shared helpers I've seen so far are more AST-only queries (no llvm stuff), and if we can put them under
IMO a |
Having library code that describes the layout of an RTTI object seems reasonable enough. I don't have strong opinions about whether that should go in AST or a new library. I'm not sure I understand why ClangIR actually needs to lower RTTI objects, however. This seems like exactly the sort of thing that should not, in fact, be lowered in a high-level IR. |
We might get there at some point, probably as soon as we have a new pass that wants to look into that information. We lift some operations early, but not all of them. In the meantime this allows us to make progress (build more C++ sources) by following the known patterns in original codegen. |
Another way of putting that is that you are cloning IRGen on autopilot and making a lot of extra work for yourselves in the process. You should be thinking carefully about what operations should stay abstract in ClangIR as you go along rather than "following the known code patterns" and then realizing months later that that wasn't a good use of time. I do not see any good reason that |
30ffdad
to
70a5ef2
Compare
e9b8c12
to
30ffdad
Compare
You're right that transformations working with CIR shouldn't need this level of detail. However, at the moment we're focused on trying to make compilation through CIR a fully functional path that can compile real programs. What that means is that we want to have the complete AST->CIR->LLVM dialect->LLVM IR->binary path as we add things. So even though we could (and arguably should) use some kind of abstraction at the top level of CIR generation, we need the detail pieces immediately as we lower this to the LLVM dialect. At that point, having something that shares the structure of the existing LLVM IR CodeGen is the path of least resistance. As I mentioned before, we've been deferring most of the work to actually try to share that code, and maybe we should again in this case for the parts that require IR-specific constructs, but "cloning IRGen on autopilot" is generally the quickest way to get something working, particularly in light of the fact that it's already been implemented that way in the incubator. (That is, we're actually cloning the incubator not-quite-on-autopilot after the incubator had already cloned IRGen not-quite-on-autopilot, hopefully improving things on each iteration. We're trying to question things as we go so everyone is happy with the code that lands upstream, which is what led to the discussion here.) |
So, part of the problem here is that it's not tenable long-term for Clang to support completely separate lowering libraries for lowering to LLVM IR and LLVM-dialect MLIR. I continue to believe that the Clang IR work should be focused on lowering to LLVM IR because that will be the required IR for the rest of the compilation pipeline for the foreseeable future. Clients that want LLVM-dialect MLIR can get it by translating from LLVM IR, which will definitely add overhead for those clients, but that is then a problem we can tackle separately with some sort of compile-time or possibly even run-time abstraction. Chris Lattner suggested exactly this path at last fall's conference. I understand why your current approach feels like the path of least resistance. The problem that I and a lot of other Clang maintainers see is that it is leading towards an enormous conflict that we really, really want to avoid. You effectively forked CodeGen two or three years ago, and this work is probably going to keep going for another two or three years, and at that point we will have two independent implementations that diverged 5+ years in the past. I have no idea how we are going to resolve the integration problem at that point, and I am very worried that we will just have two wholly separate implementations that support different sets of features or offer substantially different behavior. This has been repeatedly pointed out, and it's very frustrating to feel like it's not being treated like a serious problem that is worth not taking the "path of least resistance" to avoid. It is hard for me to not to reach the somewhat uncharitable conclusion that a lot of the people working on Clang IR simply don't expect to have to deal with the problem themselves — either because they imagine that MLIR will have displaced LLVM IR by then, which I find highly unlikely, or because they are focused on supporting out-of-tree clients that do not want LLVM IR and don't care much about matching the current behavior of Clang. If we were taking the approach of lowering Clang IR to LLVM IR directly, we'd have a much clearer technical direction for CodeGenShared: we would just be moving parts of the current CodeGen library into a separate library that does common abstract tasks like emitting v-tables, RTTI, bit-field accesses, and so on, with the idea of CodeGen ultimately only having basically the same content as Clang IR generation, just directly emitting statements, expressions, and the like to LLVM IR rather than to Clang IR. That would leave us with a much more obvious long-term integration path for Clang IR, because large amounts of CodeGen would never really have been forked. Ideally, we'd only need to duplicate work between the ClangIR and direct-to-LLVM paths when e.g. the AST adds a new kind of |
@rjmccall First, let me assure you that I am 100% committed to having a fully functional in-tree CIR implementation that matches the behavior of Clang without CIR. I am well aware of what a difficult task this is going to be for the reasons that you described, but those of us working on the CIR project have discussed ideas for this and are trying to put them in place as we go. This includes putting a non-CIR compilation run in the upstream CIR tests, so that we can compare the LLVM IR output with and without CIR enabled and be alerted when the non-CIR output changes. Eventually (and I realize this is an extremely aspirational goal) we hope to be able to run all of the standard Clang codegen tests with CIR enabled and pass them with, at most, semantically equivalent changes to the checks. Trying to keep the structure of the CIR codegen consistent with the LLVM IR codegen whenever we don't have a good reason to diverge is also a decision that we've made for the sake of keeping these two paths in sync as much as possible as they both move. The idea is that when the CIR code is generating different LLVM IR, we can compare the two implementations to see what's missing or wrong in the CIR implementation and fix is accordingly. We've already done this several times. I don't understand what you have in mind with regards to lowering CIR directly to LLVM IR. We are currently focused on lowering CIR to LLVM IR, but the natural MLIR way to do that is to lower to the LLVM dialect, which is then lowered to LLVM IR. We are not lowering CIR to the LLVM dialect because we think the LLVM dialect is useful in itself. We are doing it precisely as a way to generate LLVM IR. I would love to have an abstraction that is shared between LLVM IR codegen and CIR codegen, but I don't see how lowering CIR directly to LLVM IR would help with that. Can you say more, because right now I have the feeling that if I keep talking whatever I say is going to be irrelevant because I'm missing your point? |
My expectation would be that almost every instruction in CIR would be rewritten by this lowering, so I guess I don't see why it's easier or more natural to lower to the dialect "in place" in MLIR rather than just walking the CIR to generate LLVM IR, the same way that Swift's IRGen walks SIL to produce LLVM IR. CIR would keep operations like "emit a reference to the This has higher up-front costs — you basically have to tease CodeGen apart into two libraries as you go — but by doing that up-front, you're keeping a viable integration path intact because both paths are ultimately using the same code as much as possible. |
My take on it is that MLIR is all about mixing and evolving dialects, and once people start using CIR for interesting optimizations we'll very quickly get to a point where you have a module that is a mix of CIR and other dialects. So when you want to lower it to LLVM IR, you just plug the CIR-to-LLVM dialect lowering into a pipeline with a bunch of other lowerings that are funneling things towards the LLVM dialect, but I suppose that's not the only way to solve the problem. I have to admit, this is one of the choices made in the incubator implementation that I didn't really question.
OK. I'm going to have to chew on that for a while. I can definitely see how that could work for things like RTTI that we can keep abstract in CIR without losing any immediate value. It's less obvious to me how we would be able to do this with things like loop representations, for which we definitely want CIR-specific representations. I'm not saying we can't figure out a way to mix them, just that it isn't immediately obvious to me. It's a promising idea. |
Oh interesting, I hadn't considered this, but it makes sense. But yes, if these lowerings can't just rewrite to CIR instead of LLVM dialect, you could at least have something that just translates LLVM dialect to IR directly. I suppose the existing passes for that aren't easy to just plug in to a transform that's otherwise doing custom lowering, though.
I definitely would not expect you to call into any common code to handle loop lowering. But, you know, loading an aggregate in CIR presumably looks like a load of any other value, and then CIR-to-LLVM lowering calls EmitAggregateCopy; or calling a function in CIR keeps the original type structure intact, and then CIR-to-LLVM lowering turns the function type into a |
In this refactor, I moved functions that are used in ItaniumRTTIBuilder implementation and not using LLVM IR classes into the CodeGenShared library that will contain shared code between Clang classical CodeGen and ClangIR.