1 //===-- lib/Evaluate/fold-complex.cpp -------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "fold-implementation.h"
10 #include "fold-matmul.h"
11 #include "fold-reduction.h"
13 namespace Fortran::evaluate
{
16 Expr
<Type
<TypeCategory::Complex
, KIND
>> FoldIntrinsicFunction(
17 FoldingContext
&context
,
18 FunctionRef
<Type
<TypeCategory::Complex
, KIND
>> &&funcRef
) {
19 using T
= Type
<TypeCategory::Complex
, KIND
>;
20 using Part
= typename
T::Part
;
21 ActualArguments
&args
{funcRef
.arguments()};
22 auto *intrinsic
{std::get_if
<SpecificIntrinsic
>(&funcRef
.proc().u
)};
24 std::string name
{intrinsic
->name
};
25 if (name
== "acos" || name
== "acosh" || name
== "asin" || name
== "asinh" ||
26 name
== "atan" || name
== "atanh" || name
== "cos" || name
== "cosh" ||
27 name
== "exp" || name
== "log" || name
== "sin" || name
== "sinh" ||
28 name
== "sqrt" || name
== "tan" || name
== "tanh") {
29 if (auto callable
{GetHostRuntimeWrapper
<T
, T
>(name
)}) {
30 return FoldElementalIntrinsic
<T
, T
>(
31 context
, std::move(funcRef
), *callable
);
32 } else if (context
.languageFeatures().ShouldWarn(
33 common::UsageWarning::FoldingFailure
)) {
34 context
.messages().Say(common::UsageWarning::FoldingFailure
,
35 "%s(complex(kind=%d)) cannot be folded on host"_warn_en_US
, name
,
38 } else if (name
== "conjg") {
39 return FoldElementalIntrinsic
<T
, T
>(
40 context
, std::move(funcRef
), &Scalar
<T
>::CONJG
);
41 } else if (name
== "cmplx") {
42 if (args
.size() > 0 && args
[0].has_value()) {
43 if (auto *x
{UnwrapExpr
<Expr
<SomeComplex
>>(args
[0])}) {
44 // CMPLX(X [, KIND]) with complex X
45 return Fold(context
, ConvertToType
<T
>(std::move(*x
)));
47 if (args
.size() >= 2 && args
[1].has_value()) {
48 // Do not fold CMPLX with an Y argument that may be absent at runtime
49 // into a complex constructor so that lowering can deal with the
50 // optional aspect (there is no optional aspect with the complex
52 if (MayBePassedAsAbsentOptional(*args
[1]->UnwrapExpr())) {
53 return Expr
<T
>{std::move(funcRef
)};
56 // CMPLX(X [, Y [, KIND]]) with non-complex X
57 Expr
<SomeType
> re
{std::move(*args
[0].value().UnwrapExpr())};
58 Expr
<SomeType
> im
{args
.size() >= 2 && args
[1].has_value()
59 ? std::move(*args
[1]->UnwrapExpr())
60 : AsGenericExpr(Constant
<Part
>{Scalar
<Part
>{}})};
63 ComplexConstructor
<KIND
>{ToReal
<KIND
>(context
, std::move(re
)),
64 ToReal
<KIND
>(context
, std::move(im
))}});
67 } else if (name
== "dot_product") {
68 return FoldDotProduct
<T
>(context
, std::move(funcRef
));
69 } else if (name
== "matmul") {
70 return FoldMatmul(context
, std::move(funcRef
));
71 } else if (name
== "product") {
72 auto one
{Scalar
<Part
>::FromInteger(value::Integer
<8>{1}).value
};
73 return FoldProduct
<T
>(context
, std::move(funcRef
), Scalar
<T
>{one
});
74 } else if (name
== "sum") {
75 return FoldSum
<T
>(context
, std::move(funcRef
));
77 return Expr
<T
>{std::move(funcRef
)};
81 Expr
<Type
<TypeCategory::Complex
, KIND
>> FoldOperation(
82 FoldingContext
&context
, ComplexConstructor
<KIND
> &&x
) {
83 if (auto array
{ApplyElementwise(context
, x
)}) {
86 using Result
= Type
<TypeCategory::Complex
, KIND
>;
87 if (auto folded
{OperandsAreConstants(x
)}) {
89 Constant
<Result
>{Scalar
<Result
>{folded
->first
, folded
->second
}}};
91 return Expr
<Result
>{std::move(x
)};
94 #ifdef _MSC_VER // disable bogus warning about missing definitions
95 #pragma warning(disable : 4661)
97 FOR_EACH_COMPLEX_KIND(template class ExpressionBase
, )
98 template class ExpressionBase
<SomeComplex
>;
99 } // namespace Fortran::evaluate