Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang] Allow derf as alternate spelling for erf #95784

Merged
merged 2 commits into from
Jun 25, 2024
Merged

Conversation

DavidTruby
Copy link
Member

This patch adds derf as an alternate spelling for the erf intrinsic.
This spelling is supported by multiple other compilers and used by WRF.

@DavidTruby DavidTruby requested a review from klausler June 17, 2024 13:26
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:semantics labels Jun 17, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 17, 2024

@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-fir-hlfir

Author: David Truby (DavidTruby)

Changes

This patch adds derf as an alternate spelling for the erf intrinsic.
This spelling is supported by multiple other compilers and used by WRF.


Full diff: https://github.com/llvm/llvm-project/pull/95784.diff

5 Files Affected:

  • (modified) flang/lib/Evaluate/fold-real.cpp (+3)
  • (modified) flang/lib/Evaluate/intrinsics.cpp (+1)
  • (modified) flang/lib/Optimizer/Builder/IntrinsicCall.cpp (+5)
  • (modified) flang/test/Evaluate/folding02.f90 (+3)
  • (modified) flang/test/Intrinsics/math-codegen.fir (+80)
diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp
index f71addcc4094a..d951197b8eb6c 100644
--- a/flang/lib/Evaluate/fold-real.cpp
+++ b/flang/lib/Evaluate/fold-real.cpp
@@ -153,6 +153,9 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
   auto *intrinsic{std::get_if<SpecificIntrinsic>(&funcRef.proc().u)};
   CHECK(intrinsic);
   std::string name{intrinsic->name};
