[clang] [clang][CodeGen] Do not use atomicrmw in compound assignments with FP conversions (PR #209114)
Antonio Frighetto via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 02:06:18 PDT 2026
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/209114
>From 462b7b4c244a7c146b668b3098f0121ddf249607 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Sun, 12 Jul 2026 17:10:51 +0200
Subject: [PATCH 1/3] [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 <me at antoniofrighetto.com>
Date: Mon, 13 Jul 2026 10:50:24 +0200
Subject: [PATCH 2/3] [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;
}
>From 627b3e39987c88dc6f025c7f8df886d43b9e5163 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Thu, 16 Jul 2026 11:05:53 +0200
Subject: [PATCH 3/3] !fixup add fixme
---
clang/test/CodeGen/c11atomics.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c
index 9f17c3b1c0bf9..1c916d55366e4 100644
--- a/clang/test/CodeGen/c11atomics.c
+++ b/clang/test/CodeGen/c11atomics.c
@@ -155,6 +155,7 @@ void testandeq(void)
// 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
@@ -163,6 +164,7 @@ void testaddeq_fp(void)
// 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
More information about the cfe-commits
mailing list