[clang] [Clang][CodeGen] Respect FP pragma options for fneg and calls (PR #212141)
Shivam Gupta via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 4 02:56:04 PDT 2026
https://github.com/xgupta updated https://github.com/llvm/llvm-project/pull/212141
>From 2b98375c6ffd40f9952d183917dc25fb1e51ff3b Mon Sep 17 00:00:00 2001
From: Shivam Gupta <shivam98.tkg at gmail.com>
Date: Sun, 26 Jul 2026 20:47:26 +0530
Subject: [PATCH 1/2] [clang][CodeGen] Respect FP pragma options for fneg and
calls
Apply expression-specific floating-point options
when emitting fneg and call instructions.
This prevents these instructions from retaining fast-math
flags disabled by local FP pragmas, such as #pragma
clang fp reassociate(off).
Builtin calls are excluded because their lowering handles
floating-point options separately.
Fixes #51905
---
clang/lib/CodeGen/CGExprScalar.cpp | 10 +++++++++-
clang/test/CodeGen/fp-reassoc-pragma.cpp | 16 ++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 8783b43846434..1d26fde39885f 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -682,6 +682,12 @@ class ScalarExprEmitter
if (E->getCallReturnType(CGF.getContext())->isReferenceType())
return EmitLoadOfLValue(E);
+ std::optional<CodeGenFunction::CGFPOptionsRAII> FPOptsRAII;
+ const FunctionDecl *FD = E->getDirectCallee();
+ bool IsBuiltin = FD && FD->getBuiltinID() != 0;
+ if (!IsBuiltin && E->getType()->hasFloatingRepresentation())
+ FPOptsRAII.emplace(CGF, E);
+
Value *V = CGF.EmitCallExpr(E).getScalarVal();
EmitLValueAlignmentAssumption(E, V);
@@ -3707,8 +3713,10 @@ Value *ScalarExprEmitter::VisitMinus(const UnaryOperator *E,
Op = Visit(E->getSubExpr());
// Generate a unary FNeg for FP ops.
- if (Op->getType()->isFPOrFPVectorTy())
+ if (Op->getType()->isFPOrFPVectorTy()) {
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
return Builder.CreateFNeg(Op, "fneg");
+ }
// Emit unary minus with EmitSub so we handle overflow cases etc.
BinOpInfo BinOp;
diff --git a/clang/test/CodeGen/fp-reassoc-pragma.cpp b/clang/test/CodeGen/fp-reassoc-pragma.cpp
index 8b9329c40174b..45d5ecde34484 100644
--- a/clang/test/CodeGen/fp-reassoc-pragma.cpp
+++ b/clang/test/CodeGen/fp-reassoc-pragma.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -funsafe-math-optimizations -emit-llvm -o - %s | FileCheck %s --check-prefix=UNSAFE
+
// Simple case
float fp_reassoc_simple(float a, float b, float c) {
// CHECK: _Z17fp_reassoc_simplefff
@@ -90,3 +92,17 @@ float fp_reassoc_call_helper(float a, float b, float c) {
#pragma clang fp reassociate(on)
return helper_func(a, b, c);
}
+
+
+double fp_reassoc_call_helper(bool flag, double x, double y) {
+ return flag ? x : y;
+}
+
+#pragma clang fp reassociate(off)
+double fp_reassoc_off_fneg_call(double x) {
+ // UNSAFE-LABEL: _Z24fp_reassoc_off_fneg_calld
+ // UNSAFE: fcmp nsz arcp afn
+ // UNSAFE: fneg nsz arcp afn
+ // UNSAFE: call nsz arcp afn
+ return fp_reassoc_call_helper(x < 0, -x, x);
+}
>From 790398200adec03fdabcfcaf0fa3a83c5d0d7a7d Mon Sep 17 00:00:00 2001
From: Shivam Gupta <shivam98.tkg at gmail.com>
Date: Tue, 4 Aug 2026 15:08:54 +0530
Subject: [PATCH 2/2] Addressed test case's review comments
---
clang/test/CodeGen/fp-reassoc-pragma.cpp | 41 ++++++++++++------------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/clang/test/CodeGen/fp-reassoc-pragma.cpp b/clang/test/CodeGen/fp-reassoc-pragma.cpp
index 45d5ecde34484..ce32a93c6620c 100644
--- a/clang/test/CodeGen/fp-reassoc-pragma.cpp
+++ b/clang/test/CodeGen/fp-reassoc-pragma.cpp
@@ -1,15 +1,18 @@
// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -funsafe-math-optimizations -emit-llvm -o - %s | FileCheck %s --check-prefix=UNSAFE
+float func(float);
+
// Simple case
float fp_reassoc_simple(float a, float b, float c) {
// CHECK: _Z17fp_reassoc_simplefff
// CHECK: %[[A:.+]] = fadd reassoc float %b, %c
-// CHECK: %[[M:.+]] = fmul reassoc float %b, %[[A]]
-// CHECK-NEXT: fadd reassoc float %c, %[[M]]
+// CHECK: %[[C:.+]] = tail call reassoc {{.*}} @_Z4funcf(float {{.*}} %[[A]])
+// CHECK: %[[N:.+]] = fneg reassoc float %[[C]]
+// CHECK: call reassoc {{.*}} @_Z4funcf(float {{.*}} %[[N]])
#pragma clang fp reassociate(on)
- a = b + c;
- return a * b + c;
+ a = func(b + c);
+ return func(-a);
}
// Reassoc pragma should only apply to its scope
@@ -67,10 +70,19 @@ float fp_file_scope_stop(float a, float b, float c) {
#pragma clang fp reassociate(off)
float fp_reassoc_off(float a, float b, float c) {
// CHECK: _Z14fp_reassoc_offfff
- // CHECK: %[[D1:.+]] = fdiv float %a, %c
- // CHECK-NEXT: %[[D2:.+]] = fdiv float %b, %c
- // CHECK-NEXT: fadd float %[[D1]], %[[D2]]
- return (a / c) + (b / c);
+ // CHECK: %[[N:.+]] = fneg float %a
+ // CHECK: %[[C:.+]] = tail call noundef float @_Z4funcf(float noundef %[[N]])
+ // CHECK: %[[D1:.+]] = fdiv float %[[C]], %c
+ // CHECK: %[[D2:.+]] = fdiv float %b, %c
+ // CHECK: fadd float %[[D2]], %[[D1]]
+ //
+ // UNSAFE: _Z14fp_reassoc_offfff
+ // UNSAFE: %[[N:.+]] = fneg nsz arcp afn float
+ // UNSAFE: %[[C:.+]] = call nsz arcp afn noundef float @_Z4funcf(float noundef %[[N]])
+ // UNSAFE: %[[D1:.+]] = fdiv nsz arcp afn float %[[C]]
+ // UNSAFE: %[[D2:.+]] = fdiv nsz arcp afn float
+ // UNSAFE: fadd nsz arcp afn float %[[D1]], %[[D2]]
+ return (func(-a) / c) + (b / c);
}
// Takes latest flag
@@ -93,16 +105,3 @@ float fp_reassoc_call_helper(float a, float b, float c) {
return helper_func(a, b, c);
}
-
-double fp_reassoc_call_helper(bool flag, double x, double y) {
- return flag ? x : y;
-}
-
-#pragma clang fp reassociate(off)
-double fp_reassoc_off_fneg_call(double x) {
- // UNSAFE-LABEL: _Z24fp_reassoc_off_fneg_calld
- // UNSAFE: fcmp nsz arcp afn
- // UNSAFE: fneg nsz arcp afn
- // UNSAFE: call nsz arcp afn
- return fp_reassoc_call_helper(x < 0, -x, x);
-}
More information about the cfe-commits
mailing list