================
@@ -1931,159 +1988,171 @@ template <typename DERIVED, typename RESULT, typename
LEFT, typename RIGHT>
auto ApplyElementwise(
FoldingContext &context, Operation<DERIVED, RESULT, LEFT, RIGHT>
&operation)
-> std::optional<Expr<RESULT>> {
+ const int kind{operation.kind()};
return ApplyElementwise(context, operation,
std::function<Expr<RESULT>(Expr<LEFT> &&, Expr<RIGHT> &&)>{
- [](Expr<LEFT> &&left, Expr<RIGHT> &&right) {
- return Expr<RESULT>{DERIVED{std::move(left), std::move(right)}};
+ [kind](Expr<LEFT> &&left, Expr<RIGHT> &&right) {
+ return Expr<RESULT>{
+ DERIVED{kind, std::move(left), std::move(right)}};
}});
}
// Unary operations
template <typename TO, typename FROM>
-common::IfNoLvalue<std::optional<TO>, FROM> ConvertString(FROM &&s) {
- if constexpr (std::is_same_v<TO, FROM>) {
+common::IfNoLvalue<std::optional<TO>, FROM> ConvertString(
+ int toKind, FROM &&s) {
+ const int fromKind{s.kind()};
+ if (std::is_same_v<TO, FROM> && toKind == fromKind) {
return std::make_optional<TO>(std::move(s));
+ } else if (auto result{s.ToAscii(toKind)}; !result.IsNull()) {
+ return result;
} else {
- // Fortran character conversion is well defined between distinct kinds
- // only when the actual characters are valid 7-bit ASCII.
- TO str;
- for (auto iter{s.cbegin()}; iter != s.cend(); ++iter) {
- if (static_cast<std::uint64_t>(*iter) > 127) {
- return std::nullopt;
- }
- str.push_back(static_cast<typename TO::value_type>(*iter));
- }
- return std::make_optional<TO>(std::move(str));
+ return std::nullopt;
}
}
template <typename TO, TypeCategory FROMCAT>
Expr<TO> FoldOperation(
FoldingContext &context, Convert<TO, FROMCAT> &&convert) {
+ const int toKind{convert.kind()};
if (auto array{ApplyElementwise(context, convert)}) {
return *array;
}
struct {
FoldingContext &context;
Convert<TO, FROMCAT> &convert;
- } msvcWorkaround{context, convert};
+ int toKind;
+ } msvcWorkaround{context, convert, toKind};
return common::visit(
[&msvcWorkaround](auto &kindExpr) -> Expr<TO> {
using Operand = ResultType<decltype(kindExpr)>;
+ const int operandKind{kindExpr.kind()};
+ const int toKind{msvcWorkaround.toKind};
// This variable is a workaround for msvc which emits an error when
// using the FROMCAT template parameter below.
TypeCategory constexpr FromCat{FROMCAT};
static_assert(FromCat == Operand::category);
auto &convert{msvcWorkaround.convert};
if (auto value{GetScalarConstantValue<Operand>(kindExpr)}) {
FoldingContext &ctx{msvcWorkaround.context};
+ const int fromKind{value->kind()};
if constexpr (TO::category == TypeCategory::Integer) {
if constexpr (FromCat == TypeCategory::Integer) {
- auto converted{Scalar<TO>::ConvertSigned(*value)};
+ auto converted{Scalar<TO>::ConvertSigned(toKind, *value)};
if (converted.overflow) {
ctx.Warn(common::UsageWarning::FoldingException,
"conversion of %s_%d to INTEGER(%d) overflowed; result is
%s"_warn_en_US,
- value->SignedDecimal(), Operand::kind, TO::kind,
+ value->SignedDecimal(), fromKind, toKind,
converted.value.SignedDecimal());
}
- return ScalarConstantToExpr(std::move(converted.value));
+ return MakeConstantExpr<TO>(toKind, std::move(converted.value));
} else if constexpr (FromCat == TypeCategory::Unsigned) {
- auto converted{Scalar<TO>::ConvertUnsigned(*value)};
+ auto converted{Scalar<TO>::ConvertUnsigned(toKind, *value)};
if ((converted.overflow || converted.value.IsNegative())) {
ctx.Warn(common::UsageWarning::FoldingException,
"conversion of %s_U%d to INTEGER(%d) overflowed; result is
%s"_warn_en_US,
- value->UnsignedDecimal(), Operand::kind, TO::kind,
+ value->UnsignedDecimal(), fromKind, toKind,
converted.value.SignedDecimal());
}
- return ScalarConstantToExpr(std::move(converted.value));
+ return MakeConstantExpr<TO>(toKind, std::move(converted.value));
} else if constexpr (FromCat == TypeCategory::Real) {
- auto converted{value->template ToInteger<Scalar<TO>>()};
+ auto converted{value->ToInteger(
+ common::RoundingMode::ToZero, Scalar<TO>::bits(toKind))};
if (converted.flags.test(RealFlag::InvalidArgument)) {
ctx.Warn(common::UsageWarning::FoldingException,
"REAL(%d) to INTEGER(%d) conversion: invalid
argument"_warn_en_US,
- Operand::kind, TO::kind);
+ fromKind, toKind);
} else if (converted.flags.test(RealFlag::Overflow)) {
ctx.Warn(common::UsageWarning::FoldingException,
"REAL(%d) to INTEGER(%d) conversion overflowed"_warn_en_US,
- Operand::kind, TO::kind);
+ fromKind, toKind);
}
- return ScalarConstantToExpr(std::move(converted.value));
+ return MakeConstantExpr<TO>(toKind, std::move(converted.value));
}
} else if constexpr (TO::category == TypeCategory::Unsigned) {
if constexpr (FromCat == TypeCategory::Integer ||
FromCat == TypeCategory::Unsigned) {
- return Expr<TO>{
- Constant<TO>{Scalar<TO>::ConvertUnsigned(*value).value}};
+ return MakeConstantExpr<TO>(
+ toKind, Scalar<TO>::ConvertUnsigned(toKind, *value).value);
} else if constexpr (FromCat == TypeCategory::Real) {
- return Expr<TO>{
- Constant<TO>{value->template ToInteger<Scalar<TO>>().value}};
+ return MakeConstantExpr<TO>(toKind,
+ value
+ ->ToInteger(common::RoundingMode::ToZero,
+ Scalar<TO>::bits(toKind))
+ .value);
}
} else if constexpr (TO::category == TypeCategory::Real) {
if constexpr (FromCat == TypeCategory::Integer ||
FromCat == TypeCategory::Unsigned) {
auto converted{Scalar<TO>::FromInteger(
- *value, FromCat == TypeCategory::Unsigned)};
+ toKind, *value, FromCat == TypeCategory::Unsigned)};
if (!converted.flags.empty()) {
char buffer[64];
std::snprintf(buffer, sizeof buffer,
- "INTEGER(%d) to REAL(%d) conversion", Operand::kind,
- TO::kind);
+ "INTEGER(%d) to REAL(%d) conversion", fromKind, toKind);
ctx.RealFlagWarnings(converted.flags, buffer);
}
- return ScalarConstantToExpr(std::move(converted.value));
+ return MakeConstantExpr<TO>(toKind, std::move(converted.value));
} else if constexpr (FromCat == TypeCategory::Real) {
- auto converted{Scalar<TO>::Convert(*value)};
+ auto converted{Scalar<TO>::Convert(toKind, *value)};
char buffer[64];
if (!converted.flags.empty()) {
std::snprintf(buffer, sizeof buffer,
- "REAL(%d) to REAL(%d) conversion", Operand::kind,
TO::kind);
+ "REAL(%d) to REAL(%d) conversion", fromKind, toKind);
ctx.RealFlagWarnings(converted.flags, buffer);
}
if (ctx.targetCharacteristics().areSubnormalsFlushedToZero()) {
converted.value = converted.value.FlushSubnormalToZero();
}
- return ScalarConstantToExpr(std::move(converted.value));
+ return MakeConstantExpr<TO>(toKind, std::move(converted.value));
}
} else if constexpr (TO::category == TypeCategory::Complex) {
if constexpr (FromCat == TypeCategory::Complex) {
return FoldOperation(ctx,
- ComplexConstructor<TO::kind>{
- AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
- Constant<typename Operand::Part>{value->REAL()})}),
- AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
- Constant<typename
Operand::Part>{value->AIMAG()})})});
+ ComplexConstructor{toKind,
+ Fold(ctx,
+ AsExpr(Convert<typename TO::Part>(toKind,
+ AsCategoryExpr(Constant<typename Operand::Part>{
+ toKind, value->REAL()})))),
+ Fold(ctx,
+ AsExpr(Convert<typename TO::Part>(toKind,
+ AsCategoryExpr(Constant<typename Operand::Part>{
+ toKind, value->AIMAG()}))))});
}
} else if constexpr (TO::category == TypeCategory::Character &&
FromCat == TypeCategory::Character) {
- if (auto converted{ConvertString<Scalar<TO>>(std::move(*value))}) {
+ if (auto converted{
+ ConvertString<Scalar<TO>>(toKind, std::move(*value))}) {
return ScalarConstantToExpr(std::move(*converted));
}
} else if constexpr (TO::category == TypeCategory::Logical &&
FromCat == TypeCategory::Logical) {
- return Expr<TO>{value->IsTrue()};
+ return MakeConstantExpr<TO>(toKind, value->IsTrue());
}
} else if constexpr (TO::category == FromCat &&
FromCat != TypeCategory::Character) {
// Conversion of non-constant in same type category
- if constexpr (std::is_same_v<Operand, TO>) {
+ if (Operand::category == TO::category && toKind == operandKind) {
return std::move(kindExpr); // remove needless conversion
} else if constexpr (TO::category == TypeCategory::Logical ||
TO::category == TypeCategory::Integer) {
if (auto *innerConv{
std::get_if<Convert<Operand, TO::category>>(&kindExpr.u)})
{
// Conversion of conversion of same category & kind
if (auto *x{std::get_if<Expr<TO>>(&innerConv->left().u)}) {
- if constexpr (TO::category == TypeCategory::Logical ||
- TO::kind <= Operand::kind) {
+ if (TO::category == TypeCategory::Logical ||
+ toKind <= operandKind) {
----------------
tblah wrote:
I think this needs to be `==`. The relational operator isn't new, but it is
newly exposed. Previously, the kind was encoded into the type and so the
`get_if` would fail if the kinds differed. Now this code is actually reachable
with non-equal kinds.
Otherwise something like `integer(8) :: x`,
`int(int(x,kind=4),kind=2)` therefore returns `x` and drops both
conversions
https://github.com/llvm/llvm-project/pull/216960
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits