[clang] 428a03d - [CIR] Implement CompoundAssignLValue for Atomic Complex (#201895)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 6 06:54:39 PDT 2026
Author: Amr Hesham
Date: 2026-06-06T15:54:34+02:00
New Revision: 428a03d5ff9352a1da801bf2a6a94db982dee79c
URL: https://github.com/llvm/llvm-project/commit/428a03d5ff9352a1da801bf2a6a94db982dee79c
DIFF: https://github.com/llvm/llvm-project/commit/428a03d5ff9352a1da801bf2a6a94db982dee79c.diff
LOG: [CIR] Implement CompoundAssignLValue for Atomic Complex (#201895)
Implement CompoundAssignLValue support for Atomic Complex
Issue https://github.com/llvm/llvm-project/issues/192331
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.cpp
clang/test/CIR/CodeGen/complex-compound-assignment.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 758defeed7660..6ba6bc1c0405a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -68,6 +68,7 @@ class AtomicInfo {
}
QualType getValueType() const { return valueTy; }
+ QualType getAtomicType() const { return atomicTy; }
CharUnits getAtomicAlignment() const { return atomicAlign; }
TypeEvaluationKind getEvaluationKind() const { return evaluationKind; }
mlir::Value getAtomicPointer() const {
@@ -115,7 +116,8 @@ class AtomicInfo {
bool asValue) const;
/// Converts a rvalue to integer value.
- mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
+ mlir::Value convertRValueToInt(RValue rvalue, mlir::Location loc,
+ bool cmpxchg = false) const;
RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
SourceLocation loc, bool asValue,
@@ -141,6 +143,9 @@ class AtomicInfo {
RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
bool asValue, cir::MemOrder order, bool isVolatile);
+ /// Materialize an atomic r-value in atomic-layout memory.
+ Address materializeRValue(RValue rvalue, mlir::Location loc) const;
+
/// Creates temp alloca for intermediate operations on atomic value.
Address createTempAlloca() const;
@@ -328,7 +333,8 @@ mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
return op;
}
-mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
+mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
+ bool cmpxchg) const {
// If we've got a scalar value of the right size, try to avoid going
// through memory. Floats get casted if needed by AtomicExpandPass.
if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
@@ -340,9 +346,14 @@ mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
return nullptr;
}
- cgf.cgm.errorNYI(
- loc, "AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
- return nullptr;
+ // Otherwise, we need to go through memory.
+ // Put the r-value in memory.
+ Address addr = materializeRValue(rvalue, loc);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ addr = castToAtomicIntPointer(addr);
+
+ return cgf.getBuilder().createLoad(loc, addr);
}
RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
@@ -416,6 +427,22 @@ void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
}
}
+/// Materialize an r-value into memory for the purposes of storing it
+/// to an atomic type.
+Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc) const {
+ // Aggregate r-values are already in memory, and EmitAtomicStore
+ // requires them to be values of the atomic type.
+ if (rvalue.isAggregate())
+ return rvalue.getAggregateAddress();
+
+ // Otherwise, make a temporary and materialize into it.
+ LValue tempLV = cgf.makeAddrLValue(createTempAlloca(), getAtomicType());
+ AtomicInfo atomics(cgf, tempLV, loc);
+
+ atomics.emitCopyIntoMemory(rvalue);
+ return tempLV.getAddress();
+}
+
static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc) {
mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
mlir::OpBuilder::InsertPoint insertPoint;
@@ -1392,7 +1419,7 @@ void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest,
}
// Okay, we're doing this natively.
- mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
+ mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
// Do the atomic store.
Address addr = atomics.getAtomicAddress();
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index fb8ace089a4c5..c873124521f28 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -847,11 +847,6 @@ ComplexExprEmitter::emitBinOps(const BinaryOperator *e, QualType promotionTy) {
LValue ComplexExprEmitter::emitCompoundAssignLValue(
const CompoundAssignOperator *e,
mlir::Value (ComplexExprEmitter::*func)(const BinOpInfo &), RValue &value) {
- if (e->getLHS()->getType()->getAs<AtomicType>()) {
- cgf.cgm.errorNYI("emitCompoundAssignLValue AtmoicType");
- return {};
- }
-
QualType lhsTy = e->getLHS()->getType().getAtomicUnqualifiedType();
QualType rhsTy = e->getRHS()->getType();
SourceLocation exprLoc = e->getExprLoc();
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 4ecb47a864146..6049d98d54a78 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1186,11 +1186,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
return emitBinaryOperatorLValue(cast<BinaryOperator>(e));
case Expr::CompoundAssignOperatorClass: {
QualType ty = e->getType();
- if (ty->getAs<AtomicType>()) {
- cgm.errorNYI(e->getSourceRange(),
- "CompoundAssignOperator with AtomicType");
- return LValue();
- }
+ if (const AtomicType *at = ty->getAs<AtomicType>())
+ ty = at->getValueType();
if (!ty->isAnyComplexType())
return emitCompoundAssignmentLValue(cast<CompoundAssignOperator>(e));
diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
index 77c6686e57215..78363e2ead193 100644
--- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
+++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
@@ -858,3 +858,68 @@ void foo9() {
// C_OGCG: %[[TMP_B:.*]] = load float, ptr %[[B_ADDR]], align 4
// C_OGCG: %[[ADD_REAL:.*]] = fadd float %[[TMP_B]], %[[A_REAL]]
// C_OGCG: store float %[[ADD_REAL]], ptr %[[B_ADDR]], align 4
+
+void compound_assignment_atomic() {
+ _Atomic _Complex float a = 2.0f;
+ a += 1.0f;
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init]
+// CIR: %[[ATOMIC_TMP1_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["atomic-temp"]
+// CIR: %[[ATOMIC_TMP2_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["atomic-temp"]
+// CIR: %[[CONST_2F:.*]] = cir.const #cir.fp<2.000000e+00> : !cir.float
+// CIR: %[[CONST_0F:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float
+// CIR: %[[COMPLEX_INIT:.*]] = cir.complex.create %[[CONST_2F]], %[[CONST_0F]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: cir.store {{.*}} %[[COMPLEX_INIT]], %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[CONST_1F:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float
+// CIR: %[[A_PTR:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!u64i>
+// CIR: %[[TMP_A:.*]] = cir.load {{.*}} atomic(seq_cst) %[[A_PTR]] : !cir.ptr<!u64i>, !u64i
+// CIR: %[[ATOMIC_TMP1_PTR:.*]] = cir.cast bitcast %[[ATOMIC_TMP1_ADDR]] : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!u64i>
+// CIR: cir.store {{.*}} %[[TMP_A]], %[[ATOMIC_TMP1_PTR]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[ATOMIC_TMP1:.*]] = cir.load {{.*}} %[[ATOMIC_TMP1_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: %[[ATOMIC_TMP1_REAL:.*]] = cir.complex.real %[[ATOMIC_TMP1]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[ATOMIC_TMP1_IMAG:.*]] = cir.complex.imag %[[ATOMIC_TMP1]] : !cir.complex<!cir.float> -> !cir.float
+// CIR: %[[RESULT_REAL:.*]] = cir.fadd %[[ATOMIC_TMP1_REAL]], %[[CONST_1F]] : !cir.float
+// CIR: %[[COMPLEX_RESULT:.*]] = cir.complex.create %[[RESULT_REAL]], %[[ATOMIC_TMP1_IMAG]] : !cir.float -> !cir.complex<!cir.float>
+// CIR: cir.store {{.*}} %[[COMPLEX_RESULT]], %[[ATOMIC_TMP2_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[ATOMIC_TMP2_PTR:.*]] = cir.cast bitcast %[[ATOMIC_TMP2_ADDR]] : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!u64i>
+// CIR: %[[RESULT:.*]] = cir.load {{.*}} %[[ATOMIC_TMP2_PTR]] : !cir.ptr<!u64i>, !u64i
+// CIR: %[[A_PTR:.*]] = cir.cast bitcast %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>> -> !cir.ptr<!u64i>
+// CIR: cir.store {{.*}} atomic(seq_cst) %[[RESULT]], %[[A_PTR]] : !u64i, !cir.ptr<!u64i>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 8
+// LLVM: %[[ATOMIC_TMP1_ADDR:.*]] = alloca { float, float }, i64 1, align 8
+// LLVM: %[[ATOMIC_TMP2_ADDR:.*]] = alloca { float, float }, i64 1, align 8
+// LLVM: store { float, float } { float 2.000000e+00, float 0.000000e+00 }, ptr %[[A_ADDR]], align 8
+// LLVM: %[[TMP_A:.*]] = load atomic i64, ptr %[[A_ADDR]] seq_cst, align 8
+// LLVM: store i64 %[[TMP_A]], ptr %[[ATOMIC_TMP1_ADDR]], align 8
+// LLVM: %[[ATOMIC_TMP1:.*]] = load { float, float }, ptr %[[ATOMIC_TMP1_ADDR]], align 8
+// LLVM: %[[ATOMIC_TMP1_REAL:.*]] = extractvalue { float, float } %[[ATOMIC_TMP1]], 0
+// LLVM: %[[ATOMIC_TMP1_IMAG:.*]] = extractvalue { float, float } %[[ATOMIC_TMP1]], 1
+// LLVM: %[[RESULT_REAL:.*]] = fadd float %[[ATOMIC_TMP1_REAL]], 1.000000e+00
+// LLVM: %[[COMPLEX_RESULT_TMP:.*]] = insertvalue { float, float } {{.*}}, float %[[RESULT_REAL]], 0
+// LLVM: %[[COMPLEX_RESULT:.*]] = insertvalue { float, float } %[[COMPLEX_RESULT_TMP]], float %[[ATOMIC_TMP1_IMAG]], 1
+// LLVM: store { float, float } %[[COMPLEX_RESULT]], ptr %[[ATOMIC_TMP2_ADDR]], align 8
+// LLVM: %[[RESULT:.*]] = load i64, ptr %[[ATOMIC_TMP2_ADDR]], align 8
+// LLVM: store atomic i64 %[[RESULT]], ptr %[[A_ADDR]] seq_cst, align 8
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 8
+// OGCG: %[[ATOMIC_TMP1_ADDR:.*]] = alloca { float, float }, align 8
+// OGCG: %[[ATOMIC_TMP2_ADDR:.*]] = alloca { float, float }, align 8
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: store float 2.000000e+00, ptr %[[A_REAL_PTR]], align 8
+// OGCG: store float 0.000000e+00, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[TMP_A:.*]] = load atomic i64, ptr %[[A_ADDR]] seq_cst, align 8
+// OGCG: store i64 %[[TMP_A]], ptr %[[ATOMIC_TMP1_ADDR]], align 8
+// OGCG: %[[ATOMIC_TMP1_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ATOMIC_TMP1_ADDR]], i32 0, i32 0
+// OGCG: %[[ATOMIC_TMP1_REAL:.*]] = load float, ptr %[[ATOMIC_TMP1_REAL_PTR]], align 8
+// OGCG: %[[ATOMIC_TMP1_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ATOMIC_TMP1_ADDR]], i32 0, i32 1
+// OGCG: %[[ATOMIC_TMP1_IMAG:.*]] = load float, ptr %[[ATOMIC_TMP1_IMAG_PTR]], align 4
+// OGCG: %[[RESULT_REAL:.*]] = fadd float %[[ATOMIC_TMP1_REAL]], 1.000000e+00
+// OGCG: %[[ATOMIC_TMP2_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ATOMIC_TMP2_ADDR]], i32 0, i32 0
+// OGCG: %[[ATOMIC_TMP2_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ATOMIC_TMP2_ADDR]], i32 0, i32 1
+// OGCG: store float %[[RESULT_REAL]], ptr %[[ATOMIC_TMP2_REAL_PTR]], align 8
+// OGCG: store float %[[ATOMIC_TMP1_IMAG]], ptr %[[ATOMIC_TMP2_IMAG_PTR]], align 4
+// OGCG: %[[RESULT:.*]] = load i64, ptr %[[ATOMIC_TMP2_ADDR]], align 8
+// OGCG: store atomic i64 %[[RESULT]], ptr %[[A_ADDR]] seq_cst, align 8
More information about the cfe-commits
mailing list