Skip to content

Commit bae3577

Browse files
authored
[flang] Define ERF, ERFC and ERFC_SCALED intrinsics with Q and D prefix (#125217)
`ERF`, `ERFC` and `ERFC_SCALED` intrinsics prefixed by `Q` and `D` are missing. Codes such as `CP2K`(https://github.com/cp2k/cp2k) and `TurboRVB`(https://github.com/sissaschool/turborvb) use these intrinsics just like defined in the GNU standard and here: https://www.ibm.com/docs/fr/xl-fortran-aix/16.1.0?topic=reference-intrinsic-procedures These intrinsics are based on the existing intrinsics but apply a restriction on the type kind. - `DERF`, `DERFC` and `DERFC_SCALED` are for double précision only. - `QERF`, `QERFC` and `QERFC_SCALED` are for quad précision only.
1 parent 091dcb8 commit bae3577

File tree

11 files changed

+176
-5
lines changed

11 files changed

+176
-5
lines changed

flang/docs/Intrinsics.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,14 @@ BESSEL_Y0(REAL(k) X) -> REAL(k)
241241
BESSEL_Y1(REAL(k) X) -> REAL(k)
242242
BESSEL_YN(INTEGER(n) N, REAL(k) X) -> REAL(k)
243243
ERF(REAL(k) X) -> REAL(k)
244+
DERF(REAL(8) X) -> REAL(8)
245+
QERF(REAL(16) X) -> REAL(16)
244246
ERFC(REAL(k) X) -> REAL(k)
247+
DERFC(REAL(8) X) -> REAL(8)
248+
QERFC(REAL(16) X) -> REAL(16)
245249
ERFC_SCALED(REAL(k) X) -> REAL(k)
250+
DERFC_SCALED(REAL(8) X) -> REAL(8)
251+
QERFC_SCALED(REAL(16) X) -> REAL(16)
246252
FRACTION(REAL(k) X) -> REAL(k)
247253
GAMMA(REAL(k) X) -> REAL(k)
248254
HYPOT(REAL(k) X, REAL(k) Y) -> REAL(k) = SQRT(X*X+Y*Y) without spurious overflow
@@ -810,7 +816,7 @@ otherwise an error message will be produced by f18 when attempting to fold relat
810816

811817
| C/C++ Host Type | Intrinsic Functions with Host Standard C++ Library Based Folding Support |
812818
| --- | --- |
813-
| float, double and long double | ACOS, ACOSH, ASINH, ATAN, ATAN2, ATANH, COS, COSH, ERF, ERFC, EXP, GAMMA, HYPOT, LOG, LOG10, LOG_GAMMA, MOD, SIN, SQRT, SINH, SQRT, TAN, TANH |
819+
| float, double and long double | ACOS, ACOSH, ASINH, ATAN, ATAN2, ATANH, COS, COSH, DERF, DERFC, ERF, ERFC, EXP, GAMMA, HYPOT, LOG, LOG10, LOG_GAMMA, MOD, QERF, QERFC, SIN, SQRT, SINH, SQRT, TAN, TANH |
814820
| std::complex for float, double and long double| ACOS, ACOSH, ASIN, ASINH, ATAN, ATANH, COS, COSH, EXP, LOG, SIN, SINH, SQRT, TAN, TANH |
815821

816822
On top of the default usage of C++ standard library functions for folding described
@@ -829,7 +835,7 @@ types related to host float and double types.
829835

830836
| C/C++ Host Type | Additional Intrinsic Function Folding Support with Libpgmath (Optional) |
831837
| --- | --- |
832-
|float and double| BESSEL_J0, BESSEL_J1, BESSEL_JN (elemental only), BESSEL_Y0, BESSEL_Y1, BESSEL_Yn (elemental only), ERFC_SCALED |
838+
|float and double| BESSEL_J0, BESSEL_J1, BESSEL_JN (elemental only), BESSEL_Y0, BESSEL_Y1, BESSEL_Yn (elemental only), DERFC_SCALED, ERFC_SCALED, QERFC_SCALED |
833839

834840
Libpgmath comes in three variants (precise, relaxed and fast). So far, only the
835841
precise version is used for intrinsic function folding in f18. It guarantees the greatest numerical precision.

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "flang/Evaluate/intrinsics.h"
1010
#include "flang/Common/enum-set.h"
11+
#include "flang/Common/float128.h"
1112
#include "flang/Common/idioms.h"
1213
#include "flang/Evaluate/check-expression.h"
1314
#include "flang/Evaluate/common.h"
@@ -83,7 +84,7 @@ static constexpr CategorySet AnyType{IntrinsicType | DerivedType};
8384

8485
ENUM_CLASS(KindCode, none, defaultIntegerKind,
8586
defaultRealKind, // is also the default COMPLEX kind
86-
doublePrecision, defaultCharKind, defaultLogicalKind,
87+
doublePrecision, quadPrecision, defaultCharKind, defaultLogicalKind,
8788
greaterOrEqualToKind, // match kind value greater than or equal to a single
8889
// explicit kind value
8990
any, // matches any kind value; each instance is independent
@@ -139,6 +140,7 @@ static constexpr TypePattern DoublePrecision{
139140
RealType, KindCode::doublePrecision};
140141
static constexpr TypePattern DoublePrecisionComplex{
141142
ComplexType, KindCode::doublePrecision};
143+
static constexpr TypePattern QuadPrecision{RealType, KindCode::quadPrecision};
142144
static constexpr TypePattern SubscriptInt{IntType, KindCode::subscript};
143145

144146
// Match any kind of some intrinsic or derived types
@@ -1199,6 +1201,9 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
11991201
DoublePrecision},
12001202
"dim"},
12011203
{{"derf", {{"x", DoublePrecision}}, DoublePrecision}, "erf"},
1204+
{{"derfc", {{"x", DoublePrecision}}, DoublePrecision}, "erfc"},
1205+
{{"derfc_scaled", {{"x", DoublePrecision}}, DoublePrecision},
1206+
"erfc_scaled"},
12021207
{{"dexp", {{"x", DoublePrecision}}, DoublePrecision}, "exp"},
12031208
{{"dfloat", {{"a", AnyInt}}, DoublePrecision}, "real", true},
12041209
{{"dim", {{"x", DefaultReal}, {"y", DefaultReal}}, DefaultReal}},
@@ -1299,6 +1304,9 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
12991304
"min", true, true},
13001305
{{"mod", {{"a", DefaultInt}, {"p", DefaultInt}}, DefaultInt}},
13011306
{{"nint", {{"a", DefaultReal}}, DefaultInt}},
1307+
{{"qerf", {{"x", QuadPrecision}}, QuadPrecision}, "erf"},
1308+
{{"qerfc", {{"x", QuadPrecision}}, QuadPrecision}, "erfc"},
1309+
{{"qerfc_scaled", {{"x", QuadPrecision}}, QuadPrecision}, "erfc_scaled"},
13021310
{{"sign", {{"a", DefaultReal}, {"b", DefaultReal}}, DefaultReal}},
13031311
{{"sin", {{"x", DefaultReal}}, DefaultReal}},
13041312
{{"sinh", {{"x", DefaultReal}}, DefaultReal}},
@@ -2033,6 +2041,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
20332041
case KindCode::doublePrecision:
20342042
argOk = type->kind() == defaults.doublePrecisionKind();
20352043
break;
2044+
case KindCode::quadPrecision:
2045+
argOk = type->kind() == defaults.quadPrecisionKind();
2046+
break;
20362047
case KindCode::defaultCharKind:
20372048
argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Character);
20382049
break;
@@ -2343,6 +2354,18 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
23432354
CHECK(FloatingType.test(*category));
23442355
resultType = DynamicType{*category, defaults.doublePrecisionKind()};
23452356
break;
2357+
case KindCode::quadPrecision:
2358+
CHECK(result.categorySet == CategorySet{*category});
2359+
CHECK(FloatingType.test(*category));
2360+
resultType = DynamicType{*category, defaults.quadPrecisionKind()};
2361+
if (!context.targetCharacteristics().CanSupportType(
2362+
*category, defaults.quadPrecisionKind())) {
2363+
messages.Say(
2364+
"%s(KIND=%jd) type not supported on this target."_err_en_US,
2365+
parser::ToUpperCaseLetters(EnumToString(*category)),
2366+
defaults.quadPrecisionKind());
2367+
}
2368+
break;
23462369
case KindCode::defaultLogicalKind:
23472370
CHECK(result.categorySet == LogicalType);
23482371
CHECK(*category == TypeCategory::Logical);
@@ -3341,6 +3364,7 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33413364
case KindCode::defaultIntegerKind:
33423365
break;
33433366
case KindCode::doublePrecision:
3367+
case KindCode::quadPrecision:
33443368
case KindCode::defaultRealKind:
33453369
category = TypeCategory::Real;
33463370
break;
@@ -3349,6 +3373,8 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33493373
}
33503374
int kind{interface.result.kindCode == KindCode::doublePrecision
33513375
? defaults.doublePrecisionKind()
3376+
: interface.result.kindCode == KindCode::quadPrecision
3377+
? defaults.quadPrecisionKind()
33523378
: defaults.GetDefaultKind(category)};
33533379
return DynamicType{category, kind};
33543380
}
@@ -3589,6 +3615,8 @@ DynamicType IntrinsicProcTable::Implementation::GetSpecificType(
35893615
TypeCategory category{set.LeastElement().value()};
35903616
if (pattern.kindCode == KindCode::doublePrecision) {
35913617
return DynamicType{category, defaults_.doublePrecisionKind()};
3618+
} else if (pattern.kindCode == KindCode::quadPrecision) {
3619+
return DynamicType{category, defaults_.quadPrecisionKind()};
35923620
} else if (category == TypeCategory::Character) {
35933621
// All character arguments to specific intrinsic functions are
35943622
// assumed-length.

flang/test/Lower/Intrinsics/erf.f90

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
! RUN: bbc -emit-fir %s -o - --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %s
2+
! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=fast %s -o - | FileCheck --check-prefixes=ALL,FAST %s
3+
! RUN: bbc -emit-fir %s -o - --math-runtime=relaxed | FileCheck --check-prefixes=ALL,RELAXED %s
4+
! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=relaxed %s -o - | FileCheck --check-prefixes=ALL,RELAXED %s
5+
! RUN: bbc -emit-fir %s -o - --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %s
6+
! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=precise %s -o - | FileCheck --check-prefixes=ALL,PRECISE %s
7+
8+
function dtest_real8(x)
9+
real(8) :: x, dtest_real8
10+
dtest_real8 = derf(x)
11+
end function
12+
13+
! ALL-LABEL: @_QPdtest_real8
14+
! FAST: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} {{.*}}: f64
15+
! RELAXED: {{%[A-Za-z0-9._]+}} = math.erf {{%[A-Za-z0-9._]+}} {{.*}}: f64
16+
! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @erf({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> f64

flang/test/Lower/Intrinsics/erf_real16.f90

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
55

66
! CHECK: fir.call @_FortranAErfF128({{.*}}){{.*}}: (f128) -> f128
7-
real(16) :: a, b
7+
! CHECK: fir.call @_FortranAErfF128({{.*}}){{.*}}: (f128) -> f128
8+
real(16) :: a, b, c
89
b = erf(a)
10+
c = qerf(a)
911
end

flang/test/Lower/Intrinsics/erfc.f90

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,13 @@ function test_real8(x)
2424
! FAST: {{%[A-Za-z0-9._]+}} = math.erfc {{%[A-Za-z0-9._]+}} {{.*}}: f64
2525
! RELAXED: {{%[A-Za-z0-9._]+}} = math.erfc {{%[A-Za-z0-9._]+}} {{.*}}: f64
2626
! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @erfc({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> f64
27+
28+
function dtest_real8(x)
29+
real(8) :: x, dtest_real8
30+
dtest_real8 = derfc(x)
31+
end function
32+
33+
! ALL-LABEL: @_QPdtest_real8
34+
! FAST: {{%[A-Za-z0-9._]+}} = math.erfc {{%[A-Za-z0-9._]+}} {{.*}}: f64
35+
! RELAXED: {{%[A-Za-z0-9._]+}} = math.erfc {{%[A-Za-z0-9._]+}} {{.*}}: f64
36+
! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @erfc({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> f64

flang/test/Lower/Intrinsics/erfc_real16.f90

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
55

66
! CHECK: fir.call @_FortranAErfcF128({{.*}}){{.*}}: (f128) -> f128
7-
real(16) :: a, b
7+
! CHECK: fir.call @_FortranAErfcF128({{.*}}){{.*}}: (f128) -> f128
8+
real(16) :: a, b, c
89
b = erfc(a)
10+
c = qerfc(a)
911
end

flang/test/Lower/Intrinsics/erfc_scaled.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,14 @@ function erfc_scaled8(x)
2121
! CHECK: %[[a1:.*]] = fir.load %[[x]] : !fir.ref<f64>
2222
! CHECK: %{{.*}} = fir.call @_FortranAErfcScaled8(%[[a1]]) {{.*}}: (f64) -> f64
2323
end function erfc_scaled8
24+
25+
26+
! CHECK-LABEL: func @_QPderfc_scaled8(
27+
! CHECK-SAME: %[[x:[^:]+]]: !fir.ref<f64>{{.*}}) -> f64
28+
function derfc_scaled8(x)
29+
real(kind=8) :: derfc_scaled8
30+
real(kind=8) :: x
31+
derfc_scaled8 = derfc_scaled(x);
32+
! CHECK: %[[a1:.*]] = fir.load %[[x]] : !fir.ref<f64>
33+
! CHECK: %{{.*}} = fir.call @_FortranAErfcScaled8(%[[a1]]) {{.*}}: (f64) -> f64
34+
end function derfc_scaled8
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
! REQUIRES: flang-supports-f128-math
2+
! RUN: bbc -emit-fir %s -o - | FileCheck %s
3+
! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s
4+
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
5+
6+
! CHECK: fir.call @_FortranAErfcScaled16({{.*}}) {{.*}}: (f128) -> f128
7+
real(16) :: a, b
8+
b = qerfc_scaled(a)
9+
end

flang/test/Semantics/erf.f90

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=ERROR %s
2+
3+
function derf8_error4(x)
4+
real(kind=8) :: derf8_error4
5+
real(kind=4) :: x
6+
derf8_error4 = derf(x);
7+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
8+
end function derf8_error4
9+
10+
function derf8_error16(x)
11+
real(kind=8) :: derf8_error16
12+
real(kind=16) :: x
13+
derf8_error16 = derf(x);
14+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(16)'
15+
end function derf8_error16
16+
17+
function qerf16_error4(x)
18+
real(kind=16) :: qerf16_error4
19+
real(kind=4) :: x
20+
qerf16_error4 = qerf(x);
21+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
22+
end function qerf16_error4
23+
24+
function qerf16_error8(x)
25+
real(kind=16) :: qerf16_error8
26+
real(kind=8) :: x
27+
qerf16_error8 = qerf(x);
28+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(8)'
29+
end function qerf16_error8

flang/test/Semantics/erfc.f90

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=ERROR %s
2+
3+
function derfc8_error4(x)
4+
real(kind=8) :: derfc8_error4
5+
real(kind=4) :: x
6+
derfc8_error4 = derfc(x);
7+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
8+
end function derfc8_error4
9+
10+
function derfc8_error16(x)
11+
real(kind=8) :: derfc8_error16
12+
real(kind=16) :: x
13+
derfc8_error16 = derfc(x);
14+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(16)'
15+
end function derfc8_error16
16+
17+
function qerfc16_error4(x)
18+
real(kind=16) :: qerfc16_error4
19+
real(kind=4) :: x
20+
qerfc16_error4 = qerfc(x);
21+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
22+
end function qerfc16_error4
23+
24+
function qerfc16_error8(x)
25+
real(kind=16) :: qerfc16_error8
26+
real(kind=8) :: x
27+
qerfc16_error8 = qerfc(x);
28+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(8)'
29+
end function qerfc16_error8

flang/test/Semantics/erfc_scaled.f90

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=ERROR %s
2+
3+
function derfc_scaled8_error4(x)
4+
real(kind=8) :: derfc_scaled8_error4
5+
real(kind=4) :: x
6+
derfc_scaled8_error4 = derfc_scaled(x);
7+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
8+
end function derfc_scaled8_error4
9+
10+
function derfc_scaled8_error16(x)
11+
real(kind=8) :: derfc_scaled8_error16
12+
real(kind=16) :: x
13+
derfc_scaled8_error16 = derfc_scaled(x);
14+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(16)'
15+
end function derfc_scaled8_error16
16+
17+
function qerfc_scaled16_error4(x)
18+
real(kind=16) :: qerfc_scaled16_error4
19+
real(kind=4) :: x
20+
qerfc_scaled16_error4 = qerfc_scaled(x);
21+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(4)'
22+
end function qerfc_scaled16_error4
23+
24+
function qerfc_scaled16_error8(x)
25+
real(kind=16) :: qerfc_scaled16_error8
26+
real(kind=8) :: x
27+
qerfc_scaled16_error8 = qerfc_scaled(x);
28+
! ERROR: Actual argument for 'x=' has bad type or kind 'REAL(8)'
29+
end function qerfc_scaled16_error8

0 commit comments

Comments
 (0)