Author: Erich Keane Date: 2026-02-24T06:23:44-08:00 New Revision: 06c673ed49eaa504123b23791d393172e94eabbf
URL: https://github.com/llvm/llvm-project/commit/06c673ed49eaa504123b23791d393172e94eabbf DIFF: https://github.com/llvm/llvm-project/commit/06c673ed49eaa504123b23791d393172e94eabbf.diff LOG: [CIR] Add support for globals reference variables (#182608) These are fairly simple, particularly if they don't need special cleanups (which is left unimplemented), but this provides init for a global reference variable. Added: clang/test/CIR/CodeGenCXX/global-refs.cpp Modified: clang/lib/CIR/CodeGen/CIRGenCXX.cpp clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h clang/lib/CIR/CodeGen/CIRGenExpr.cpp clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenModule.h Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index c3457e40a9110..c111705783773 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -294,5 +294,34 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl, return; } - errorNYI(varDecl->getSourceRange(), "global with reference type"); + mlir::OpBuilder::InsertionGuard guard(builder); + auto *block = builder.createBlock(&addr.getCtorRegion()); + CIRGenFunction::LexicalScope scope{*curCGF, addr.getLoc(), + builder.getInsertionBlock()}; + scope.setAsGlobalInit(); + builder.setInsertionPointToStart(block); + mlir::Value getGlobal = builder.createGetGlobal(addr); + + Address declAddr(getGlobal, getASTContext().getDeclAlign(varDecl)); + assert(performInit && "cannot have a constant initializer which needs " + "destruction for reference"); + RValue rv = cgf.emitReferenceBindingToExpr(varDecl->getInit()); + { + mlir::OpBuilder::InsertionGuard guard(builder); + mlir::Operation *rvalDefOp = rv.getValue().getDefiningOp(); + if (rvalDefOp && rvalDefOp->getBlock()) { + mlir::Block *rvalSrcBlock = rvalDefOp->getBlock(); + + if (!rvalSrcBlock->empty() && isa<cir::YieldOp>(rvalSrcBlock->back())) { + mlir::Operation &front = rvalSrcBlock->front(); + getGlobal.getDefiningOp()->moveBefore(&front); + builder.setInsertionPoint(cast<cir::YieldOp>(rvalSrcBlock->back())); + } + } + cgf.emitStoreOfScalar(rv.getValue(), declAddr, /*isVolatile=*/false, ty, + LValueBaseInfo{}); + } + + builder.setInsertionPointToEnd(block); + cir::YieldOp::create(builder, addr->getLoc()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h b/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h index 1cd7b5bffb1dc..5280198524773 100644 --- a/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h +++ b/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h @@ -65,6 +65,8 @@ class ConstantEmitter { /// constant. If this succeeds, the emission must be finalized. mlir::Attribute tryEmitForInitializer(const VarDecl &d); + mlir::Attribute emitForInitializer(const APValue &value, QualType destType); + void finalize(cir::GlobalOp gv); // All of the "abstract" emission methods below permit the emission to diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 83d51bac01d1e..69d98c34c249c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1657,10 +1657,13 @@ static Address createReferenceTemporary(CIRGenFunction &cgf, } case SD_Thread: case SD_Static: { - cgf.cgm.errorNYI( - m->getSourceRange(), - "createReferenceTemporary: static/thread storage duration"); - return Address::invalid(); + auto addr = + mlir::cast<cir::GlobalOp>(cgf.cgm.getAddrOfGlobalTemporary(m, inner)); + auto getGlobal = cgf.cgm.getBuilder().createGetGlobal(addr); + assert(addr.getAlignment().has_value() && + "This should always have an alignment"); + return Address(getGlobal, + clang::CharUnits::fromQuantity(addr.getAlignment().value())); } case SD_Dynamic: diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index 462e73b3acc8d..e3dca9bc0f3c7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -1485,9 +1485,11 @@ ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *e) { ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *e) { - cgm.errorNYI(e->getSourceRange(), - "ConstantLValueEmitter: materialize temporary expr"); - return {}; + assert(e->getStorageDuration() == SD_Static); + const Expr *inner = e->getSubExpr()->skipRValueSubobjectAdjustments(); + mlir::Operation *global = cgm.getAddrOfGlobalTemporary(e, inner); + return ConstantLValue( + cgm.getBuilder().getGlobalViewAttr(mlir::cast<cir::GlobalOp>(global))); } //===----------------------------------------------------------------------===// @@ -1499,6 +1501,14 @@ mlir::Attribute ConstantEmitter::tryEmitForInitializer(const VarDecl &d) { return markIfFailed(tryEmitPrivateForVarInit(d)); } +mlir::Attribute ConstantEmitter::emitForInitializer(const APValue &value, + QualType destType) { + initializeNonAbstract(); + auto c = tryEmitPrivateForMemory(value, destType); + assert(c && "couldn't emit constant value non-abstractly?"); + return c; +} + void ConstantEmitter::finalize(cir::GlobalOp gv) { assert(initializedNonAbstract && "finalizing emitter that was used for abstract emission?"); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 397f80c17b4cb..953f9221b07a4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2887,3 +2887,119 @@ cir::LabelOp CIRGenModule::lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo) { return blockAddressInfoToLabel.lookup(blockInfo); } + +mlir::Operation * +CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, + const Expr *init) { + assert((mte->getStorageDuration() == SD_Static || + mte->getStorageDuration() == SD_Thread) && + "not a global temporary"); + const auto *varDecl = cast<VarDecl>(mte->getExtendingDecl()); + + // If we're not materializing a subobject of the temporary, keep the + // cv-qualifiers from the type of the MaterializeTemporaryExpr. + QualType materializedType = init->getType(); + if (init == mte->getSubExpr()) + materializedType = mte->getType(); + + CharUnits align = getASTContext().getTypeAlignInChars(materializedType); + + auto insertResult = materializedGlobalTemporaryMap.insert({mte, nullptr}); + if (!insertResult.second) + errorNYI(mte->getSourceRange(), "duplicate materialized temporaries"); + + // FIXME: If an externally-visible declaration extends multiple temporaries, + // we need to give each temporary the same name in every translation unit (and + // we also need to make the temporaries externally-visible). + llvm::SmallString<256> name; + llvm::raw_svector_ostream out(name); + getCXXABI().getMangleContext().mangleReferenceTemporary( + varDecl, mte->getManglingNumber(), out); + + APValue *value = nullptr; + if (mte->getStorageDuration() == SD_Static && varDecl->evaluateValue()) { + // If the initializer of the extending declaration is a constant + // initializer, we should have a cached constant initializer for this + // temporay. Note taht this m ight have a diff erent value from the value + // computed by evaluating the initializer if the surrounding constant + // expression modifies the temporary. + value = mte->getOrCreateValue(/*MayCreate=*/false); + } + + // Try evaluating it now, it might have a constant initializer + Expr::EvalResult evalResult; + if (!value && init->EvaluateAsRValue(evalResult, getASTContext()) && + !evalResult.hasSideEffects()) + value = &evalResult.Val; + + assert(!cir::MissingFeatures::addressSpace()); + + std::optional<ConstantEmitter> emitter; + mlir::Attribute initialValue = nullptr; + bool isConstant = false; + mlir::Type type; + + if (value) { + emitter.emplace(*this); + initialValue = emitter->emitForInitializer(*value, materializedType); + + isConstant = materializedType.isConstantStorage( + getASTContext(), /*ExcludeCtor=*/value, /*ExcludeDtor=*/false); + + type = mlir::cast<mlir::TypedAttr>(initialValue).getType(); + } else { + // No initializer, the initialization will be provided when we initialize + // the declaration which performed lifetime extension. + type = getTypes().convertTypeForMem(materializedType); + } + + // Create a global variable for this lifetime-extended temporary. + cir::GlobalLinkageKind linkage = + getCIRLinkageVarDefinition(varDecl, /*isConstant=*/false); + if (linkage == cir::GlobalLinkageKind::ExternalLinkage) { + const VarDecl *initVD; + if (varDecl->isStaticDataMember() && varDecl->getAnyInitializer(initVD) && + isa<CXXRecordDecl>(initVD->getLexicalDeclContext())) { + // Temporaries defined inside a class get linkonce_odr linkage because the + // calss can be defined in multiple translation units. + errorNYI(mte->getSourceRange(), "static data member initialization"); + } else { + // There is no need for this temporary to have external linkage if the + // VarDecl has external linkage. + linkage = cir::GlobalLinkageKind::InternalLinkage; + } + } + mlir::Location loc = getLoc(mte->getSourceRange()); + cir::GlobalOp gv = createGlobalOp(*this, loc, name, type, isConstant); + gv.setInitialValueAttr(initialValue); + + if (emitter) + emitter->finalize(gv); + // Don't assign dllimport or dllexport to local linkage globals + if (!gv.hasLocalLinkage()) { + setGVProperties(gv, varDecl); + assert(!cir::MissingFeatures::setDLLStorageClass()); + } + + gv.setAlignment(align.getAsAlign().value()); + if (supportsCOMDAT() && gv.isWeakForLinker()) + errorNYI(mte->getSourceRange(), + "Global temporary with comdat/weak linkage"); + if (varDecl->getTLSKind()) + errorNYI(mte->getSourceRange(), + "Global temporary with thread local storage"); + mlir::Operation *cv = gv; + + assert(!cir::MissingFeatures::addressSpace()); + + // Update the map with the new temporary. If we created a placeholder above, + // replace it with the new global now. + mlir::Operation *&entry = materializedGlobalTemporaryMap[mte]; + if (entry) { + entry->replaceAllUsesWith(cv); + entry->erase(); + } + entry = cv; + + return cv; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index e7bb0fa499c1b..52464a8bc30c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -117,6 +117,9 @@ class CIRGenModule : public CIRGenTypeCache { /// `noundef` on a return is possible. bool hasStrictReturn(QualType retTy, const Decl *targetDecl); + llvm::DenseMap<const Expr *, mlir::Operation *> + materializedGlobalTemporaryMap; + public: mlir::ModuleOp getModule() const { return theModule; } CIRGenBuilderTy &getBuilder() { return builder; } @@ -658,6 +661,11 @@ class CIRGenModule : public CIRGenTypeCache { // Finalize CIR code generation. void release(); + /// Returns a pointer to a global variable representing a temporary with + /// static or thread storage duration. + mlir::Operation *getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, + const Expr *init); + /// ------- /// Visibility and Linkage /// ------- diff --git a/clang/test/CIR/CodeGenCXX/global-refs.cpp b/clang/test/CIR/CodeGenCXX/global-refs.cpp new file mode 100644 index 0000000000000..8c891f377f1c2 --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/global-refs.cpp @@ -0,0 +1,149 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir +// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR,CIR-BEFORE +// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR,CIR-AFTER +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM + +struct DefCtor{}; +struct WithCtor{ + WithCtor(); + WithCtor(int); +}; + +struct WithCtorDtor{ + WithCtorDtor(); + WithCtorDtor(int); + ~WithCtorDtor(); +}; + + +int globalInt; +// CIR: cir.global external @globalInt = #cir.int<0> : !s32i {alignment = 4 : i64} +// LLVM: @globalInt = global i32 0, align 4 + +int &globalIntRef = globalInt; +// CIR: cir.global constant external @globalIntRef = #cir.global_view<@globalInt> : !cir.ptr<!s32i> {alignment = 8 : i64} +// LLVM: @globalIntRef = constant ptr @globalInt, align 8 + +const int &constGlobalIntRef = 5; +// CIR: cir.global "private" external @_ZGR17constGlobalIntRef_ = #cir.int<5> : !s32i {alignment = 4 : i64} +// CIR: cir.global constant external @constGlobalIntRef = #cir.global_view<@_ZGR17constGlobalIntRef_> : !cir.ptr<!s32i> {alignment = 8 : i64} +// LLVM: @_ZGR17constGlobalIntRef_ = {{.*}}global i32 5, align 4 +// LLVM: @constGlobalIntRef = constant ptr @_ZGR17constGlobalIntRef_, align 8 +// CIR-BEFORE-LLP: FAIL + +DefCtor defCtor{}; +// CIR: cir.global external @defCtor = #cir.undef : !rec_DefCtor {alignment = 1 : i64} +// LLVM: @defCtor = global %struct.DefCtor undef, align 1 + +DefCtor &defCtorRef = defCtor; +// CIR: cir.global constant external @defCtorRef = #cir.global_view<@defCtor> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64} +// LLVM: @defCtorRef = constant ptr @defCtor, align 8 + +const DefCtor &constDefCtorRef{}; +// CIR: cir.global "private" constant external @_ZGR15constDefCtorRef_ = #cir.undef : !rec_DefCtor {alignment = 1 : i64} +// CIR: cir.global constant external @constDefCtorRef = #cir.global_view<@_ZGR15constDefCtorRef_> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64} +// LLVM: @_ZGR15constDefCtorRef_ = {{.*}}constant %struct.DefCtor undef, align 1 +// LLVM: @constDefCtorRef = constant ptr @_ZGR15constDefCtorRef_, align 8 + +WithCtor withCtor{}; +// CIR-BEFORE: cir.global external @withCtor = ctor : !rec_WithCtor { +// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor> +// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>) -> () +// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor> +// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () +// CIR-AFTER-NEXT: cir.return +// CIR-AFTER-NEXT: } +// LLVM: @withCtor = global %struct.WithCtor zeroinitializer, align 1 + +WithCtor &withCtorRef = withCtor; +// CIR: cir.global constant external @withCtorRef = #cir.global_view<@withCtor> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64} +// LLVM: @withCtorRef = constant ptr @withCtor, align 8 + +const WithCtor &constWithCtorRef{}; +// CIR-BEFORE: cir.global external @constWithCtorRef = ctor : !cir.ptr<!rec_WithCtor> { +// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor> +// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>) -> () +// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor> +// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () +// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-AFTER-NEXT: cir.return +// CIR-AFTER-NEXT: } +// LLVM: @constWithCtorRef = global ptr null, align 8 + +const WithCtor &constWithCtorRef2{5}; +// CIR-BEFORE: cir.global external @constWithCtorRef2 = ctor : !cir.ptr<!rec_WithCtor> { +// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor> +// CIR-BEFORE-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>, !s32i) -> () +// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor> +// CIR-AFTER-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>{{.*}}, !s32i{{.*}}) -> () +// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-AFTER-NEXT: cir.return +// CIR-AFTER-NEXT: } +// LLVM: @constWithCtorRef2 = global ptr null, align 8 + +WithCtorDtor withCtorDtor{}; +// CIR-BEFORE: cir.global external @withCtorDtor = ctor : !rec_WithCtorDtor { +// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> () +// CIR-BEFORE-NEXT: } dtor { +// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorD1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> () +// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR-AFTER: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-AFTER-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>{{.*}}) -> () +// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-AFTER-NEXT: %[[GET_DTOR:.*]] = cir.get_global @_ZN12WithCtorDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> +// CIR-AFTER-NEXT: %[[VOID_FN_PTR:.*]] = cir.cast bitcast %[[GET_DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>> +// CIR-AFTER-NEXT: %[[GLOB_TO_VOID:.*]] = cir.cast bitcast %[[GET_GLOB]] : !cir.ptr<!rec_WithCtorDtor> -> !cir.ptr<!void> +// CIR-AFTER-NEXT: %[[DSO_HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR-AFTER-NEXT: cir.call @__cxa_atexit(%[[VOID_FN_PTR]], %[[GLOB_TO_VOID]], %[[DSO_HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>{{.*}}) -> () +// CIR-AFTER-NEXT: cir.return +// CIR-AFTER-NEXT: } +// LLVM: @withCtorDtor = global %struct.WithCtorDtor zeroinitializer, align 1 + +WithCtorDtor &withCtorDtorRef = withCtorDtor; +// CIR: cir.global constant external @withCtorDtorRef = #cir.global_view<@withCtorDtor> : !cir.ptr<!rec_WithCtorDtor> {alignment = 8 : i64} +// LLVM: @withCtorDtorRef = constant ptr @withCtorDtor, align 8 + +// LLVM: define internal void @__cxx_global_var_init{{.*}}() +// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@withCtor) +// LLVM-NEXT: ret void + +// LLVM: define internal void @__cxx_global_var_init{{.*}}() +// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@_ZGR16constWithCtorRef_) +// LLVM-NEXT: store ptr @_ZGR16constWithCtorRef_, ptr @constWithCtorRef, align 8 +// LLVM-NEXT: ret void + +// LLVM: define internal void @__cxx_global_var_init{{.*}}() +// LLVM: call void @_ZN8WithCtorC1Ei(ptr {{.*}}@_ZGR17constWithCtorRef2_, i32 {{.*}}5) +// LLVM-NEXT: store ptr @_ZGR17constWithCtorRef2_, ptr @constWithCtorRef2, align 8 +// LLVM-NEXT: ret void + +// LLVM: define internal void @__cxx_global_var_init{{.*}}() +// LLVM: call void @_ZN12WithCtorDtorC1Ev(ptr {{.*}}@withCtorDtor) +// LLVM-NEXT: call {{.*}}@__cxa_atexit(ptr {{.*}}@_ZN12WithCtorDtorD1Ev, ptr {{.*}}@withCtorDtor, ptr {{.*}}@__dso_handle) +// LLVM-NEXT: ret void + +// TODO(cir): Once we get destructors for temporaries done, we should test them +// here, same as the 'const-WithCtor' examples, except with the 'withCtorDtor' +// versions. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
