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


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

Reply via email to