[flang-commits] [flang] 7172836 - [flang] Fold real-valued MODULO() and MOD()

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue May 10 08:15:40 PDT 2022


Author: Peter Klausler
Date: 2022-05-10T08:15:29-07:00
New Revision: 71728360ada3e0f6c21d4c09d33424f6150afcc9

URL: https://github.com/llvm/llvm-project/commit/71728360ada3e0f6c21d4c09d33424f6150afcc9
DIFF: https://github.com/llvm/llvm-project/commit/71728360ada3e0f6c21d4c09d33424f6150afcc9.diff

LOG: [flang] Fold real-valued MODULO() and MOD()

Evaluate real-valued references to the intrinsic functions MODULO
and MOD at compilation time without recourse to an external math
library.

Differential Revision: https://reviews.llvm.org/D125151

Added: 
    flang/test/Evaluate/fold-mod.f90

Modified: 
    flang/include/flang/Evaluate/real.h
    flang/lib/Evaluate/fold-real.cpp
    flang/lib/Evaluate/intrinsics-library.cpp
    flang/lib/Evaluate/real.cpp
    flang/test/Evaluate/folding04.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/real.h b/flang/include/flang/Evaluate/real.h
index ab4268a9a904..4e992693535c 100644
--- a/flang/include/flang/Evaluate/real.h
+++ b/flang/include/flang/Evaluate/real.h
@@ -119,14 +119,21 @@ class Real : public common::RealDetails<PREC> {
       const Real &, Rounding rounding = defaultRounding) const;
 
   ValueWithRealFlags<Real> SQRT(Rounding rounding = defaultRounding) const;
-
   // NEAREST(), IEEE_NEXT_AFTER(), IEEE_NEXT_UP(), and IEEE_NEXT_DOWN()
   ValueWithRealFlags<Real> NEAREST(bool upward) const;
-
   // HYPOT(x,y)=SQRT(x**2 + y**2) computed so as to avoid spurious
   // intermediate overflows.
   ValueWithRealFlags<Real> HYPOT(
       const Real &, Rounding rounding = defaultRounding) const;
+  // DIM(X,Y) = MAX(X-Y, 0)
+  ValueWithRealFlags<Real> DIM(
+      const Real &, Rounding rounding = defaultRounding) const;
+  // MOD(x,y) = x - AINT(x/y)*y
+  // MODULO(x,y) = x - FLOOR(x/y)*y
+  ValueWithRealFlags<Real> MOD(
+      const Real &, Rounding rounding = defaultRounding) const;
+  ValueWithRealFlags<Real> MODULO(
+      const Real &, Rounding rounding = defaultRounding) const;
 
   // DIM(X,Y) = MAX(X-Y, 0)
   ValueWithRealFlags<Real> DIM(

diff  --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp
index f2375a5bcd7d..667a5a0e1477 100644
--- a/flang/lib/Evaluate/fold-real.cpp
+++ b/flang/lib/Evaluate/fold-real.cpp
@@ -72,7 +72,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
   } else if (name == "amax0" || name == "amin0" || name == "amin1" ||
       name == "amax1" || name == "dmin1" || name == "dmax1") {
     return RewriteSpecificMINorMAX(context, std::move(funcRef));
-  } else if (name == "atan" || name == "atan2" || name == "mod") {
+  } else if (name == "atan" || name == "atan2") {
     std::string localName{name == "atan" ? "atan2" : name};
     CHECK(args.size() == 2);
     if (auto callable{GetHostRuntimeWrapper<T, T, T>(localName)}) {
@@ -159,6 +159,35 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
         RelationalOperator::GT, T::Scalar::HUGE().Negate());
   } else if (name == "merge") {
     return FoldMerge<T>(context, std::move(funcRef));
+  } else if (name == "min") {
+    return FoldMINorMAX(context, std::move(funcRef), Ordering::Less);
+  } else if (name == "minval") {
+    return FoldMaxvalMinval<T>(
+        context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
+  } else if (name == "mod") {
+    CHECK(args.size() == 2);
+    return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
+        ScalarFunc<T, T, T>(
+            [&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
+              auto result{x.MOD(y)};
+              if (result.flags.test(RealFlag::DivideByZero)) {
+                context.messages().Say(
+                    "second argument to MOD must not be zero"_warn_en_US);
+              }
+              return result.value;
+            }));
+  } else if (name == "modulo") {
+    CHECK(args.size() == 2);
+    return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
+        ScalarFunc<T, T, T>(
+            [&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
+              auto result{x.MODULO(y)};
+              if (result.flags.test(RealFlag::DivideByZero)) {
+                context.messages().Say(
+                    "second argument to MODULO must not be zero"_warn_en_US);
+              }
+              return result.value;
+            }));
   } else if (name == "nearest") {
     if (const auto *sExpr{UnwrapExpr<Expr<SomeReal>>(args[1])}) {
       return common::visit(
@@ -184,11 +213,6 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
           },
           sExpr->u);
     }
