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

Reply via email to