-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[Clang] Fix clang to emit llvm-ir for fadd/fsub atomics #162679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Currently, Clang emits CAS loops for atoic fp compound assignments, instead of atomicrmw instructions. The code in CGExprScalar.cpp now checks for both integer and floating-point atomic types and emits atomicrmw fadd/fsub instructions in the LLVM IR.
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: Amina Chabane (Amichaxx) ChangesCurrently, Clang emits CAS loops for atomic fp compound assignments, instead of atomicrmw instructions. The code in CGExprScalar.cpp now checks for both integer and floating-point atomic types and emits atomicrmw fadd/fsub instructions in the LLVM IR. cc: @efriedma-quic ? Full diff: https://github.com/llvm/llvm-project/pull/162679.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index f319b176513f8..4028a91ad7639 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3847,7 +3847,16 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::PHINode *atomicPHI = nullptr;
if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
QualType type = atomicTy->getValueType();
- if (!type->isBooleanType() && type->isIntegerType() &&
+ const bool isFloat = type->isFloatingType();
+ const bool isInteger = type->isIntegerType();
+
+ bool isPowerOfTwo = false;
+ if (isFloat || isInteger) {
+ llvm::Type *IRTy = CGF.ConvertType(type);
+ uint64_t StoreBits = CGF.CGM.getDataLayout().getTypeStoreSizeInBits(IRTy);
+ isPowerOfTwo = llvm::isPowerOf2_64(StoreBits);
+ }
+ if (!type->isBooleanType() && (isInteger || isFloat) && isPowerOfTwo &&
!(type->isUnsignedIntegerType() &&
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
CGF.getLangOpts().getSignedOverflowBehavior() !=
@@ -3862,12 +3871,14 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
case BO_ShrAssign:
break;
case BO_AddAssign:
- AtomicOp = llvm::AtomicRMWInst::Add;
- Op = llvm::Instruction::Add;
+ AtomicOp =
+ isFloat ? llvm::AtomicRMWInst::FAdd : llvm::AtomicRMWInst::Add;
+ Op = isFloat ? llvm::Instruction::FAdd : llvm::Instruction::Add;
break;
case BO_SubAssign:
- AtomicOp = llvm::AtomicRMWInst::Sub;
- Op = llvm::Instruction::Sub;
+ AtomicOp =
+ isFloat ? llvm::AtomicRMWInst::FSub : llvm::AtomicRMWInst::Sub;
+ Op = isFloat ? llvm::Instruction::FSub : llvm::Instruction::Sub;
break;
case BO_AndAssign:
AtomicOp = llvm::AtomicRMWInst::And;
diff --git a/clang/test/CodeGen/aarch64-lsfe-atomics.c b/clang/test/CodeGen/aarch64-lsfe-atomics.c
new file mode 100644
index 0000000000000..957e960b3fe3a
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-lsfe-atomics.c
@@ -0,0 +1,61 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=aarch64-linux-gnu | FileCheck %s --check-prefix=CHECK-LLVM
+
+_Atomic(float) f;
+_Atomic(double) d;
+
+// CHECK-LLVM-LABEL: define dso_local void @test_float_add(
+// CHECK-LLVM-SAME: float noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-LLVM-NEXT: [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT: [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-LLVM-NEXT: store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-LLVM-NEXT: [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-LLVM-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] seq_cst, align 4
+// CHECK-LLVM-NEXT: [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-LLVM-NEXT: ret void
+//
+void test_float_add(float val) {
+ f += val;
+}
+
+// CHECK-LLVM-LABEL: define dso_local void @test_double_add(
+// CHECK-LLVM-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-LLVM-NEXT: [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT: [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-LLVM-NEXT: store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-LLVM-NEXT: [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-LLVM-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr @d, double [[TMP0]] seq_cst, align 8
+// CHECK-LLVM-NEXT: [[TMP2:%.*]] = fadd double [[TMP1]], [[TMP0]]
+// CHECK-LLVM-NEXT: ret void
+//
+void test_double_add(double val) {
+ d += val;
+}
+
+// CHECK-LLVM-LABEL: define dso_local void @test_float_sub(
+// CHECK-LLVM-SAME: float noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-LLVM-NEXT: [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT: [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-LLVM-NEXT: store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-LLVM-NEXT: [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-LLVM-NEXT: [[TMP1:%.*]] = atomicrmw fsub ptr @f, float [[TMP0]] seq_cst, align 4
+// CHECK-LLVM-NEXT: [[TMP2:%.*]] = fsub float [[TMP1]], [[TMP0]]
+// CHECK-LLVM-NEXT: ret void
+//
+void test_float_sub(float val) {
+ f -= val;
+}
+
+// CHECK-LLVM-LABEL: define dso_local void @test_double_sub(
+// CHECK-LLVM-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-LLVM-NEXT: [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT: [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-LLVM-NEXT: store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-LLVM-NEXT: [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-LLVM-NEXT: [[TMP1:%.*]] = atomicrmw fsub ptr @d, double [[TMP0]] seq_cst, align 8
+// CHECK-LLVM-NEXT: [[TMP2:%.*]] = fsub double [[TMP1]], [[TMP0]]
+// CHECK-LLVM-NEXT: ret void
+//
+void test_double_sub(double val){
+ d -= val;
+}
|
Currently, Clang emits CAS loops for atomic fp compound assignments, instead of atomicrmw instructions. The code in CGExprScalar.cpp now checks for both integer and floating-point atomic types and emits atomicrmw fadd/fsub instructions in the LLVM IR.
cc: @efriedma-quic ?