https://github.com/antoniofrighetto created 
https://github.com/llvm/llvm-project/pull/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.

>From 462b7b4c244a7c146b668b3098f0121ddf249607 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <[email protected]>
Date: Sun, 12 Jul 2026 17:10:51 +0200
Subject: [PATCH 1/2] [clang][CodeGen] Precommit test (NFC)

---
 clang/test/CodeGen/c11atomics.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c
index 6a66cd8cbae89..132ffdbea55b8 100644
--- a/clang/test/CodeGen/c11atomics.c
+++ b/clang/test/CodeGen/c11atomics.c
@@ -152,6 +152,17 @@ void testandeq(void)
   l &= 42;
   s &= 42;
 }
+// CHECK: testaddeq_fp
+void testaddeq_fp(void)
+{
+  // CHECK:      [[TMP0:%.*]] = atomicrmw add ptr @i, i32 0 seq_cst, align 4
+  // CHECK-NEXT: add i32 [[TMP0]], 0
+  i += -0.5;
+
+  // CHECK:      [[TMP1:%.*]] = atomicrmw add ptr @i, i32 poison seq_cst, 
align 4
+  // CHECK-NEXT: add i32 [[TMP1]], poison
+  i += -2.5;
+}
 
 // CHECK-LABEL: define{{.*}} arm_aapcscc void @testFloat(ptr
 void testFloat(_Atomic(float) *fp) {

>From 6eb00ca6f9e0382944d959b9fa7a761e1a7e4711 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <[email protected]>
Date: Mon, 13 Jul 2026 10:50:24 +0200
Subject: [PATCH 2/2] [clang][CodeGen] Do not use atomicrmw in compound
 assignments with FP conversions

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.
---
 clang/lib/CodeGen/CGExprScalar.cpp | 22 +++++++++++++++++-----
 clang/test/CodeGen/c11atomics.c    | 16 ++++++++++++----
 2 files changed, 29 insertions(+), 9 deletions(-)

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 132ffdbea55b8..9f17c3b1c0bf9 100644
--- a/clang/test/CodeGen/c11atomics.c
+++ b/clang/test/CodeGen/c11atomics.c
@@ -155,12 +155,20 @@ void testandeq(void)
 // CHECK: testaddeq_fp
 void testaddeq_fp(void)
 {
-  // CHECK:      [[TMP0:%.*]] = atomicrmw add ptr @i, i32 0 seq_cst, align 4
-  // CHECK-NEXT: add i32 [[TMP0]], 0
+  // 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;
 
-  // CHECK:      [[TMP1:%.*]] = atomicrmw add ptr @i, i32 poison seq_cst, 
align 4
-  // CHECK-NEXT: add i32 [[TMP1]], poison
+  // 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;
 }
 

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

Reply via email to