[flang-commits] [flang] [flang] Improve warnings for invalid arguments when folding host runtime (PR #96807)

Pete Steinfeld via flang-commits flang-commits at lists.llvm.org
Tue Jul 2 07:45:35 PDT 2024


https://github.com/psteinfeld updated https://github.com/llvm/llvm-project/pull/96807

>From 01d13405a698fb506110b888714994b1655f821f Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Wed, 26 Jun 2024 11:07:56 -0700
Subject: [PATCH 01/13] [flang] Improve warnings for invalid arguments when
 folding host runtime

This is another attempt at a change that Jean made to Phabricator in
https://reviews.llvm.org/D116934.  That attempt ran into problems with
building on Windows.

This change improves the messages that are produced when running into
invalid arguments during constant folding.
---
 flang/lib/Evaluate/intrinsics-library.cpp | 240 +++++++++++++++++++++-
 flang/test/Evaluate/folding04.f90         |  31 ++-
 2 files changed, 263 insertions(+), 8 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 7315a7a057b10..e6588ba4ec9c1 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -633,10 +633,243 @@ static DynamicType BiggerType(DynamicType type) {
   return type;
 }
 
+/// Structure to register intrinsic argument checks that must be performed.
+using ArgumentVerifierFunc = bool (*)(
+    const std::vector<Expr<SomeType>> &, FoldingContext &);
+struct ArgumentVerifier {
+  using Key = std::string_view;
+  // Needed for implicit compare with keys.
+  constexpr operator Key() const { return key; }
+  Key key; // intrinsic name
+  ArgumentVerifierFunc verifier;
+};
+
+static constexpr int lastArg{-1};
+static constexpr int firstArg{0};
+
+static const Expr<SomeType> &getArg(
+    int position, const std::vector<Expr<SomeType>> &args) {
+  if (position == lastArg) {
+    CHECK(!args.empty());
+    return args.back();
+  }
+  CHECK(position >= 0 && static_cast<std::size_t>(position) < args.size());
+  return args[position];
+}
+
+template <typename T>
+static bool IsInRange(const Expr<T> &expr, int lb, int ub) {
+  if (auto scalar{GetScalarConstantValue<T>(expr)}) {
+    auto lbValue{Scalar<T>::FromInteger(value::Integer<8>{lb}).value};
+    auto ubValue{Scalar<T>::FromInteger(value::Integer<8>{ub}).value};
+    return Satisfies(RelationalOperator::LE, lbValue.Compare(*scalar)) &&
+        Satisfies(RelationalOperator::LE, scalar->Compare(ubValue));
+  }
+  return true;
+}
+
+/// Verify that the argument in an intrinsic call belongs to [lb, ub] if is
+/// real.
+template <int lb, int ub>
+static bool VerifyInRangeIfReal(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someReal =
+          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
+    const bool isInRange{
+        std::visit([&](const auto &x) -> bool { return IsInRange(x, lb, ub); },
+            someReal->u)};
+    if (!isInRange) {
+      context.messages().Say(
+          "argument is out of range [%d., %d.]"_warn_en_US, lb, ub);
+    }
+    return isInRange;
+  }
+  return true;
+}
+
+template <int argPosition, const char *argName>
+static bool VerifyStrictlyPositiveIfReal(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someReal =
+          std::get_if<Expr<SomeReal>>(&getArg(argPosition, args).u)) {
+    const bool isStrictlyPositive{std::visit(
+        [&](const auto &x) -> bool {
+          using T = typename std::decay_t<decltype(x)>::Result;
+          auto scalar{GetScalarConstantValue<T>(x)};
+          return Satisfies(
+              RelationalOperator::LT, Scalar<T>{}.Compare(*scalar));
+        },
+        someReal->u)};
+    if (!isStrictlyPositive) {
+      context.messages().Say(
+          "argument '%s' must be strictly positive"_warn_en_US, argName);
+    }
+    return isStrictlyPositive;
+  }
+  return true;
+}
+
+/// Verify that an intrinsic call argument is not zero if it is real.
+template <int argPosition, const char *argName>
+static bool VerifyNotZeroIfReal(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someReal =
+          std::get_if<Expr<SomeReal>>(&getArg(argPosition, args).u)) {
+    const bool isNotZero{std::visit(
+        [&](const auto &x) -> bool {
+          using T = typename std::decay_t<decltype(x)>::Result;
+          auto scalar{GetScalarConstantValue<T>(x)};
+          return !scalar || !scalar->IsZero();
+        },
+        someReal->u)};
+    if (!isNotZero) {
+      context.messages().Say(
+          "argument '%s' must be different from zero"_warn_en_US, argName);
+    }
+    return isNotZero;
+  }
+  return true;
+}
+
+/// Verify that the argument in an intrinsic call is not zero if is complex.
+static bool VerifyNotZeroIfComplex(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someComplex =
+          std::get_if<Expr<SomeComplex>>(&getArg(firstArg, args).u)) {
+    const bool isNotZero{std::visit(
+        [&](const auto &z) -> bool {
+          using T = typename std::decay_t<decltype(z)>::Result;
+          auto scalar{GetScalarConstantValue<T>(z)};
+          return !scalar || !scalar->IsZero();
+        },
+        someComplex->u)};
+    if (!isNotZero) {
+      context.messages().Say(
+          "complex argument must be different from zero"_warn_en_US);
+    }
+    return isNotZero;
+  }
+  return true;
+}
+
+// Verify that the argument in an intrinsic call is not zero and not a negative
+// integer.
+static bool VerifyGammaLikeArgument(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someReal =
+          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
+    const bool isValid{std::visit(
+        [&](const auto &x) -> bool {
+          using T = typename std::decay_t<decltype(x)>::Result;
+          auto scalar{GetScalarConstantValue<T>(x)};
+          if (scalar) {
+            return !scalar->IsZero() &&
+                !(scalar->IsNegative() &&
+                    scalar->ToWholeNumber().value == scalar);
+          }
+          return true;
+        },
+        someReal->u)};
+    if (!isValid) {
+      context.messages().Say(
+          "argument must not be a negative integer or zero"_en_US);
+    }
+    return isValid;
+  }
+  return true;
+}
+
+// Verify that two real arguments are not both zero.
+static bool VerifyAtan2LikeArguments(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  if (const auto *someReal =
+          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
+    const bool isValid{std::visit(
+        [&](const auto &typedExpr) -> bool {
+          using T = typename std::decay_t<decltype(typedExpr)>::Result;
+          auto x{GetScalarConstantValue<T>(typedExpr)};
+          auto y{GetScalarConstantValue<T>(getArg(lastArg, args))};
+          if (x && y) {
+            return !(x->IsZero() && y->IsZero());
+          }
+          return true;
+        },
+        someReal->u)};
+    if (!isValid) {
+      context.messages().Say(
+          "'x' and 'y' arguments must not be both zero"_en_US);
+    }
+    return isValid;
+  }
+  return true;
+}
+
+template <ArgumentVerifierFunc... F>
+static bool CombineVerifiers(
+    const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
+  return (... & F(args, context));
+}
+
+/// Define argument names to be used error messages when the intrinsic have
+/// several arguments.
+static constexpr char xName[]{"x"};
+static constexpr char pName[]{"p"};
+
+/// Register argument verifiers for all intrinsics folded with runtime.
+static constexpr ArgumentVerifier intrinsicArgumentVerifiers[]{
+    {"acos", VerifyInRangeIfReal<-1, 1>},
+    {"asin", VerifyInRangeIfReal<-1, 1>},
+    {"atan2", VerifyAtan2LikeArguments},
+    {"bessel_y0", VerifyStrictlyPositiveIfReal<firstArg, xName>},
+    {"bessel_y1", VerifyStrictlyPositiveIfReal<firstArg, xName>},
+    {"bessel_yn", VerifyStrictlyPositiveIfReal<lastArg, xName>},
+    {"gamma", VerifyGammaLikeArgument},
+    {"log",
+        CombineVerifiers<VerifyStrictlyPositiveIfReal<firstArg, xName>,
+            VerifyNotZeroIfComplex>},
+    {"log10", VerifyStrictlyPositiveIfReal<firstArg, xName>},
+    {"log_gamma", VerifyGammaLikeArgument},
+    {"mod", VerifyNotZeroIfReal<lastArg, pName>},
+};
+
+const ArgumentVerifierFunc *findVerifier(const std::string &intrinsicName) {
+  static constexpr Fortran::common::StaticMultimapView<ArgumentVerifier>
+      verifiers(intrinsicArgumentVerifiers);
+  static_assert(verifiers.Verify(), "map must be sorted");
+  auto range{verifiers.equal_range(intrinsicName)};
+  if (range.first != range.second) {
+    return &range.first->verifier;
+  }
+  return nullptr;
+}
+
+/// Ensure argument verifiers, if any, are run before calling the runtime
+/// wrapper to fold an intrinsic.
+static HostRuntimeWrapper AddArgumentVerifierIfAny(
+    const std::string &intrinsicName, const HostRuntimeFunction &hostFunction) {
+  if (const auto *verifier{findVerifier(intrinsicName)}) {
+    const HostRuntimeFunction *hostFunctionPtr = &hostFunction;
+    return [hostFunctionPtr, verifier](
+               FoldingContext &context, std::vector<Expr<SomeType>> &&args) {
+      const bool validArguments{(*verifier)(args, context)};
+      if (!validArguments) {
+        // Silence fp signal warnings since a more detailed warning about
+        // invalid arguments was already emitted.
+        parser::Messages localBuffer;
+        parser::ContextualMessages localMessages{&localBuffer};
+        FoldingContext localContext{context, localMessages};
+        return hostFunctionPtr->folder(localContext, std::move(args));
+      }
+      return hostFunctionPtr->folder(context, std::move(args));
+    };
+  }
+  return hostFunction.folder;
+}
+
 std::optional<HostRuntimeWrapper> GetHostRuntimeWrapper(const std::string &name,
     DynamicType resultType, const std::vector<DynamicType> &argTypes) {
   if (const auto *hostFunction{SearchHostRuntime(name, resultType, argTypes)}) {
-    return hostFunction->folder;
+    return AddArgumentVerifierIfAny(name, *hostFunction);
   }
   // If no exact match, search with "bigger" types and insert type
   // conversions around the folder.
@@ -647,7 +880,8 @@ std::optional<HostRuntimeWrapper> GetHostRuntimeWrapper(const std::string &name,
   }
   if (const auto *hostFunction{
           SearchHostRuntime(name, biggerResultType, biggerArgTypes)}) {
-    return [hostFunction, resultType](
+    auto hostFolderWithChecks{AddArgumentVerifierIfAny(name, *hostFunction)};
+    return [hostFunction, resultType, hostFolderWithChecks](
                FoldingContext &context, std::vector<Expr<SomeType>> &&args) {
       auto nArgs{args.size()};
       for (size_t i{0}; i < nArgs; ++i) {
@@ -657,7 +891,7 @@ std::optional<HostRuntimeWrapper> GetHostRuntimeWrapper(const std::string &name,
       }
       return Fold(context,
           ConvertToType(
-              resultType, hostFunction->folder(context, std::move(args)))
+              resultType, hostFolderWithChecks(context, std::move(args)))
               .value());
     };
   }
diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index c7815b0340360..cc46e31a33388 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -17,24 +17,45 @@ module real_tests
   !WARN: warning: division by zero
   real(4), parameter :: r4_ninf = -1._4/0._4
 
-  !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos1 = acos(1.1)
   TEST_ISNAN(nan_r4_acos1)
-  !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos2 = acos(r4_pmax)
   TEST_ISNAN(nan_r4_acos2)
-  !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos3 = acos(r4_nmax)
   TEST_ISNAN(nan_r4_acos3)
-  !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos4 = acos(r4_ninf)
   TEST_ISNAN(nan_r4_acos4)
-  !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
   TEST_ISNAN(nan_r4_acos5)
+  !WARN: warning: argument is out of range [-1., 1.]
+  real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
+  TEST_ISNAN(nan_r8_dasin1)
+  !WARN: warning: argument 'x' must be strictly positive
+  real(8), parameter :: nan_r8_dlog1 = dlog(-0.1_8)
+  TEST_ISNAN(nan_r8_dlog1)
+  !WARN: warning: complex argument must be different from zero
+  complex(4), parameter :: c4_clog1 = clog((0., 0.))
   !WARN: warning: MOD: P argument is zero
   real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
   TEST_ISNAN(nan_r4_mod)
+  real(4), parameter :: ok_r4_gamma = gamma(-1.1)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_gamma1 = gamma(0.)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_gamma2 = gamma(-1.)
+  real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_log_gamma1 = log_gamma(0.)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_log_gamma2 = log_gamma(-100001.)
+  !WARN: 'x' and 'y' arguments must not be both zero
+  real(4), parameter :: r4_atan2 = atan2(0., 0.)
+
   !WARN: warning: overflow on evaluation of intrinsic function or operation
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf
  contains

>From 59be62c80d89bd92c3f5f1db87cc3348ae2b6c49 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Wed, 26 Jun 2024 12:56:13 -0700
Subject: [PATCH 02/13] Just trying to figure out why the Windows build is
 failing.

---
 flang/test/Evaluate/folding04.f90 | 36 -------------------------------
 1 file changed, 36 deletions(-)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index cc46e31a33388..1a982b6c5e9a5 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -17,44 +17,8 @@ module real_tests
   !WARN: warning: division by zero
   real(4), parameter :: r4_ninf = -1._4/0._4
 
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(4), parameter :: nan_r4_acos1 = acos(1.1)
-  TEST_ISNAN(nan_r4_acos1)
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(4), parameter :: nan_r4_acos2 = acos(r4_pmax)
-  TEST_ISNAN(nan_r4_acos2)
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(4), parameter :: nan_r4_acos3 = acos(r4_nmax)
-  TEST_ISNAN(nan_r4_acos3)
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(4), parameter :: nan_r4_acos4 = acos(r4_ninf)
-  TEST_ISNAN(nan_r4_acos4)
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
-  TEST_ISNAN(nan_r4_acos5)
-  !WARN: warning: argument is out of range [-1., 1.]
-  real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
-  TEST_ISNAN(nan_r8_dasin1)
-  !WARN: warning: argument 'x' must be strictly positive
-  real(8), parameter :: nan_r8_dlog1 = dlog(-0.1_8)
-  TEST_ISNAN(nan_r8_dlog1)
-  !WARN: warning: complex argument must be different from zero
-  complex(4), parameter :: c4_clog1 = clog((0., 0.))
-  !WARN: warning: MOD: P argument is zero
-  real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
-  TEST_ISNAN(nan_r4_mod)
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
-  !WARN: argument must not be a negative integer or zero
-  real(4), parameter :: r4_gamma1 = gamma(0.)
-  !WARN: argument must not be a negative integer or zero
-  real(4), parameter :: r4_gamma2 = gamma(-1.)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
-  !WARN: argument must not be a negative integer or zero
-  real(4), parameter :: r4_log_gamma1 = log_gamma(0.)
-  !WARN: argument must not be a negative integer or zero
-  real(4), parameter :: r4_log_gamma2 = log_gamma(-100001.)
-  !WARN: 'x' and 'y' arguments must not be both zero
-  real(4), parameter :: r4_atan2 = atan2(0., 0.)
 
   !WARN: warning: overflow on evaluation of intrinsic function or operation
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf

>From b3a822d09f455e09e890462f417d6be60eed07a9 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Wed, 26 Jun 2024 13:16:59 -0700
Subject: [PATCH 03/13] Second test.

---
 flang/test/Evaluate/folding04.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 1a982b6c5e9a5..fe1accf13527a 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -17,6 +17,9 @@ module real_tests
   !WARN: warning: division by zero
   real(4), parameter :: r4_ninf = -1._4/0._4
 
+ !WARN: warning: argument is out of range [-1., 1.]
+  real(4), parameter :: nan_r4_acos1 = acos(1.1)
+  TEST_ISNAN(nan_r4_acos1)
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
 

>From 5513c5537341490628b428dea4dc56619abea50e Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Wed, 26 Jun 2024 20:18:38 -0700
Subject: [PATCH 04/13] Third test.

---
 flang/test/Evaluate/folding04.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index fe1accf13527a..d31f9fc4889e3 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -22,6 +22,9 @@ module real_tests
   TEST_ISNAN(nan_r4_acos1)
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
+ !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  real(4), parameter :: nan_r4_acos3 = acos(r4_nmax)
+  TEST_ISNAN(nan_r4_acos3)
 
   !WARN: warning: overflow on evaluation of intrinsic function or operation
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf

>From 44bc8331e42ed455c6a462ccd95ff827da157d5c Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Wed, 26 Jun 2024 20:51:03 -0700
Subject: [PATCH 05/13] Fourth test.

---
 flang/test/Evaluate/folding04.f90 | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index d31f9fc4889e3..7453a0f2c89bf 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -17,14 +17,17 @@ module real_tests
   !WARN: warning: division by zero
   real(4), parameter :: r4_ninf = -1._4/0._4
 
- !WARN: warning: argument is out of range [-1., 1.]
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos1 = acos(1.1)
   TEST_ISNAN(nan_r4_acos1)
-  real(4), parameter :: ok_r4_gamma = gamma(-1.1)
-  real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
- !WARN: warning: invalid argument on evaluation of intrinsic function or operation
+  !WARN: warning: argument is out of range [-1., 1.]
+  real(4), parameter :: nan_r4_acos2 = acos(r4_pmax)
+  TEST_ISNAN(nan_r4_acos2)
+  !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos3 = acos(r4_nmax)
   TEST_ISNAN(nan_r4_acos3)
+  real(4), parameter :: ok_r4_gamma = gamma(-1.1)
+  real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
 
   !WARN: warning: overflow on evaluation of intrinsic function or operation
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf

>From 3ef0fa71e07e0d9ed26ba400860893a452564225 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 05:45:00 -0700
Subject: [PATCH 06/13] Fifth test.

---
 flang/test/Evaluate/folding04.f90 | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 7453a0f2c89bf..6e866a6b483ac 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -26,6 +26,13 @@ module real_tests
   !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos3 = acos(r4_nmax)
   TEST_ISNAN(nan_r4_acos3)
+  !WARN: warning: argument is out of range [-1., 1.]
+  real(4), parameter :: nan_r4_acos4 = acos(r4_ninf)
+  TEST_ISNAN(nan_r4_acos4)
+  !WARN: warning: argument is out of range [-1., 1.]
+  real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
+  TEST_ISNAN(nan_r4_acos5)
+
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
 

>From b04d78796ad0a98fae6eb1cb22ba8a56e90d97b3 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 08:17:09 -0700
Subject: [PATCH 07/13] Sixth test.

---
 flang/test/Evaluate/folding04.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 6e866a6b483ac..17dd2baf8ce1c 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -32,6 +32,9 @@ module real_tests
   !WARN: warning: argument is out of range [-1., 1.]
   real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
   TEST_ISNAN(nan_r4_acos5)
+  !WARN: warning: argument is out of range [-1., 1.]
+  real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
+  TEST_ISNAN(nan_r8_dasin1)
 
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)

>From 704fbc6cce15deaa8b0f30cac9ded583a6218aa7 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 14:55:55 -0700
Subject: [PATCH 08/13] Seventh test.

---
 flang/test/Evaluate/folding04.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 17dd2baf8ce1c..c62a77b8fd59c 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -35,6 +35,9 @@ module real_tests
   !WARN: warning: argument is out of range [-1., 1.]
   real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
   TEST_ISNAN(nan_r8_dasin1)
+  !WARN: warning: argument 'x' must be strictly positive
+  real(8), parameter :: nan_r8_dlog1 = dlog(-0.1_8)
+  TEST_ISNAN(nan_r8_dlog1)
 
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)

