[clang] [CIR] Add support for globals reference variables (PR #182608)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 23 07:29:03 PST 2026
https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/182608
>From d461fc0f99daaf8d94f6fd48c405f7e1270ce596 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
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 <ekeane at nvidia.com>
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 <ekeane at nvidia.com>
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 <ekeane at nvidia.com>
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;
More information about the cfe-commits
mailing list