[flang-commits] [flang] [Flang] Fold complex ** (1, 0) to identity in constant folding (PR #213256)
via flang-commits
flang-commits at lists.llvm.org
Fri Jul 31 05:12:13 PDT 2026
https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/213256
>From 3815d8e3e8bb4384c2703f4464be1034818351b7 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Fri, 31 Jul 2026 11:56:10 +0000
Subject: [PATCH] [Flang] Fold complex ** (1,0) to identity in constant folding
Treat a constant exponent exactly equal to (1,0) as the identity in FoldOperation for complex Power, returning the base instead of calling libm cpow*. This avoids rounding error for cases like z**(1,0) where the result should be exactly z. Added folding tests for kind=8, kind=16, and a named complex parameter base.
---
flang/lib/Evaluate/fold-implementation.h | 19 +++++++++++++++++++
flang/test/Evaluate/folding-cpow-unity.f90 | 17 +++++++++++++++++
flang/test/Evaluate/folding-cpow-unity16.f90 | 14 ++++++++++++++
3 files changed, 50 insertions(+)
create mode 100644 flang/test/Evaluate/folding-cpow-unity.f90
create mode 100644 flang/test/Evaluate/folding-cpow-unity16.f90
diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index 918d20da8b880..1fa36f20e897e 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -2222,6 +2222,13 @@ Expr<T> FoldOperation(FoldingContext &context, Divide<T> &&x) {
return Expr<T>{std::move(x)};
}
+template <typename T> bool IsComplexUnity(const typename T::Scalar &z) {
+ static_assert(T::category == TypeCategory::Complex);
+ using Part = typename T::Part::Scalar;
+ auto one{Part::FromInteger(value::Integer<8>{1}).value};
+ return z.AIMAG().IsZero() && z.REAL().Compare(one) == Relation::Equal;
+}
+
template <typename T>
Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
if (auto array{ApplyElementwise(context, x)}) {
@@ -2242,6 +2249,11 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
}
return Expr<T>{Constant<T>{power.power}};
} else {
+ if constexpr (T::category == TypeCategory::Complex) {
+ if (IsComplexUnity<T>(folded->second)) {
+ return Expr<T>{Constant<T>{folded->first}};
+ }
+ }
if (folded->first.IsZero()) {
if (folded->second.IsZero()) {
context.Warn(common::UsageWarning::FoldingException,
@@ -2259,6 +2271,13 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
}
}
}
+ if constexpr (T::category == TypeCategory::Complex) {
+ if (auto exp{GetScalarConstantValue<T>(x.right())}) {
+ if (IsComplexUnity<T>(*exp)) {
+ return Fold(context, std::move(x.left()));
+ }
+ }
+ }
return Expr<T>{std::move(x)};
}
diff --git a/flang/test/Evaluate/folding-cpow-unity.f90 b/flang/test/Evaluate/folding-cpow-unity.f90
new file mode 100644
index 0000000000000..950191a74ea5c
--- /dev/null
+++ b/flang/test/Evaluate/folding-cpow-unity.f90
@@ -0,0 +1,17 @@
+! RUN: %python %S/test_folding.py %s %flang_fc1
+
+! z**(1,0) must fold to z exactly.
+
+real(8), parameter :: &
+ r_cplx = real((3.0_8, 0.0_8) ** (1.0_8, 0.0_8), kind=8)
+logical, parameter :: test_cpow_unity_cplx = r_cplx == 3.0_8
+
+real(8), parameter :: &
+ r_real = real(3.0_8 ** (1.0_8, 0.0_8), kind=8)
+logical, parameter :: test_cpow_unity_real = r_real == 3.0_8
+
+complex(8), parameter :: z = (3.0_8, 0.0_8)
+real(8), parameter :: r_var = real(z ** (1.0_8, 0.0_8), kind=8)
+logical, parameter :: test_cpow_unity_var = r_var == 3.0_8
+
+end
diff --git a/flang/test/Evaluate/folding-cpow-unity16.f90 b/flang/test/Evaluate/folding-cpow-unity16.f90
new file mode 100644
index 0000000000000..4c5dc44eb9f82
--- /dev/null
+++ b/flang/test/Evaluate/folding-cpow-unity16.f90
@@ -0,0 +1,14 @@
+! REQUIRES: flang-supports-f128-math
+! RUN: %python %S/test_folding.py %s %flang_fc1
+
+! z**(1,0) must fold to z exactly at quad precision.
+
+real(16), parameter :: &
+ r_cplx16 = real((3.0_16, 0.0_16) ** (1.0_16, 0.0_16), kind=16)
+logical, parameter :: test_cpow_unity_cplx16 = r_cplx16 == 3.0_16
+
+complex(16), parameter :: z16 = (3.0_16, 0.0_16)
+real(16), parameter :: r_var16 = real(z16 ** (1.0_16, 0.0_16), kind=16)
+logical, parameter :: test_cpow_unity_var16 = r_var16 == 3.0_16
+
+end
More information about the flang-commits
mailing list