[clang] [CIR] Implement shouldCreateMemCpyFromGlobal in LoweringPrepare (PR #181276)
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 13 17:01:23 PST 2026
https://github.com/bcardosolopes updated https://github.com/llvm/llvm-project/pull/181276
>From 2dc59d7ead89a04ca33ede2046ad61898ebcba1e Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Wed, 11 Feb 2026 17:03:10 -0800
Subject: [PATCH 1/2] [CIR] Implement shouldCreateMemCpyFromGlobal in
LoweringPrepare
CIRGen emits cir.const + cir.store for aggregate initialization, keeping
closer to source-level semantics. LoweringPrepare transforms stores of
constant aggregates (arrays, records) into cir.global + cir.get_global +
cir.copy, matching OG codegen's shouldCreateMemCpyFromGlobal
optimization.
The transform only applies to stores targeting cir.alloca (local
variables inside cir.func). Stores in other contexts (e.g. OpenACC
reduction recipe init blocks, base class initialization) are left
as cir.const + cir.store.
Also fixes CopyOp lowering to use i64 for the memcpy length instead
of i32, matching OG codegen behavior on 64-bit targets.
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 16 ++--
.../Dialect/Transforms/LoweringPrepare.cpp | 84 ++++++++++++++++++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +-
clang/test/CIR/CodeGen/agg-expr-lvalue.c | 16 +++-
clang/test/CIR/CodeGen/array.cpp | 47 ++++++-----
clang/test/CIR/CodeGen/binassign.c | 4 +-
clang/test/CIR/CodeGen/compound_literal.cpp | 9 +-
clang/test/CIR/CodeGen/copy-constructor.cpp | 2 +-
clang/test/CIR/CodeGen/embed-expr.c | 8 +-
clang/test/CIR/CodeGen/lambda.cpp | 2 +-
clang/test/CIR/CodeGen/loop.cpp | 9 +-
clang/test/CIR/CodeGen/no-odr-use.cpp | 23 ++---
clang/test/CIR/CodeGen/paren-init-list.cpp | 9 +-
.../CIR/CodeGen/pointer-to-member-func.cpp | 28 ++++---
clang/test/CIR/CodeGen/statement-exprs.c | 11 ++-
clang/test/CIR/CodeGen/struct-init.cpp | 15 ++--
clang/test/CIR/CodeGen/struct.cpp | 47 ++++++-----
clang/test/CIR/CodeGen/var-arg-aggregate.c | 2 +-
.../CIR/CodeGen/variable-decomposition.cpp | 9 +-
clang/test/CIR/Lowering/array.cpp | 16 ++--
21 files changed, 248 insertions(+), 112 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 5cb0991326a3c..fef47eea6b342 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -332,7 +332,6 @@ struct MissingFeatures {
static bool setNonGC() { return false; }
static bool setObjCGCLValueClass() { return false; }
static bool setTargetAttributes() { return false; }
- static bool shouldCreateMemCpyFromGlobal() { return false; }
static bool shouldSplitConstantStore() { return false; }
static bool shouldUseBZeroPlusStoresToInitialize() { return false; }
static bool shouldUseMemSetToInitialize() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 42a7d70677b61..f6f32e34798be 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -191,16 +191,6 @@ static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d,
return;
assert(!cir::MissingFeatures::addAutoInitAnnotation());
assert(!cir::MissingFeatures::vectorConstants());
- assert(!cir::MissingFeatures::shouldUseBZeroPlusStoresToInitialize());
- assert(!cir::MissingFeatures::shouldUseMemSetToInitialize());
- assert(!cir::MissingFeatures::shouldSplitConstantStore());
- assert(!cir::MissingFeatures::shouldCreateMemCpyFromGlobal());
- // In CIR we want to emit a store for the whole thing, later lowering
- // prepare to LLVM should unwrap this into the best policy (see asserts
- // above).
- //
- // FIXME(cir): This is closer to memcpy behavior but less optimal, instead of
- // copy from a global, we just create a cir.const out of it.
if (addr.getElementType() != ty)
addr = addr.withElementType(builder, ty);
@@ -218,6 +208,12 @@ static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d,
mlir::Location loc = builder.getUnknownLoc();
if (d.getSourceRange().isValid())
loc = cgm.getLoc(d.getSourceRange());
+
+ // Emit cir.const + cir.store, preserving source-level semantics. For
+ // aggregate types (arrays, records), LoweringPrepare implements the OG
+ // optimization tiers (shouldCreateMemCpyFromGlobal, shouldUseBZeroPlusStores,
+ // shouldUseMemSetToInitialize, shouldSplitConstantStore) by transforming
+ // into cir.global + cir.get_global + cir.copy when appropriate.
builder.createStore(loc, builder.getConstant(loc, constant), addr);
}
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index b7cc8775d298f..3d8ef6ec53f73 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -73,6 +73,7 @@ struct LoweringPreparePass
void lowerArrayDtor(cir::ArrayDtor op);
void lowerArrayCtor(cir::ArrayCtor op);
void lowerTrivialCopyCall(cir::CallOp op);
+ void lowerStoreOfConstAggregate(cir::StoreOp op);
/// Build the function that initializes the specified global
cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -1072,6 +1073,84 @@ void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
}
}
+void LoweringPreparePass::lowerStoreOfConstAggregate(cir::StoreOp op) {
+ // Check if the value operand is a cir.const with aggregate type.
+ auto constOp = op.getValue().getDefiningOp<cir::ConstantOp>();
+ if (!constOp)
+ return;
+
+ mlir::Type ty = constOp.getType();
+ if (!mlir::isa<cir::ArrayType, cir::RecordType>(ty))
+ return;
+
+ // Only transform stores to local variables (backed by cir.alloca).
+ // Stores to other addresses (e.g. base_class_addr) should not be
+ // transformed as they may be partial initializations.
+ auto alloca = op.getAddr().getDefiningOp<cir::AllocaOp>();
+ if (!alloca)
+ return;
+
+ mlir::TypedAttr constant = constOp.getValue();
+
+ // OG implements several optimization tiers for constant aggregate
+ // initialization. For now we always create a global constant + memcpy
+ // (shouldCreateMemCpyFromGlobal). Future work can add the intermediate
+ // tiers.
+ assert(!cir::MissingFeatures::shouldUseBZeroPlusStoresToInitialize());
+ assert(!cir::MissingFeatures::shouldUseMemSetToInitialize());
+ assert(!cir::MissingFeatures::shouldSplitConstantStore());
+
+ // Get function name from parent cir.func.
+ auto func = op->getParentOfType<cir::FuncOp>();
+ if (!func)
+ return;
+ llvm::StringRef funcName = func.getSymName();
+
+ // Get variable name from the alloca.
+ llvm::StringRef varName = alloca.getName();
+
+ // Build name: __const.<func>.<var>
+ std::string name = ("__const." + funcName + "." + varName).str();
+
+ // Create the global constant.
+ CIRBaseBuilderTy builder(getContext());
+
+ // Use InsertionGuard to create the global at module level.
+ {
+ mlir::OpBuilder::InsertionGuard guard(builder);
+ builder.setInsertionPointToStart(mlirModule.getBody());
+
+ // If a global with this name already exists (e.g. CIRGen materializes
+ // constexpr locals as globals when their address is taken), reuse it.
+ if (!mlir::SymbolTable::lookupNearestSymbolFrom(
+ mlirModule, mlir::StringAttr::get(&getContext(), name))) {
+ auto gv = cir::GlobalOp::create(builder, op.getLoc(), name, ty,
+ /*isConstant=*/true,
+ cir::GlobalLinkageKind::PrivateLinkage);
+ mlir::SymbolTable::setSymbolVisibility(
+ gv, mlir::SymbolTable::Visibility::Private);
+ gv.setInitialValueAttr(constant);
+ }
+ }
+
+ // Now replace the store with get_global + copy.
+ builder.setInsertionPoint(op);
+
+ auto ptrTy = cir::PointerType::get(ty);
+ mlir::Value globalPtr =
+ cir::GetGlobalOp::create(builder, op.getLoc(), ptrTy, name);
+
+ // Replace store with copy.
+ builder.createCopy(op.getAddr(), globalPtr);
+
+ // Erase the original store.
+ op.erase();
+
+ // Erase the cir.const if it has no remaining users.
+ if (constOp.use_empty())
+ constOp.erase();
+}
+
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
lowerArrayCtor(arrayCtor);
@@ -1089,6 +1168,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerUnaryOp(unary);
} else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
lowerTrivialCopyCall(callOp);
+ } else if (auto storeOp = dyn_cast<cir::StoreOp>(op)) {
+ lowerStoreOfConstAggregate(storeOp);
} else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
if (auto globalCtor = fnOp.getGlobalCtorPriority())
globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
@@ -1107,7 +1188,8 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
- cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::UnaryOp>(op))
+ cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::StoreOp,
+ cir::UnaryOp>(op))
opsToTransform.push_back(op);
});
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 28b3454d20613..1ee895c6004e1 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -181,7 +181,7 @@ mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
mlir::ConversionPatternRewriter &rewriter) const {
mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
const mlir::Value length = mlir::LLVM::ConstantOp::create(
- rewriter, op.getLoc(), rewriter.getI32Type(), op.getLength(layout));
+ rewriter, op.getLoc(), rewriter.getI64Type(), op.getLength(layout));
assert(!cir::MissingFeatures::aggValueSlotVolatile());
rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(
op, adaptor.getDst(), adaptor.getSrc(), length, op.getIsVolatile());
diff --git a/clang/test/CIR/CodeGen/agg-expr-lvalue.c b/clang/test/CIR/CodeGen/agg-expr-lvalue.c
index 509f0218e9912..1986491dab75d 100644
--- a/clang/test/CIR/CodeGen/agg-expr-lvalue.c
+++ b/clang/test/CIR/CodeGen/agg-expr-lvalue.c
@@ -20,21 +20,31 @@ void test_member_in_array(void) {
struct Point arr[1] = {line.start};
}
+// CIR-DAG: cir.global "private" constant cir_private @[[LINE_CONST:.*]] = #cir.const_record<{#cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s32i}> : !rec_Point, #cir.const_record<{#cir.int<3> : !s32i, #cir.int<4> : !s32i}> : !rec_Point}> : !rec_Line
+// CIR-DAG: cir.global "private" constant cir_private @[[MATRIX_CONST:.*]] = #cir.const_array<[#cir.const_array<[#cir.int<104> : !s8i, #cir.int<101> : !s8i, #cir.int<108> : !s8i, #cir.int<108> : !s8i, #cir.int<111> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>, #cir.const_array<[#cir.int<119> : !s8i, #cir.int<111> : !s8i, #cir.int<114> : !s8i, #cir.int<108> : !s8i, #cir.int<100> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>]>
+
+// LLVM-DAG: @[[LINE_CONST:.*]] = private constant %struct.Line { %struct.Point { i32 1, i32 2 }, %struct.Point { i32 3, i32 4 } }
+// LLVM-DAG: @[[MATRIX_CONST:.*]] = private constant [2 x [6 x i8]] {{.*}}
+
// CIR-LABEL: cir.func{{.*}} @test_member_in_array
// CIR: %[[LINE:.*]] = cir.alloca !rec_Line{{.*}}, ["line", init]
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!rec_Point x 1>{{.*}}, ["arr", init]
+// CIR: cir.get_global @[[LINE_CONST]]
+// CIR: cir.copy
// CIR: %[[MEMBER:.*]] = cir.get_member %[[LINE]][0] {name = "start"}
// CIR: cir.copy
// LLVM-LABEL: define{{.*}} @test_member_in_array
// LLVM: %[[LINE:.*]] = alloca %struct.Line
// LLVM: %[[ARR:.*]] = alloca [1 x %struct.Point]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[LINE]], ptr @[[LINE_CONST]]
// LLVM: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0
// LLVM: call void @llvm.memcpy
// OGCG-LABEL: define{{.*}} @test_member_in_array
// OGCG: %[[LINE:.*]] = alloca %struct.Line
// OGCG: %[[ARR:.*]] = alloca [1 x %struct.Point]
+// OGCG: call void @llvm.memcpy{{.*}}(ptr{{.*}} %[[LINE]], ptr{{.*}} @__const.test_member_in_array.line
// OGCG: %[[MEMBER:.*]] = getelementptr{{.*}}%struct.Line{{.*}}%[[LINE]]{{.*}}i32 0, i32 0
// OGCG: call void @llvm.memcpy
@@ -96,12 +106,12 @@ void test_string_array_in_array(void) {
// CIR-LABEL: cir.func{{.*}} @test_string_array_in_array
// CIR: %[[MATRIX:.*]] = cir.alloca !cir.array<!cir.array<!s8i x 6> x 2>, {{.*}}, ["matrix", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<104> : !s8i, #cir.int<101> : !s8i, #cir.int<108> : !s8i, #cir.int<108> : !s8i, #cir.int<111> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>, #cir.const_array<[#cir.int<119> : !s8i, #cir.int<111> : !s8i, #cir.int<114> : !s8i, #cir.int<108> : !s8i, #cir.int<100> : !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>]>
-// CIR: cir.store{{.*}} %[[CONST]], %[[MATRIX]]
+// CIR: %[[CONST:.*]] = cir.get_global @[[MATRIX_CONST]] : !cir.ptr<!cir.array<!cir.array<!s8i x 6> x 2>>
+// CIR: cir.copy %[[CONST]] to %[[MATRIX]]
// LLVM-LABEL: define{{.*}} @test_string_array_in_array
// LLVM: %[[MATRIX:.*]] = alloca [2 x [6 x i8]]
-// LLVM: store [2 x [6 x i8]] {{\[}}[6 x i8] c"hello\00", [6 x i8] c"world\00"], ptr %[[MATRIX]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[MATRIX]], ptr @[[MATRIX_CONST]]
// OGCG-LABEL: define{{.*}} @test_string_array_in_array
// OGCG: alloca [2 x [6 x i8]]
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 341d4ce25c040..3486c08d3b515 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -5,6 +5,13 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[FUNC2_ARR:.*]] = #cir.const_array<[#cir.int<5> : !s32i, #cir.int<0> : !s32i]> : !cir.array<!s32i x 2>
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[FUNC3_ARR:.*]] = #cir.const_array<[#cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 2>
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[FUNC4_ARR:.*]] = #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.const_array<[#cir.int<6> : !s32i]> : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2>
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[FUNC5_ARR:.*]] = #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.zero : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2>
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[FUNC7_ARR:.*]] = #cir.zero : !cir.array<!cir.ptr<!s32i> x 1>
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[COMPLEX_ARR:.*]] =
+
int a[10];
// CIR: cir.global external @a = #cir.zero : !cir.array<!s32i x 10>
@@ -147,12 +154,12 @@ void func2() {
}
// CIR: %[[ARR2:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.int<5> : !s32i, #cir.int<0> : !s32i]> : !cir.array<!s32i x 2>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR2]] : !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FUNC2_ARR]] : !cir.ptr<!cir.array<!s32i x 2>>
+// CIR: cir.copy %[[CONST]] to %[[ARR2]] : !cir.ptr<!cir.array<!s32i x 2>>
// LLVM: define{{.*}} void @_Z5func2v(){{.*}}
// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4
-// LLVM: store [2 x i32] [i32 5, i32 0], ptr %[[ARR]], align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR]], ptr @[[FUNC2_ARR:.*]], i64 8, i1 false)
// OGCG: %[[ARR:.*]] = alloca [2 x i32], align 4
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN2_ARR]], i64 8, i1 false)
@@ -167,8 +174,8 @@ void func3() {
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>, ["arr", init]
// CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["idx", init]
// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 2>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!s32i x 2>, !cir.ptr<!cir.array<!s32i x 2>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FUNC3_ARR]] : !cir.ptr<!cir.array<!s32i x 2>>
+// CIR: cir.copy %[[CONST]] to %[[ARR]] : !cir.ptr<!cir.array<!s32i x 2>>
// CIR: %[[IDX_V:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store{{.*}} %[[IDX_V]], %[[IDX]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP_IDX:.*]] = cir.load{{.*}} %[[IDX]] : !cir.ptr<!s32i>, !s32i
@@ -180,7 +187,7 @@ void func3() {
// LLVM: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4
// LLVM: %[[IDX:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4
-// LLVM: store [2 x i32] [i32 5, i32 6], ptr %[[ARR]], align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR]], ptr @[[FUNC3_ARR:.*]], i64 8, i1 false)
// LLVM: store i32 1, ptr %[[IDX]], align 4
// LLVM: %[[TMP1:.*]] = load i32, ptr %[[IDX]], align 4
// LLVM: %[[IDX_I64:.*]] = sext i32 %[[TMP1]] to i64
@@ -206,8 +213,8 @@ void func4() {
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.const_array<[#cir.int<6> : !s32i]> : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FUNC4_ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
+// CIR: cir.copy %[[CONST]] to %[[ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
// CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
// CIR: %[[ARR_1:.*]] = cir.get_element %[[ARR]][%[[IDX_1]] : !s32i] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>>
@@ -218,7 +225,7 @@ void func4() {
// LLVM: define{{.*}} void @_Z5func4v(){{.*}}
// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
// LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4
-// LLVM: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] [i32 6]], ptr %[[ARR]], align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR]], ptr @[[FUNC4_ARR:.*]], i64 8, i1 false)
// LLVM: %[[ARR_1:.*]] = getelementptr [2 x [1 x i32]], ptr %[[ARR]], i32 0, i64 1
// LLVM: %[[ELE_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1]], i32 0, i64 0
// LLVM: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
@@ -237,15 +244,15 @@ void func5() {
}
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>, ["arr", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_array<[#cir.int<5> : !s32i]> : !cir.array<!s32i x 1>, #cir.zero : !cir.array<!s32i x 1>]> : !cir.array<!cir.array<!s32i x 1> x 2>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FUNC5_ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
+// CIR: cir.copy %[[CONST]] to %[[ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
// LLVM: define{{.*}} void @_Z5func5v(){{.*}}
// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
-// LLVM: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] zeroinitializer], ptr %[[ARR]], align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR]], ptr @[[FUNC5_ARR:.*]], i64 8, i1 false)
-// ORGC: %[[ARR:.*]] = alloca [2 x [1 x i32]], align 4
-// ORGC: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN5_ARR]], i64 8, i1 false)
+// OGCG: %[[ARR:.*]] = alloca [2 x [1 x i32]], align 4
+// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR]], ptr align 4 @[[FUN5_ARR]], i64 8, i1 false)
void func6() {
int x = 4;
@@ -287,12 +294,12 @@ void func7() {
}
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>, ["arr", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.zero : !cir.array<!cir.ptr<!s32i> x 1>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.ptr<!s32i> x 1>, !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FUNC7_ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>
+// CIR: cir.copy %[[CONST]] to %[[ARR]] : !cir.ptr<!cir.array<!cir.ptr<!s32i> x 1>>
// LLVM: define{{.*}} void @_Z5func7v(){{.*}}
// LLVM: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8
-// LLVM: store [1 x ptr] zeroinitializer, ptr %[[ARR]], align 8
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR]], ptr @[[FUNC7_ARR:.*]], i64 8, i1 false)
// OGCG: %[[ARR:.*]] = alloca [1 x ptr], align 8
// OGCG: call void @llvm.memset.p0.i64(ptr align 8 %[[ARR]], i8 0, i64 8, i1 false)
@@ -439,11 +446,11 @@ void array_with_complex_elements() {
}
// CIR: %[[ARR_ADDR:.*]] = cir.alloca !cir.array<!cir.complex<!cir.float> x 2>, !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>, ["arr", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_array<[#cir.const_complex<#cir.fp<1.100000e+00> : !cir.float, #cir.fp<2.200000e+00> : !cir.float> : !cir.complex<!cir.float>, #cir.const_complex<#cir.fp<3.300000e+00> : !cir.float, #cir.fp<4.400000e+00> : !cir.float> : !cir.complex<!cir.float>]> : !cir.array<!cir.complex<!cir.float> x 2>
-// CIR: cir.store{{.*}} %[[CONST]], %[[ARR_ADDR]] : !cir.array<!cir.complex<!cir.float> x 2>, !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
+// CIR: %[[CONST:.*]] = cir.get_global @[[COMPLEX_ARR]] : !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
+// CIR: cir.copy %[[CONST]] to %[[ARR_ADDR]] : !cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
// LLVM: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], i64 1, align 16
-// LLVM: store [2 x { float, float }] [{ float, float } { float 0x3FF19999A0000000, float 0x40019999A0000000 }, { float, float } { float 0x400A666660000000, float 0x40119999A0000000 }], ptr %[[ARR_ADDR]], align 16
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ARR_ADDR]], ptr @[[COMPLEX_ARR:.*]], i64 16, i1 false)
// OGCG: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], align 16
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[ARR_ADDR]], ptr align 16 @__const._Z27array_with_complex_elementsv.arr, i64 16, i1 false)
diff --git a/clang/test/CIR/CodeGen/binassign.c b/clang/test/CIR/CodeGen/binassign.c
index 3dc428779a19a..a6941f116dfdc 100644
--- a/clang/test/CIR/CodeGen/binassign.c
+++ b/clang/test/CIR/CodeGen/binassign.c
@@ -89,8 +89,8 @@ void binary_assign_struct() {
// LLVM: define {{.*}}void @binary_assign_struct()
// LLVM: %[[LS_PTR:.*]] = alloca %struct.S
// LLVM: %[[LSV_PTR:.*]] = alloca %struct.SV
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[LS_PTR]], ptr @gs, i32 8, i1 false)
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[LSV_PTR]], ptr @gsv, i32 8, i1 true)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[LS_PTR]], ptr @gs, i64 8, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[LSV_PTR]], ptr @gsv, i64 8, i1 true)
// LLVM: ret void
// OGCG: define {{.*}}void @binary_assign_struct()
diff --git a/clang/test/CIR/CodeGen/compound_literal.cpp b/clang/test/CIR/CodeGen/compound_literal.cpp
index 5219710d3e8bc..cb130ffa920e4 100644
--- a/clang/test/CIR/CodeGen/compound_literal.cpp
+++ b/clang/test/CIR/CodeGen/compound_literal.cpp
@@ -10,6 +10,9 @@ int foo() {
return e;
}
+// CIR-DAG: cir.global "private" constant cir_private @[[FOO4_P:.*]] = #cir.const_record<{#cir.int<5> : !s32i, #cir.int<10> : !s32i}> : !rec_Point
+// LLVM-DAG: @[[FOO4_P:.*]] = private constant %struct.Point { i32 5, i32 10 }
+
// CIR: %[[RET:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
// CIR: %[[COMPOUND:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, [".compoundliteral", init]
@@ -107,12 +110,12 @@ void foo4() {
// CIR-LABEL: @_Z4foo4v
// CIR: %[[P:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["p", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<5> : !s32i, #cir.int<10> : !s32i}> : !rec_Point
-// CIR: cir.store{{.*}} %[[CONST]], %[[P]] : !rec_Point, !cir.ptr<!rec_Point>
+// CIR: %[[CONST:.*]] = cir.get_global @[[FOO4_P]] : !cir.ptr<!rec_Point>
+// CIR: cir.copy %[[CONST]] to %[[P]] : !cir.ptr<!rec_Point>
// LLVM-LABEL: @_Z4foo4v
// LLVM: %[[P:.*]] = alloca %struct.Point
-// LLVM: store %struct.Point { i32 5, i32 10 }, ptr %[[P]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[P]], ptr @[[FOO4_P]]
// OGCG-LABEL: @_Z4foo4v
// OGCG: %[[P:.*]] = alloca %struct.Point
diff --git a/clang/test/CIR/CodeGen/copy-constructor.cpp b/clang/test/CIR/CodeGen/copy-constructor.cpp
index 97c514ac67e03..ceb493d828988 100644
--- a/clang/test/CIR/CodeGen/copy-constructor.cpp
+++ b/clang/test/CIR/CodeGen/copy-constructor.cpp
@@ -34,7 +34,7 @@ HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = defau
// LLVM-NEXT: %[[THIS_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[THIS_LOAD]], i32 0, i32 0
// LLVM-NEXT: %[[OTHER_LOAD:.*]] = load ptr, ptr %[[OTHER]]
// LLVM-NEXT: %[[OTHER_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[OTHER_LOAD]], i32 0, i32 0
-// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %[[THIS_ARR]], ptr %[[OTHER_ARR]], i32 16, i1 false)
+// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %[[THIS_ARR]], ptr %[[OTHER_ARR]], i64 16, i1 false)
// LLVM-NEXT: ret void
// OGCG-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_(
diff --git a/clang/test/CIR/CodeGen/embed-expr.c b/clang/test/CIR/CodeGen/embed-expr.c
index 24009e3732736..4350f69d2ac97 100644
--- a/clang/test/CIR/CodeGen/embed-expr.c
+++ b/clang/test/CIR/CodeGen/embed-expr.c
@@ -13,12 +13,14 @@ void embed_expr_on_scalar_with_constants() {
};
}
+// CIR-DAG: cir.global "private" constant cir_private @[[EMBED_A:.*]] = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<47> : !s32i]> : !cir.array<!s32i x 3>
+
// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.array<!s32i x 3>, !cir.ptr<!cir.array<!s32i x 3>>, ["a", init]
-// CIR: %[[ARRAY:.*]] = cir.const #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<47> : !s32i]> : !cir.array<!s32i x 3>
-// CIR: cir.store {{.*}} %[[ARRAY]], %[[A_ADDR]] : !cir.array<!s32i x 3>, !cir.ptr<!cir.array<!s32i x 3>>
+// CIR: %[[ARRAY:.*]] = cir.get_global @[[EMBED_A]] : !cir.ptr<!cir.array<!s32i x 3>>
+// CIR: cir.copy %[[ARRAY]] to %[[A_ADDR]] : !cir.ptr<!cir.array<!s32i x 3>>
// LLVM: %[[A_ADDR:.*]] = alloca [3 x i32], i64 1, align 4
-// LLVM: store [3 x i32] [i32 1, i32 2, i32 47], ptr %[[A_ADDR]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[EMBED_A:.*]], i64 12, i1 false)
// OGCG: %[[A_ADDR:.*]] = alloca [3 x i32], align 4
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[A_ADDR]], ptr align 4 @__const.embed_expr_on_scalar_with_constants.a, i64 12, i1 false)
diff --git a/clang/test/CIR/CodeGen/lambda.cpp b/clang/test/CIR/CodeGen/lambda.cpp
index 3c2b0969fa7a2..956a4489dd2ce 100644
--- a/clang/test/CIR/CodeGen/lambda.cpp
+++ b/clang/test/CIR/CodeGen/lambda.cpp
@@ -383,7 +383,7 @@ struct A {
// LLVM: br label %[[SCOPE_BB:.*]]
// LLVM: [[SCOPE_BB]]:
// LLVM: %[[STRUCT_A:.*]] = getelementptr %[[REC_LAM_A]], ptr %[[LAM_ALLOCA]], i32 0, i32 0
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[STRUCT_A]], ptr %[[THIS]], i32 4, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[STRUCT_A]], ptr %[[THIS]], i64 4, i1 false)
// LLVM: %[[LAM_RET:.*]] = call i32 @_ZZN1A3fooEvENKUlvE_clEv(ptr %[[LAM_ALLOCA]])
// LLVM: store i32 %[[LAM_RET]], ptr %[[RETVAL]]
// LLVM: br label %[[RET_BB:.*]]
diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp
index 463434c38a1af..cb80dc5887fe6 100644
--- a/clang/test/CIR/CodeGen/loop.cpp
+++ b/clang/test/CIR/CodeGen/loop.cpp
@@ -5,6 +5,9 @@
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+// CIR-DAG: cir.global "private" constant cir_private @[[L5_ARR:.*]] = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]>
+// LLVM-DAG: @[[L5_ARR:.*]] = private constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
+
void l0() {
for (;;) {
}
@@ -312,8 +315,8 @@ void l5() {
// CIR: %[[BEGIN_ADDR:.*]] = cir.alloca {{.*}} ["__begin1", init]
// CIR: %[[END_ADDR:.*]] = cir.alloca {{.*}} ["__end1", init]
// CIR: %[[X_ADDR:.*]] = cir.alloca {{.*}} ["x", init]
-// CIR: %[[ARR_INIT:.*]] = cir.const #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]>
-// CIR: cir.store{{.*}} %[[ARR_INIT]], %[[ARR_ADDR]]
+// CIR: %[[ARR_INIT:.*]] = cir.get_global @[[L5_ARR]]
+// CIR: cir.copy %[[ARR_INIT]] to %[[ARR_ADDR]]
// CIR: cir.store{{.*}} %[[ARR_ADDR]], %[[RANGE_ADDR]]
// CIR: %[[RANGE_LOAD:.*]] = cir.load %[[RANGE_ADDR]]
// CIR: %[[RANGE_CAST:.*]] = cir.cast array_to_ptrdecay %[[RANGE_LOAD]] : {{.*}}
@@ -350,7 +353,7 @@ void l5() {
// LLVM: %[[X_ADDR:.*]] = alloca i32
// LLVM: br label %[[SETUP:.*]]
// LLVM: [[SETUP]]:
-// LLVM: store [4 x i32] [i32 1, i32 2, i32 3, i32 4], ptr %[[ARR_ADDR]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[ARR_ADDR]], ptr @[[L5_ARR]], i64 16, i1 false)
// LLVM: store ptr %[[ARR_ADDR]], ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
// LLVM: %[[BEGIN_CAST:.*]] = getelementptr i32, ptr %[[BEGIN]], i32 0
diff --git a/clang/test/CIR/CodeGen/no-odr-use.cpp b/clang/test/CIR/CodeGen/no-odr-use.cpp
index 0f1feb8f1e86c..cb43b6210c663 100644
--- a/clang/test/CIR/CodeGen/no-odr-use.cpp
+++ b/clang/test/CIR/CodeGen/no-odr-use.cpp
@@ -11,8 +11,8 @@
// RUN: %clang_cc1 -std=c++2a -emit-llvm -o %t-cxx2a.ll -triple x86_64-linux-gnu %s
// RUN: FileCheck %s --input-file=%t-cxx2a.ll --check-prefixes=OGCG,OGCG-CXX2A
-// CIR-DAG: cir.global "private" constant cir_private @__const._Z1fi.a = #cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>}> : !rec_A
-// LLVM-DAG: @__const._Z1fi.a = private constant {{.*}} { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }
+// CIR-DAG: cir.global "private" constant cir_private @[[F_A:.*]] = #cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>}> : !rec_A
+// LLVM-DAG: @[[F_A:.*]] = private constant {{.*}} { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }
// OGCG-DAG: @__const._Z1fi.a = private unnamed_addr constant {{.*}} { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }
// CIR-CXX11-DAG: cir.global "private" constant cir_private @_ZN7PR422765State1mE.const = #cir.const_array<[#cir.const_record<{#cir.global_view<@_ZN7PR422765State2f1Ev> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct, #cir.const_record<{#cir.global_view<@_ZN7PR422765State2f2Ev> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct]> : !cir.array<!rec_anon_struct x 2>
@@ -40,22 +40,22 @@ int f(int i) {
// LLVM: br i1
// OGCG: br i1
return (n >= 0
- // CIR: %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+ // CIR: %[[A:.*]] = cir.get_global @[[F_A]] : !cir.ptr<!rec_A>
// CIR: %[[ARR:.*]] = cir.get_member %[[A]][2] {name = "arr"} : !cir.ptr<!rec_A> -> !cir.ptr<!cir.array<!s32i x 3>>
// CIR: cir.get_element %[[ARR]][%{{.*}} : !s32i] : !cir.ptr<!cir.array<!s32i x 3>> -> !cir.ptr<!s32i>
- // LLVM: getelementptr [3 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const._Z1fi.a, i64 12), i32 0, i64 %{{.*}}
+ // LLVM: getelementptr [3 x i32], ptr getelementptr inbounds nuw (i8, ptr @[[F_A]], i64 12), i32 0, i64 %{{.*}}
// OGCG: getelementptr inbounds [3 x i32], ptr getelementptr inbounds nuw ({{.*}} @__const._Z1fi.a, i32 0, i32 2), i64 0, i64 %{{.*}}
? a.arr[n]
// CIR: cir.ternary
// LLVM: br i1
// OGCG: br i1
: (n == -1
- // CIR: %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+ // CIR: %[[A:.*]] = cir.get_global @[[F_A]] : !cir.ptr<!rec_A>
// CIR: %[[N:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i
// CIR: %[[A_BYTE_PTR:.*]] = cir.cast bitcast %[[A]] : !cir.ptr<!rec_A> -> !cir.ptr<!s8i>
// CIR: cir.ptr_stride %[[A_BYTE_PTR]], %[[N]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i>
- // LLVM: getelementptr i8, ptr @__const._Z1fi.a, i64 %{{.*}}
+ // LLVM: getelementptr i8, ptr @[[F_A]], i64 %{{.*}}
// LLVM: load i32
// OGCG: getelementptr inbounds i8, ptr @__const._Z1fi.a, i64 %{{.*}}
@@ -64,11 +64,11 @@ int f(int i) {
// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
// CIR: %[[N:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i
// CIR: %[[SUB:.*]] = cir.binop(sub, %[[TWO]], %[[N]]) nsw : !s32i
- // CIR: %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+ // CIR: %[[A:.*]] = cir.get_global @[[F_A]] : !cir.ptr<!rec_A>
// CIR: %[[Y:.*]] = cir.get_member %[[A]][1] {name = "y"} : !cir.ptr<!rec_A> -> !cir.ptr<!cir.array<!s32i x 2>>
// CIR: cir.get_element %[[Y]][%[[SUB]] : !s32i] : !cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i>
- // LLVM: getelementptr [2 x i32], ptr getelementptr inbounds nuw ({{.*}} @__const._Z1fi.a, i64 4), i32 0, i64 %{{.*}}
+ // LLVM: getelementptr [2 x i32], ptr getelementptr inbounds nuw ({{.*}} @[[F_A]], i64 4), i32 0, i64 %{{.*}}
// LLVM: load i32
// OGCG: getelementptr inbounds [2 x i32], ptr getelementptr inbounds nuw ({{.*}} @__const._Z1fi.a, i32 0, i32 1), i64 0, i64 %{{.*}}
@@ -79,13 +79,14 @@ int f(int i) {
// With CIR, f1() is emitted after the lambda.
// CIR-LABEL: cir.func {{.*}} @_Z1fi(
-// CIR: %[[A_INIT:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>}> : !rec_A
-// CIR: cir.store{{.*}} %[[A_INIT]], %{{.*}}
+// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["a", init, const]
+// CIR: %[[A_INIT:.*]] = cir.get_global @[[F_A]] : !cir.ptr<!rec_A>
+// CIR: cir.copy %[[A_INIT]] to %[[A_ADDR]]
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s64i
// CIR: cir.call @_ZZ1fiENK3$_0clEiM1Ai({{.*}}, {{.*}}, %[[ZERO]])
// LLVM-LABEL: define{{.*}} i32 @_Z1fi(
-// LLVM: store %struct.A { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }, ptr %{{.*}}
+// LLVM: call void @llvm.memcpy{{.*}}({{.*}}, ptr @[[F_A]]
// LLVM: call i32 @"_ZZ1fiENK3$_0clEiM1Ai"(ptr %{{.*}}, i32 %{{.*}}, i64 0)
namespace PR42276 {
diff --git a/clang/test/CIR/CodeGen/paren-init-list.cpp b/clang/test/CIR/CodeGen/paren-init-list.cpp
index a5676e2b31667..aba8b05374b1b 100644
--- a/clang/test/CIR/CodeGen/paren-init-list.cpp
+++ b/clang/test/CIR/CodeGen/paren-init-list.cpp
@@ -12,12 +12,15 @@ struct CompleteS {
void cxx_paren_list_init_expr() { CompleteS a(1, 'a'); }
+// CIR-DAG: cir.global "private" constant cir_private @[[PAREN_A:.*]] = #cir.const_record<{#cir.int<1> : !s32i, #cir.int<97> : !s8i}> : !rec_CompleteS
+// LLVM-DAG: @[[PAREN_A:.*]] = private constant %struct.CompleteS { i32 1, i8 97 }
+
// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<97> : !s8i}> : !rec_CompleteS
-// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]]
+// CIR: %[[CONST:.*]] = cir.get_global @[[PAREN_A]] : !cir.ptr<!rec_CompleteS>
+// CIR: cir.copy %[[CONST]] to %[[A_ADDR]]
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: store %struct.CompleteS { i32 1, i8 97 }, ptr %[[A_ADDR]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[PAREN_A]]
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[A_ADDR]], ptr align 4 @__const._Z24cxx_paren_list_init_exprv.a, i64 8, i1 false)
diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp
index 21238f2eda859..7a86427d09a56 100644
--- a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp
+++ b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp
@@ -16,8 +16,14 @@ struct Foo {
void (Foo::*m1_ptr)(int) = &Foo::m1;
// CIR-BEFORE: cir.global external @m1_ptr = #cir.method<@_ZN3Foo2m1Ei> : !cir.method<!cir.func<(!s32i)> in !rec_Foo>
+// CIR-AFTER-DAG: cir.global "private" constant cir_private @[[NONVIRT_RET:.*]] = #cir.const_record<{#cir.global_view<@_ZN3Foo2m1Ei> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
+// CIR-AFTER-DAG: cir.global "private" constant cir_private @[[VIRT_RET:.*]] = #cir.const_record<{#cir.int<9> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
+// CIR-AFTER-DAG: cir.global "private" constant cir_private @[[NULL_RET:.*]] = #cir.const_record<{#cir.int<0> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
// CIR-AFTER: cir.global external @m1_ptr = #cir.const_record<{#cir.global_view<@_ZN3Foo2m1Ei> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
-// LLVM: @m1_ptr = global { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 }
+// LLVM-DAG: @m1_ptr = global { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 }
+// LLVM-DAG: @[[NONVIRT_RET:.*]] = private constant { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 }
+// LLVM-DAG: @[[VIRT_RET:.*]] = private constant { i64, i64 } { i64 9, i64 0 }
+// LLVM-DAG: @[[NULL_RET:.*]] = private constant { i64, i64 } zeroinitializer
// OGCG: @m1_ptr = global { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 }
// Global pointer to virtual method
@@ -25,7 +31,7 @@ void (Foo::*m2_ptr)(int) = &Foo::m2;
// CIR-BEFORE: cir.global external @m2_ptr = #cir.method<vtable_offset = 0> : !cir.method<!cir.func<(!s32i)> in !rec_Foo>
// CIR-AFTER: cir.global external @m2_ptr = #cir.const_record<{#cir.int<1> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
-// LLVM: @m2_ptr = global { i64, i64 } { i64 1, i64 0 }
+// LLVM-DAG: @m2_ptr = global { i64, i64 } { i64 1, i64 0 }
// OGCG: @m2_ptr = global { i64, i64 } { i64 1, i64 0 }
auto make_non_virtual() -> void (Foo::*)(int) {
@@ -41,14 +47,14 @@ auto make_non_virtual() -> void (Foo::*)(int) {
// CIR-AFTER: cir.func {{.*}} @_Z16make_non_virtualv() -> !rec_anon_struct {
// CIR-AFTER: %[[RETVAL:.*]] = cir.alloca !rec_anon_struct, !cir.ptr<!rec_anon_struct>, ["__retval"]
-// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.const #cir.const_record<{#cir.global_view<@_ZN3Foo2m1Ei> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
-// CIR-AFTER: cir.store %[[METHOD_PTR]], %[[RETVAL]]
+// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.get_global @[[NONVIRT_RET]] : !cir.ptr<!rec_anon_struct>
+// CIR-AFTER: cir.copy %[[METHOD_PTR]] to %[[RETVAL]] : !cir.ptr<!rec_anon_struct>
// CIR-AFTER: %[[RET:.*]] = cir.load %[[RETVAL]]
// CIR-AFTER: cir.return %[[RET]] : !rec_anon_struct
// LLVM: define {{.*}} { i64, i64 } @_Z16make_non_virtualv()
// LLVM: %[[RETVAL:.*]] = alloca { i64, i64 }
-// LLVM: store { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 }, ptr %[[RETVAL]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[RETVAL]], ptr @[[NONVIRT_RET]]
// LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RETVAL]]
// LLVM: ret { i64, i64 } %[[RET]]
@@ -68,14 +74,14 @@ auto make_virtual() -> void (Foo::*)(int) {
// CIR-AFTER: cir.func {{.*}} @_Z12make_virtualv() -> !rec_anon_struct
// CIR-AFTER: %[[RETVAL:.*]] = cir.alloca !rec_anon_struct, !cir.ptr<!rec_anon_struct>, ["__retval"]
-// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.const #cir.const_record<{#cir.int<9> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
-// CIR-AFTER: cir.store %[[METHOD_PTR]], %[[RETVAL]]
+// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.get_global @[[VIRT_RET]] : !cir.ptr<!rec_anon_struct>
+// CIR-AFTER: cir.copy %[[METHOD_PTR]] to %[[RETVAL]] : !cir.ptr<!rec_anon_struct>
// CIR-AFTER: %[[RET:.*]] = cir.load %[[RETVAL]]
// CIR-AFTER: cir.return %[[RET]] : !rec_anon_struct
// LLVM: define {{.*}} @_Z12make_virtualv()
// LLVM: %[[RETVAL:.*]] = alloca { i64, i64 }
-// LLVM: store { i64, i64 } { i64 9, i64 0 }, ptr %[[RETVAL]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[RETVAL]], ptr @[[VIRT_RET]]
// LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RETVAL]]
// LLVM: ret { i64, i64 } %[[RET]]
@@ -95,14 +101,14 @@ auto make_null() -> void (Foo::*)(int) {
// CIR-AFTER: cir.func {{.*}} @_Z9make_nullv() -> !rec_anon_struct
// CIR-AFTER: %[[RETVAL:.*]] = cir.alloca !rec_anon_struct, !cir.ptr<!rec_anon_struct>, ["__retval"]
-// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.const #cir.const_record<{#cir.int<0> : !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct
-// CIR-AFTER: cir.store %[[METHOD_PTR]], %[[RETVAL]]
+// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.get_global @[[NULL_RET]] : !cir.ptr<!rec_anon_struct>
+// CIR-AFTER: cir.copy %[[METHOD_PTR]] to %[[RETVAL]] : !cir.ptr<!rec_anon_struct>
// CIR-AFTER: %[[RET:.*]] = cir.load %[[RETVAL]]
// CIR-AFTER: cir.return %[[RET]] : !rec_anon_struct
// LLVM: define {{.*}} @_Z9make_nullv()
// LLVM: %[[RETVAL:.*]] = alloca { i64, i64 }
-// LLVM: store { i64, i64 } zeroinitializer, ptr %[[RETVAL]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[RETVAL]], ptr @[[NULL_RET]]
// LLVM: %[[RET:.*]] = load { i64, i64 }, ptr %[[RETVAL]]
// LLVM: ret { i64, i64 } %[[RET]]
diff --git a/clang/test/CIR/CodeGen/statement-exprs.c b/clang/test/CIR/CodeGen/statement-exprs.c
index 05fccb28ac67a..30baaf0ec8736 100644
--- a/clang/test/CIR/CodeGen/statement-exprs.c
+++ b/clang/test/CIR/CodeGen/statement-exprs.c
@@ -9,6 +9,9 @@ int f19(void) {
return ({ 3;;4; });
}
+// CIR-DAG: cir.global "private" constant cir_private @[[TEST3_S:.*]] = #cir.const_record<{#cir.int<1> : !s32i}> : !rec_S
+// LLVM-DAG: @[[TEST3_S:.*]] = private constant %struct.S { i32 1 }
+
// CIR: cir.func {{.*}} @f19() -> !s32i
// CIR: %[[RETVAL:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
// CIR: %[[TMP:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["tmp"]
@@ -232,8 +235,8 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// CIR: %[[TMP:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["tmp"]
// CIR: cir.scope {
// CIR: %[[S:.+]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i}> : !rec_S
-// CIR: cir.store{{.*}} %[[CONST]], %[[S]] : !rec_S, !cir.ptr<!rec_S>
+// CIR: %[[CONST:.*]] = cir.get_global @[[TEST3_S]] : !cir.ptr<!rec_S>
+// CIR: cir.copy %[[CONST]] to %[[S]] : !cir.ptr<!rec_S>
// CIR: cir.copy %[[S]] to %[[REF_TMP0]] : !cir.ptr<!rec_S>
// CIR: }
// CIR: %[[GEP_X_TMP:.+]] = cir.get_member %[[REF_TMP0]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
@@ -252,8 +255,8 @@ int test3() { return ({ struct S s = {1}; s; }).x; }
// LLVM: [[LBL5]]:
// LLVM: br label %[[LBL6:.+]]
// LLVM: [[LBL6]]:
-// LLVM: store %struct.S { i32 1 }, ptr %[[VAR3]]
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[VAR1]], ptr %[[VAR3]], i32 4, i1 false)
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[VAR3]], ptr @[[TEST3_S]], i64 4, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[VAR1]], ptr %[[VAR3]], i64 4, i1 false)
// LLVM: br label %[[LBL8:.+]]
// LLVM: [[LBL8]]:
// LLVM: %[[GEP_VAR1:.+]] = getelementptr %struct.S, ptr %[[VAR1]], i32 0, i32 0
diff --git a/clang/test/CIR/CodeGen/struct-init.cpp b/clang/test/CIR/CodeGen/struct-init.cpp
index f5c013a599a40..c8ad5430658e9 100644
--- a/clang/test/CIR/CodeGen/struct-init.cpp
+++ b/clang/test/CIR/CodeGen/struct-init.cpp
@@ -5,6 +5,9 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[INIT_S1:.*]] = #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i}> : !rec_S
+// CIR-DAG: cir.global "private"{{.*}}constant cir_private @[[INIT_S2:.*]] = #cir.const_record<{#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<0> : !s32i}> : !rec_S
+
struct BitfieldStruct {
unsigned int a:4;
unsigned int b:14;
@@ -65,16 +68,16 @@ void init() {
// CIR: cir.func{{.*}} @_Z4initv()
// CIR: %[[S1:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s1", init]
// CIR: %[[S2:.*]] = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s2", init]
-// CIR: %[[CONST_1:.*]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i}> : !rec_S
-// CIR: cir.store{{.*}} %[[CONST_1]], %[[S1]]
-// CIR: %[[CONST_2:.*]] = cir.const #cir.const_record<{#cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<0> : !s32i}> : !rec_S
-// CIR: cir.store{{.*}} %[[CONST_2]], %[[S2]]
+// CIR: %[[CONST_1:.*]] = cir.get_global @[[INIT_S1]] : !cir.ptr<!rec_S>
+// CIR: cir.copy %[[CONST_1]] to %[[S1]] : !cir.ptr<!rec_S>
+// CIR: %[[CONST_2:.*]] = cir.get_global @[[INIT_S2]] : !cir.ptr<!rec_S>
+// CIR: cir.copy %[[CONST_2]] to %[[S2]] : !cir.ptr<!rec_S>
// LLVM: define{{.*}} void @_Z4initv()
// LLVM: %[[S1:.*]] = alloca %struct.S
// LLVM: %[[S2:.*]] = alloca %struct.S
-// LLVM: store %struct.S { i32 1, i32 2, i32 3 }, ptr %[[S1]], align 4
-// LLVM: store %struct.S { i32 4, i32 5, i32 0 }, ptr %[[S2]], align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[S1]], ptr @[[INIT_S1:.*]], i64 12, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[S2]], ptr @[[INIT_S2:.*]], i64 12, i1 false)
// OGCG: @__const._Z4initv.s1 = private unnamed_addr constant %struct.S { i32 1, i32 2, i32 3 }
// OGCG: @__const._Z4initv.s2 = private unnamed_addr constant %struct.S { i32 4, i32 5, i32 0 }
diff --git a/clang/test/CIR/CodeGen/struct.cpp b/clang/test/CIR/CodeGen/struct.cpp
index fffd014e21917..73a7878c2d0a1 100644
--- a/clang/test/CIR/CodeGen/struct.cpp
+++ b/clang/test/CIR/CodeGen/struct.cpp
@@ -8,9 +8,18 @@
struct IncompleteS;
IncompleteS *p;
-// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteS>
-// LLVM: @p = global ptr null
-// OGCG: @p = global ptr null, align 8
+// CIR-DAG: cir.global "private" constant cir_private @[[PAREN_A:.*]] = #cir.zero : !rec_Point
+// CIR-DAG: cir.global "private" constant cir_private @__const.{{.*}} = #cir.zero : !rec_CompleteS
+// CIR-DAG: cir.global "private" constant cir_private @__const.{{.*}} = #cir.zero : !rec_CompleteS
+// CIR-DAG: cir.global "private" constant cir_private @__const.{{.*}} = #cir.zero : !rec_CompleteS
+// CIR-DAG: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteS>
+
+// LLVM-DAG: @[[PAREN_A:.*]] = private constant %struct.Point zeroinitializer
+// LLVM-DAG: @__const.{{.*}} = private constant %struct.CompleteS zeroinitializer
+// LLVM-DAG: @__const.{{.*}} = private constant %struct.CompleteS zeroinitializer
+// LLVM-DAG: @__const.{{.*}} = private constant %struct.CompleteS zeroinitializer
+// LLVM-DAG: @p = global ptr null
+// OGCG-DAG: @p = global ptr null, align 8
struct CompleteS {
int a;
@@ -107,15 +116,15 @@ void paren_expr() {
// CIR: cir.func{{.*}} @_Z10paren_exprv()
// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["a", init]
// CIR: %[[B_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["b", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_Point
-// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_Point, !cir.ptr<!rec_Point>
+// CIR: %[[CONST:.*]] = cir.get_global @[[PAREN_A]] : !cir.ptr<!rec_Point>
+// CIR: cir.copy %[[CONST]] to %[[A_ADDR]] : !cir.ptr<!rec_Point>
// CIR: cir.copy %[[A_ADDR]] to %[[B_ADDR]] : !cir.ptr<!rec_Point>
// LLVM: define{{.*}} void @_Z10paren_exprv()
// LLVM: %[[A_ADDR:.*]] = alloca %struct.Point, i64 1, align 4
// LLVM: %[[B_ADDR:.*]] = alloca %struct.Point, i64 1, align 4
-// LLVM: store %struct.Point zeroinitializer, ptr %[[A_ADDR]], align 4
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[B_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false)
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[PAREN_A]]
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[B_ADDR]], ptr %[[A_ADDR]], i64 8, i1 false)
// OGCG: define{{.*}} void @_Z10paren_exprv()
// OGCG: %[[A_ADDR:.*]] = alloca %struct.Point, align 4
@@ -139,7 +148,7 @@ void choose_expr() {
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
// LLVM: %[[B_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
// LLVM: %[[C_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i64 8, i1 false)
// OGCG: define{{.*}} void @_Z11choose_exprv()
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
@@ -166,7 +175,7 @@ void generic_selection() {
// LLVM: %2 = alloca %struct.CompleteS, i64 1, align 4
// LLVM: %3 = alloca i32, i64 1, align 4
// LLVM: %4 = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %4, ptr %1, i32 8, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %4, ptr %1, i64 8, i1 false)
// OGCG: define{{.*}} void @_Z17generic_selectionv()
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
@@ -195,7 +204,7 @@ void designated_init_update_expr() {
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
// LLVM: %[[B_ADDR:.*]] = alloca %struct.Container, i64 1, align 4
// LLVM: %[[C_ADDR:.*]] = getelementptr %struct.Container, ptr %[[B_ADDR]], i32 0, i32 0
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i32 8, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[C_ADDR]], ptr %[[A_ADDR]], i64 8, i1 false)
// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[C_ADDR]], i32 0, i32 0
// LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4
// LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[C_ADDR]], i32 0, i32 1
@@ -241,11 +250,11 @@ void unary_extension() {
}
// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init]
-// CIR: %[[ZERO_INIT:.*]] = cir.const #cir.zero : !rec_CompleteS
-// CIR: cir.store{{.*}} %[[ZERO_INIT]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS>
+// CIR: %[[ZERO_INIT:.*]] = cir.get_global @[[UNARY_A:.*]] : !cir.ptr<!rec_CompleteS>
+// CIR: cir.copy %[[ZERO_INIT]] to %[[A_ADDR]] : !cir.ptr<!rec_CompleteS>
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[UNARY_A:.*]]
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false)
@@ -256,12 +265,12 @@ void bin_comma() {
// CIR: cir.func{{.*}} @_Z9bin_commav()
// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_CompleteS
-// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS>
+// CIR: %[[CONST:.*]] = cir.get_global @[[COMMA_A:.*]] : !cir.ptr<!rec_CompleteS>
+// CIR: cir.copy %[[CONST]] to %[[A_ADDR]] : !cir.ptr<!rec_CompleteS>
// LLVM: define{{.*}} void @_Z9bin_commav()
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[COMMA_A:.*]]
// OGCG: define{{.*}} void @_Z9bin_commav()
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
@@ -270,13 +279,13 @@ void bin_comma() {
void compound_literal_expr() { CompleteS a = (CompleteS){}; }
// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init]
-// CIR: %[[CONST:.*]] = cir.const #cir.zero : !rec_CompleteS
-// CIR: cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS>
+// CIR: %[[CONST:.*]] = cir.get_global @[[COMPLIT_A:.*]] : !cir.ptr<!rec_CompleteS>
+// CIR: cir.copy %[[CONST]] to %[[A_ADDR]] : !cir.ptr<!rec_CompleteS>
// TODO(cir): zero-initialize the padding
// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[A_ADDR]], ptr @[[COMPLIT_A:.*]]
// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false)
diff --git a/clang/test/CIR/CodeGen/var-arg-aggregate.c b/clang/test/CIR/CodeGen/var-arg-aggregate.c
index 5897bc41a116b..6cb623821f8b3 100644
--- a/clang/test/CIR/CodeGen/var-arg-aggregate.c
+++ b/clang/test/CIR/CodeGen/var-arg-aggregate.c
@@ -42,7 +42,7 @@ struct Bar varargs_aggregate(int count, ...) {
// LLVM: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %{{.*}}, i32 0
// LLVM: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], %struct.Bar
// LLVM: store %struct.Bar %[[VA_ARG]], ptr %{{.*}}
-// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %{{.*}}, ptr %{{.*}}, i32 12, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %{{.*}}, ptr %{{.*}}, i64 12, i1 false)
// OGCG-LABEL: define dso_local { <2 x float>, i32 } @varargs_aggregate
// OGCG: call void @llvm.va_start.p0(ptr %{{.*}})
diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp
index 3ba2fac3151c9..34fddf837e8cd 100644
--- a/clang/test/CIR/CodeGen/variable-decomposition.cpp
+++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp
@@ -16,11 +16,14 @@ float function() {
return a + b;
}
+// CIR-DAG: cir.global "private" constant cir_private @[[FUNC_CONST:.*]] = #cir.const_record<{#cir.int<1> : !s32i, #cir.fp<2.000000e+00> : !cir.float}> : !rec_some_struct
+// LLVM-DAG: @[[FUNC_CONST:.*]] = private constant %struct.some_struct { i32 1, float 2.000000e+00 }
+
// CIR-LABEL: cir.func {{.*}} @_Z8functionv() -> !cir.float
// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"]
// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, ["", init]
-// CIR: %[[CONST:.+]] = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.fp<2.000000e+00> : !cir.float}> : !rec_some_struct
-// CIR: cir.store{{.*}} %[[CONST]], %[[STRUCT]]
+// CIR: %[[CONST:.+]] = cir.get_global @[[FUNC_CONST]] : !cir.ptr<!rec_some_struct>
+// CIR: cir.copy %[[CONST]] to %[[STRUCT]]
// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i>
// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[CAST_A:.+]] = cir.cast int_to_float %[[LOAD_A]] : !s32i -> !cir.float
@@ -34,7 +37,7 @@ float function() {
// LLVM-LABEL: define dso_local float @_Z8functionv()
// LLVM: %[[RETVAL:.+]] = alloca float, i64 1
// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1
-// LLVM: store %struct.some_struct { i32 1, float 2.000000e+00 }, ptr %[[STRUCT]]
+// LLVM: call void @llvm.memcpy{{.*}}(ptr %[[STRUCT]], ptr @[[FUNC_CONST]], i64 8, i1 false)
// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0
// LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]]
// LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float
diff --git a/clang/test/CIR/Lowering/array.cpp b/clang/test/CIR/Lowering/array.cpp
index 2b61ec1f45fcf..9239944df0644 100644
--- a/clang/test/CIR/Lowering/array.cpp
+++ b/clang/test/CIR/Lowering/array.cpp
@@ -1,6 +1,12 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s
+// CHECK-DAG: @[[FUNC2_ARR:.*]] = private constant [2 x i32] [i32 5, i32 0]
+// CHECK-DAG: @[[FUNC3_ARR:.*]] = private constant [2 x i32] [i32 5, i32 6]
+// CHECK-DAG: @[[FUNC4_ARR:.*]] = private constant [2 x [1 x i32]] {{.*}}[1 x i32] [i32 5], [1 x i32] [i32 6]{{.*}}
+// CHECK-DAG: @[[FUNC5_ARR:.*]] = private constant [2 x [1 x i32]] {{.*}}[1 x i32] [i32 5], [1 x i32] zeroinitializer{{.*}}
+// CHECK-DAG: @[[FUNC7_ARR:.*]] = private constant [1 x ptr] zeroinitializer
+
int a[10];
// CHECK: @a = global [10 x i32] zeroinitializer
@@ -58,7 +64,7 @@ void func2() {
// CHECK: define{{.*}} void @_Z5func2v()
// CHECK: %[[ARR:.*]] = alloca [2 x i32], i64 1, align 4
-// CHECK: store [2 x i32] [i32 5, i32 0], ptr %[[ARR]], align 4
+// CHECK: call void @llvm.memcpy{{.*}}(ptr %[[ARR]], ptr @[[FUNC2_ARR]], i64 8, i1 false)
// CHECK: ret void
void func3() {
@@ -66,7 +72,7 @@ void func3() {
}
// CHECK: define{{.*}} void @_Z5func3v()
// CHECK: %[[ARR_ALLOCA:.*]] = alloca [2 x i32], i64 1, align 4
-// CHECK: store [2 x i32] [i32 5, i32 6], ptr %[[ARR_ALLOCA]], align 4
+// CHECK: call void @llvm.memcpy{{.*}}(ptr %[[ARR_ALLOCA]], ptr @[[FUNC3_ARR]], i64 8, i1 false)
void func4() {
int arr[2][1] = {{5}, {6}};
@@ -75,7 +81,7 @@ void func4() {
// CHECK: define{{.*}} void @_Z5func4v()
// CHECK: %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
// CHECK: %[[INIT:.*]] = alloca i32, i64 1, align 4
-// CHECK: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] [i32 6]], ptr %[[ARR_ALLOCA]], align 4
+// CHECK: call void @llvm.memcpy{{.*}}(ptr %[[ARR_ALLOCA]], ptr @[[FUNC4_ARR]], i64 8, i1 false)
// CHECK: %[[ARR_1:.*]] = getelementptr [2 x [1 x i32]], ptr %[[ARR_ALLOCA]], i32 0, i64 1
// CHECK: %[[ELE_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1]], i32 0, i64 0
// CHECK: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
@@ -86,7 +92,7 @@ void func5() {
}
// CHECK: define{{.*}} void @_Z5func5v()
// CHECK: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
-// CHECK: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] zeroinitializer], ptr %[[ARR]], align 4
+// CHECK: call void @llvm.memcpy{{.*}}(ptr %[[ARR]], ptr @[[FUNC5_ARR]], i64 8, i1 false)
// CHECK: ret void
void func6() {
@@ -108,7 +114,7 @@ void func7() {
}
// CHECK: define{{.*}} void @_Z5func7v()
// CHECK: %[[ARR:.*]] = alloca [1 x ptr], i64 1, align 8
-// CHECK: store [1 x ptr] zeroinitializer, ptr %[[ARR]], align 8
+// CHECK: call void @llvm.memcpy{{.*}}(ptr %[[ARR]], ptr @[[FUNC7_ARR]], i64 8, i1 false)
// CHECK: ret void
void func8(int p[10]) {}
>From 416e141cfd8fcf14f19a9b55ab2b0fbcb1d017d6 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Fri, 13 Feb 2026 17:01:07 -0800
Subject: [PATCH 2/2] address review
---
.../Dialect/Transforms/LoweringPrepare.cpp | 27 +++++++++----------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 3d8ef6ec53f73..7c529a7593f9f 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1116,21 +1116,18 @@ void LoweringPreparePass::lowerStoreOfConstAggregate(cir::StoreOp op) {
CIRBaseBuilderTy builder(getContext());
// Use InsertionGuard to create the global at module level.
- {
- mlir::OpBuilder::InsertionGuard guard(builder);
- builder.setInsertionPointToStart(mlirModule.getBody());
-
- // If a global with this name already exists (e.g. CIRGen materializes
- // constexpr locals as globals when their address is taken), reuse it.
- if (!mlir::SymbolTable::lookupNearestSymbolFrom(
- mlirModule, mlir::StringAttr::get(&getContext(), name))) {
- auto gv = cir::GlobalOp::create(builder, op.getLoc(), name, ty,
- /*isConstant=*/true,
- cir::GlobalLinkageKind::PrivateLinkage);
- mlir::SymbolTable::setSymbolVisibility(
- gv, mlir::SymbolTable::Visibility::Private);
- gv.setInitialValueAttr(constant);
- }
+ builder.setInsertionPointToStart(mlirModule.getBody());
+
+ // If a global with this name already exists (e.g. CIRGen materializes
+ // constexpr locals as globals when their address is taken), reuse it.
+ if (!mlir::SymbolTable::lookupNearestSymbolFrom(
+ mlirModule, mlir::StringAttr::get(&getContext(), name))) {
+ auto gv = cir::GlobalOp::create(builder, op.getLoc(), name, ty,
+ /*isConstant=*/true,
+ cir::GlobalLinkageKind::PrivateLinkage);
+ mlir::SymbolTable::setSymbolVisibility(
+ gv, mlir::SymbolTable::Visibility::Private);
+ gv.setInitialValueAttr(constant);
}
// Now replace the store with get_global + copy.
More information about the cfe-commits
mailing list