https://github.com/Lukacma updated 
https://github.com/llvm/llvm-project/pull/216033

>From e6e5b45547b052996a73fb3c2a0fd83710ecce60 Mon Sep 17 00:00:00 2001
From: Marian Lukac <[email protected]>
Date: Thu, 13 Aug 2026 12:33:17 +0000
Subject: [PATCH 1/2] [Clang] Lower fp atomic compound stmts into atomicrmw

This patch lowers fp atomic compound stmts into
atomicrmw when not in strictfp environment as
exception handling and status flags updates can be
ignored. This should improve final assembly.

Co-authored-by: Amina Chabane <[email protected]>
---
 clang/lib/CodeGen/CGExprScalar.cpp        |  25 +-
 clang/test/CodeGen/aarch64-lsfe-atomics.c | 269 ++++++++++++++++++++++
 2 files changed, 287 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/CodeGen/aarch64-lsfe-atomics.c

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 8783b43846434..106d39bc5a4e2 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4089,6 +4089,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
   // Load/convert the LHS.
   LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
 
+  CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, OpInfo.FPFeatures);
   llvm::PHINode *atomicPHI = nullptr;
   if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
     // Type wrapped by _Atomic.
@@ -4101,14 +4102,21 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
     // the loaded integer to double, performing FP arithmetics, and truncation
     // back as a single atomic operation. Integer promotion is still
     // semantically safe.
-    bool CanEmitAtomicRMW =
+    bool CanEmitIntegerRMW =
         !AtomicValueTy->isBooleanType() && AtomicValueTy->isIntegerType() &&
         ResultTy->isIntegerType() &&
         !(AtomicValueTy->isUnsignedIntegerType() &&
           CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) &&
         CGF.getLangOpts().getSignedOverflowBehavior() !=
             LangOptions::SOB_Trapping;
