Author: adams381
Date: 2025-12-18T14:40:41-08:00
New Revision: d524ecbf0f735fa2b5ea73ea70da8c68985afe33

URL: 
https://github.com/llvm/llvm-project/commit/d524ecbf0f735fa2b5ea73ea70da8c68985afe33
DIFF: 
https://github.com/llvm/llvm-project/commit/d524ecbf0f735fa2b5ea73ea70da8c68985afe33.diff

LOG: [CIR] Add emitDeclInvariant for global with constant storage (#171915)

Implement emitDeclInvariant to emit llvm.invariant.start intrinsic for
global variables with constant storage. This enables optimizations by
marking when a global becomes read-only after initialization.

## Changes
- Add emitDeclInvariant and emitInvariantStart functions in
CIRGenCXX.cpp
- Add emitInvariantStart declaration in CIRGenFunction.h
- Update emitCXXGlobalVarDeclInit to call emitDeclInvariant for constant
storage globals after initialization
- Update getOrCreateCIRGlobal to set constant flag on globals with
constant storage
- Add comprehensive test covering positive and negative cases

## Implementation Details
The implementation handles address spaces correctly, dynamically
constructing the intrinsic name (e.g., invariant.start.p0,
invariant.start.p10) based on the pointer's address space. The intrinsic
is only emitted when optimizations are enabled, matching classic codegen
behavior.

## Testing
All tests pass (411/412, 1 unsupported). The test file includes CIR,
LLVM, and OGCG checks for both optimized and non-optimized builds.

Added: 
    clang/test/CIR/CodeGen/global-constant-storage.cpp

Modified: 
    clang/lib/CIR/CodeGen/CIRGenCXX.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenModule.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
index 71568ec87a31b..f8a058b521c54 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
@@ -21,6 +21,35 @@
 using namespace clang;
 using namespace clang::CIRGen;
 
+/// Emit code to cause the variable at the given address to be considered as
+/// constant from this point onwards.
+static void emitDeclInvariant(CIRGenFunction &cgf, const VarDecl *d) {
+  mlir::Value addr = cgf.cgm.getAddrOfGlobalVar(d);
+  cgf.emitInvariantStart(cgf.getContext().getTypeSizeInChars(d->getType()),
+                         addr, cgf.getLoc(d->getSourceRange()));
+}
+
+void CIRGenFunction::emitInvariantStart(CharUnits size, mlir::Value addr,
+                                        mlir::Location loc) {
+  // Do not emit the intrinsic if we're not optimizing.
+  if (!cgm.getCodeGenOpts().OptimizationLevel)
+    return;
+
+  CIRGenBuilderTy &builder = getBuilder();
+
+  // Create the size constant as i64
+  uint64_t width = size.getQuantity();
+  mlir::Value sizeValue = builder.getConstInt(loc, builder.getSInt64Ty(),
+                                              static_cast<int64_t>(width));
+
+  // Create the intrinsic call. The llvm.invariant.start intrinsic returns a
+  // token, but we don't need to capture it. The address space will be
+  // automatically handled when the intrinsic is lowered to LLVM IR.
+  cir::LLVMIntrinsicCallOp::create(
+      builder, loc, builder.getStringAttr("invariant.start"), addr.getType(),
+      mlir::ValueRange{sizeValue, addr});
+}
+
 static void emitDeclInit(CIRGenFunction &cgf, const VarDecl *varDecl,
                          cir::GlobalOp globalOp) {
   assert((varDecl->hasGlobalStorage() ||
@@ -234,13 +263,32 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl 
*varDecl,
 
     bool needsDtor = varDecl->needsDestruction(getASTContext()) ==
                      QualType::DK_cxx_destructor;
+    bool isConstantStorage =
+        varDecl->getType().isConstantStorage(getASTContext(), true, 
!needsDtor);
     // PerformInit, constant store invariant / destroy handled below.
-    if (performInit)
+    if (performInit) {
       emitDeclInit(cgf, varDecl, addr);
-
-    if (varDecl->getType().isConstantStorage(getASTContext(), true, 
!needsDtor))
-      errorNYI(varDecl->getSourceRange(), "global with constant storage");
-    else
+      // For constant storage, emit invariant.start in the ctor region after
+      // initialization but before the yield.
+      if (isConstantStorage) {
+        CIRGenBuilderTy &builder = cgf.getBuilder();
+        mlir::OpBuilder::InsertionGuard guard(builder);
+        // Set insertion point to end of ctor region (before yield)
+        if (!addr.getCtorRegion().empty()) {
+          mlir::Block *block = &addr.getCtorRegion().back();
+          // Find the yield op and insert before it
+          mlir::Operation *yieldOp = block->getTerminator();
+          if (yieldOp) {
+            builder.setInsertionPoint(yieldOp);
+            emitDeclInvariant(cgf, varDecl);
+          }
+        }
+      }
+    } else if (isConstantStorage) {
+      emitDeclInvariant(cgf, varDecl);
+    }
+
+    if (!isConstantStorage)
       emitDeclDestroy(cgf, varDecl, addr);
     return;
   }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 254a8c5883d48..faba6878a9707 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1630,6 +1630,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee,
                               llvm::ArrayRef<mlir::Value> args = {});
 
+  void emitInvariantStart(CharUnits size, mlir::Value addr, mlir::Location 
loc);
+
   /// Emit the computation of the specified expression of scalar type.
   mlir::Value emitScalarExpr(const clang::Expr *e,
                              bool ignoreResultAssign = false);

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 15bc870da91e7..42df6304628dc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -662,10 +662,21 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, 
mlir::Type ty,
 
   mlir::Location loc = getLoc(d->getSourceRange());
 
+  // Calculate constant storage flag before creating the global. This was moved
+  // from after the global creation to ensure the constant flag is set 
correctly
+  // at creation time, matching the logic used in emitCXXGlobalVarDeclInit.
+  bool isConstant = false;
+  if (d) {
+    bool needsDtor =
+        d->needsDestruction(astContext) == QualType::DK_cxx_destructor;
+    isConstant = d->getType().isConstantStorage(
+        astContext, /*ExcludeCtor=*/true, /*ExcludeDtor=*/!needsDtor);
+  }
+
   // mlir::SymbolTable::Visibility::Public is the default, no need to 
explicitly
   // mark it as such.
   cir::GlobalOp gv =
-      CIRGenModule::createGlobalOp(*this, loc, mangledName, ty, false,
+      CIRGenModule::createGlobalOp(*this, loc, mangledName, ty, isConstant,
                                    /*insertPoint=*/entry.getOperation());
 
   // This is the first use or definition of a mangled name.  If there is a
@@ -685,10 +696,6 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, 
mlir::Type ty,
       errorNYI(d->getSourceRange(), "OpenMP target global variable");
 
     gv.setAlignmentAttr(getSize(astContext.getDeclAlign(d)));
-    // FIXME: This code is overly simple and should be merged with other global
-    // handling.
-    gv.setConstant(d->getType().isConstantStorage(
-        astContext, /*ExcludeCtor=*/false, /*ExcludeDtor=*/false));
 
     setLinkageForGV(gv, d);
 
@@ -880,10 +887,12 @@ void CIRGenModule::emitGlobalVarDefinition(const 
clang::VarDecl *vd,
     emitter->finalize(gv);
 
   // If it is safe to mark the global 'constant', do so now.
+  // Use the same logic as classic codegen EmitGlobalVarDefinition.
   gv.setConstant((vd->hasAttr<CUDAConstantAttr>() && langOpts.CUDAIsDevice) ||
                  (!needsGlobalCtor && !needsGlobalDtor &&
-                  vd->getType().isConstantStorage(
-                      astContext, /*ExcludeCtor=*/true, 
/*ExcludeDtor=*/true)));
+                  vd->getType().isConstantStorage(astContext,
+                                                  /*ExcludeCtor=*/true,
+                                                  /*ExcludeDtor=*/true)));
   assert(!cir::MissingFeatures::opGlobalSection());
 
   // Set CIR's linkage type as appropriate.

diff  --git a/clang/test/CIR/CodeGen/global-constant-storage.cpp 
b/clang/test/CIR/CodeGen/global-constant-storage.cpp
new file mode 100644
index 0000000000000..6f62823b8235f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/global-constant-storage.cpp
@@ -0,0 +1,266 @@
+// RUN: %clang_cc1 -std=c++20 -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 --check-prefix=CIR-BEFORE-LPP --input-file=%t-before.cir %s
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir -O1 %s -o %t-o1.cir
+// RUN: FileCheck --check-prefix=CIR-O1 --input-file=%t-o1.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm -O1 -disable-llvm-passes %s -o %t-opt.ll
+// RUN: FileCheck --check-prefix=LLVM-OPT --input-file=%t-opt.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -O1 
-disable-llvm-passes %s -o %t-opt-ogcg.ll
+// RUN: FileCheck --check-prefix=OGCG-OPT --input-file=%t-opt-ogcg.ll %s
+
+// Test for global with constant storage - const object with constructor but 
no destructor
+// Check that we add an llvm.invariant.start to mark when a global becomes 
read-only.
+
+struct A {
+  A();
+  int n;
+};
+
+// Should emit invariant.start - has constructor, no destructor, no mutable
+extern const A a = A();
+
+struct A2 {
+  A2();
+  constexpr ~A2() {}
+  int n;
+};
+
+// Should emit invariant.start - constexpr destructor doesn't prevent constant 
storage
+extern const A2 a2 = A2();
+
+struct B {
+  B();
+  mutable int n;
+};
+
+// Should NOT emit invariant.start - has mutable member
+extern const B b = B();
+
+// Simple case - just const C c; (no initializer) - Andy's suggestion
+class C {
+public:
+  C();
+  int a;
+  int b;
+};
+
+const C c;
+
+// CIR checks before LoweringPrepare transformation - globals have ctor regions
+// Test case 'a' - before LoweringPrepare
+// CIR-BEFORE-LPP: cir.global external @a = ctor : !rec_A {
+// CIR-BEFORE-LPP:   %[[OBJ:.*]] = cir.get_global @a : !cir.ptr<!rec_A>
+// CIR-BEFORE-LPP:   cir.call @_ZN1AC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_A>) -> ()
+// CIR-BEFORE-LPP:   %[[OBJ2:.*]] = cir.get_global @a : !cir.ptr<!rec_A>
+// CIR-BEFORE-LPP: }
+
+// Test case 'a2' - before LoweringPrepare
+// CIR-BEFORE-LPP: cir.global external @a2 = ctor : !rec_A2 {
+// CIR-BEFORE-LPP:   %[[OBJ:.*]] = cir.get_global @a2 : !cir.ptr<!rec_A2>
+// CIR-BEFORE-LPP:   cir.call @_ZN2A2C1Ev(%[[OBJ]]) : (!cir.ptr<!rec_A2>) -> ()
+// CIR-BEFORE-LPP:   %[[OBJ2:.*]] = cir.get_global @a2 : !cir.ptr<!rec_A2>
+// CIR-BEFORE-LPP: }
+
+// Test case 'b' - before LoweringPrepare
+// CIR-BEFORE-LPP: cir.global external @b = ctor : !rec_B {
+// CIR-BEFORE-LPP:   %[[OBJ:.*]] = cir.get_global @b : !cir.ptr<!rec_B>
+// CIR-BEFORE-LPP:   cir.call @_ZN1BC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_B>) -> ()
+// CIR-BEFORE-LPP: }
+
+// Test case 'c' - before LoweringPrepare (internal linkage)
+// CIR-BEFORE-LPP: cir.global {{.*}} internal {{.*}} @_ZL1c = ctor : !rec_C {
+// CIR-BEFORE-LPP:   %[[OBJ:.*]] = cir.get_global @_ZL1c : !cir.ptr<!rec_C>
+// CIR-BEFORE-LPP:   cir.call @_ZN1CC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_C>) -> ()
+// CIR-BEFORE-LPP:   %[[OBJ2:.*]] = cir.get_global @_ZL1c : !cir.ptr<!rec_C>
+// CIR-BEFORE-LPP: }
+
+// Check all globals first (they appear at the top of LLVM/OGCG output)
+// LLVM: @a ={{.*}} global {{.*}} zeroinitializer
+// LLVM: @a2 ={{.*}} global {{.*}} zeroinitializer
+// LLVM: @b ={{.*}} global {{.*}} zeroinitializer
+// LLVM: @_ZL1c ={{.*}} global {{.*}} zeroinitializer
+
+// OGCG: @a ={{.*}} global {{.*}} zeroinitializer
+// OGCG: @a2 ={{.*}} global {{.*}} zeroinitializer
+// OGCG: @b ={{.*}} global {{.*}} zeroinitializer
+// OGCG: @_ZL1c ={{.*}} global {{.*}} zeroinitializer
+
+// Test case 'a' - should have constant storage
+// CIR checks for 'a'
+// CIR: cir.global external @a = #cir.zero : !rec_A
+// CIR: cir.func internal private @__cxx_global_var_init() {
+// CIR:   %[[OBJ:.*]] = cir.get_global @a : !cir.ptr<!rec_A>
+// CIR:   cir.call @_ZN1AC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_A>) -> ()
+// CIR:   cir.return
+// CIR: }
+
+// LLVM checks for 'a' (no optimization)
+// LLVM: define internal void @__cxx_global_var_init() {
+// LLVM:   call void @_ZN1AC1Ev(ptr @a)
+// LLVM:   ret void
+// LLVM: }
+
+// OGCG checks for 'a' (no optimization)
+// OGCG: define internal void @__cxx_global_var_init() {{.*}} section 
".text.startup" {
+// OGCG:   call void @_ZN1AC1Ev(ptr noundef nonnull align 4 dereferenceable(4) 
@a)
+// OGCG:   ret void
+// OGCG: }
+
+// Test case 'a2' - should have constant storage (constexpr dtor)
+// CIR checks for 'a2'
+// CIR: cir.global external @a2 = #cir.zero : !rec_A2
+// CIR: cir.func internal private @__cxx_global_var_init.1() {
+// CIR:   %[[OBJ:.*]] = cir.get_global @a2 : !cir.ptr<!rec_A2>
+// CIR:   cir.call @_ZN2A2C1Ev(%[[OBJ]]) : (!cir.ptr<!rec_A2>) -> ()
+// CIR:   cir.return
+// CIR: }
+
+// LLVM checks for 'a2' (no optimization)
+// LLVM: define internal void @__cxx_global_var_init.1() {
+// LLVM:   call void @_ZN2A2C1Ev(ptr @a2)
+// LLVM:   ret void
+// LLVM: }
+
+// OGCG checks for 'a2' (no optimization)
+// OGCG: define internal void @__cxx_global_var_init.1() {{.*}} section 
".text.startup" {
+// OGCG:   call void @_ZN2A2C1Ev(ptr noundef nonnull align 4 
dereferenceable(4) @a2)
+// OGCG:   ret void
+// OGCG: }
+
+// Test case 'b' - should NOT have constant storage (mutable member)
+// CIR checks for 'b'
+// CIR: cir.global external @b = #cir.zero : !rec_B
+// CIR: cir.func internal private @__cxx_global_var_init.2() {
+// CIR:   %[[OBJ:.*]] = cir.get_global @b : !cir.ptr<!rec_B>
+// CIR:   cir.call @_ZN1BC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_B>) -> ()
+// CIR:   cir.return
+// CIR: }
+
+// LLVM checks for 'b' (no optimization)
+// LLVM: define internal void @__cxx_global_var_init.2() {
+// LLVM:   call void @_ZN1BC1Ev(ptr @b)
+// LLVM:   ret void
+// LLVM: }
+
+// OGCG checks for 'b' (no optimization)
+// OGCG: define internal void @__cxx_global_var_init.2() {{.*}} section 
".text.startup" {
+// OGCG:   call void @_ZN1BC1Ev(ptr noundef nonnull align 4 dereferenceable(4) 
@b)
+// OGCG:   ret void
+// OGCG: }
+
+// Test case 'c' - Andy's simple case, should have constant storage (internal 
linkage)
+// CIR checks for 'c'
+// CIR: cir.global {{.*}} internal {{.*}} @_ZL1c = #cir.zero : !rec_C
+// CIR: cir.func internal private @__cxx_global_var_init.3() {
+// CIR:   %[[OBJ:.*]] = cir.get_global @_ZL1c : !cir.ptr<!rec_C>
+// CIR:   cir.call @_ZN1CC1Ev(%[[OBJ]]) : (!cir.ptr<!rec_C>) -> ()
+// CIR:   cir.return
+// CIR: }
+
+// LLVM checks for 'c' (no optimization)
+// LLVM: define internal void @__cxx_global_var_init.3() {
+// LLVM:   call void @_ZN1CC1Ev(ptr @_ZL1c)
+// LLVM:   ret void
+// LLVM: }
+
+// OGCG checks for 'c' (no optimization)
+// OGCG: define internal void @__cxx_global_var_init.3() {{.*}} section 
".text.startup" {
+// OGCG:   call void @_ZN1CC1Ev(ptr noundef nonnull align 4 dereferenceable(8) 
@_ZL1c)
+// OGCG:   ret void
+// OGCG: }
+
+// With optimization enabled, should emit invariant.start intrinsic for 
constant storage cases
+
+// Check all globals first (they appear at the top of optimized LLVM/OGCG 
output)
+// LLVM-OPT: @a ={{.*}} global {{.*}} zeroinitializer
+// LLVM-OPT: @a2 ={{.*}} global {{.*}} zeroinitializer
+// LLVM-OPT: @b ={{.*}} global {{.*}} zeroinitializer
+// LLVM-OPT: @_ZL1c ={{.*}} global {{.*}} zeroinitializer
+
+// OGCG-OPT: @a ={{.*}} global {{.*}} zeroinitializer
+// OGCG-OPT: @a2 ={{.*}} global {{.*}} zeroinitializer
+// OGCG-OPT: @b ={{.*}} global {{.*}} zeroinitializer
+// OGCG-OPT: @_ZL1c ={{.*}} global {{.*}} zeroinitializer
+
+// Test case 'a' - optimized checks
+// LLVM-OPT: define internal void @__cxx_global_var_init() {
+// LLVM-OPT:   call void @_ZN1AC1Ev(ptr @a)
+// LLVM-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 4, ptr @a)
+// LLVM-OPT:   ret void
+// LLVM-OPT: }
+
+// OGCG-OPT: define internal void @__cxx_global_var_init() {{.*}} section 
".text.startup" {
+// OGCG-OPT:   call void @_ZN1AC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) @a)
+// OGCG-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 4, ptr @a)
+// OGCG-OPT:   ret void
+// OGCG-OPT: }
+
+// Test case 'a2' - optimized checks
+// LLVM-OPT: define internal void @__cxx_global_var_init.1() {
+// LLVM-OPT:   call void @_ZN2A2C1Ev(ptr @a2)
+// LLVM-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 4, ptr @a2)
+// LLVM-OPT:   ret void
+// LLVM-OPT: }
+
+// OGCG-OPT: define internal void @__cxx_global_var_init.1() {{.*}} section 
".text.startup" {
+// OGCG-OPT:   call void @_ZN2A2C1Ev(ptr noundef nonnull align 4 
dereferenceable(4) @a2)
+// OGCG-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 4, ptr @a2)
+// OGCG-OPT:   ret void
+// OGCG-OPT: }
+
+// Test case 'b' - optimized checks (should NOT emit invariant.start)
+// LLVM-OPT: define internal void @__cxx_global_var_init.2() {
+// LLVM-OPT:   call void @_ZN1BC1Ev(ptr @b)
+// LLVM-OPT-NOT: call {{.*}}@llvm.invariant.start.p0(i64 {{.*}}, ptr @b)
+// LLVM-OPT:   ret void
+// LLVM-OPT: }
+
+// OGCG-OPT: define internal void @__cxx_global_var_init.2() {{.*}} section 
".text.startup" {
+// OGCG-OPT:   call void @_ZN1BC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) @b)
+// OGCG-OPT-NOT: call {{.*}}@llvm.invariant.start.p0(i64 {{.*}}, ptr @b)
+// OGCG-OPT:   ret void
+// OGCG-OPT: }
+
+// Test case 'c' - optimized checks
+// LLVM-OPT: define internal void @__cxx_global_var_init.3() {
+// LLVM-OPT:   call void @_ZN1CC1Ev(ptr @_ZL1c)
+// LLVM-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 8, ptr @_ZL1c)
+// LLVM-OPT:   ret void
+// LLVM-OPT: }
+
+// OGCG-OPT: define internal void @__cxx_global_var_init.3() {{.*}} section 
".text.startup" {
+// OGCG-OPT:   call void @_ZN1CC1Ev(ptr noundef nonnull align 4 
dereferenceable(8) @_ZL1c)
+// OGCG-OPT:   call {{.*}}@llvm.invariant.start.p0(i64 8, ptr @_ZL1c)
+// OGCG-OPT:   ret void
+// OGCG-OPT: }
+
+// CIR checks at -O1 - should include invariant.start intrinsic calls for 
constant storage cases
+// CIR-O1: module {{.*}} attributes {{.*}} cir.opt_info = #cir.opt_info<level 
= 1
+
+// Test case 'a' - CIR at -O1
+// CIR-O1: cir.func internal private @__cxx_global_var_init() {
+// CIR-O1:   cir.call @_ZN1AC1Ev(%{{.*}}) : (!cir.ptr<!rec_A>) -> ()
+// CIR-O1:   cir.call_llvm_intrinsic "invariant.start" {{.*}} : (!s64i, 
!cir.ptr<!rec_A>) -> !cir.ptr<!rec_A>
+// CIR-O1: }
+
+// Test case 'a2' - CIR at -O1
+// CIR-O1: cir.func internal private @__cxx_global_var_init.1() {
+// CIR-O1:   cir.call @_ZN2A2C1Ev(%{{.*}}) : (!cir.ptr<!rec_A2>) -> ()
+// CIR-O1:   cir.call_llvm_intrinsic "invariant.start" {{.*}} : (!s64i, 
!cir.ptr<!rec_A2>) -> !cir.ptr<!rec_A2>
+// CIR-O1: }
+
+// Test case 'b' - CIR at -O1 (should NOT emit invariant.start)
+// CIR-O1: cir.func internal private @__cxx_global_var_init.2() {
+// CIR-O1:   cir.call @_ZN1BC1Ev(%{{.*}}) : (!cir.ptr<!rec_B>) -> ()
+// CIR-O1-NOT: cir.call_llvm_intrinsic "invariant.start"
+// CIR-O1: }
+
+// Test case 'c' - CIR at -O1
+// CIR-O1: cir.func internal private @__cxx_global_var_init.3() {
+// CIR-O1:   cir.call @_ZN1CC1Ev(%{{.*}}) : (!cir.ptr<!rec_C>) -> ()
+// CIR-O1:   cir.call_llvm_intrinsic "invariant.start" {{.*}} : (!s64i, 
!cir.ptr<!rec_C>) -> !cir.ptr<!rec_C>
+// CIR-O1: }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to