[clang] [CIR] Implement Atomic Complex to Complex cast (PR #199260)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 22 12:18:15 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Amr Hesham (AmrDeveloper)
<details>
<summary>Changes</summary>
Implement Atomic Complex to Complex types cast
Issue https://github.com/llvm/llvm-project/issues/192331
---
Full diff: https://github.com/llvm/llvm-project/pull/199260.diff
3 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenAtomic.cpp (+44-2)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+2-6)
- (modified) clang/test/CIR/CodeGen/complex-atomic-cast.c (+37)
``````````diff
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 5f7e616f2f28b..0e5c5fe8b622d 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());
@@ -457,16 +457,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
``````````
</details>
https://github.com/llvm/llvm-project/pull/199260
More information about the cfe-commits
mailing list