https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/182608
>From d461fc0f99daaf8d94f6fd48c405f7e1270ce596 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Fri, 20 Feb 2026 08:32:50 -0800 Subject: [PATCH 1/4] [CIR] Add support for globals reference variables 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. --- clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenCXX.cpp | 31 ++++- clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h | 2 + clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 11 +- clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 16 ++- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 108 +++++++++++++++ clang/lib/CIR/CodeGen/CIRGenModule.h | 5 + clang/test/CIR/CodeGenCXX/global-refs.cpp | 130 ++++++++++++++++++ 8 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 clang/test/CIR/CodeGenCXX/global-refs.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 97c76df0bb0b9..4b26dd96fc3ee 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -279,6 +279,7 @@ struct MissingFeatures { static bool emitNullabilityCheck() { return false; } static bool emitTypeCheck() { return false; } static bool emitTypeMetadataCodeForVCall() { return false; } + static bool materializedGlobalTempCache() { return false; } // Fast math. static bool fastMathGuard() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index c3457e40a9110..3033f1c810845 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 dbd3c92797f23..8c8483bae94d9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2884,3 +2884,111 @@ 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); + + assert(!cir::MissingFeatures::materializedGlobalTempCache()); + + // 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 different 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; + } + } + auto loc = getLoc(mte->getSourceRange()); + auto 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()); + + assert(!cir::MissingFeatures::materializedGlobalTempCache()); + + return cv; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 5b8a105e4912f..3f5a8490864b3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -655,6 +655,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..4271b7ecf3e6b --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/global-refs.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefixes=CIR +// 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 + +DefCtor defCtor{}; +// CIR: cir.global external @defCtor = #cir.undef : !rec_DefCtor {alignment = 1 : i64} +// LLVM: @defCtor = global %struct.DefCtor undef, align 1 +// OGCG: FAIL + +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 +// OGCG: FAIL + +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 +// OGCG: FAIL + +WithCtor withCtor{}; +// CIR: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor> +// CIR-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () +// CIR-NEXT: cir.return +// CIR-NEXT: } +// LLVM: @withCtor = global %struct.WithCtor zeroinitializer, align 1 +// OGCG: FAIL + +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 +// OGCG: FAIL + +const WithCtor &constWithCtorRef{}; +// CIR: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor> +// CIR-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () +// CIR-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-NEXT: cir.return +// CIR-NEXT: } +// LLVM: @constWithCtorRef = global ptr null, align 8 +// OGCG: FAIL + +const WithCtor &constWithCtorRef2{5}; +// CIR: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} +// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor> +// CIR-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i +// CIR-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>{{.*}}, !s32i{{.*}}) -> () +// CIR-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> +// CIR-NEXT: cir.return +// CIR-NEXT: } +// LLVM: @constWithCtorRef2 = global ptr null, align 8 +// OGCG: FAIL + +WithCtorDtor withCtorDtor{}; +// CIR: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast} +// CIR: cir.func internal private @__cxx_global_var_init{{.*}}() { +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>{{.*}}) -> () +// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> +// CIR-NEXT: %[[GET_DTOR:.*]] = cir.get_global @_ZN12WithCtorDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> +// CIR-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-NEXT: %[[GLOB_TO_VOID:.*]] = cir.cast bitcast %[[GET_GLOB]] : !cir.ptr<!rec_WithCtorDtor> -> !cir.ptr<!void> +// CIR-NEXT: %[[DSO_HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> +// CIR-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-NEXT: cir.return +// CIR-NEXT: } +// LLVM: @withCtorDtor = global %struct.WithCtorDtor zeroinitializer, align 1 +// OGCG: FAIL + +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 +// OGCG: FAIL + +// 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. >From d22abcd92d1f6f70009738dfa9038ef5f736b3c9 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Fri, 20 Feb 2026 14:40:20 -0800 Subject: [PATCH 2/4] Remove incorrect check lines --- clang/test/CIR/CodeGenCXX/global-refs.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/clang/test/CIR/CodeGenCXX/global-refs.cpp b/clang/test/CIR/CodeGenCXX/global-refs.cpp index 4271b7ecf3e6b..2e59bc9cb065e 100644 --- a/clang/test/CIR/CodeGenCXX/global-refs.cpp +++ b/clang/test/CIR/CodeGenCXX/global-refs.cpp @@ -31,19 +31,16 @@ const int &constGlobalIntRef = 5; DefCtor defCtor{}; // CIR: cir.global external @defCtor = #cir.undef : !rec_DefCtor {alignment = 1 : i64} // LLVM: @defCtor = global %struct.DefCtor undef, align 1 -// OGCG: FAIL 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 -// OGCG: FAIL 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 -// OGCG: FAIL WithCtor withCtor{}; // CIR: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast} @@ -53,12 +50,10 @@ WithCtor withCtor{}; // CIR-NEXT: cir.return // CIR-NEXT: } // LLVM: @withCtor = global %struct.WithCtor zeroinitializer, align 1 -// OGCG: FAIL 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 -// OGCG: FAIL const WithCtor &constWithCtorRef{}; // CIR: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} @@ -70,7 +65,6 @@ const WithCtor &constWithCtorRef{}; // CIR-NEXT: cir.return // CIR-NEXT: } // LLVM: @constWithCtorRef = global ptr null, align 8 -// OGCG: FAIL const WithCtor &constWithCtorRef2{5}; // CIR: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} @@ -83,7 +77,6 @@ const WithCtor &constWithCtorRef2{5}; // CIR-NEXT: cir.return // CIR-NEXT: } // LLVM: @constWithCtorRef2 = global ptr null, align 8 -// OGCG: FAIL WithCtorDtor withCtorDtor{}; // CIR: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast} @@ -99,12 +92,10 @@ WithCtorDtor withCtorDtor{}; // CIR-NEXT: cir.return // CIR-NEXT: } // LLVM: @withCtorDtor = global %struct.WithCtorDtor zeroinitializer, align 1 -// OGCG: FAIL 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 -// OGCG: FAIL // LLVM: define internal void @__cxx_global_var_init{{.*}}() // LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@withCtor) >From 45ad6ac71a3dde1dca9f79451ba0f116488d29b7 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Fri, 20 Feb 2026 14:40:43 -0800 Subject: [PATCH 3/4] Clang-format --- clang/lib/CIR/CodeGen/CIRGenCXX.cpp | 4 ++-- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index 3033f1c810845..c111705783773 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -318,8 +318,8 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl, builder.setInsertionPoint(cast<cir::YieldOp>(rvalSrcBlock->back())); } } - cgf.emitStoreOfScalar(rv.getValue(), declAddr, /*isVolatile=*/false, - ty, LValueBaseInfo{}); + cgf.emitStoreOfScalar(rv.getValue(), declAddr, /*isVolatile=*/false, ty, + LValueBaseInfo{}); } builder.setInsertionPointToEnd(block); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 8c8483bae94d9..126b1514e2f3b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2936,8 +2936,7 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, if (value) { emitter.emplace(*this); - initialValue = - emitter->emitForInitializer(*value, materializedType); + initialValue = emitter->emitForInitializer(*value, materializedType); isConstant = materializedType.isConstantStorage( getASTContext(), /*ExcludeCtor=*/value, /*ExcludeDtor=*/false); >From d36d2e402ca3e1108d9ecb6967a62aff2701cd34 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Mon, 23 Feb 2026 07:28:40 -0800 Subject: [PATCH 4/4] added global-refs test 'before', plus added the temporary storage cache iwth an NYI to match incubator behavior --- clang/include/clang/CIR/MissingFeatures.h | 1 - clang/lib/CIR/CodeGen/CIRGenModule.cpp | 17 +++- clang/lib/CIR/CodeGen/CIRGenModule.h | 3 + clang/test/CIR/CodeGenCXX/global-refs.cpp | 100 ++++++++++++++-------- 4 files changed, 80 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 4b26dd96fc3ee..97c76df0bb0b9 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -279,7 +279,6 @@ struct MissingFeatures { static bool emitNullabilityCheck() { return false; } static bool emitTypeCheck() { return false; } static bool emitTypeMetadataCodeForVCall() { return false; } - static bool materializedGlobalTempCache() { return false; } // Fast math. static bool fastMathGuard() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 126b1514e2f3b..42960cf9e2fa9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2901,7 +2901,9 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, CharUnits align = getASTContext().getTypeAlignInChars(materializedType); - assert(!cir::MissingFeatures::materializedGlobalTempCache()); + 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 @@ -2964,8 +2966,8 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, linkage = cir::GlobalLinkageKind::InternalLinkage; } } - auto loc = getLoc(mte->getSourceRange()); - auto gv = createGlobalOp(*this, loc, name, type, isConstant); + mlir::Location loc = getLoc(mte->getSourceRange()); + cir::GlobalOp gv = createGlobalOp(*this, loc, name, type, isConstant); gv.setInitialValueAttr(initialValue); if (emitter) @@ -2987,7 +2989,14 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte, assert(!cir::MissingFeatures::addressSpace()); - assert(!cir::MissingFeatures::materializedGlobalTempCache()); + // 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 3f5a8490864b3..6bc1be1d0d756 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -115,6 +115,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; } diff --git a/clang/test/CIR/CodeGenCXX/global-refs.cpp b/clang/test/CIR/CodeGenCXX/global-refs.cpp index 2e59bc9cb065e..8c891f377f1c2 100644 --- a/clang/test/CIR/CodeGenCXX/global-refs.cpp +++ b/clang/test/CIR/CodeGenCXX/global-refs.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefixes=CIR +// 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 @@ -14,6 +16,7 @@ struct WithCtorDtor{ ~WithCtorDtor(); }; + int globalInt; // CIR: cir.global external @globalInt = #cir.int<0> : !s32i {alignment = 4 : i64} // LLVM: @globalInt = global i32 0, align 4 @@ -27,6 +30,7 @@ const int &constGlobalIntRef = 5; // 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} @@ -43,12 +47,16 @@ const DefCtor &constDefCtorRef{}; // LLVM: @constDefCtorRef = constant ptr @_ZGR15constDefCtorRef_, align 8 WithCtor withCtor{}; -// CIR: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast} -// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { -// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor> -// CIR-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () -// CIR-NEXT: cir.return -// CIR-NEXT: } +// 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; @@ -56,41 +64,61 @@ WithCtor &withCtorRef = withCtor; // LLVM: @withCtorRef = constant ptr @withCtor, align 8 const WithCtor &constWithCtorRef{}; -// CIR: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} -// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { -// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>> -// CIR-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor> -// CIR-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> () -// CIR-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> -// CIR-NEXT: cir.return -// CIR-NEXT: } +// 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: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast} -// CIR-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() { -// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>> -// CIR-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor> -// CIR-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i -// CIR-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>{{.*}}, !s32i{{.*}}) -> () -// CIR-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>> -// CIR-NEXT: cir.return -// CIR-NEXT: } +// 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: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast} -// CIR: cir.func internal private @__cxx_global_var_init{{.*}}() { -// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> -// CIR-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>{{.*}}) -> () -// CIR-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor> -// CIR-NEXT: %[[GET_DTOR:.*]] = cir.get_global @_ZN12WithCtorDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> -// CIR-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-NEXT: %[[GLOB_TO_VOID:.*]] = cir.cast bitcast %[[GET_GLOB]] : !cir.ptr<!rec_WithCtorDtor> -> !cir.ptr<!void> -// CIR-NEXT: %[[DSO_HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8> -// CIR-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-NEXT: cir.return -// CIR-NEXT: } +// 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; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
