[clang] [CIR] Implement Atomic Complex to Complex cast (PR #199260)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Sun May 31 04:09:54 PDT 2026
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/199260
>From 3480548421290a83b62f333b9244ef847940bd3c Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Fri, 22 May 2026 21:14:24 +0200
Subject: [PATCH 1/2] [CIR] Implement Atomic Complex to Complex cast
---
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp | 46 +++++++++++++++++++-
clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 8 +---
clang/test/CIR/CodeGen/complex-atomic-cast.c | 37 ++++++++++++++++
3 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 3df0cd23d570e..95280242618a2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -110,6 +110,10 @@ class AtomicInfo {
/// copy the value across.
Address convertToAtomicIntPointer(Address addr) const;
+ /// Turn an atomic-layout object into an r-value.
+ RValue convertAtomicTempToRValue(Address addr, SourceLocation loc,
+ bool asValue) const;
+
/// Converts a rvalue to integer value.
mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
@@ -202,6 +206,33 @@ Address AtomicInfo::convertToAtomicIntPointer(Address addr) const {
return castToAtomicIntPointer(addr);
}
+RValue AtomicInfo::convertAtomicTempToRValue(Address addr, SourceLocation loc,
+ bool asValue) const {
+ if (lvalue.isSimple()) {
+ if (evaluationKind == TEK_Aggregate) {
+ cgf.cgm.errorNYI(
+ loc,
+ "AtomicInfo::convertAtomicTempToRValue: evaluationKind is aggregate");
+ return RValue::get(nullptr);
+ }
+
+ // Drill into the padding structure if we have one.
+ if (hasPadding()) {
+ cgf.cgm.errorNYI(loc,
+ "AtomicInfo::convertAtomicTempToRValue: hasPadding");
+ return RValue::get(nullptr);
+ }
+
+ // Otherwise, just convert the temporary to an r-value using the
+ // normal conversion routine.
+ return cgf.convertTempToRValue(addr, getValueType(), loc);
+ }
+
+ cgf.cgm.errorNYI(
+ loc, "AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
+ return RValue::get(nullptr);
+}
+
RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
bool asValue, cir::MemOrder order,
bool isVolatile) {
@@ -334,8 +365,19 @@ RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
return RValue::get(nullptr);
}
- cgf.cgm.errorNYI("convertToValueOrAtomic: convert through temp");
- return RValue::get(nullptr);
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ if (asValue && getEvaluationKind() == TEK_Aggregate) {
+ cgf.cgm.errorNYI("convertToValueOrAtomic: temporary aggregate");
+ return RValue::get(nullptr);
+ }
+
+ Address temp = createTempAlloca();
+
+ // Slam the integer into the temporary.
+ Address castTemp = castToAtomicIntPointer(temp);
+ cgf.getBuilder().createStore(cgf.getLoc(loc), intVal, castTemp);
+ return convertAtomicTempToRValue(temp, loc, asValue);
}
/// Copy an r-value into memory as part of storing to an atomic type.
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 53a3e6e6f2cc7..c576cb9159f36 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -333,7 +333,7 @@ mlir::Value ComplexExprEmitter::emitLoadOfLValue(LValue lv,
SourceLocation loc) {
assert(lv.isSimple() && "non-simple complex l-value?");
if (lv.getType()->isAtomicType())
- cgf.cgm.errorNYI(loc, "emitLoadOfLValue with Atomic LV");
+ return cgf.emitAtomicLoad(lv, loc).getComplexValue();
const Address srcAddr = lv.getAddress();
return builder.createLoad(cgf.getLoc(loc), srcAddr, lv.isVolatileQualified());
@@ -459,16 +459,12 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op,
// Atomic to non-atomic casts may be more than a no-op for some platforms
// and for some types.
case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic:
case CK_NoOp:
case CK_LValueToRValue:
case CK_UserDefinedConversion:
return Visit(op);
- case CK_AtomicToNonAtomic: {
- cgf.cgm.errorNYI("ComplexExprEmitter::emitCast AtomicToNonAtomic");
- return {};
- }
-
case CK_LValueBitCast: {
LValue origLV = cgf.emitLValue(op);
Address addr =
diff --git a/clang/test/CIR/CodeGen/complex-atomic-cast.c b/clang/test/CIR/CodeGen/complex-atomic-cast.c
index 9500db594ea85..a15858fcf9711 100644
--- a/clang/test/CIR/CodeGen/complex-atomic-cast.c
+++ b/clang/test/CIR/CodeGen/complex-atomic-cast.c
@@ -30,3 +30,40 @@ void complex_to_atomic_complex() {
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1
// OGCG: store i32 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 8
// OGCG: store i32 %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4
+
+void atomic_complex_to_complex() {
+ _Atomic _Complex int a;
+ _Complex int b = a;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR: %[[ATOMIC_TMP_ADDR:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["atomic-temp"]
+// CIR: %[[A_U64I:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!cir.complex<!s32i>> -> !cir.ptr<!u64i>
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} atomic(seq_cst) %[[A_U64I]] : !cir.ptr<!u64i>, !u64i
+// CIR: %[[ATOMIC_TMP_U64I:.*]] = cir.cast bitcast %[[ATOMIC_TMP_ADDR]] : !cir.ptr<!cir.complex<!s32i>> -> !cir.ptr<!u64i>
+// CIR: cir.store {{.*}} %[[TMP_A]], %[[ATOMIC_TMP_U64I]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[TMP_ATOMIC:.*]] = cir.load {{.*}} %[[ATOMIC_TMP_ADDR]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR: cir.store {{.*}} %[[TMP_ATOMIC]], %[[B_ADDR]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 8
+// LLVM: %[[B_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[ATOMIC_TMP_ADDR:.*]] = alloca { i32, i32 }, i64 1, align 8
+// LLVM: %[[TMP_A:.*]] = load atomic i64, ptr %[[A_ADDR]] seq_cst, align 8
+// LLVM: store i64 %[[TMP_A]], ptr %[[ATOMIC_TMP_ADDR]], align 8
+// LLVM: %[[TMP_ATOMIC:.*]] = load { i32, i32 }, ptr %[[ATOMIC_TMP_ADDR]], align 8
+// LLVM: store { i32, i32 } %[[TMP_ATOMIC]], ptr %[[B_ADDR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { i32, i32 }, align 8
+// OGCG: %[[B_ADDR:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[ATOMIC_TMP_ADDR:.*]] = alloca { i32, i32 }, align 8
+// OGCG: %[[TMP_A:.*]] = load atomic i64, ptr %[[A_ADDR]] seq_cst, align 8
+// OGCG: store i64 %[[TMP_A]], ptr %[[ATOMIC_TMP_ADDR]], align 8
+// OGCG: %[[ATOMIC_TMP_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[ATOMIC_TMP_ADDR]], i32 0, i32 0
+// OGCG: %[[ATOMIC_TMP_REAL:.*]] = load i32, ptr %[[ATOMIC_TMP_REAL_PTR]], align 8
+// OGCG: %[[ATOMIC_TMP_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[ATOMIC_TMP_ADDR]], i32 0, i32 1
+// OGCG: %[[ATOMIC_TMP_IMAG:.*]] = load i32, ptr %[[ATOMIC_TMP_IMAG_PTR]], align 4
+// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG: store i32 %[[ATOMIC_TMP_REAL]], ptr %[[B_REAL_PTR]], align 4
+// OGCG: store i32 %[[ATOMIC_TMP_IMAG]], ptr %[[B_IMAG_PTR]], align 4
>From 60bbfad7143a665a8c739f4a851f2e8b21cdf181 Mon Sep 17 00:00:00 2001
From: Amr Hesham <amr96 at programmer.net>
Date: Sun, 31 May 2026 13:06:32 +0200
Subject: [PATCH 2/2] Address code review comments
---
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 95280242618a2..33ddf8e1539db 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -367,13 +367,14 @@ RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
// Create a temporary. This needs to be big enough to hold the
// atomic integer.
+ Address temp = Address::invalid();
if (asValue && getEvaluationKind() == TEK_Aggregate) {
cgf.cgm.errorNYI("convertToValueOrAtomic: temporary aggregate");
return RValue::get(nullptr);
+ } else {
+ temp = createTempAlloca();
}
- Address temp = createTempAlloca();
-
// Slam the integer into the temporary.
Address castTemp = castToAtomicIntPointer(temp);
cgf.getBuilder().createStore(cgf.getLoc(loc), intVal, castTemp);
More information about the cfe-commits
mailing list