>From 3f72b69db4e54ac090cb9713184eab958064fd00 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 18:18:51 -0700
Subject: [PATCH 09/13] Eighth test.

---
 flang/test/Evaluate/folding04.f90 | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index c62a77b8fd59c..28d8d5c2cf990 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -37,7 +37,6 @@ module real_tests
   TEST_ISNAN(nan_r8_dasin1)
   !WARN: warning: argument 'x' must be strictly positive
   real(8), parameter :: nan_r8_dlog1 = dlog(-0.1_8)
-  TEST_ISNAN(nan_r8_dlog1)
 
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)

>From 49853a43c03e94c2546e893ec878152012e019b7 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 19:02:00 -0700
Subject: [PATCH 10/13] Ninth test.

---
 flang/test/Evaluate/folding04.f90 | 2 --
 1 file changed, 2 deletions(-)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 28d8d5c2cf990..17dd2baf8ce1c 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -35,8 +35,6 @@ module real_tests
   !WARN: warning: argument is out of range [-1., 1.]
   real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
   TEST_ISNAN(nan_r8_dasin1)
-  !WARN: warning: argument 'x' must be strictly positive
-  real(8), parameter :: nan_r8_dlog1 = dlog(-0.1_8)
 
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)

>From 83da7e6cfe4c0fbdb5f7e23281c6d23970ab5d35 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Thu, 27 Jun 2024 20:27:37 -0700
Subject: [PATCH 11/13] Tenth test.

