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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
//===-- 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) {
if (i.IsNegative() || i.BGE(Scalar<IntT>{0}.IBSET(8 * KIND))) {
context.messages().Say(
"%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
parser::ToUpperCaseLetters(name),
static_cast<std::intmax_t>(i.ToInt64()), KIND);
}
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())}) {
auto str{std::get<Scalar<T>>(*scalars)};
auto n{std::get<Scalar<SubscriptInteger>>(*scalars).ToInt64()};
if (n < 0) {
context.messages().Say(
"NCOPIES= argument to REPEAT() should be nonnegative, but is %jd"_err_en_US,
static_cast<std::intmax_t>(n));
} else if (static_cast<double>(n) * str.size() >
(1 << 20)) { // sanity limit of 1MiB
context.messages().Say(
"Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
static_cast<double>(n) * str.size());
} else {
return Expr<T>{Constant<T>{CharacterUtils<KIND>::REPEAT(str, n)}};
}
}
} 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))}};
}
} else if (name == "__builtin_compiler_options") {
auto &o = context.targetCharacteristics().compilerOptionsString();
return Expr<T>{Constant<T>{StringType(o.begin(), o.end())}};
} else if (name == "__builtin_compiler_version") {
auto &v = context.targetCharacteristics().compilerVersionString();
return Expr<T>{Constant<T>{StringType(v.begin(), v.end())}};
}
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)};
}
#ifdef _MSC_VER // disable bogus warning about missing definitions
#pragma warning(disable : 4661)
#endif
FOR_EACH_CHARACTER_KIND(template class ExpressionBase, )
template class ExpressionBase<SomeCharacter>;
} // namespace Fortran::evaluate
|