-  } else if (name == "min") {
-    return FoldMINorMAX(context, std::move(funcRef), Ordering::Less);
-  } else if (name == "minval") {
-    return FoldMaxvalMinval<T>(
-        context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
   } else if (name == "product") {
     auto one{Scalar<T>::FromInteger(value::Integer<8>{1}).value};
     return FoldProduct<T>(context, std::move(funcRef), one);

diff  --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 2f56dcc9eedf..160a5894f38e 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -230,7 +230,6 @@ struct HostRuntimeLibrary<HostT, LibraryVersion::Libm> {
       FolderFactory<F, F{std::log}>::Create("log"),
       FolderFactory<F, F{std::log10}>::Create("log10"),
       FolderFactory<F, F{std::lgamma}>::Create("log_gamma"),
-      FolderFactory<F2, F2{std::fmod}>::Create("mod"),
       FolderFactory<F2, F2{std::pow}>::Create("pow"),
       FolderFactory<F, F{std::sin}>::Create("sin"),
       FolderFactory<F, F{std::sinh}>::Create("sinh"),

diff  --git a/flang/lib/Evaluate/real.cpp b/flang/lib/Evaluate/real.cpp
index 00d21c088dbd..3b81d23afe41 100644
--- a/flang/lib/Evaluate/real.cpp
+++ b/flang/lib/Evaluate/real.cpp
@@ -422,6 +422,32 @@ ValueWithRealFlags<Real<W, P>> Real<W, P>::HYPOT(
   return result;
 }
 
+// MOD(x,y) = x - AINT(x/y)*y
+template <typename W, int P>
+ValueWithRealFlags<Real<W, P>> Real<W, P>::MOD(
+    const Real &y, Rounding rounding) const {
+  ValueWithRealFlags<Real> result;
+  Real quotient{Divide(y, rounding).AccumulateFlags(result.flags)};
+  Real toInt{quotient.ToWholeNumber(common::RoundingMode::ToZero)
+                 .AccumulateFlags(result.flags)};
+  Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)};
+  result.value = Subtract(product, rounding).AccumulateFlags(result.flags);
+  return result;
+}
+
+// MODULO(x,y) = x - FLOOR(x/y)*y
+template <typename W, int P>
+ValueWithRealFlags<Real<W, P>> Real<W, P>::MODULO(
+    const Real &y, Rounding rounding) const {
+  ValueWithRealFlags<Real> result;
+  Real quotient{Divide(y, rounding).AccumulateFlags(result.flags)};
+  Real toInt{quotient.ToWholeNumber(common::RoundingMode::Down)
+                 .AccumulateFlags(result.flags)};
+  Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)};
+  result.value = Subtract(product, rounding).AccumulateFlags(result.flags);
+  return result;
+}
+
 template <typename W, int P>
 ValueWithRealFlags<Real<W, P>> Real<W, P>::DIM(
     const Real &y, Rounding rounding) const {

diff  --git a/flang/test/Evaluate/fold-mod.f90 b/flang/test/Evaluate/fold-mod.f90
new file mode 100644
index 000000000000..6b5188a39b21
--- /dev/null
+++ b/flang/test/Evaluate/fold-mod.f90
@@ -0,0 +1,24 @@
+! RUN: %python %S/test_folding.py %s %flang_fc1
+! Tests folding of integer and real MOD and MODULO
+module m1
+  logical, parameter :: test_mod_i1 = mod(8, 5) == 3
+  logical, parameter :: test_mod_i2 = mod(-8, 5) == -3
+  logical, parameter :: test_mod_i3 = mod(8, -5) == 3
+  logical, parameter :: test_mod_i4 = mod(-8, -5) == -3
+
+  logical, parameter :: test_mod_r1 = mod(3., 2.) == 1.
+  logical, parameter :: test_mod_r2 = mod(8., 5.) == 3.
+  logical, parameter :: test_mod_r3 = mod(-8., 5.) == -3.
+  logical, parameter :: test_mod_r4 = mod(8., -5.) == 3.
+  logical, parameter :: test_mod_r5 = mod(-8., -5.) == -3.
+
+  logical, parameter :: test_modulo_i1 = modulo(8, 5) == 3
+  logical, parameter :: test_modulo_i2 = modulo(-8, 5) == 2
+  logical, parameter :: test_modulo_i3 = modulo(8, -5) == -2
+  logical, parameter :: test_modulo_i4 = modulo(-8, -5) == -3
+
+  logical, parameter :: test_modulo_r1 = modulo(8., 5.) == 3.
+  logical, parameter :: test_modulo_r2 = modulo(-8., 5.) == 2.
+  logical, parameter :: test_modulo_r3 = modulo(8., -5.) == -2.
+  logical, parameter :: test_modulo_r4 = modulo(-8., -5.) == -3.
+end module

diff  --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 4e69eeb44f1b..4c669a4ec598 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -32,6 +32,9 @@ module real_tests
   !WARN: warning: invalid argument on intrinsic function
   real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
   TEST_ISNAN(nan_r4_acos5)
+  !WARN: warning: second argument to MOD must not be zero
+  real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
+  TEST_ISNAN(nan_r4_mod)
 
   !WARN: warning: overflow on intrinsic function
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf


        


More information about the flang-commits mailing list