---
 flang/test/Evaluate/folding04.f90 | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 17dd2baf8ce1c..c7d7c46b8c21a 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -35,9 +35,23 @@ module real_tests
   !WARN: warning: argument is out of range [-1., 1.]
   real(8), parameter :: nan_r8_dasin1 = dasin(-1.1_8)
   TEST_ISNAN(nan_r8_dasin1)
-
+  !WARN: warning: complex argument must be different from zero
+  complex(4), parameter :: c4_clog1 = clog((0., 0.))
+  !WARN: warning: MOD: P argument is zero
+  real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
+  TEST_ISNAN(nan_r4_mod)
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_gamma1 = gamma(0.)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_gamma2 = gamma(-1.)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_log_gamma1 = log_gamma(0.)
+  !WARN: argument must not be a negative integer or zero
+  real(4), parameter :: r4_log_gamma2 = log_gamma(-100001.)
+  !WARN: 'x' and 'y' arguments must not be both zero
+  real(4), parameter :: r4_atan2 = atan2(0., 0.)
 
   !WARN: warning: overflow on evaluation of intrinsic function or operation
   logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf

>From 95933cdf79de699af7d3f1bdcfa0cc5319b22bee Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Fri, 28 Jun 2024 14:45:58 -0700
Subject: [PATCH 12/13] Responding to Peter's comments.

