1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
//===-- lib/Evaluate/fold-character.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "fold-implementation.h"
#include "fold-reduction.h"
namespace Fortran::evaluate {
static std::optional<ConstantSubscript> GetConstantLength(
FoldingContext &context, Expr<SomeType> &&expr) {
expr = Fold(context, std::move(expr));
if (auto *chExpr{UnwrapExpr<Expr<SomeCharacter>>(expr)}) {
if (auto len{chExpr->LEN()}) {
return ToInt64(*len);
}
}
return std::nullopt;
}
template <typename T>
static std::optional<ConstantSubscript> GetConstantLength(
FoldingContext &context, FunctionRef<T> &funcRef, int zeroBasedArg) {
if (auto *expr{funcRef.UnwrapArgExpr(zeroBasedArg)}) {
return GetConstantLength(context, std::move(*expr));
} else {
return std::nullopt;
}
}
template <typename T>
static std::optional<Scalar<T>> Identity(
Scalar<T> str, std::optional<ConstantSubscript> len) {
if (len) {
return CharacterUtils<T::kind>::REPEAT(
str, std::max<ConstantSubscript>(*len, 0));
} else {
return std::nullopt;
}
}
template <int KIND>
Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
FoldingContext &context,
FunctionRef<Type<TypeCategory::Character, KIND>> &&funcRef) {
using T = Type<TypeCategory::Character, KIND>;
using StringType = Scalar<T>; // std::string or larger
using SingleCharType = typename StringType::value_type; // char &c.
auto *intrinsic{std::get_if<SpecificIntrinsic>(&funcRef.proc().u)};
CHECK(intrinsic);
std::string name{intrinsic->name};
if (name == "achar" || name == "char") {
using IntT = SubscriptInteger;
return FoldElementalIntrinsic<T, IntT>(context, std::move(funcRef),
ScalarFunc<T, IntT>([](const Scalar<IntT> &i) {
return CharacterUtils<KIND>::CHAR(i.ToUInt64());
}));
} else if (name == "adjustl") {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), CharacterUtils<KIND>::ADJUSTL);
} else if (name == "adjustr") {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), CharacterUtils<KIND>::ADJUSTR);
} else if (name == "max") {
return FoldMINorMAX(context, std::move(funcRef), Ordering::Greater);
} else if (name == "maxval") {
SingleCharType least{0};
if (auto identity{Identity<T>(
StringType{least}, GetConstantLength(context, funcRef, 0))}) {
return FoldMaxvalMinval<T>(
context, std::move(funcRef), RelationalOperator::GT, *identity);
}
} else if (name == "merge") {
return FoldMerge<T>(context, std::move(funcRef));
} else if (name == "min") {
return FoldMINorMAX(context, std::move(funcRef), Ordering::Less);
} else if (name == "minval") {
// Collating sequences correspond to positive integers (3.31)
SingleCharType most{0x7fffffff >> (8 * (4 - KIND))};
if (auto identity{Identity<T>(
StringType{most}, GetConstantLength(context, funcRef, 0))}) {
return FoldMaxvalMinval<T>(
context, std::move(funcRef), RelationalOperator::LT, *identity);
}
} else if (name == "new_line") {
return Expr<T>{Constant<T>{CharacterUtils<KIND>::NEW_LINE()}};
} else if (name == "repeat") { // not elemental
if (auto scalars{GetScalarConstantArguments<T, SubscriptInteger>(
context, funcRef.arguments())}) {
return Expr<T>{Constant<T>{
CharacterUtils<KIND>::REPEAT(std::get<Scalar<T>>(*scalars),
std::get<Scalar<SubscriptInteger>>(*scalars).ToInt64())}};
}
} else if (name == "trim") { // not elemental
if (auto scalar{
GetScalarConstantArguments<T>(context, funcRef.arguments())}) {
return Expr<T>{Constant<T>{
CharacterUtils<KIND>::TRIM(std::get<Scalar<T>>(*scalar))}};
}
}
// TODO: cshift, eoshift, maxloc, minloc, pack, spread, transfer,
// transpose, unpack
return Expr<T>{std::move(funcRef)};
}
template <int KIND>
Expr<Type<TypeCategory::Character, KIND>> FoldOperation(
FoldingContext &context, Concat<KIND> &&x) {
if (auto array{ApplyElementwise(context, x)}) {
return *array;
}
using Result = Type<TypeCategory::Character, KIND>;
if (auto folded{OperandsAreConstants(x)}) {
return Expr<Result>{Constant<Result>{folded->first + folded->second}};
}
return Expr<Result>{std::move(x)};
}
template <int KIND>
Expr<Type<TypeCategory::Character, KIND>> FoldOperation(
FoldingContext &context, SetLength<KIND> &&x) {
if (auto array{ApplyElementwise(context, x)}) {
return *array;
}
using Result = Type<TypeCategory::Character, KIND>;
if (auto folded{OperandsAreConstants(x)}) {
auto oldLength{static_cast<ConstantSubscript>(folded->first.size())};
auto newLength{folded->second.ToInt64()};
if (newLength < oldLength) {
folded->first.erase(newLength);
} else {
folded->first.append(newLength - oldLength, ' ');
}
CHECK(static_cast<ConstantSubscript>(folded->first.size()) == newLength);
return Expr<Result>{Constant<Result>{std::move(folded->first)}};
}
return Expr<Result>{std::move(x)};
}
FOR_EACH_CHARACTER_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeCharacter>;
} // namespace Fortran::evaluate
|