1 //===-- lib/Evaluate/fold-complex.cpp -------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "fold-implementation.h" 10 #include "fold-matmul.h" 11 #include "fold-reduction.h" 12 13 namespace Fortran::evaluate { 14 15 template <int KIND> 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)}; 23 CHECK(intrinsic); 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, 36 KIND); 37 } 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))); 46 } else { 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 51 // constructor). 52 if (MayBePassedAsAbsentOptional(*args[1]->UnwrapExpr())) { 53 return Expr<T>{std::move(funcRef)}; 54 } 55 } 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>{}})}; 61 return Fold(context, 62 Expr<T>{ 63 ComplexConstructor<KIND>{ToReal<KIND>(context, std::move(re)), 64 ToReal<KIND>(context, std::move(im))}}); 65 } 66 } 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)); 76 } 77 return Expr<T>{std::move(funcRef)}; 78 } 79 80 template <int KIND> 81 Expr<Type<TypeCategory::Complex, KIND>> FoldOperation( 82 FoldingContext &context, ComplexConstructor<KIND> &&x) { 83 if (auto array{ApplyElementwise(context, x)}) { 84 return *array; 85 } 86 using Result = Type<TypeCategory::Complex, KIND>; 87 if (auto folded{OperandsAreConstants(x)}) { 88 return Expr<Result>{ 89 Constant<Result>{Scalar<Result>{folded->first, folded->second}}}; 90 } 91 return Expr<Result>{std::move(x)}; 92 } 93 94 #ifdef _MSC_VER // disable bogus warning about missing definitions 95 #pragma warning(disable : 4661) 96 #endif 97 FOR_EACH_COMPLEX_KIND(template class ExpressionBase, ) 98 template class ExpressionBase<SomeComplex>; 99 } // namespace Fortran::evaluate 100