---
 flang/lib/Evaluate/intrinsics-library.cpp | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index e6588ba4ec9c1..76c1efeb68e25 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -640,14 +640,14 @@ struct ArgumentVerifier {
   using Key = std::string_view;
   // Needed for implicit compare with keys.
   constexpr operator Key() const { return key; }
-  Key key; // intrinsic name
+  Key key;
   ArgumentVerifierFunc verifier;
 };
 
 static constexpr int lastArg{-1};
 static constexpr int firstArg{0};
 
-static const Expr<SomeType> &getArg(
+static const Expr<SomeType> &GetArg(
     int position, const std::vector<Expr<SomeType>> &args) {
   if (position == lastArg) {
     CHECK(!args.empty());
@@ -673,9 +673,9 @@ static bool IsInRange(const Expr<T> &expr, int lb, int ub) {
 template <int lb, int ub>
 static bool VerifyInRangeIfReal(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
-  if (const auto *someReal =
-          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
-    const bool isInRange{
+  if (const auto *someReal{
+          std::get_if<Expr<SomeReal>>(&GetArg(firstArg, args).u)}) {
+    bool isInRange{
         std::visit([&](const auto &x) -> bool { return IsInRange(x, lb, ub); },
             someReal->u)};
     if (!isInRange) {
@@ -691,7 +691,7 @@ template <int argPosition, const char *argName>
 static bool VerifyStrictlyPositiveIfReal(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
   if (const auto *someReal =
-          std::get_if<Expr<SomeReal>>(&getArg(argPosition, args).u)) {
+          std::get_if<Expr<SomeReal>>(&GetArg(argPosition, args).u)) {
     const bool isStrictlyPositive{std::visit(
         [&](const auto &x) -> bool {
           using T = typename std::decay_t<decltype(x)>::Result;
@@ -714,7 +714,7 @@ template <int argPosition, const char *argName>
 static bool VerifyNotZeroIfReal(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
   if (const auto *someReal =
-          std::get_if<Expr<SomeReal>>(&getArg(argPosition, args).u)) {
+          std::get_if<Expr<SomeReal>>(&GetArg(argPosition, args).u)) {
     const bool isNotZero{std::visit(
         [&](const auto &x) -> bool {
           using T = typename std::decay_t<decltype(x)>::Result;
@@ -735,7 +735,7 @@ static bool VerifyNotZeroIfReal(
 static bool VerifyNotZeroIfComplex(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
   if (const auto *someComplex =
-          std::get_if<Expr<SomeComplex>>(&getArg(firstArg, args).u)) {
+          std::get_if<Expr<SomeComplex>>(&GetArg(firstArg, args).u)) {
     const bool isNotZero{std::visit(
         [&](const auto &z) -> bool {
           using T = typename std::decay_t<decltype(z)>::Result;
@@ -757,7 +757,7 @@ static bool VerifyNotZeroIfComplex(
 static bool VerifyGammaLikeArgument(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
   if (const auto *someReal =
-          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
+          std::get_if<Expr<SomeReal>>(&GetArg(firstArg, args).u)) {
     const bool isValid{std::visit(
         [&](const auto &x) -> bool {
           using T = typename std::decay_t<decltype(x)>::Result;
@@ -783,12 +783,12 @@ static bool VerifyGammaLikeArgument(
 static bool VerifyAtan2LikeArguments(
     const std::vector<Expr<SomeType>> &args, FoldingContext &context) {
   if (const auto *someReal =
-          std::get_if<Expr<SomeReal>>(&getArg(firstArg, args).u)) {
+          std::get_if<Expr<SomeReal>>(&GetArg(firstArg, args).u)) {
     const bool isValid{std::visit(
         [&](const auto &typedExpr) -> bool {
           using T = typename std::decay_t<decltype(typedExpr)>::Result;
           auto x{GetScalarConstantValue<T>(typedExpr)};
-          auto y{GetScalarConstantValue<T>(getArg(lastArg, args))};
+          auto y{GetScalarConstantValue<T>(GetArg(lastArg, args))};
           if (x && y) {
             return !(x->IsZero() && y->IsZero());
           }

>From ce705972657f7afdde3badc6928b78d3454ef870 Mon Sep 17 00:00:00 2001
From: Peter Steinfeld <psteinfeld at nvidia.com>
Date: Tue, 2 Jul 2024 07:44:18 -0700
Subject: [PATCH 13/13] Marking some of the new messages as warnings.

---
 flang/lib/Evaluate/intrinsics-library.cpp |  4 ++--
 flang/test/Evaluate/folding04.f90         | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 76c1efeb68e25..c3bd3a501c0c5 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -772,7 +772,7 @@ static bool VerifyGammaLikeArgument(
         someReal->u)};
     if (!isValid) {
       context.messages().Say(
-          "argument must not be a negative integer or zero"_en_US);
+          "argument must not be a negative integer or zero"_warn_en_US);
     }
     return isValid;
   }
@@ -797,7 +797,7 @@ static bool VerifyAtan2LikeArguments(
         someReal->u)};
     if (!isValid) {
       context.messages().Say(
-          "'x' and 'y' arguments must not be both zero"_en_US);
+          "'x' and 'y' arguments must not be both zero"_warn_en_US);
     }
     return isValid;
   }
diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index c7d7c46b8c21a..08c5c6eee9b12 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -41,16 +41,16 @@ module real_tests
   real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
   TEST_ISNAN(nan_r4_mod)
   real(4), parameter :: ok_r4_gamma = gamma(-1.1)
-  !WARN: argument must not be a negative integer or zero
+  !WARN: warning: argument must not be a negative integer or zero
   real(4), parameter :: r4_gamma1 = gamma(0.)
-  !WARN: argument must not be a negative integer or zero
+  !WARN: warning: argument must not be a negative integer or zero
   real(4), parameter :: r4_gamma2 = gamma(-1.)
   real(4), parameter :: ok_r4_log_gamma = log_gamma(-2.001)
-  !WARN: argument must not be a negative integer or zero
+  !WARN: warning: argument must not be a negative integer or zero
   real(4), parameter :: r4_log_gamma1 = log_gamma(0.)
-  !WARN: argument must not be a negative integer or zero
+  !WARN: warning: argument must not be a negative integer or zero
   real(4), parameter :: r4_log_gamma2 = log_gamma(-100001.)
-  !WARN: 'x' and 'y' arguments must not be both zero
+  !WARN: warning: 'x' and 'y' arguments must not be both zero
   real(4), parameter :: r4_atan2 = atan2(0., 0.)
 
   !WARN: warning: overflow on evaluation of intrinsic function or operation



More information about the flang-commits mailing list