[clang] 08d4996 - [CIR] Support Aggregate cast from and to atomic type (#220689)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 4 10:08:33 PDT 2026
Author: Amr Hesham
Date: 2026-09-04T19:08:27+02:00
New Revision: 08d499665a145b4f9074324ed259015850809473
URL: https://github.com/llvm/llvm-project/commit/08d499665a145b4f9074324ed259015850809473
DIFF: https://github.com/llvm/llvm-project/commit/08d499665a145b4f9074324ed259015850809473.diff
LOG: [CIR] Support Aggregate cast from and to atomic type (#220689)
Support Aggregate cast from and to atomic type
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
clang/test/CIR/CodeGen/agg-atomic-cast.c
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 2b3cf598f35a3..16bfdae8cb0f1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -183,7 +183,13 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
// If we have an atomic type, evaluate into the destination and then
// do an atomic copy.
- assert(!cir::MissingFeatures::atomicTypes());
+ if (lhs.getType()->isAtomicType() ||
+ cgf.isLValueSuitableForInlineAtomic(lhs)) {
+ ensureDest(cgf.getLoc(e->getExprLoc()), e->getRHS()->getType());
+ Visit(e->getRHS());
+ cgf.emitAtomicStore(dest.asRValue(), lhs, /*isInit=*/false);
+ return;
+ }
// Codegen the RHS so that it stores directly into the LHS.
assert(!cir::MissingFeatures::aggValueSlotGC());
@@ -296,18 +302,39 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
// These two cases are reverses of each other; try to peephole them.
CastKind peepholeTarget =
(isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
+
+ // These two cases are reverses of each other; try to peephole them.
if (Expr *op =
findPeephole(e->getSubExpr(), peepholeTarget, cgf.getContext())) {
- cgf.cgm.errorNYI(op->getSourceRange(),
- "AggExprEmitter: VisitCastExpr peephole");
+ assert(cgf.getContext().hasSameUnqualifiedType(op->getType(),
+ e->getType()) &&
+ "peephole significantly changed types?");
+ return Visit(op);
}
// If we're converting an r-value of non-atomic type to an r-value
// of atomic type, just emit directly into the relevant sub-object.
if (isToAtomic) {
- cgf.cgm.errorNYI(e->getSourceRange(),
- "AggExprEmitter: VisitCastExpr r-value of non-atomic "
- "type to an r-value of atomic type");
+ AggValueSlot valueDest = dest;
+ if (!valueDest.isIgnored() && cgf.cgm.isPaddedAtomicType(atomicType)) {
+ // Zero-initialize. (Strictly speaking, we only need to initialize
+ // the padding at the end, but this is simpler.)
+ mlir::Location loc = cgf.getLoc(e->getExprLoc());
+ if (!dest.isZeroed())
+ cgf.emitNullInitialization(loc, dest.getAddress(), atomicType);
+
+ Address valueAddr = cgf.getBuilder().createGetMember(
+ loc, valueDest.getAddress(), "value_addr", 0);
+
+ assert(!cir::MissingFeatures::aggValueSlotGC());
+ valueDest = AggValueSlot::forAddr(
+ valueAddr, valueDest.getQualifiers(),
+ valueDest.isExternallyDestructed(),
+ valueDest.isPotentiallyAliased(), AggValueSlot::DoesNotOverlap,
+ AggValueSlot::IsZeroed);
+ }
+
+ cgf.emitAggExpr(e->getSubExpr(), valueDest);
return;
}
diff --git a/clang/test/CIR/CodeGen/agg-atomic-cast.c b/clang/test/CIR/CodeGen/agg-atomic-cast.c
index a6c7452ce94d3..ac34d056dccd1 100644
--- a/clang/test/CIR/CodeGen/agg-atomic-cast.c
+++ b/clang/test/CIR/CodeGen/agg-atomic-cast.c
@@ -101,3 +101,73 @@ struct T load_atomic_struct() {
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RET_ADDR]], ptr align 1 %[[RET_VAL_ADDR]], i64 3, i1 false)
// OGCG: %[[TMP_RET:.*]] = load i24, ptr %[[RET_ADDR]], align 4
// OGCG: ret i24 %[[TMP_RET]]
+
+void load_atomic_struct_to_atomic_struct() {
+ _Atomic(struct T) a;
+ _Atomic(struct T) b;
+ b = a;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!rec_anon_struct>
+// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!rec_anon_struct>
+// CIR: %[[AGG_TMP_ADDR:.*]] = cir.alloca "agg.tmp.ensured" {{.*}} : !cir.ptr<!rec_anon_struct>
+// CIR: %[[A_ADDR_U32:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} atomic(seq_cst) %[[A_ADDR_U32]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[AGG_TMP_ADDR_U32:.*]] = cir.cast bitcast %[[AGG_TMP_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: cir.store {{.*}} %[[TMP_A]], %[[AGG_TMP_ADDR_U32]] : !u32i, !cir.ptr<!u32i>
+// CIR: %[[AGG_TMP_ADDR_U32:.*]] = cir.cast bitcast %[[AGG_TMP_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: %[[AGG_TMP:.*]] = cir.load {{.*}} %[[AGG_TMP_ADDR_U32]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[B_ADDR_U32:.*]] = cir.cast bitcast %[[B_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: cir.store {{.*}} atomic(seq_cst) %[[AGG_TMP]], %[[B_ADDR_U32]] : !u32i, !cir.ptr<!u32i>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// LLVM: %[[B_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// LLVM: %[[AGG_TMP_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// LLVM: %[[TMP_A:.*]] = load atomic i32, ptr %[[A_ADDR]] seq_cst, align 4
+// LLVM: store i32 %[[TMP_A]], ptr %[[AGG_TMP_ADDR]], align 4
+// LLVM: %[[AGG_TMP:.*]] = load i32, ptr %[[AGG_TMP_ADDR]], align 4
+// LLVM: store atomic i32 %[[AGG_TMP]], ptr %[[B_ADDR]] seq_cst, align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// OGCG: %[[B_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// OGCG: %[[AGG_TMP_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// OGCG: %[[TMP_A:.*]] = load atomic i32, ptr %[[A_ADDR]] seq_cst, align 4
+// OGCG: store i32 %[[TMP_A]], ptr %[[AGG_TMP_ADDR]], align 4
+// OGCG: %[[AGG_TMP:.*]] = load i32, ptr %[[AGG_TMP_ADDR]], align 4
+// OGCG: store atomic i32 %[[AGG_TMP]], ptr %[[B_ADDR]] seq_cst, align 4
+
+void load_struct_to_atomic_struct() {
+ struct T a;
+ _Atomic(struct T) b;
+ b = a;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!rec_T>
+// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!rec_anon_struct>
+// CIR: %[[AGG_TMP_ADDR:.*]] = cir.alloca "agg.tmp.ensured" {{.*}} : !cir.ptr<!rec_anon_struct>
+// CIR: %[[AGG_TMP_ZERO:.*]] = cir.get_global @__const.load_struct_to_atomic_struct.agg.tmp.ensured : !cir.ptr<!rec_anon_struct>
+// CIR: cir.copy %[[AGG_TMP_ZERO]] to %[[AGG_TMP_ADDR]] : !cir.ptr<!rec_anon_struct>
+// CIR: %[[AGG_TMP_PTR:.*]] = cir.get_member %[[AGG_TMP_ADDR]][0] {name = "value_addr"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!rec_T>
+// CIR: cir.copy %[[A_ADDR]] {{.*}} to %[[AGG_TMP_PTR]] {{.*}} : !cir.ptr<!rec_T>
+// CIR: %[[AGG_TMP_ADDR_U32:.*]] = cir.cast bitcast %[[AGG_TMP_ADDR]] : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: %[[AGG_TMP:.*]] = cir.load {{.*}} %[[AGG_TMP_ADDR_U32]] : !cir.ptr<!u32i>, !u32i
+// CIR: %[[B_ADDR_U32:.*]] = cir.cast bitcast %1 : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR: cir.store {{.*}} atomic(seq_cst) %[[AGG_TMP]], %[[B_ADDR_U32]] : !u32i, !cir.ptr<!u32i>
+
+// LLVM: %[[A_ADDR:.*]] = alloca %struct.T, align 1
+// LLVM: %[[B_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// LLVM: %[[AGG_TMP_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[AGG_TMP_ADDR]], ptr align 1 @__const.load_struct_to_atomic_struct.agg.tmp.ensured, i64 4, i1 false)
+// LLVM: %[[AGG_TMP_PTR:.*]] = getelementptr inbounds nuw { %struct.T, [1 x i8] }, ptr %[[AGG_TMP_ADDR]], i32 0, i32 0
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[AGG_TMP_PTR]], ptr align 1 %[[A_ADDR]], i64 3, i1 false)
+// LLVM: %[[AGG_TMP:.*]] = load i32, ptr %[[AGG_TMP_ADDR]], align 4
+// LLVM: store atomic i32 %[[AGG_TMP]], ptr %[[B_ADDR]] seq_cst, align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca %struct.T, align 1
+// OGCG: %[[B_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// OGCG: %[[AGG_TMP_ADDR:.*]] = alloca { %struct.T, [1 x i8] }, align 4
+// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[AGG_TMP_ADDR]], i8 0, i64 4, i1 false)
+// OGCG: %[[AGG_TMP_PTR:.*]] = getelementptr inbounds nuw { %struct.T, [1 x i8] }, ptr %[[AGG_TMP_ADDR]], i32 0, i32 0
+// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[AGG_TMP_PTR]], ptr align 1 %[[A_ADDR]], i64 3, i1 false)
+// OGCG: %[[AGG_TMP:.*]] = load i32, ptr %[[AGG_TMP_ADDR]], align 4
+// OGCG: store atomic i32 %[[AGG_TMP]], ptr %[[B_ADDR]] seq_cst, align 4
More information about the cfe-commits
mailing list