Skip to content

Commit 9b04319

Browse files
committed
[flang] Define ERF, ERFC and ERFC_SCALED with Q and D prefix name
1 parent ab18cc2 commit 9b04319

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
@@ -1195,6 +1197,9 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
11951197
DoublePrecision},
11961198
"dim"},
11971199
{{"derf", {{"x", DoublePrecision}}, DoublePrecision}, "erf"},
1200+
{{"derfc", {{"x", DoublePrecision}}, DoublePrecision}, "erfc"},
1201+
{{"derfc_scaled", {{"x", DoublePrecision}}, DoublePrecision},
1202+
"erfc_scaled"},
11981203
{{"dexp", {{"x", DoublePrecision}}, DoublePrecision}, "exp"},
11991204
{{"dfloat", {{"a", AnyInt}}, DoublePrecision}, "real", true},
12001205
{{"dim", {{"x", DefaultReal}, {"y", DefaultReal}}, DefaultReal}},
@@ -1295,6 +1300,9 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
12951300
"min", true, true},
12961301
{{"mod", {{"a", DefaultInt}, {"p", DefaultInt}}, DefaultInt}},
12971302
{{"nint", {{"a", DefaultReal}}, DefaultInt}},
1303+
{{"qerf", {{"x", QuadPrecision}}, QuadPrecision}, "erf"},
1304+
{{"qerfc", {{"x", QuadPrecision}}, QuadPrecision}, "erfc"},
1305+
{{"qerfc_scaled", {{"x", QuadPrecision}}, QuadPrecision}, "erfc_scaled"},
12981306
{{"sign", {{"a", DefaultReal}, {"b", DefaultReal}}, DefaultReal}},
12991307
{{"sin", {{"x", DefaultReal}}, DefaultReal}},
13001308
{{"sinh", {{"x", DefaultReal}}, DefaultReal}},
@@ -2023,6 +2031,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
20232031
case KindCode::doublePrecision:
20242032
argOk = type->kind() == defaults.doublePrecisionKind();
20252033
break;
2034+
case KindCode::quadPrecision:
2035+
argOk = type->kind() == defaults.quadPrecisionKind();
2036+
break;
20262037
case KindCode::defaultCharKind:
20272038
argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Character);
20282039
break;
@@ -2333,6 +2344,18 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
23332344
CHECK(FloatingType.test(*category));
23342345
resultType = DynamicType{*category, defaults.doublePrecisionKind()};
23352346
break;
2347+
case KindCode::quadPrecision:
2348+
CHECK(result.categorySet == CategorySet{*category});
2349+
CHECK(FloatingType.test(*category));
2350+
resultType = DynamicType{*category, defaults.quadPrecisionKind()};
2351+
if (!context.targetCharacteristics().CanSupportType(
2352+
*category, defaults.quadPrecisionKind())) {
2353+
messages.Say(
2354+
"%s(KIND=%jd) type not supported on this target."_err_en_US,
2355+
parser::ToUpperCaseLetters(EnumToString(*category)),
2356+
defaults.quadPrecisionKind());
2357+
}
2358+
break;
23362359
case KindCode::defaultLogicalKind:
23372360
CHECK(result.categorySet == LogicalType);
23382361
CHECK(*category == TypeCategory::Logical);
@@ -3331,6 +3354,7 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33313354
case KindCode::defaultIntegerKind:
33323355
break;
33333356
case KindCode::doublePrecision:
3357+
case KindCode::quadPrecision:
33343358
case KindCode::defaultRealKind:
33353359
category = TypeCategory::Real;
33363360
break;
@@ -3339,6 +3363,8 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33393363
}
33403364
int kind{interface.result.kindCode == KindCode::doublePrecision
33413365
? defaults.doublePrecisionKind()
3366+
: interface.result.kindCode == KindCode::quadPrecision
3367+
? defaults.quadPrecisionKind()
33423368
: defaults.GetDefaultKind(category)};
33433369
return DynamicType{category, kind};
33443370
}
@@ -3579,6 +3605,8 @@ DynamicType IntrinsicProcTable::Implementation::GetSpecificType(
35793605
TypeCategory category{set.LeastElement().value()};
35803606
if (pattern.kindCode == KindCode::doublePrecision) {
35813607
return DynamicType{category, defaults_.doublePrecisionKind()};
3608+
} else if (pattern.kindCode == KindCode::quadPrecision) {
3609+
return DynamicType{category, defaults_.quadPrecisionKind()};
35823610
} else if (category == TypeCategory::Character) {
35833611
// All character arguments to specific intrinsic functions are
35843612
// 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)