Skip to content

Commit 1912115

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

File tree

11 files changed

+198
-5
lines changed

11 files changed

+198
-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: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static constexpr CategorySet AnyType{IntrinsicType | DerivedType};
8383

8484
ENUM_CLASS(KindCode, none, defaultIntegerKind,
8585
defaultRealKind, // is also the default COMPLEX kind
86-
doublePrecision, defaultCharKind, defaultLogicalKind,
86+
doublePrecision, quadPrecision, defaultCharKind, defaultLogicalKind,
8787
greaterOrEqualToKind, // match kind value greater than or equal to a single
8888
// explicit kind value
8989
any, // matches any kind value; each instance is independent
@@ -139,6 +139,7 @@ static constexpr TypePattern DoublePrecision{
139139
RealType, KindCode::doublePrecision};
140140
static constexpr TypePattern DoublePrecisionComplex{
141141
ComplexType, KindCode::doublePrecision};
142+
static constexpr TypePattern QuadPrecision{RealType, KindCode::quadPrecision};
142143
static constexpr TypePattern SubscriptInt{IntType, KindCode::subscript};
143144

144145
// Match any kind of some intrinsic or derived types
@@ -434,6 +435,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
434435
{"shift", AnyInt, Rank::dimRemovedOrScalar}, OptionalDIM},
435436
SameType, Rank::conformable, IntrinsicClass::transformationalFunction},
436437
{"dble", {{"a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision},
438+
{"derf", {{"x", DoublePrecision}}, DoublePrecision},
439+
{"derfc", {{"x", DoublePrecision}}, DoublePrecision},
440+
{"derfc_scaled", {{"x", DoublePrecision}}, DoublePrecision},
437441
{"digits",
438442
{{"x", AnyIntUnsignedOrReal, Rank::anyOrAssumedRank,
439443
Optionality::required, common::Intent::In,
@@ -836,6 +840,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
836840
DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction},
837841
{"present", {{"a", Addressable, Rank::anyOrAssumedRank}}, DefaultLogical,
838842
Rank::scalar, IntrinsicClass::inquiryFunction},
843+
{"qerf", {{"x", QuadPrecision}}, QuadPrecision},
844+
{"qerfc", {{"x", QuadPrecision}}, QuadPrecision},
845+
{"qerfc_scaled", {{"x", QuadPrecision}}, QuadPrecision},
839846
{"radix",
840847
{{"x", AnyIntOrReal, Rank::anyOrAssumedRank, Optionality::required,
841848
common::Intent::In, {ArgFlag::canBeMoldNull}}},
@@ -2023,6 +2030,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
20232030
case KindCode::doublePrecision:
20242031
argOk = type->kind() == defaults.doublePrecisionKind();
20252032
break;
2033+
case KindCode::quadPrecision:
2034+
argOk = type->kind() == defaults.quadPrecisionKind();
2035+
break;
20262036
case KindCode::defaultCharKind:
20272037
argOk = type->kind() == defaults.GetDefaultKind(TypeCategory::Character);
20282038
break;
@@ -2333,6 +2343,11 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
23332343
CHECK(FloatingType.test(*category));
23342344
resultType = DynamicType{*category, defaults.doublePrecisionKind()};
23352345
break;
2346+
case KindCode::quadPrecision:
2347+
CHECK(result.categorySet == CategorySet{*category});
2348+
CHECK(FloatingType.test(*category));
2349+
resultType = DynamicType{*category, defaults.quadPrecisionKind()};
2350+
break;
23362351
case KindCode::defaultLogicalKind:
23372352
CHECK(result.categorySet == LogicalType);
23382353
CHECK(*category == TypeCategory::Logical);
@@ -3331,6 +3346,7 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33313346
case KindCode::defaultIntegerKind:
33323347
break;
33333348
case KindCode::doublePrecision:
3349+
case KindCode::quadPrecision:
33343350
case KindCode::defaultRealKind:
33353351
category = TypeCategory::Real;
33363352
break;
@@ -3339,6 +3355,8 @@ static DynamicType GetReturnType(const SpecificIntrinsicInterface &interface,
33393355
}
33403356
int kind{interface.result.kindCode == KindCode::doublePrecision
33413357
? defaults.doublePrecisionKind()
3358+
: interface.result.kindCode == KindCode::quadPrecision
3359+
? defaults.quadPrecisionKind()
33423360
: defaults.GetDefaultKind(category)};
33433361
return DynamicType{category, kind};
33443362
}
@@ -3579,6 +3597,8 @@ DynamicType IntrinsicProcTable::Implementation::GetSpecificType(
35793597
TypeCategory category{set.LeastElement().value()};
35803598
if (pattern.kindCode == KindCode::doublePrecision) {
35813599
return DynamicType{category, defaults_.doublePrecisionKind()};
3600+
} else if (pattern.kindCode == KindCode::quadPrecision) {
3601+
return DynamicType{category, defaults_.quadPrecisionKind()};
35823602
} else if (category == TypeCategory::Character) {
35833603
// All character arguments to specific intrinsic functions are
35843604
// assumed-length.

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ static constexpr IntrinsicHandler handlers[]{
400400
{"values", asBox, handleDynamicOptional}}},
401401
/*isElemental=*/false},
402402
{"dble", &I::genConversion},
403+
{"derfc_scaled",
404+
&I::genErfcScaled,
405+
{{{"x", asValue}}},
406+
/*isElemental=*/true},
403407
{"dim", &I::genDim},
404408
{"dot_product",
405409
&I::genDotProduct,
@@ -761,6 +765,10 @@ static constexpr IntrinsicHandler handlers[]{
761765
{"dim", asValue},
762766
{"mask", asBox, handleDynamicOptional}}},
763767
/*isElemental=*/false},
768+
{"qerfc_scaled",
769+
&I::genErfcScaled,
770+
{{{"x", asValue}}},
771+
/*isElemental=*/true},
764772
{"random_init",
765773
&I::genRandomInit,
766774
{{{"repeatable", asValue}, {"image_distinct", asValue}}},
@@ -1393,6 +1401,10 @@ static constexpr MathOperation mathOperations[] = {
13931401
{"cosh", "ccosh", genFuncType<Ty::Complex<8>, Ty::Complex<8>>, genLibCall},
13941402
{"cosh", RTNAME_STRING(CCoshF128), FuncTypeComplex16Complex16,
13951403
genLibF128Call},
1404+
{"derf", "erf", genFuncType<Ty::Real<8>, Ty::Real<8>>,
1405+
genMathOp<mlir::math::ErfOp>},
1406+
{"derfc", "erfc", genFuncType<Ty::Real<8>, Ty::Real<8>>,
1407+
genMathOp<mlir::math::ErfcOp>},
13961408
{"divc",
13971409
{},
13981410
genFuncType<Ty::Complex<2>, Ty::Complex<2>, Ty::Complex<2>>,
@@ -1576,6 +1588,8 @@ static constexpr MathOperation mathOperations[] = {
15761588
genFuncType<Ty::Complex<8>, Ty::Complex<8>, Ty::Integer<8>>, genLibCall},
15771589
{"pow", RTNAME_STRING(cqpowk), FuncTypeComplex16Complex16Integer8,
15781590
genLibF128Call},
1591+
{"qerf", RTNAME_STRING(ErfF128), FuncTypeReal16Real16, genLibF128Call},
1592+
{"qerfc", RTNAME_STRING(ErfcF128), FuncTypeReal16Real16, genLibF128Call},
15791593
{"remainder", "remainderf",
15801594
genFuncType<Ty::Real<4>, Ty::Real<4>, Ty::Real<4>>, genLibCall},
15811595
{"remainder", "remainder",

flang/test/Lower/Intrinsics/erf.f90

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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
17+
18+
function qtest_real16(x)
19+
real(16) :: x, qtest_real16
20+
qtest_real16 = qerf(x)
21+
end function
22+
23+
! ALL-LABEL: @_QPqtest_real16
24+
! CHECK: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAErfF128({{%[A-Za-z0-9._]+}}) {{.*}}: (f128) -> f128

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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,21 @@ 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
37+
38+
function qtest_real16(x)
39+
real(16) :: x, qtest_real16
40+
qtest_real16 = qerfc(x)
41+
end function
42+
43+
! ALL-LABEL: @_QPqtest_real16
44+
! ALL: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAErfcF128({{%[A-Za-z0-9._]+}}) {{.*}}: (f128)

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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,23 @@ 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
35+
36+
! CHECK-LABEL: func @_QPqerfc_scaled16(
37+
! CHECK: %[[a1:.*]] = fir.load %[[x]] : !fir.ref<f128>
38+
function qerfc_scaled16(x)
39+
real(kind=16) :: qerfc_scaled16
40+
real(kind=16) :: x
41+
qerfc_scaled16 = qerfc_scaled(x);
42+
! CHECK: %{{.*}} = fir.call @_FortranAErfcScaled16(%[[a1]]) {{.*}}: (f128) -> f128
43+
end function qerfc_scaled16

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)