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
