aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenBuilder.h5
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCXX.cpp139
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenCXXABI.h3
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp28
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp8
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp4
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.cpp12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h12
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp1063
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp28
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.h25
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenRecordLayout.h2
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenVTables.cpp43
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenVTables.h2
-rw-r--r--clang/lib/CIR/CodeGen/CMakeLists.txt1
16 files changed, 1355 insertions, 22 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 6a1746a..58345b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -89,6 +89,11 @@ public:
return cir::ConstRecordAttr::get(sTy, arrayAttr);
}
+ cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
+ cir::ConstRecordAttr anonRecord = getAnonConstRecord(fieldsAttr);
+ return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
+ }
+
std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
std::string getUniqueRecordName(const std::string &baseName) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
index da507d6..d5b35c2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
@@ -15,10 +15,89 @@
#include "clang/AST/GlobalDecl.h"
#include "clang/CIR/MissingFeatures.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace clang::CIRGen;
+static void emitDeclInit(CIRGenFunction &cgf, const VarDecl *varDecl,
+ cir::GlobalOp globalOp) {
+ assert((varDecl->hasGlobalStorage() ||
+ (varDecl->hasLocalStorage() &&
+ cgf.getContext().getLangOpts().OpenCLCPlusPlus)) &&
+ "VarDecl must have global or local (in the case of OpenCL) storage!");
+ assert(!varDecl->getType()->isReferenceType() &&
+ "Should not call emitDeclInit on a reference!");
+
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+
+ // Set up the ctor region.
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ mlir::Block *block = builder.createBlock(&globalOp.getCtorRegion());
+ CIRGenFunction::LexicalScope lexScope{cgf, globalOp.getLoc(),
+ builder.getInsertionBlock()};
+ lexScope.setAsGlobalInit();
+ builder.setInsertionPointToStart(block);
+
+ Address declAddr(cgf.cgm.getAddrOfGlobalVar(varDecl),
+ cgf.cgm.getASTContext().getDeclAlign(varDecl));
+
+ QualType type = varDecl->getType();
+ LValue lv = cgf.makeAddrLValue(declAddr, type);
+
+ const Expr *init = varDecl->getInit();
+ switch (CIRGenFunction::getEvaluationKind(type)) {
+ case cir::TEK_Scalar:
+ assert(!cir::MissingFeatures::objCGC());
+ cgf.emitScalarInit(init, cgf.getLoc(varDecl->getLocation()), lv, false);
+ break;
+ case cir::TEK_Complex:
+ cgf.cgm.errorNYI(varDecl->getSourceRange(), "complex global initializer");
+ break;
+ case cir::TEK_Aggregate:
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+ cgf.emitAggExpr(init,
+ AggValueSlot::forLValue(lv, AggValueSlot::IsDestructed,
+ AggValueSlot::IsNotAliased,
+ AggValueSlot::DoesNotOverlap));
+ break;
+ }
+
+ // Finish the ctor region.
+ builder.setInsertionPointToEnd(block);
+ cir::YieldOp::create(builder, globalOp.getLoc());
+}
+
+static void emitDeclDestroy(CIRGenFunction &cgf, const VarDecl *vd,
+ cir::GlobalOp addr) {
+ // Honor __attribute__((no_destroy)) and bail instead of attempting
+ // to emit a reference to a possibly nonexistent destructor, which
+ // in turn can cause a crash. This will result in a global constructor
+ // that isn't balanced out by a destructor call as intended by the
+ // attribute. This also checks for -fno-c++-static-destructors and
+ // bails even if the attribute is not present.
+ QualType::DestructionKind dtorKind = vd->needsDestruction(cgf.getContext());
+
+ // FIXME: __attribute__((cleanup)) ?
+
+ switch (dtorKind) {
+ case QualType::DK_none:
+ return;
+
+ case QualType::DK_cxx_destructor:
+ break;
+
+ case QualType::DK_objc_strong_lifetime:
+ case QualType::DK_objc_weak_lifetime:
+ case QualType::DK_nontrivial_c_struct:
+ // We don't care about releasing objects during process teardown.
+ assert(!vd->getTLSKind() && "should have rejected this");
+ return;
+ }
+
+ cgf.cgm.errorNYI(vd->getSourceRange(), "global with destructor");
+}
+
cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {
const CIRGenFunctionInfo &fnInfo =
getTypes().arrangeCXXStructorDeclaration(gd);
@@ -38,3 +117,63 @@ cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {
assert(!cir::MissingFeatures::opFuncAttributesForDefinition());
return fn;
}
+
+// Global variables requiring non-trivial initialization are handled
+// differently in CIR than in classic codegen. Classic codegen emits
+// a global init function (__cxx_global_var_init) and inserts
+// initialization for each global there. In CIR, we attach a ctor
+// region to the global variable and insert the initialization code
+// into the ctor region. This will be moved into the
+// __cxx_global_var_init function during the LoweringPrepare pass.
+void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,
+ cir::GlobalOp addr,
+ bool performInit) {
+ QualType ty = varDecl->getType();
+
+ // TODO: handle address space
+ // The address space of a static local variable (addr) may be different
+ // from the address space of the "this" argument of the constructor. In that
+ // case, we need an addrspacecast before calling the constructor.
+ //
+ // struct StructWithCtor {
+ // __device__ StructWithCtor() {...}
+ // };
+ // __device__ void foo() {
+ // __shared__ StructWithCtor s;
+ // ...
+ // }
+ //
+ // For example, in the above CUDA code, the static local variable s has a
+ // "shared" address space qualifier, but the constructor of StructWithCtor
+ // expects "this" in the "generic" address space.
+ assert(!cir::MissingFeatures::addressSpace());
+
+ // Create a CIRGenFunction to emit the initializer. While this isn't a true
+ // function, the handling works the same way.
+ CIRGenFunction cgf{*this, builder, true};
+ llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);
+ curCGF->curFn = addr;
+
+ CIRGenFunction::SourceLocRAIIObject fnLoc{cgf,
+ getLoc(varDecl->getLocation())};
+
+ assert(!cir::MissingFeatures::astVarDeclInterface());
+
+ if (!ty->isReferenceType()) {
+ assert(!cir::MissingFeatures::openMP());
+
+ bool needsDtor = varDecl->needsDestruction(getASTContext()) ==
+ QualType::DK_cxx_destructor;
+ // PerformInit, constant store invariant / destroy handled below.
+ if (performInit)
+ emitDeclInit(cgf, varDecl, addr);
+
+ if (varDecl->getType().isConstantStorage(getASTContext(), true, !needsDtor))
+ errorNYI(varDecl->getSourceRange(), "global with constant storage");
+ else
+ emitDeclDestroy(cgf, varDecl, addr);
+ return;
+ }
+
+ errorNYI(varDecl->getSourceRange(), "global with reference type");
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index ae92259..1dee774 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -114,6 +114,9 @@ public:
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
+ virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) = 0;
+
/// Get the type of the implicit "this" parameter used by a method. May return
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
/// parameter to point to some artificial offset in a complete object due to
diff --git a/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
new file mode 100644
index 0000000..d1efed8
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 contains code dealing with code generation of C++ declarations
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenModule.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/LangOptions.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *vd,
+ cir::GlobalOp addr,
+ bool performInit) {
+ assert(!cir::MissingFeatures::cudaSupport());
+
+ assert(!cir::MissingFeatures::deferredCXXGlobalInit());
+
+ emitCXXGlobalVarDeclInit(vd, addr, performInit);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 4a8aac90..af42d1d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -131,9 +131,7 @@ public:
std::string("AggExprEmitter::VisitStmt: ") +
s->getStmtClassName());
}
- void VisitParenExpr(ParenExpr *pe) {
- cgf.cgm.errorNYI(pe->getSourceRange(), "AggExprEmitter: VisitParenExpr");
- }
+ void VisitParenExpr(ParenExpr *pe) { Visit(pe->getSubExpr()); }
void VisitGenericSelectionExpr(GenericSelectionExpr *ge) {
cgf.cgm.errorNYI(ge->getSourceRange(),
"AggExprEmitter: VisitGenericSelectionExpr");
@@ -213,9 +211,7 @@ public:
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitAbstractConditionalOperator");
}
- void VisitChooseExpr(const ChooseExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitChooseExpr");
- }
+ void VisitChooseExpr(const ChooseExpr *e) { Visit(e->getChosenSubExpr()); }
void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXParenListInitExpr");
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 178b276..e20a4fc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -775,7 +775,9 @@ public:
}
mlir::Attribute VisitCXXConstructExpr(CXXConstructExpr *e, QualType ty) {
- cgm.errorNYI(e->getBeginLoc(), "ConstExprEmitter::VisitCXXConstructExpr");
+ if (!e->getConstructor()->isTrivial())
+ return nullptr;
+ cgm.errorNYI(e->getBeginLoc(), "trivial constructor const handling");
return {};
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 0abb21a..a404c0c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -342,10 +342,12 @@ void CIRGenFunction::LexicalScope::cleanup() {
cir::ReturnOp CIRGenFunction::LexicalScope::emitReturn(mlir::Location loc) {
CIRGenBuilderTy &builder = cgf.getBuilder();
- if (!cgf.curFn.getFunctionType().hasVoidReturn()) {
+ auto fn = dyn_cast<cir::FuncOp>(cgf.curFn);
+ assert(fn && "emitReturn from non-function");
+ if (!fn.getFunctionType().hasVoidReturn()) {
// Load the value from `__retval` and return it via the `cir.return` op.
auto value = builder.create<cir::LoadOp>(
- loc, cgf.curFn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);
+ loc, fn.getFunctionType().getReturnType(), *cgf.fnRetAlloca);
return builder.create<cir::ReturnOp>(loc,
llvm::ArrayRef(value.getResult()));
}
@@ -459,7 +461,9 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
const auto *md = cast<CXXMethodDecl>(d);
if (md->getParent()->isLambda() && md->getOverloadedOperator() == OO_Call) {
// We're in a lambda.
- curFn.setLambda(true);
+ auto fn = dyn_cast<cir::FuncOp>(curFn);
+ assert(fn && "lambda in non-function region");
+ fn.setLambda(true);
// Figure out the captures.
md->getParent()->getCaptureFields(lambdaCaptureFields,
@@ -841,6 +845,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
return emitCastLValue(cast<CastExpr>(e));
case Expr::MaterializeTemporaryExprClass:
return emitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(e));
+ case Expr::ChooseExprClass:
+ return emitLValue(cast<ChooseExpr>(e)->getChosenSubExpr());
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index ef07db3..c0ed8b4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -98,8 +98,10 @@ public:
/// This is the inner-most code context, which includes blocks.
const clang::Decl *curCodeDecl = nullptr;
- /// The function for which code is currently being generated.
- cir::FuncOp curFn;
+ /// The current function or global initializer that is generated code for.
+ /// This is usually a cir::FuncOp, but it can also be a cir::GlobalOp for
+ /// global initializers.
+ mlir::Operation *curFn = nullptr;
using DeclMapTy = llvm::DenseMap<const clang::Decl *, Address>;
/// This keeps track of the CIR allocas or globals for local C
@@ -116,7 +118,11 @@ public:
CIRGenModule &getCIRGenModule() { return cgm; }
const CIRGenModule &getCIRGenModule() const { return cgm; }
- mlir::Block *getCurFunctionEntryBlock() { return &curFn.getRegion().front(); }
+ mlir::Block *getCurFunctionEntryBlock() {
+ // We currently assume this isn't called for a global initializer.
+ auto fn = mlir::cast<cir::FuncOp>(curFn);
+ return &fn.getRegion().front();
+ }
/// Sanitizers enabled for this function.
clang::SanitizerSet sanOpts;
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 0bf6cf5..debea8af 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -103,6 +103,9 @@ public:
const CXXRecordDecl *rd) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
+ mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) override;
+
bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
}
@@ -111,6 +114,34 @@ public:
getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
Address thisAddr, const CXXRecordDecl *classDecl,
const CXXRecordDecl *baseClassDecl) override;
+
+ /**************************** RTTI Uniqueness ******************************/
+protected:
+ /// Returns true if the ABI requires RTTI type_info objects to be unique
+ /// across a program.
+ virtual bool shouldRTTIBeUnique() const { return true; }
+
+public:
+ /// What sort of unique-RTTI behavior should we use?
+ enum RTTIUniquenessKind {
+ /// We are guaranteeing, or need to guarantee, that the RTTI string
+ /// is unique.
+ RUK_Unique,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// can demote to hidden visibility but must use string comparisons.
+ RUK_NonUniqueHidden,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// have to use string comparisons, but we also have to emit it with
+ /// non-hidden visibility.
+ RUK_NonUniqueVisible
+ };
+
+ /// Return the required visibility status for the given type and linkage in
+ /// the current ABI.
+ RTTIUniquenessKind
+ classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;
};
} // namespace
@@ -424,6 +455,1038 @@ 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;
+}
+
+const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
+ // 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";
+
+ 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:
+ cgm.errorNYI("VTableClassNameForType: __fundamental_type_info");
+ break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ cgm.errorNYI("VTableClassNameForType: __array_type_info");
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ cgm.errorNYI("VTableClassNameForType: __function_type_info");
+ break;
+
+ case Type::Enum:
+ cgm.errorNYI("VTableClassNameForType: Enum");
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *rd =
+ cast<CXXRecordDecl>(cast<RecordType>(ty)->getOriginalDecl())
+ ->getDefinitionOrSelf();
+
+ if (!rd->hasDefinition() || !rd->getNumBases()) {
+ return classTypeInfo;
+ }
+
+ if (canUseSingleInheritance(rd)) {
+ return siClassTypeInfo;
+ }
+
+ return vmiClassTypeInfo;
+ }
+
+ case Type::ObjCObject:
+ cgm.errorNYI("VTableClassNameForType: ObjCObject");
+ break;
+
+ case Type::ObjCInterface:
+ cgm.errorNYI("VTableClassNameForType: ObjCInterface");
+ break;
+
+ case Type::ObjCObjectPointer:
+ case Type::Pointer:
+ cgm.errorNYI("VTableClassNameForType: __pointer_type_info");
+ break;
+
+ case Type::MemberPointer:
+ cgm.errorNYI("VTableClassNameForType: __pointer_to_member_type_info");
+ break;
+
+ case Type::HLSLAttributedResource:
+ case Type::HLSLInlineSpirv:
+ llvm_unreachable("HLSL doesn't support virtual functions");
+ }
+
+ return nullptr;
+}
+} // namespace
+
+/// 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!");
+}
+
+cir::GlobalOp
+CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage) {
+ CIRGenBuilderTy &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()) {
+ cgm.errorNYI("getAddrOfExternalRTTIDescriptor: hasPS4DLLImportExport");
+ }
+ }
+
+ return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
+}
+
+void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc,
+ const Type *ty) {
+ CIRGenBuilderTy &builder = cgm.getBuilder();
+ const char *vTableName = vTableClassNameForType(cgm, ty);
+
+ // Check if the alias exists. If it doesn't, then get or create the global.
+ if (cgm.getItaniumVTableContext().isRelativeLayout()) {
+ cgm.errorNYI("buildVTablePointer: isRelativeLayout");
+ return;
+ }
+
+ mlir::Type vtableGlobalTy = builder.getPointerTo(builder.getUInt8PtrTy());
+ llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtableGlobalTy);
+ cir::GlobalOp vTable = cgm.createOrReplaceCXXRuntimeVariable(
+ loc, vTableName, vtableGlobalTy, cir::GlobalLinkageKind::ExternalLinkage,
+ CharUnits::fromQuantity(align));
+
+ // The vtable address point is 2.
+ mlir::Attribute field{};
+ if (cgm.getItaniumVTableContext().isRelativeLayout()) {
+ cgm.errorNYI("buildVTablePointer: isRelativeLayout");
+ } else {
+ SmallVector<mlir::Attribute, 4> offsets{
+ cgm.getBuilder().getI32IntegerAttr(2)};
+ auto indices = mlir::ArrayAttr::get(builder.getContext(), offsets);
+ field = cgm.getBuilder().getGlobalViewAttr(cgm.getBuilder().getUInt8PtrTy(),
+ vTable, indices);
+ }
+
+ assert(field && "expected attribute");
+ fields.push_back(field);
+}
+
+/// Build an abi::__si_class_type_info, used for single inheritance, according
+/// to the Itanium C++ ABI, 2.95p6b.
+void CIRGenItaniumRTTIBuilder::buildSIClassTypeInfo(mlir::Location loc,
+ const CXXRecordDecl *rd) {
+ // Itanium C++ ABI 2.9.5p6b:
+ // It adds to abi::__class_type_info a single member pointing to the
+ // type_info structure for the base type,
+ mlir::Attribute baseTypeInfo =
+ CIRGenItaniumRTTIBuilder(cxxABI, cgm)
+ .buildTypeInfo(loc, rd->bases_begin()->getType());
+ fields.push_back(baseTypeInfo);
+}
+
+/// Build an abi::__vmi_class_type_info, used for
+/// classes with bases that do not satisfy the abi::__si_class_type_info
+/// constraints, according to the Itanium C++ ABI, 2.9.5p5c.
+void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,
+ const CXXRecordDecl *rd) {
+ mlir::Type unsignedIntLTy =
+ cgm.convertType(cgm.getASTContext().UnsignedIntTy);
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __flags is a word with flags describing details about the class
+ // structure, which may be referenced by using the __flags_masks
+ // enumeration. These flags refer to both direct and indirect bases.
+ unsigned flags = computeVmiClassTypeInfoFlags(rd);
+ fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_count is a word with the number of direct proper base class
+ // descriptions that follow.
+ fields.push_back(cir::IntAttr::get(unsignedIntLTy, rd->getNumBases()));
+
+ if (!rd->getNumBases())
+ return;
+
+ // Now add the base class descriptions.
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_info[] is an array of base class descriptions -- one for every
+ // direct proper base. Each description is of the type:
+ //
+ // struct abi::__base_class_type_info {
+ // public:
+ // const __class_type_info *__base_type;
+ // long __offset_flags;
+ //
+ // enum __offset_flags_masks {
+ // __virtual_mask = 0x1,
+ // __public_mask = 0x2,
+ // __offset_shift = 8
+ // };
+ // };
+
+ // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long
+ // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on
+ // LLP64 platforms.
+ // FIXME: Consider updating libc++abi to match, and extend this logic to all
+ // LLP64 platforms.
+ QualType offsetFlagsTy = cgm.getASTContext().LongTy;
+ const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
+ if (ti.getTriple().isOSCygMing() &&
+ ti.getPointerWidth(LangAS::Default) > ti.getLongWidth())
+ offsetFlagsTy = cgm.getASTContext().LongLongTy;
+ mlir::Type offsetFlagsLTy = cgm.convertType(offsetFlagsTy);
+
+ for (const CXXBaseSpecifier &base : rd->bases()) {
+ // The __base_type member points to the RTTI for the base type.
+ fields.push_back(CIRGenItaniumRTTIBuilder(cxxABI, cgm)
+ .buildTypeInfo(loc, base.getType()));
+
+ CXXRecordDecl *baseDecl = base.getType()->castAsCXXRecordDecl();
+ int64_t offsetFlags = 0;
+
+ // All but the lower 8 bits of __offset_flags are a signed offset.
+ // For a non-virtual base, this is the offset in the object of the base
+ // subobject. For a virtual base, this is the offset in the virtual table of
+ // the virtual base offset for the virtual base referenced (negative).
+ CharUnits offset;
+ if (base.isVirtual())
+ offset = cgm.getItaniumVTableContext().getVirtualBaseOffsetOffset(
+ rd, baseDecl);
+ else {
+ const ASTRecordLayout &layout =
+ cgm.getASTContext().getASTRecordLayout(rd);
+ offset = layout.getBaseClassOffset(baseDecl);
+ }
+ offsetFlags = uint64_t(offset.getQuantity()) << 8;
+
+ // The low-order byte of __offset_flags contains flags, as given by the
+ // masks from the enumeration __offset_flags_masks.
+ if (base.isVirtual())
+ offsetFlags |= BCTI_Virtual;
+ if (base.getAccessSpecifier() == AS_public)
+ offsetFlags |= BCTI_Public;
+
+ fields.push_back(cir::IntAttr::get(offsetFlagsLTy, offsetFlags));
+ }
+}
+
+mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
+ QualType ty) {
+ // We want to operate on the canonical type.
+ ty = ty.getCanonicalType();
+
+ // Check if we've already emitted an RTTI descriptor for this type.
+ SmallString<256> name;
+ llvm::raw_svector_ostream out(name);
+ cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out);
+
+ auto oldGV = dyn_cast_or_null<cir::GlobalOp>(
+ mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));
+
+ if (oldGV && !oldGV.isDeclaration()) {
+ assert(!oldGV.hasAvailableExternallyLinkage() &&
+ "available_externally typeinfos not yet implemented");
+ return cgm.getBuilder().getGlobalViewAttr(cgm.getBuilder().getUInt8PtrTy(),
+ oldGV);
+ }
+
+ // Check if there is already an external RTTI descriptor for this type.
+ if (isStandardLibraryRttiDescriptor(ty) ||
+ shouldUseExternalRttiDescriptor(cgm, ty))
+ return getAddrOfExternalRTTIDescriptor(loc, ty);
+
+ // Emit the standard library with external linkage.
+ cir::GlobalLinkageKind linkage = getTypeInfoLinkage(cgm, ty);
+
+ // Give the type_info object and name the formal visibility of the
+ // type itself.
+ assert(!cir::MissingFeatures::hiddenVisibility());
+ assert(!cir::MissingFeatures::protectedVisibility());
+
+ mlir::SymbolTable::Visibility symVisibility;
+ if (cir::isLocalLinkage(linkage))
+ // If the linkage is local, only default visibility makes sense.
+ symVisibility = mlir::SymbolTable::Visibility::Public;
+ else if (cxxABI.classifyRTTIUniqueness(ty, linkage) ==
+ CIRGenItaniumCXXABI::RUK_NonUniqueHidden) {
+ cgm.errorNYI(
+ "buildTypeInfo: classifyRTTIUniqueness == RUK_NonUniqueHidden");
+ symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
+ } else
+ symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
+
+ return buildTypeInfo(loc, ty, linkage, symVisibility);
+}
+
+mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
+ mlir::Location loc, QualType ty, cir::GlobalLinkageKind linkage,
+ mlir::SymbolTable::Visibility visibility) {
+ CIRGenBuilderTy &builder = cgm.getBuilder();
+
+ assert(!cir::MissingFeatures::setDLLStorageClass());
+
+ // Add the vtable pointer.
+ buildVTablePointer(loc, cast<Type>(ty));
+
+ // And the name.
+ cir::GlobalOp typeName = getAddrOfTypeName(loc, ty, linkage);
+ mlir::Attribute typeNameField;
+
+ // If we're supposed to demote the visibility, be sure to set a flag
+ // to use a string comparison for type_info comparisons.
+ CIRGenItaniumCXXABI::RTTIUniquenessKind rttiUniqueness =
+ cxxABI.classifyRTTIUniqueness(ty, linkage);
+ if (rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique) {
+ // The flag is the sign bit, which on ARM64 is defined to be clear
+ // for global pointers. This is very ARM64-specific.
+ cgm.errorNYI(
+ "buildTypeInfo: rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique");
+ } else {
+ typeNameField =
+ builder.getGlobalViewAttr(builder.getUInt8PtrTy(), typeName);
+ }
+
+ fields.push_back(typeNameField);
+
+ 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");
+
+ // GCC treats vector types as fundamental types.
+ case Type::Builtin:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::ConstantMatrix:
+ case Type::Complex:
+ case Type::BlockPointer:
+ // Itanium C++ ABI 2.9.5p4:
+ // abi::__fundamental_type_info adds no data members to std::type_info.
+ break;
+
+ 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:
+ break;
+
+ case Type::BitInt:
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::ArrayParameter:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__array_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__function_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Enum:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__enum_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Record: {
+ const auto *rd =
+ cast<CXXRecordDecl>(cast<RecordType>(ty)->getOriginalDecl())
+ ->getDefinitionOrSelf();
+ if (!rd->hasDefinition() || !rd->getNumBases()) {
+ // We don't need to emit any fields.
+ break;
+ }
+
+ if (canUseSingleInheritance(rd)) {
+ buildSIClassTypeInfo(loc, rd);
+ } else {
+ buildVMIClassTypeInfo(loc, rd);
+ }
+
+ break;
+ }
+
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ cgm.errorNYI("buildTypeInfo: ObjCObject & ObjCInterface");
+ break;
+
+ case Type::ObjCObjectPointer:
+ cgm.errorNYI("buildTypeInfo: ObjCObjectPointer");
+ break;
+
+ case Type::Pointer:
+ cgm.errorNYI("buildTypeInfo: Pointer");
+ break;
+
+ case Type::MemberPointer:
+ cgm.errorNYI("buildTypeInfo: MemberPointer");
+ break;
+
+ case Type::Atomic:
+ // No fields, at least for the moment.
+ break;
+
+ case Type::HLSLAttributedResource:
+ case Type::HLSLInlineSpirv:
+ llvm_unreachable("HLSL doesn't support RTTI");
+ }
+
+ assert(!cir::MissingFeatures::opGlobalDLLImportExport());
+ cir::TypeInfoAttr init = builder.getTypeInfo(builder.getArrayAttr(fields));
+
+ SmallString<256> name;
+ llvm::raw_svector_ostream out(name);
+ cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out);
+
+ // Create new global and search for an existing global.
+ auto oldGV = dyn_cast_or_null<cir::GlobalOp>(
+ mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));
+
+ cir::GlobalOp gv =
+ CIRGenModule::createGlobalOp(cgm, loc, name, init.getType(),
+ /*isConstant=*/true);
+
+ // Export the typeinfo in the same circumstances as the vtable is
+ // exported.
+ if (cgm.getTarget().hasPS4DLLImportExport()) {
+ cgm.errorNYI("buildTypeInfo: target hasPS4DLLImportExport");
+ return {};
+ }
+
+ // If there's already an old global variable, replace it with the new one.
+ if (oldGV) {
+ // Replace occurrences of the old variable if needed.
+ gv.setName(oldGV.getName());
+ if (!oldGV->use_empty()) {
+ cgm.errorNYI("buildTypeInfo: old GV !use_empty");
+ return {};
+ }
+ oldGV->erase();
+ }
+
+ if (cgm.supportsCOMDAT() && cir::isWeakForLinker(gv.getLinkage())) {
+ assert(!cir::MissingFeatures::setComdat());
+ cgm.errorNYI("buildTypeInfo: supportsCOMDAT & isWeakForLinker");
+ return {};
+ }
+
+ CharUnits align = cgm.getASTContext().toCharUnitsFromBits(
+ cgm.getTarget().getPointerAlign(LangAS::Default));
+ gv.setAlignmentAttr(cgm.getSize(align));
+
+ // The Itanium ABI specifies that type_info objects must be globally
+ // unique, with one exception: if the type is an incomplete class
+ // type or a (possibly indirect) pointer to one. That exception
+ // affects the general case of comparing type_info objects produced
+ // by the typeid operator, which is why the comparison operators on
+ // std::type_info generally use the type_info name pointers instead
+ // of the object addresses. However, the language's built-in uses
+ // of RTTI generally require class types to be complete, even when
+ // manipulating pointers to those class types. This allows the
+ // implementation of dynamic_cast to rely on address equality tests,
+ // which is much faster.
+
+ // All of this is to say that it's important that both the type_info
+ // object and the type_info name be uniqued when weakly emitted.
+
+ mlir::SymbolTable::setSymbolVisibility(typeName, visibility);
+ assert(!cir::MissingFeatures::setDLLStorageClass());
+ assert(!cir::MissingFeatures::opGlobalPartition());
+ assert(!cir::MissingFeatures::setDSOLocal());
+
+ mlir::SymbolTable::setSymbolVisibility(gv, visibility);
+ assert(!cir::MissingFeatures::setDLLStorageClass());
+ assert(!cir::MissingFeatures::opGlobalPartition());
+ assert(!cir::MissingFeatures::setDSOLocal());
+
+ CIRGenModule::setInitializer(gv, init);
+ return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
+}
+
+mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) {
+ return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);
+}
+
+/// What sort of uniqueness rules should we use for the RTTI for the
+/// given type?
+CIRGenItaniumCXXABI::RTTIUniquenessKind
+CIRGenItaniumCXXABI::classifyRTTIUniqueness(
+ QualType canTy, cir::GlobalLinkageKind linkage) const {
+ if (shouldRTTIBeUnique())
+ return RUK_Unique;
+
+ // It's only necessary for linkonce_odr or weak_odr linkage.
+ if (linkage != cir::GlobalLinkageKind::LinkOnceODRLinkage &&
+ linkage != cir::GlobalLinkageKind::WeakODRLinkage)
+ return RUK_Unique;
+
+ // It's only necessary with default visibility.
+ if (canTy->getVisibility() != DefaultVisibility)
+ return RUK_Unique;
+
+ // If we're not required to publish this symbol, hide it.
+ if (linkage == cir::GlobalLinkageKind::LinkOnceODRLinkage)
+ return RUK_NonUniqueHidden;
+
+ // If we're required to publish this symbol, as we might be under an
+ // explicit instantiation, leave it with default visibility but
+ // enable string-comparisons.
+ assert(linkage == cir::GlobalLinkageKind::WeakODRLinkage);
+ return RUK_NonUniqueVisible;
+}
+
void CIRGenItaniumCXXABI::emitDestructorCall(
CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index c977ff9..2bd2729 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -730,7 +730,6 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
// since this is the job for its original source.
bool isDefinitionAvailableExternally =
astContext.GetGVALinkageForVariable(vd) == GVA_AvailableExternally;
- assert(!cir::MissingFeatures::needsGlobalCtorDtor());
// It is useless to emit the definition for an available_externally variable
// which can't be marked as const.
@@ -743,6 +742,10 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
return;
mlir::Attribute init;
+ bool needsGlobalCtor = false;
+ bool needsGlobalDtor =
+ !isDefinitionAvailableExternally &&
+ vd->needsDestruction(astContext) == QualType::DK_cxx_destructor;
const VarDecl *initDecl;
const Expr *initExpr = vd->getAnyInitializer(initDecl);
@@ -777,8 +780,8 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
if (initDecl->hasFlexibleArrayInit(astContext))
errorNYI(vd->getSourceRange(), "flexible array initializer");
init = builder.getZeroInitAttr(convertType(qt));
- if (astContext.GetGVALinkageForVariable(vd) != GVA_AvailableExternally)
- errorNYI(vd->getSourceRange(), "global constructor");
+ if (!isDefinitionAvailableExternally)
+ needsGlobalCtor = true;
} else {
errorNYI(vd->getSourceRange(), "static initializer");
}
@@ -787,8 +790,7 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
// We don't need an initializer, so remove the entry for the delayed
// initializer position (just in case this entry was delayed) if we
// also don't need to register a destructor.
- if (vd->needsDestruction(astContext) == QualType::DK_cxx_destructor)
- errorNYI(vd->getSourceRange(), "delayed destructor");
+ assert(!cir::MissingFeatures::deferredCXXGlobalInit());
}
}
@@ -827,6 +829,9 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
if (emitter)
emitter->finalize(gv);
+ assert(!cir::MissingFeatures::opGlobalConstant());
+ assert(!cir::MissingFeatures::opGlobalSection());
+
// Set CIR's linkage type as appropriate.
cir::GlobalLinkageKind linkage =
getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);
@@ -844,6 +849,10 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
assert(!cir::MissingFeatures::opGlobalThreadLocal());
maybeSetTrivialComdat(*vd, gv);
+
+ // Emit the initializer function if necessary.
+ if (needsGlobalCtor || needsGlobalDtor)
+ emitCXXGlobalVarDeclInitFunc(vd, gv, needsGlobalCtor);
}
void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
@@ -2184,8 +2193,13 @@ mlir::Attribute CIRGenModule::getAddrOfRTTIDescriptor(mlir::Location loc,
if (!shouldEmitRTTI(forEh))
return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
- errorNYI(loc, "getAddrOfRTTIDescriptor");
- return mlir::Attribute();
+ if (forEh && ty->isObjCObjectPointerType() &&
+ langOpts.ObjCRuntime.isGNUFamily()) {
+ errorNYI(loc, "getAddrOfRTTIDescriptor: Objc PtrType & Objc RT GUN");
+ return {};
+ }
+
+ return getCXXABI().getAddrOfRTTIDescriptor(loc, ty);
}
// TODO(cir): this can be shared with LLVM codegen.
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 073e8d9..2c4c6dd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -256,6 +256,24 @@ public:
mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty,
bool forEH = false);
+ static mlir::SymbolTable::Visibility getMLIRVisibility(Visibility v) {
+ switch (v) {
+ case DefaultVisibility:
+ return mlir::SymbolTable::Visibility::Public;
+ case HiddenVisibility:
+ return mlir::SymbolTable::Visibility::Private;
+ case ProtectedVisibility:
+ // The distinction between ProtectedVisibility and DefaultVisibility is
+ // that symbols with ProtectedVisibility, while visible to the dynamic
+ // linker like DefaultVisibility, are guaranteed to always dynamically
+ // resolve to a symbol in the current shared object. There is currently no
+ // equivalent MLIR visibility, so we fall back on the fact that the symbol
+ // is visible.
+ return mlir::SymbolTable::Visibility::Public;
+ }
+ llvm_unreachable("unknown visibility!");
+ }
+
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
@@ -408,6 +426,13 @@ public:
void emitGlobalVarDefinition(const clang::VarDecl *vd,
bool isTentative = false);
+ /// Emit the function that initializes the specified global
+ void emitCXXGlobalVarDeclInit(const VarDecl *varDecl, cir::GlobalOp addr,
+ bool performInit);
+
+ void emitCXXGlobalVarDeclInitFunc(const VarDecl *vd, cir::GlobalOp addr,
+ bool performInit);
+
void emitGlobalOpenACCDecl(const clang::OpenACCConstructDecl *cd);
// C++ related functions.
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
index e41c2d85..fc28ac5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCRecipe.cpp
@@ -89,7 +89,7 @@ mlir::Value OpenACCRecipeBuilderBase::makeBoundsAlloca(
std::transform_inclusive_scan(
resultTypes.begin(), resultTypes.end(),
std::back_inserter(allocasLeftArr), std::plus<bool>{},
- [](QualType ty) { return !ty->isConstantArrayType(); });
+ [](QualType ty) { return !ty->isConstantArrayType(); }, false);
// Keep track of the number of 'elements' that we're allocating. Individual
// allocas should multiply this by the size of its current allocation.
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
index 914ef16..bf0ddc5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
@@ -57,7 +57,7 @@ namespace clang::CIRGen {
/// cir.func @store_field() {
/// %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s"] {alignment = 4 : i64}
/// %1 = cir.const #cir.int<2> : !s32i
-/// %2 = cir.cast(integral, %1 : !s32i), !u32i
+/// %2 = cir.cast integral %1 : !s32i -> !u32i
/// %3 = cir.get_member %0[3] {name = "more_bits"} : !cir.ptr<!rec_S> ->
/// !cir.ptr<!u16i>
/// %4 = cir.set_bitfield(#bfi_more_bits, %3 :
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index af8f5ae..94d856b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -47,6 +47,49 @@ cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {
return cgm.getBuilder().getAnonRecordTy(tys, /*incomplete=*/false);
}
+/// At this point in the translation unit, does it appear that can we
+/// rely on the vtable being defined elsewhere in the program?
+///
+/// The response is really only definitive when called at the end of
+/// the translation unit.
+///
+/// The only semantic restriction here is that the object file should
+/// not contain a vtable definition when that vtable is defined
+/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
+/// vtables when unnecessary.
+/// TODO(cir): this should be merged into common AST helper for codegen.
+bool CIRGenVTables::isVTableExternal(const CXXRecordDecl *rd) {
+ assert(rd->isDynamicClass() && "Non-dynamic classes have no VTable.");
+
+ // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
+ // emit them even if there is an explicit template instantiation.
+ if (cgm.getTarget().getCXXABI().isMicrosoft())
+ return false;
+
+ // If we have an explicit instantiation declaration (and not a
+ // definition), the vtable is defined elsewhere.
+ TemplateSpecializationKind tsk = rd->getTemplateSpecializationKind();
+ if (tsk == TSK_ExplicitInstantiationDeclaration)
+ return true;
+
+ // Otherwise, if the class is an instantiated template, the
+ // vtable must be defined here.
+ if (tsk == TSK_ImplicitInstantiation ||
+ tsk == TSK_ExplicitInstantiationDefinition)
+ return false;
+
+ // Otherwise, if the class doesn't have a key function (possibly
+ // anymore), the vtable must be defined here.
+ const CXXMethodDecl *keyFunction =
+ cgm.getASTContext().getCurrentKeyFunction(rd);
+ if (!keyFunction)
+ return false;
+
+ // Otherwise, if we don't have a definition of the key function, the
+ // vtable must be defined somewhere else.
+ return !keyFunction->hasBody();
+}
+
/// This is a callback from Sema to tell us that a particular vtable is
/// required to be emitted in this translation unit.
///
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h
index e19242c..9c425ab 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.h
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h
@@ -100,6 +100,8 @@ public:
/// is enabled) and the VTT (if the class has virtual bases).
void generateClassData(const CXXRecordDecl *rd);
+ bool isVTableExternal(const clang::CXXRecordDecl *rd);
+
/// Returns the type of a vtable with the given layout. Normally a struct of
/// arrays of pointers, with one struct element for each vtable in the vtable
/// group.
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index c1f27ec..3ebf460 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -18,6 +18,7 @@ add_clang_library(clangCIR
CIRGenCXXABI.cpp
CIRGenBuiltin.cpp
CIRGenDecl.cpp
+ CIRGenDeclCXX.cpp
CIRGenDeclOpenACC.cpp
CIRGenException.cpp
CIRGenExpr.cpp