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


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

Reply via email to