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

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.

>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] [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;
+}

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

Reply via email to