-    if (CanEmitAtomicRMW) {
+    bool CanEmitFloatingRMW = false;
+    if (!Builder.getIsFPConstrained() && AtomicValueTy->isFloatingType() &&
+        CGF.getContext().hasSameUnqualifiedType(AtomicValueTy, ResultTy)) {
+      llvm::Type *IRTy = CGF.ConvertType(AtomicValueTy);
+      uint64_t StoreBits = 
CGF.CGM.getDataLayout().getTypeStoreSizeInBits(IRTy);
+      CanEmitFloatingRMW = llvm::isPowerOf2_64(StoreBits);
+    }
+    if (CanEmitIntegerRMW || CanEmitFloatingRMW) {
       llvm::AtomicRMWInst::BinOp AtomicOp = llvm::AtomicRMWInst::BAD_BINOP;
       llvm::Instruction::BinaryOps Op;
       switch (OpInfo.Opcode) {
@@ -4119,12 +4127,16 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
         case BO_ShrAssign:
           break;
         case BO_AddAssign:
-          AtomicOp = llvm::AtomicRMWInst::Add;
-          Op = llvm::Instruction::Add;
+          AtomicOp = CanEmitFloatingRMW ? llvm::AtomicRMWInst::FAdd
+                                        : llvm::AtomicRMWInst::Add;
+          Op = CanEmitFloatingRMW ? llvm::Instruction::FAdd
+                                  : llvm::Instruction::Add;
           break;
         case BO_SubAssign:
-          AtomicOp = llvm::AtomicRMWInst::Sub;
-          Op = llvm::Instruction::Sub;
+          AtomicOp = CanEmitFloatingRMW ? llvm::AtomicRMWInst::FSub
+                                        : llvm::AtomicRMWInst::Sub;
+          Op = CanEmitFloatingRMW ? llvm::Instruction::FSub
+                                  : llvm::Instruction::Sub;
           break;
         case BO_AndAssign:
           AtomicOp = llvm::AtomicRMWInst::And;
@@ -4171,7 +4183,6 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
   else
     OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc());
 
-  CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, OpInfo.FPFeatures);
   SourceLocation Loc = E->getExprLoc();
   if (!PromotionTypeLHS.isNull())
     OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, PromotionTypeLHS,
diff --git a/clang/test/CodeGen/aarch64-lsfe-atomics.c 
b/clang/test/CodeGen/aarch64-lsfe-atomics.c
new file mode 100644
index 0000000000000..df7422f856d57
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-lsfe-atomics.c
@@ -0,0 +1,269 @@
+// 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-C
+// RUN: %clang_cc1 -x c++ -std=c++11 %s -emit-llvm -o - 
-triple=aarch64-linux-gnu | FileCheck %s --check-prefix=CHECK-CPP
+
+_Atomic(float) f;
+_Atomic(double) d;
+_Atomic(__bf16) bf;
+_Atomic(_Float16) h;
+
+// CHECK-C-LABEL: define dso_local void @test_float_add(
+// CHECK-C-SAME: float noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z14test_float_addf(
+// CHECK-CPP-SAME: float noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_add(float val) {
+  f += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_compound_add(
+// CHECK-C-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr [[VAL_ADDR]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = atomicrmw fadd ptr @f, float 
[[ATOMIC_LOAD]] seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = fadd float [[TMP0]], [[ATOMIC_LOAD]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void 
@_Z23test_float_compound_addU7_Atomicf(
+// CHECK-CPP-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr 
[[VAL_ADDR]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = atomicrmw fadd ptr @f, float 
[[ATOMIC_LOAD]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = fadd float [[TMP0]], [[ATOMIC_LOAD]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_compound_add(_Atomic(float) val){
+  f += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_read_add(
+// CHECK-C-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f seq_cst, 
align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD1:%.*]] = load atomic float, ptr [[VAL_ADDR]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[ADD:%.*]] = fadd float [[ATOMIC_LOAD]], [[ATOMIC_LOAD1]]
+// CHECK-C-NEXT:    store atomic float [[ADD]], ptr @f seq_cst, align 4
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z19test_float_read_addU7_Atomicf(
+// CHECK-CPP-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f seq_cst, 
align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD1:%.*]] = load atomic float, ptr 
[[VAL_ADDR]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[ADD:%.*]] = fadd float [[ATOMIC_LOAD]], 
[[ATOMIC_LOAD1]]
+// CHECK-CPP-NEXT:    store atomic float [[ADD]], ptr @f seq_cst, align 4
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_read_add(_Atomic(float) val){
+  f = f + val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_double_add(
+// CHECK-C-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-C-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd double [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z15test_double_addd(
+// CHECK-CPP-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-CPP-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd double [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_double_add(double val) {
+  d += val;
+}
+
+// CHECK-LLVM-LABEL: define dso_local void @test_bf16_add(
+// CHECK-LLVM-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-LLVM-NEXT:  [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-LLVM-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-LLVM-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-LLVM-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-LLVM-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-LLVM-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-LLVM-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-LLVM-NEXT:    ret void
+// CHECK-C-LABEL: define dso_local void @test_bf16_add(
+// CHECK-C-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-C-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-C-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z13test_bf16_addu6__bf16(
+// CHECK-CPP-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-CPP-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-CPP-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_bf16_add(__bf16 val){
+  bf += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_f16_add(
+// CHECK-C-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-C-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd half [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z12test_f16_addDF16_(
+// CHECK-CPP-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-CPP-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd half [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_f16_add(_Float16 val){
+  h += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_sub(
+// CHECK-C-SAME: float noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub float [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z14test_float_subf(
+// CHECK-CPP-SAME: float noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub float [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_sub(float val) {
+  f -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_double_sub(
+// CHECK-C-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-C-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub double [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z15test_double_subd(
+// CHECK-CPP-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-CPP-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub double [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_double_sub(double val){
+  d -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_bf16_sub(
+// CHECK-C-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-C-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-C-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub bfloat [[TMP1]], [[CONV]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z13test_bf16_subu6__bf16(
+// CHECK-CPP-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-CPP-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-CPP-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub bfloat [[TMP1]], [[CONV]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_bf16_sub(__bf16 val){
+  bf -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_f16_sub(
+// CHECK-C-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-C-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub half [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z12test_f16_subDF16_(
+// CHECK-CPP-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-CPP-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub half [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_f16_sub(_Float16 val){
+  h -= val;
+}

>From 2a170f3a44b1c4837bef59bc36ab8576dab23df8 Mon Sep 17 00:00:00 2001
From: Marian Lukac <[email protected]>
Date: Thu, 13 Aug 2026 13:47:33 +0000
Subject: [PATCH 2/2] Update tests

---
 .../compound-assign-atomic-fp-fallback.c      | 234 +++++++++++++++
 .../test/CodeGen/compound-assign-atomic-fp.c  | 269 ++++++++++++++++++
 2 files changed, 503 insertions(+)
 create mode 100644 clang/test/CodeGen/compound-assign-atomic-fp-fallback.c
 create mode 100644 clang/test/CodeGen/compound-assign-atomic-fp.c

diff --git a/clang/test/CodeGen/compound-assign-atomic-fp-fallback.c 
b/clang/test/CodeGen/compound-assign-atomic-fp-fallback.c
new file mode 100644
index 0000000000000..ea186f4e04fe1
--- /dev/null
+++ b/clang/test/CodeGen/compound-assign-atomic-fp-fallback.c
@@ -0,0 +1,234 @@
+// 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-prefixes=CHECK-DEFAULT
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=aarch64-linux-gnu 
-ffp-exception-behavior=strict | FileCheck %s --check-prefixes=CHECK-STRICT
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-linux-gnu | FileCheck %s 
--check-prefixes=CHECK-X86
+
+_Atomic(float) f;
+_Atomic(long double) ld;
+
+
+// CHECK-DEFAULT-LABEL: define dso_local void @test_same_type(
+// CHECK-DEFAULT-SAME: float noundef [[VALUE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-DEFAULT-NEXT:  [[ENTRY:.*:]]
+// CHECK-DEFAULT-NEXT:    [[VALUE_ADDR:%.*]] = alloca float, align 4
+// CHECK-DEFAULT-NEXT:    store float [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-DEFAULT-NEXT:    [[TMP0:%.*]] = load float, ptr [[VALUE_ADDR]], align 
4
+// CHECK-DEFAULT-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-DEFAULT-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-DEFAULT-NEXT:    ret void
+//
+// CHECK-STRICT-LABEL: define dso_local void @test_same_type(
+// CHECK-STRICT-SAME: float noundef [[VALUE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-STRICT-NEXT:  [[ENTRY:.*]]:
+// CHECK-STRICT-NEXT:    [[VALUE_ADDR:%.*]] = alloca float, align 4
+// CHECK-STRICT-NEXT:    store float [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-STRICT-NEXT:    [[TMP0:%.*]] = load float, ptr [[VALUE_ADDR]], align 4
+// CHECK-STRICT-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f 
seq_cst, align 4
+// CHECK-STRICT-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-STRICT:       [[ATOMIC_OP]]:
+// CHECK-STRICT-NEXT:    [[TMP1:%.*]] = phi float [ [[ATOMIC_LOAD]], 
%[[ENTRY]] ], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-STRICT-NEXT:    [[ADD:%.*]] = call float 
@llvm.experimental.constrained.fadd.f32(float [[TMP1]], float [[TMP0]], 
metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2:[0-9]+]]
+// CHECK-STRICT-NEXT:    [[TMP2:%.*]] = bitcast float [[TMP1]] to i32
+// CHECK-STRICT-NEXT:    [[TMP3:%.*]] = bitcast float [[ADD]] to i32
+// CHECK-STRICT-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @f, i32 [[TMP2]], i32 
[[TMP3]] seq_cst seq_cst, align 4
+// CHECK-STRICT-NEXT:    [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
+// CHECK-STRICT-NEXT:    [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
+// CHECK-STRICT-NEXT:    [[TMP7]] = bitcast i32 [[TMP5]] to float
+// CHECK-STRICT-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-STRICT:       [[ATOMIC_CONT]]:
+// CHECK-STRICT-NEXT:    ret void
+//
+// CHECK-X86-LABEL: define dso_local void @test_same_type(
+// CHECK-X86-SAME: float noundef [[VALUE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-X86-NEXT:  [[ENTRY:.*:]]
+// CHECK-X86-NEXT:    [[VALUE_ADDR:%.*]] = alloca float, align 4
+// CHECK-X86-NEXT:    store float [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load float, ptr [[VALUE_ADDR]], align 4
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-X86-NEXT:    ret void
+//
+void test_same_type(float value) {
+  f += value;
+}
+
+// CHECK-DEFAULT-LABEL: define dso_local void @test_wider_rhs(
+// CHECK-DEFAULT-SAME: double noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-DEFAULT-NEXT:  [[ENTRY:.*]]:
+// CHECK-DEFAULT-NEXT:    [[VALUE_ADDR:%.*]] = alloca double, align 8
+// CHECK-DEFAULT-NEXT:    store double [[VALUE]], ptr [[VALUE_ADDR]], align 8
+// CHECK-DEFAULT-NEXT:    [[TMP0:%.*]] = load double, ptr [[VALUE_ADDR]], 
align 8
+// CHECK-DEFAULT-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f 
seq_cst, align 4
+// CHECK-DEFAULT-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-DEFAULT:       [[ATOMIC_OP]]:
+// CHECK-DEFAULT-NEXT:    [[TMP1:%.*]] = phi float [ [[ATOMIC_LOAD]], 
%[[ENTRY]] ], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-DEFAULT-NEXT:    [[CONV:%.*]] = fpext float [[TMP1]] to double
+// CHECK-DEFAULT-NEXT:    [[ADD:%.*]] = fadd double [[CONV]], [[TMP0]]
+// CHECK-DEFAULT-NEXT:    [[CONV1:%.*]] = fptrunc double [[ADD]] to float
+// CHECK-DEFAULT-NEXT:    [[TMP2:%.*]] = bitcast float [[TMP1]] to i32
+// CHECK-DEFAULT-NEXT:    [[TMP3:%.*]] = bitcast float [[CONV1]] to i32
+// CHECK-DEFAULT-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @f, i32 [[TMP2]], i32 
[[TMP3]] seq_cst seq_cst, align 4
+// CHECK-DEFAULT-NEXT:    [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
+// CHECK-DEFAULT-NEXT:    [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
+// CHECK-DEFAULT-NEXT:    [[TMP7]] = bitcast i32 [[TMP5]] to float
+// CHECK-DEFAULT-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-DEFAULT:       [[ATOMIC_CONT]]:
+// CHECK-DEFAULT-NEXT:    ret void
+//
+// CHECK-STRICT-LABEL: define dso_local void @test_wider_rhs(
+// CHECK-STRICT-SAME: double noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-STRICT-NEXT:  [[ENTRY:.*]]:
+// CHECK-STRICT-NEXT:    [[VALUE_ADDR:%.*]] = alloca double, align 8
+// CHECK-STRICT-NEXT:    store double [[VALUE]], ptr [[VALUE_ADDR]], align 8
+// CHECK-STRICT-NEXT:    [[TMP0:%.*]] = load double, ptr [[VALUE_ADDR]], align 
8
+// CHECK-STRICT-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f 
seq_cst, align 4
+// CHECK-STRICT-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-STRICT:       [[ATOMIC_OP]]:
+// CHECK-STRICT-NEXT:    [[TMP1:%.*]] = phi float [ [[ATOMIC_LOAD]], 
%[[ENTRY]] ], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-STRICT-NEXT:    [[CONV:%.*]] = call double 
@llvm.experimental.constrained.fpext.f64.f32(float [[TMP1]], metadata 
!"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[ADD:%.*]] = call double 
@llvm.experimental.constrained.fadd.f64(double [[CONV]], double [[TMP0]], 
metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[CONV1:%.*]] = call float 
@llvm.experimental.constrained.fptrunc.f32.f64(double [[ADD]], metadata 
!"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[TMP2:%.*]] = bitcast float [[TMP1]] to i32
+// CHECK-STRICT-NEXT:    [[TMP3:%.*]] = bitcast float [[CONV1]] to i32
+// CHECK-STRICT-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @f, i32 [[TMP2]], i32 
[[TMP3]] seq_cst seq_cst, align 4
+// CHECK-STRICT-NEXT:    [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
+// CHECK-STRICT-NEXT:    [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
+// CHECK-STRICT-NEXT:    [[TMP7]] = bitcast i32 [[TMP5]] to float
+// CHECK-STRICT-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-STRICT:       [[ATOMIC_CONT]]:
+// CHECK-STRICT-NEXT:    ret void
+//
+// CHECK-X86-LABEL: define dso_local void @test_wider_rhs(
+// CHECK-X86-SAME: double noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-X86-NEXT:  [[ENTRY:.*]]:
+// CHECK-X86-NEXT:    [[VALUE_ADDR:%.*]] = alloca double, align 8
+// CHECK-X86-NEXT:    store double [[VALUE]], ptr [[VALUE_ADDR]], align 8
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load double, ptr [[VALUE_ADDR]], align 8
+// CHECK-X86-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f seq_cst, 
align 4
+// CHECK-X86-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-X86:       [[ATOMIC_OP]]:
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = phi float [ [[ATOMIC_LOAD]], %[[ENTRY]] 
], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-X86-NEXT:    [[CONV:%.*]] = fpext float [[TMP1]] to double
+// CHECK-X86-NEXT:    [[ADD:%.*]] = fadd double [[CONV]], [[TMP0]]
+// CHECK-X86-NEXT:    [[CONV1:%.*]] = fptrunc double [[ADD]] to float
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = bitcast float [[TMP1]] to i32
+// CHECK-X86-NEXT:    [[TMP3:%.*]] = bitcast float [[CONV1]] to i32
+// CHECK-X86-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @f, i32 [[TMP2]], i32 
[[TMP3]] seq_cst seq_cst, align 4
+// CHECK-X86-NEXT:    [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
+// CHECK-X86-NEXT:    [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
+// CHECK-X86-NEXT:    [[TMP7]] = bitcast i32 [[TMP5]] to float
+// CHECK-X86-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-X86:       [[ATOMIC_CONT]]:
+// CHECK-X86-NEXT:    ret void
+//
+void test_wider_rhs(double value) {
+  f += value;
+}
+
+// CHECK-DEFAULT-LABEL: define dso_local void @test_integer_rhs(
+// CHECK-DEFAULT-SAME: i32 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-DEFAULT-NEXT:  [[ENTRY:.*:]]
+// CHECK-DEFAULT-NEXT:    [[VALUE_ADDR:%.*]] = alloca i32, align 4
+// CHECK-DEFAULT-NEXT:    store i32 [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-DEFAULT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[VALUE_ADDR]], align 4
+// CHECK-DEFAULT-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP0]] to float
+// CHECK-DEFAULT-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[CONV]] 
seq_cst, align 4
+// CHECK-DEFAULT-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[CONV]]
+// CHECK-DEFAULT-NEXT:    ret void
+//
+// CHECK-STRICT-LABEL: define dso_local void @test_integer_rhs(
+// CHECK-STRICT-SAME: i32 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-STRICT-NEXT:  [[ENTRY:.*]]:
+// CHECK-STRICT-NEXT:    [[VALUE_ADDR:%.*]] = alloca i32, align 4
+// CHECK-STRICT-NEXT:    store i32 [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-STRICT-NEXT:    [[TMP0:%.*]] = load i32, ptr [[VALUE_ADDR]], align 4
+// CHECK-STRICT-NEXT:    [[CONV:%.*]] = call float 
@llvm.experimental.constrained.sitofp.f32.i32(i32 [[TMP0]], metadata 
!"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f 
seq_cst, align 4
+// CHECK-STRICT-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-STRICT:       [[ATOMIC_OP]]:
+// CHECK-STRICT-NEXT:    [[TMP1:%.*]] = phi float [ [[ATOMIC_LOAD]], 
%[[ENTRY]] ], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-STRICT-NEXT:    [[ADD:%.*]] = call float 
@llvm.experimental.constrained.fadd.f32(float [[TMP1]], float [[CONV]], 
metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[TMP2:%.*]] = bitcast float [[TMP1]] to i32
+// CHECK-STRICT-NEXT:    [[TMP3:%.*]] = bitcast float [[ADD]] to i32
+// CHECK-STRICT-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @f, i32 [[TMP2]], i32 
[[TMP3]] seq_cst seq_cst, align 4
+// CHECK-STRICT-NEXT:    [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
+// CHECK-STRICT-NEXT:    [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
+// CHECK-STRICT-NEXT:    [[TMP7]] = bitcast i32 [[TMP5]] to float
+// CHECK-STRICT-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-STRICT:       [[ATOMIC_CONT]]:
+// CHECK-STRICT-NEXT:    ret void
+//
+// CHECK-X86-LABEL: define dso_local void @test_integer_rhs(
+// CHECK-X86-SAME: i32 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-X86-NEXT:  [[ENTRY:.*:]]
+// CHECK-X86-NEXT:    [[VALUE_ADDR:%.*]] = alloca i32, align 4
+// CHECK-X86-NEXT:    store i32 [[VALUE]], ptr [[VALUE_ADDR]], align 4
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load i32, ptr [[VALUE_ADDR]], align 4
+// CHECK-X86-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP0]] to float
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[CONV]] 
seq_cst, align 4
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[CONV]]
+// CHECK-X86-NEXT:    ret void
+//
+void test_integer_rhs(int value) {
+  f += value;
+}
+
+// CHECK-DEFAULT-LABEL: define dso_local void @test_non_power_of_two_type(
+// CHECK-DEFAULT-SAME: fp128 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-DEFAULT-NEXT:  [[ENTRY:.*:]]
+// CHECK-DEFAULT-NEXT:    [[VALUE_ADDR:%.*]] = alloca fp128, align 16
+// CHECK-DEFAULT-NEXT:    store fp128 [[VALUE]], ptr [[VALUE_ADDR]], align 16
+// CHECK-DEFAULT-NEXT:    [[TMP0:%.*]] = load fp128, ptr [[VALUE_ADDR]], align 
16
+// CHECK-DEFAULT-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @ld, fp128 
[[TMP0]] seq_cst, align 16
+// CHECK-DEFAULT-NEXT:    [[TMP2:%.*]] = fadd fp128 [[TMP1]], [[TMP0]]
+// CHECK-DEFAULT-NEXT:    ret void
+//
+// CHECK-STRICT-LABEL: define dso_local void @test_non_power_of_two_type(
+// CHECK-STRICT-SAME: fp128 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-STRICT-NEXT:  [[ENTRY:.*]]:
+// CHECK-STRICT-NEXT:    [[VALUE_ADDR:%.*]] = alloca fp128, align 16
+// CHECK-STRICT-NEXT:    store fp128 [[VALUE]], ptr [[VALUE_ADDR]], align 16
+// CHECK-STRICT-NEXT:    [[TMP0:%.*]] = load fp128, ptr [[VALUE_ADDR]], align 
16
+// CHECK-STRICT-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic fp128, ptr @ld 
seq_cst, align 16
+// CHECK-STRICT-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-STRICT:       [[ATOMIC_OP]]:
+// CHECK-STRICT-NEXT:    [[TMP1:%.*]] = phi fp128 [ [[ATOMIC_LOAD]], 
%[[ENTRY]] ], [ [[TMP7:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-STRICT-NEXT:    [[ADD:%.*]] = call fp128 
@llvm.experimental.constrained.fadd.f128(fp128 [[TMP1]], fp128 [[TMP0]], 
metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR2]]
+// CHECK-STRICT-NEXT:    [[TMP2:%.*]] = bitcast fp128 [[TMP1]] to i128
+// CHECK-STRICT-NEXT:    [[TMP3:%.*]] = bitcast fp128 [[ADD]] to i128
+// CHECK-STRICT-NEXT:    [[TMP4:%.*]] = cmpxchg ptr @ld, i128 [[TMP2]], i128 
[[TMP3]] seq_cst seq_cst, align 16
+// CHECK-STRICT-NEXT:    [[TMP5:%.*]] = extractvalue { i128, i1 } [[TMP4]], 0
+// CHECK-STRICT-NEXT:    [[TMP6:%.*]] = extractvalue { i128, i1 } [[TMP4]], 1
+// CHECK-STRICT-NEXT:    [[TMP7]] = bitcast i128 [[TMP5]] to fp128
+// CHECK-STRICT-NEXT:    br i1 [[TMP6]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-STRICT:       [[ATOMIC_CONT]]:
+// CHECK-STRICT-NEXT:    ret void
+//
+// CHECK-X86-LABEL: define dso_local void @test_non_power_of_two_type(
+// CHECK-X86-SAME: x86_fp80 noundef [[VALUE:%.*]]) #[[ATTR0]] {
+// CHECK-X86-NEXT:  [[ENTRY:.*]]:
+// CHECK-X86-NEXT:    [[VALUE_ADDR:%.*]] = alloca x86_fp80, align 16
+// CHECK-X86-NEXT:    [[ATOMIC_TEMP:%.*]] = alloca x86_fp80, align 16
+// CHECK-X86-NEXT:    [[ATOMIC_TEMP1:%.*]] = alloca x86_fp80, align 16
+// CHECK-X86-NEXT:    [[ATOMIC_TEMP2:%.*]] = alloca x86_fp80, align 16
+// CHECK-X86-NEXT:    store x86_fp80 [[VALUE]], ptr [[VALUE_ADDR]], align 16
+// CHECK-X86-NEXT:    [[TMP0:%.*]] = load x86_fp80, ptr [[VALUE_ADDR]], align 
16
+// CHECK-X86-NEXT:    call void @__atomic_load(i64 noundef 16, ptr noundef 
@ld, ptr noundef [[ATOMIC_TEMP]], i32 noundef 5)
+// CHECK-X86-NEXT:    [[TMP1:%.*]] = load x86_fp80, ptr [[ATOMIC_TEMP]], align 
16
+// CHECK-X86-NEXT:    br label %[[ATOMIC_OP:.*]]
+// CHECK-X86:       [[ATOMIC_OP]]:
+// CHECK-X86-NEXT:    [[TMP2:%.*]] = phi x86_fp80 [ [[TMP1]], %[[ENTRY]] ], [ 
[[TMP3:%.*]], %[[ATOMIC_OP]] ]
+// CHECK-X86-NEXT:    [[ADD:%.*]] = fadd x86_fp80 [[TMP2]], [[TMP0]]
+// CHECK-X86-NEXT:    call void @llvm.memset.p0.i64(ptr align 16 
[[ATOMIC_TEMP1]], i8 0, i64 16, i1 false)
+// CHECK-X86-NEXT:    store x86_fp80 [[TMP2]], ptr [[ATOMIC_TEMP1]], align 16
+// CHECK-X86-NEXT:    call void @llvm.memset.p0.i64(ptr align 16 
[[ATOMIC_TEMP2]], i8 0, i64 16, i1 false)
+// CHECK-X86-NEXT:    store x86_fp80 [[ADD]], ptr [[ATOMIC_TEMP2]], align 16
+// CHECK-X86-NEXT:    [[CALL:%.*]] = call zeroext i1 
@__atomic_compare_exchange(i64 noundef 16, ptr noundef @ld, ptr noundef 
[[ATOMIC_TEMP1]], ptr noundef [[ATOMIC_TEMP2]], i32 noundef 5, i32 noundef 5)
+// CHECK-X86-NEXT:    [[TMP3]] = load x86_fp80, ptr [[ATOMIC_TEMP1]], align 16
+// CHECK-X86-NEXT:    br i1 [[CALL]], label %[[ATOMIC_CONT:.*]], label 
%[[ATOMIC_OP]]
+// CHECK-X86:       [[ATOMIC_CONT]]:
+// CHECK-X86-NEXT:    ret void
+//
+void test_non_power_of_two_type(long double value) {
+  ld += value;
+}
\ No newline at end of file
diff --git a/clang/test/CodeGen/compound-assign-atomic-fp.c 
b/clang/test/CodeGen/compound-assign-atomic-fp.c
new file mode 100644
index 0000000000000..df7422f856d57
--- /dev/null
+++ b/clang/test/CodeGen/compound-assign-atomic-fp.c
@@ -0,0 +1,269 @@
+// 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-C
+// RUN: %clang_cc1 -x c++ -std=c++11 %s -emit-llvm -o - 
-triple=aarch64-linux-gnu | FileCheck %s --check-prefix=CHECK-CPP
+
+_Atomic(float) f;
+_Atomic(double) d;
+_Atomic(__bf16) bf;
+_Atomic(_Float16) h;
+
+// CHECK-C-LABEL: define dso_local void @test_float_add(
+// CHECK-C-SAME: float noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z14test_float_addf(
+// CHECK-CPP-SAME: float noundef [[VAL:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd float [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_add(float val) {
+  f += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_compound_add(
+// CHECK-C-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr [[VAL_ADDR]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = atomicrmw fadd ptr @f, float 
[[ATOMIC_LOAD]] seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = fadd float [[TMP0]], [[ATOMIC_LOAD]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void 
@_Z23test_float_compound_addU7_Atomicf(
+// CHECK-CPP-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr 
[[VAL_ADDR]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = atomicrmw fadd ptr @f, float 
[[ATOMIC_LOAD]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = fadd float [[TMP0]], [[ATOMIC_LOAD]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_compound_add(_Atomic(float) val){
+  f += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_read_add(
+// CHECK-C-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f seq_cst, 
align 4
+// CHECK-C-NEXT:    [[ATOMIC_LOAD1:%.*]] = load atomic float, ptr [[VAL_ADDR]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[ADD:%.*]] = fadd float [[ATOMIC_LOAD]], [[ATOMIC_LOAD1]]
+// CHECK-C-NEXT:    store atomic float [[ADD]], ptr @f seq_cst, align 4
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z19test_float_read_addU7_Atomicf(
+// CHECK-CPP-SAME: float [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD:%.*]] = load atomic float, ptr @f seq_cst, 
align 4
+// CHECK-CPP-NEXT:    [[ATOMIC_LOAD1:%.*]] = load atomic float, ptr 
[[VAL_ADDR]] seq_cst, align 4
+// CHECK-CPP-NEXT:    [[ADD:%.*]] = fadd float [[ATOMIC_LOAD]], 
[[ATOMIC_LOAD1]]
+// CHECK-CPP-NEXT:    store atomic float [[ADD]], ptr @f seq_cst, align 4
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_read_add(_Atomic(float) val){
+  f = f + val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_double_add(
+// CHECK-C-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-C-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd double [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z15test_double_addd(
+// CHECK-CPP-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-CPP-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd double [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_double_add(double val) {
+  d += val;
+}
+
+// CHECK-LLVM-LABEL: define dso_local void @test_bf16_add(
+// CHECK-LLVM-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-LLVM-NEXT:  [[ENTRY:.*:]]
+// CHECK-LLVM-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-LLVM-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-LLVM-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-LLVM-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-LLVM-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-LLVM-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-LLVM-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-LLVM-NEXT:    ret void
+// CHECK-C-LABEL: define dso_local void @test_bf16_add(
+// CHECK-C-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-C-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-C-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z13test_bf16_addu6__bf16(
+// CHECK-CPP-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-CPP-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-CPP-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd bfloat [[TMP1]], [[CONV]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_bf16_add(__bf16 val){
+  bf += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_f16_add(
+// CHECK-C-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-C-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fadd half [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z12test_f16_addDF16_(
+// CHECK-CPP-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-CPP-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fadd ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fadd half [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_f16_add(_Float16 val){
+  h += val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_float_sub(
+// CHECK-C-SAME: float noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-C-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub float [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z14test_float_subf(
+// CHECK-CPP-SAME: float noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca float, align 4
+// CHECK-CPP-NEXT:    store float [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @f, float [[TMP0]] 
seq_cst, align 4
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub float [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_float_sub(float val) {
+  f -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_double_sub(
+// CHECK-C-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-C-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub double [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z15test_double_subd(
+// CHECK-CPP-SAME: double noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca double, align 8
+// CHECK-CPP-NEXT:    store double [[VAL]], ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load double, ptr [[VAL_ADDR]], align 8
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @d, double [[TMP0]] 
seq_cst, align 8
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub double [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_double_sub(double val){
+  d -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_bf16_sub(
+// CHECK-C-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-C-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-C-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub bfloat [[TMP1]], [[CONV]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z13test_bf16_subu6__bf16(
+// CHECK-CPP-SAME: bfloat noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca bfloat, align 2
+// CHECK-CPP-NEXT:    store bfloat [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load bfloat, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[EXT:%.*]] = fpext bfloat [[TMP0]] to float
+// CHECK-CPP-NEXT:    [[CONV:%.*]] = fptrunc float [[EXT]] to bfloat
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @bf, bfloat [[CONV]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub bfloat [[TMP1]], [[CONV]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_bf16_sub(__bf16 val){
+  bf -= val;
+}
+
+// CHECK-C-LABEL: define dso_local void @test_f16_sub(
+// CHECK-C-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-C-NEXT:  [[ENTRY:.*:]]
+// CHECK-C-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-C-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-C-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-C-NEXT:    [[TMP2:%.*]] = fsub half [[TMP1]], [[TMP0]]
+// CHECK-C-NEXT:    ret void
+//
+// CHECK-CPP-LABEL: define dso_local void @_Z12test_f16_subDF16_(
+// CHECK-CPP-SAME: half noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-CPP-NEXT:  [[ENTRY:.*:]]
+// CHECK-CPP-NEXT:    [[VAL_ADDR:%.*]] = alloca half, align 2
+// CHECK-CPP-NEXT:    store half [[VAL]], ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP0:%.*]] = load half, ptr [[VAL_ADDR]], align 2
+// CHECK-CPP-NEXT:    [[TMP1:%.*]] = atomicrmw fsub ptr @h, half [[TMP0]] 
seq_cst, align 2
+// CHECK-CPP-NEXT:    [[TMP2:%.*]] = fsub half [[TMP1]], [[TMP0]]
+// CHECK-CPP-NEXT:    ret void
+//
+void test_f16_sub(_Float16 val){
+  h -= val;
+}

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

Reply via email to