+  if (name == "derf") {
+    name = "erf";
+  }
   if (name == "acos" || name == "acosh" || name == "asin" || name == "asinh" ||
       (name == "atan" && args.size() == 1) || name == "atanh" ||
       name == "bessel_j0" || name == "bessel_j1" || name == "bessel_y0" ||
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index ace316174a892..212134b75c97d 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -403,6 +403,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
             {"shift", AnyInt, Rank::dimRemovedOrScalar}, OptionalDIM},
         SameType, Rank::conformable, IntrinsicClass::transformationalFunction},
     {"dble", {{"a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision},
+    {"derf", {{"x", SameReal}}, SameReal},
     {"digits",
         {{"x", AnyIntOrReal, Rank::anyOrAssumedRank, Optionality::required,
             common::Intent::In, {ArgFlag::canBeMoldNull}}},
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index ab106f62aecfb..beb9011ee5fe6 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -1101,6 +1101,11 @@ static constexpr MathOperation mathOperations[] = {
     {"cosh", "ccosh", genFuncType<Ty::Complex<8>, Ty::Complex<8>>, genLibCall},
     {"cosh", RTNAME_STRING(CCoshF128), FuncTypeComplex16Complex16,
      genLibF128Call},
+    {"derf", "derff", genFuncType<Ty::Real<4>, Ty::Real<4>>,
+     genMathOp<mlir::math::ErfOp>},
+    {"derf", "derf", genFuncType<Ty::Real<8>, Ty::Real<8>>,
+     genMathOp<mlir::math::ErfOp>},
+    {"derf", RTNAME_STRING(ErfF128), FuncTypeReal16Real16, genLibF128Call},
     {"divc",
      {},
      genFuncType<Ty::Complex<2>, Ty::Complex<2>, Ty::Complex<2>>,
diff --git a/flang/test/Evaluate/folding02.f90 b/flang/test/Evaluate/folding02.f90
index 89e2a09aa31b7..4581b3cf8ea5b 100644
--- a/flang/test/Evaluate/folding02.f90
+++ b/flang/test/Evaluate/folding02.f90
@@ -57,6 +57,7 @@ module m
   TEST_R4(atanh, atanh(0.8_4), 1.098612308502197265625_4)
   TEST_R4(cos, cos(0.5_4), 0.877582550048828125_4)
   TEST_R4(cosh, cosh(0.1_4), 1.0050041675567626953125_4)
+  TEST_R4(derf, derf(1._4), 0.842700779438018798828125_4)
   TEST_R4(erf, erf(1._4), 0.842700779438018798828125_4)
   TEST_R4(erfc, erfc(0.1_4), 0.887537062168121337890625_4)
   TEST_R4(exp, exp(0.1_4), 1.1051709651947021484375_4)
@@ -97,6 +98,8 @@ module m
     0.8775825618903727587394314468838274478912353515625_8)
   TEST_R8(cosh, cosh(0.1_8), &
     1.0050041680558035039894093642942607402801513671875_8)
+  TEST_R8(derf, derf(1._8), &
+       0.84270079294971489414223242420121096074581146240234375_8)
   TEST_R8(erf, erf(1._8), &
     0.84270079294971489414223242420121096074581146240234375_8)
   TEST_R8(erfc, erfc(0.1_8), &
diff --git a/flang/test/Intrinsics/math-codegen.fir b/flang/test/Intrinsics/math-codegen.fir
index 62d841253075e..4555e33fead20 100644
--- a/flang/test/Intrinsics/math-codegen.fir
+++ b/flang/test/Intrinsics/math-codegen.fir
@@ -862,6 +862,86 @@ func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
 func.func private @erff(f32) -> f32
 func.func private @erf(f64) -> f64
 
+
+//--- derf_fast.fir
+// RUN: fir-opt %t/derf_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/derf_fast.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.erf %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.erf %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- derf_relaxed.fir
+// RUN: fir-opt %t/derf_relaxed.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/derf_relaxed.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = math.erf %1 : f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = math.erf %1 : f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+
+//--- derf_precise.fir
+// RUN: fir-opt %t/derf_precise.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/derf_precise.fir
+// CHECK: @_QPtest_real4
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erff({{%[A-Za-z0-9._]+}}) : (f32) -> f32
+
+// CHECK: @_QPtest_real8
+// CHECK: {{%[A-Za-z0-9._]+}} = llvm.call @erf({{%[A-Za-z0-9._]+}}) : (f64) -> f64
+
+func.func @_QPtest_real4(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}) -> f32 {
+  %0 = fir.alloca f32 {bindc_name = "test_real4", uniq_name = "_QFtest_real4Etest_real4"}
+  %1 = fir.load %arg0 : !fir.ref<f32>
+  %2 = fir.call @erff(%1) : (f32) -> f32
+  fir.store %2 to %0 : !fir.ref<f32>
+  %3 = fir.load %0 : !fir.ref<f32>
+  return %3 : f32
+}
+func.func @_QPtest_real8(%arg0: !fir.ref<f64> {fir.bindc_name = "x"}) -> f64 {
+  %0 = fir.alloca f64 {bindc_name = "test_real8", uniq_name = "_QFtest_real8Etest_real8"}
+  %1 = fir.load %arg0 : !fir.ref<f64>
+  %2 = fir.call @erf(%1) : (f64) -> f64
+  fir.store %2 to %0 : !fir.ref<f64>
+  %3 = fir.load %0 : !fir.ref<f64>
+  return %3 : f64
+}
+func.func private @erff(f32) -> f32
+func.func private @erf(f64) -> f64
+
+
+
 //--- exp_fast.fir
 // RUN: fir-opt %t/exp_fast.fir --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" | FileCheck %t/exp_fast.fir
 // CHECK: @_QPtest_real4

@kiranchandramohan
Copy link
Contributor

DERF is mentioned as a specific name extension of ERF for argument and return type Real(kind=8).
https://gcc.gnu.org/onlinedocs/gfortran/ERF.html

Is the usage in wrf and other codes you saw an alias of ERF for all Real kinds or specifically for Real(kind=8)?

@pawosm-arm
Copy link
Contributor

DERF is mentioned as a specific name extension of ERF for argument and return type Real(kind=8). https://gcc.gnu.org/onlinedocs/gfortran/ERF.html

Is the usage in wrf and other codes you saw an alias of ERF for all Real kinds or specifically for Real(kind=8)?

NB, it must match the type of other D-prefixed intrinsics as it is used in an expression like this one:

(1.-DERF(5.D+0/DSQRT(2.D+0)))*0.5

@klausler
Copy link
Contributor

Fortran extension intrinsic functions that start with D have historically been DOUBLE PRECISION versions of real intrinsics. See thestatic const SpecificIntrinsicInterface specificIntrinsicFunction table in intrinsics.cpp for other examples, and for the correct way to implement further examples.

Copy link
Contributor

@klausler klausler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically all wrong.

This patch adds derf as an alternate spelling for the erf intrinsic.
This spelling is supported by multiple other compilers and used by WRF.
@DavidTruby
Copy link
Member Author

I've reimplemented this using specificIntrinsicFunction

@tblah tblah requested a review from klausler June 24, 2024 14:32
@DavidTruby DavidTruby merged commit 954b692 into llvm:main Jun 25, 2024
7 checks passed
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
This patch adds derf as an alternate spelling for the erf intrinsic.
This spelling is supported by multiple other compilers and used by WRF.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants