[clang] 83582cf - [clang][CodeGen] Do not use atomicrmw in compound assignments with FP conversions (#209114)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 02:40:35 PDT 2026
Author: Antonio Frighetto
Date: 2026-07-16T09:40:30Z
New Revision: 83582cfcdb4973a337195c1f59d6a3468d135434
URL: https://github.com/llvm/llvm-project/commit/83582cfcdb4973a337195c1f59d6a3468d135434
DIFF: https://github.com/llvm/llvm-project/commit/83582cfcdb4973a337195c1f59d6a3468d135434.diff
LOG: [clang][CodeGen] Do not use atomicrmw in compound assignments with FP conversions (#209114)
Per C11 6.5.16.2p1, when the left operand of operator `+=` has atomic
type, the right shall have arithmetic type. Do not try the `atomicrmw`
fast-path when FP conversion, arithmetic and truncation are required, as
a single atomic operation may not correctly capture the combined
semantics.
Fixes: https://github.com/llvm/llvm-project/issues/208997.
Added:
Modified:
clang/lib/CodeGen/CGExprScalar.cpp
clang/test/CodeGen/c11atomics.c
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 6f7b7e7d6840e..81016d3d5d308 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4091,12 +4091,24 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::PHINode *atomicPHI = nullptr;
if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
- QualType type = atomicTy->getValueType();
- if (!type->isBooleanType() && type->isIntegerType() &&
- !(type->isUnsignedIntegerType() &&
+ // Type wrapped by _Atomic.
+ QualType AtomicValueTy = atomicTy->getValueType();
+ // Type resulting from FP conversion / integer promotion of the compound
+ // assignment operands.
+ QualType ResultTy = E->getComputationResultType();
+ // Do not try the atomicrmw op fast-path when the compound assignment may
+ // involve FP conversions, as the correct semantics would require promoting
+ // the loaded integer to double, performing FP arithmetics, and truncation
+ // back as a single atomic operation. Integer promotion is still
+ // semantically safe.
+ bool CanEmitAtomicRMW =
+ !AtomicValueTy->isBooleanType() && AtomicValueTy->isIntegerType() &&
+ ResultTy->isIntegerType() &&
+ !(AtomicValueTy->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
CGF.getLangOpts().getSignedOverflowBehavior() !=
- LangOptions::SOB_Trapping) {
+ LangOptions::SOB_Trapping;
+ if (CanEmitAtomicRMW) {
llvm::AtomicRMWInst::BinOp AtomicOp = llvm::AtomicRMWInst::BAD_BINOP;
llvm::Instruction::BinaryOps Op;
switch (OpInfo.Opcode) {
@@ -4149,7 +4161,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
- OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
+ OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, AtomicValueTy);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c
index 6a66cd8cbae89..1c916d55366e4 100644
--- a/clang/test/CodeGen/c11atomics.c
+++ b/clang/test/CodeGen/c11atomics.c
@@ -152,6 +152,27 @@ void testandeq(void)
l &= 42;
s &= 42;
}
+// CHECK: testaddeq_fp
+void testaddeq_fp(void)
+{
+ // FIXME: This should be a sitofp conversion.
+ // CHECK: [[CONV:%.*]] = uitofp i32 [[TMP0:%.*]] to double
+ // CHECK-NEXT: [[FADD:%.*]] = fadd double [[CONV]], -5.000000e-01
+ // CHECK-NEXT: [[CONV1:%.*]] = fptosi double [[FADD]] to i32
+ // CHECK-NEXT: store i32 [[TMP0]], ptr {{%.*}}, align 4
+ // CHECK-NEXT: store i32 [[CONV1]], ptr {{%.*}}, align 4
+ // CHECK-NEXT: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 4, ptr noundef @i, ptr noundef {{%.*}}, ptr noundef {{%.*}}, i32 noundef 5, i32 noundef 5)
+ i += -0.5;
+
+ // FIXME: This should be a sitofp conversion.
+ // CHECK: [[CONV2:%.*]] = uitofp i32 [[TMP1:%.*]] to double
+ // CHECK-NEXT: [[FADD1:%.*]] = fadd double [[CONV2]], -2.500000e+00
+ // CHECK-NEXT: [[CONV3:%.*]] = fptosi double [[FADD1]] to i32
+ // CHECK-NEXT: store i32 [[TMP1]], ptr {{%.*}}, align 4
+ // CHECK-NEXT: store i32 [[CONV3]], ptr {{%.*}}, align 4
+ // CHECK-NEXT: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 4, ptr noundef @i, ptr noundef {{%.*}}, ptr noundef {{%.*}}, i32 noundef 5, i32 noundef 5)
+ i += -2.5;
+}
// CHECK-LABEL: define{{.*}} arm_aapcscc void @testFloat(ptr
void testFloat(_Atomic(float) *fp) {
More information about the cfe-commits
mailing list