forked from OSchip/llvm-project
[flang] mixed z+i, z+r expressions
Original-commit: flang-compiler/f18@5c5d11c1f7 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
0b2d90bc00
commit
63a26fc7dc
|
@ -68,13 +68,13 @@ template<typename T> struct Constant {
|
|||
Value value;
|
||||
};
|
||||
|
||||
// BOZ literal constants need to be wide enough to hold an integer or real
|
||||
// value of any supported kind. They also need to be distinguishable from
|
||||
// BOZ literal "typeless" constants must be wide enough to hold a numeric
|
||||
// value of any supported kind. They must also be distinguishable from
|
||||
// other integer constants, since they are permitted to be used in only a
|
||||
// few situations.
|
||||
using BOZLiteralConstant = value::Integer<128>;
|
||||
using BOZLiteralConstant = value::Integer<8 * 2 * DefaultComplex::kind>;
|
||||
|
||||
// "Typeless" operands to INTEGER and REAL operations.
|
||||
// "Typeless" operands to INTEGER, REAL, and COMPLEX operations.
|
||||
template<typename T> struct BOZConstant {
|
||||
using Result = T;
|
||||
using Value = BOZLiteralConstant;
|
||||
|
@ -469,8 +469,8 @@ public:
|
|||
using Operations = std::variant<Parentheses<Result>, Negate<Result>,
|
||||
Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
|
||||
Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
|
||||
using Others = std::variant<Constant<Result>, DataReference<Result>,
|
||||
FunctionReference<Result>>;
|
||||
using Others = std::variant<Constant<Result>, BOZConstant<Result>,
|
||||
DataReference<Result>, FunctionReference<Result>>;
|
||||
|
||||
public:
|
||||
common::CombineVariants<Operations, Others> u;
|
||||
|
|
|
@ -57,11 +57,85 @@ ConvertRealOperandsResult ConvertRealOperands(
|
|||
std::move(x.u), std::move(y.u));
|
||||
}
|
||||
|
||||
// A helper template for NumericOperation below.
|
||||
// A helper template for NumericOperation and its subroutines.
|
||||
template<TypeCategory CAT>
|
||||
std::optional<Expr<SomeType>> Package(Expr<SomeKind<CAT>> &&catExpr) {
|
||||
return {AsGenericExpr(std::move(catExpr))};
|
||||
}
|
||||
template<TypeCategory CAT>
|
||||
std::optional<Expr<SomeType>> Package(
|
||||
std::optional<Expr<SomeKind<CAT>>> &&catExpr) {
|
||||
if (catExpr.has_value()) {
|
||||
return {AsGenericExpr(std::move(*catExpr))};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Expr<SomeComplex>> ConstructComplex(
|
||||
parser::ContextualMessages &messages, Expr<SomeType> &&real,
|
||||
Expr<SomeType> &&imaginary) {
|
||||
if (auto converted{ConvertRealOperands(
|
||||
messages, std::move(real), std::move(imaginary))}) {
|
||||
return {std::visit(
|
||||
[](auto &&pair) {
|
||||
return MakeComplex(std::move(pair[0]), std::move(pair[1]));
|
||||
},
|
||||
std::move(*converted))};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Expr<SomeComplex>> ConstructComplex(
|
||||
parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&real,
|
||||
std::optional<Expr<SomeType>> &&imaginary) {
|
||||
if (auto parts{common::AllPresent(std::move(real), std::move(imaginary))}) {
|
||||
return ConstructComplex(messages, std::move(std::get<0>(*parts)),
|
||||
std::move(std::get<1>(*parts)));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Expr<SomeReal> GetComplexPart(const Expr<SomeComplex> &z, bool isImaginary) {
|
||||
return std::visit(
|
||||
[&](const auto &zk) {
|
||||
static constexpr int kind{ResultType<decltype(zk)>::kind};
|
||||
return AsCategoryExpr(AsExpr(ComplexComponent<kind>{isImaginary, zk}));
|
||||
},
|
||||
z.u);
|
||||
}
|
||||
|
||||
template<template<typename> class OPR>
|
||||
std::optional<Expr<SomeType>> MixedComplex(parser::ContextualMessages &messages,
|
||||
Expr<SomeComplex> &&zx, Expr<SomeType> &&iry) {
|
||||
Expr<SomeReal> zr{GetComplexPart(zx, false)};
|
||||
Expr<SomeReal> zi{GetComplexPart(zx, true)};
|
||||
if constexpr (std::is_same_v<OPR<DefaultReal>, Add<DefaultReal>> ||
|
||||
std::is_same_v<OPR<DefaultReal>, Subtract<DefaultReal>>) {
|
||||
// Addition and subtraction: apply the operation to the real part of the
|
||||
// complex operand, and a transfer/convert its imaginary part.
|
||||
// i.e., (a,b) + c = (a+c, b)
|
||||
if (std::optional<Expr<SomeType>> rr{
|
||||
NumericOperation<OPR>(messages, std::move(zr), std::move(iry))}) {
|
||||
return Package(ConstructComplex(messages, AsGenericExpr(std::move(*rr)),
|
||||
AsGenericExpr(std::move(zi))));
|
||||
}
|
||||
} else if constexpr (std::is_same_v<OPR<DefaultReal>,
|
||||
Multiply<DefaultReal>> ||
|
||||
std::is_same_v<OPR<DefaultReal>, Divide<DefaultReal>>) {
|
||||
// Multiplication and division of a COMPLEX value by an INTEGER or REAL
|
||||
// operand: apply the operation to both components of the COMPLEX value,
|
||||
// then convert and recombine them.
|
||||
// i.e., (a,b) * c = (a*c, b*c)
|
||||
auto copy{iry};
|
||||
auto rr{NumericOperation<OPR>(messages, std::move(zr), std::move(iry))};
|
||||
auto ri{NumericOperation<OPR>(messages, std::move(zi), std::move(copy))};
|
||||
if (auto parts{common::AllPresent(std::move(rr), std::move(ri))}) {
|
||||
return Package(ConstructComplex(messages, std::move(std::get<0>(*parts)),
|
||||
std::move(std::get<1>(*parts))));
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// N.B. When a "typeless" BOZ literal constant appears as one (not both!) of
|
||||
// the operands to a dyadic INTEGER or REAL operation, it assumes the type
|
||||
|
@ -93,8 +167,9 @@ std::optional<Expr<SomeType>> NumericOperation(
|
|||
return Package(std::visit(
|
||||
[&](auto &&ryk) -> Expr<SomeReal> {
|
||||
using resultType = ResultType<decltype(ryk)>;
|
||||
return AsCategoryExpr(AsExpr(OPR<resultType>{
|
||||
ConvertToType<resultType>(std::move(ix)), std::move(ryk)}));
|
||||
return AsCategoryExpr(AsExpr(
|
||||
OPR<resultType>{ConvertToType<resultType>(std::move(ix)),
|
||||
std::move(ryk)}));
|
||||
},
|
||||
std::move(ry.u)));
|
||||
},
|
||||
|
@ -102,19 +177,30 @@ std::optional<Expr<SomeType>> NumericOperation(
|
|||
return Package(PromoteAndCombine<OPR, TypeCategory::Complex>(
|
||||
std::move(zx), std::move(zy)));
|
||||
},
|
||||
[&](Expr<SomeComplex> &&zx, Expr<SomeInteger> &&zy) {
|
||||
return MixedComplex<OPR>(messages, std::move(zx), std::move(zy));
|
||||
},
|
||||
[&](Expr<SomeComplex> &&zx, Expr<SomeReal> &&zy) {
|
||||
return MixedComplex<OPR>(messages, std::move(zx), std::move(zy));
|
||||
},
|
||||
// TODO pmk: mixed r+complex, &c.; r/z is tricky
|
||||
// TODO pmk: mixed complex + boz? yes but what about COMPLEX*16?
|
||||
[&](BOZLiteralConstant &&bx, Expr<SomeInteger> &&iy) {
|
||||
return NumericOperation<OPR>(messages, ConvertTo(iy, std::move(bx)), std::move(y));
|
||||
return NumericOperation<OPR>(
|
||||
messages, ConvertTo(iy, std::move(bx)), std::move(y));
|
||||
},
|
||||
[&](BOZLiteralConstant &&bx, Expr<SomeReal> &&ry) {
|
||||
return NumericOperation<OPR>(messages, ConvertTo(ry, std::move(bx)), std::move(y));
|
||||
return NumericOperation<OPR>(
|
||||
messages, ConvertTo(ry, std::move(bx)), std::move(y));
|
||||
},
|
||||
[&](Expr<SomeInteger> &&ix, BOZLiteralConstant &&by) {
|
||||
return NumericOperation<OPR>(messages, std::move(x), ConvertTo(ix, std::move(by)));
|
||||
return NumericOperation<OPR>(
|
||||
messages, std::move(x), ConvertTo(ix, std::move(by)));
|
||||
},
|
||||
[&](Expr<SomeReal> &&rx, BOZLiteralConstant &&by) {
|
||||
return NumericOperation<OPR>(messages, std::move(x), ConvertTo(rx, std::move(by)));
|
||||
return NumericOperation<OPR>(
|
||||
messages, std::move(x), ConvertTo(rx, std::move(by)));
|
||||
},
|
||||
// TODO pmk mixed complex; Add/Sub different from Mult/Div
|
||||
[&](auto &&, auto &&) {
|
||||
messages.Say("non-numeric operands to numeric operation"_err_en_US);
|
||||
return std::optional<Expr<SomeType>>{std::nullopt};
|
||||
|
|
|
@ -89,6 +89,16 @@ template<> inline Expr<SomeType> AsGenericExpr(GenericScalar &&x) {
|
|||
x.u);
|
||||
}
|
||||
|
||||
Expr<SomeReal> GetComplexPart(
|
||||
const Expr<SomeComplex> &, bool isImaginary = false);
|
||||
|
||||
template<int KIND>
|
||||
Expr<SomeComplex> MakeComplex(Expr<Type<TypeCategory::Real, KIND>> &&re,
|
||||
Expr<Type<TypeCategory::Real, KIND>> &&im) {
|
||||
return AsCategoryExpr(
|
||||
AsExpr(ComplexConstructor<KIND>{std::move(re), std::move(im)}));
|
||||
}
|
||||
|
||||
// Creation of conversion expressions can be done to either a known
|
||||
// specific intrinsic type with ConvertToType<T>(x) or by converting
|
||||
// one arbitrary expression to the type of another with ConvertTo(to, from).
|
||||
|
@ -123,9 +133,9 @@ Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
|
|||
}
|
||||
}
|
||||
|
||||
template<typename TO>
|
||||
Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
|
||||
template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
|
||||
// TODO: check rank == 0
|
||||
// TODO: pmk: truncation warnings
|
||||
static_assert(TO::isSpecificType);
|
||||
return Expr<TO>{BOZConstant<TO>{std::move(x)}};
|
||||
}
|
||||
|
@ -170,11 +180,14 @@ Expr<SomeType> ConvertTo(const Expr<SomeType> &to, Expr<FT> &&from) {
|
|||
}
|
||||
|
||||
template<TypeCategory CAT>
|
||||
Expr<SomeType> ConvertTo(const Expr<SomeKind<CAT>> &to, BOZLiteralConstant &&from) {
|
||||
return AsGenericExpr(std::visit([&](const auto &tok) {
|
||||
using Ty = ResultType<decltype(tok)>;
|
||||
return AsCategoryExpr(ConvertToType<Ty>(std::move(from)));
|
||||
}, to.u));
|
||||
Expr<SomeType> ConvertTo(
|
||||
const Expr<SomeKind<CAT>> &to, BOZLiteralConstant &&from) {
|
||||
return AsGenericExpr(std::visit(
|
||||
[&](const auto &tok) {
|
||||
using Ty = ResultType<decltype(tok)>;
|
||||
return AsCategoryExpr(ConvertToType<Ty>(std::move(from)));
|
||||
},
|
||||
to.u));
|
||||
}
|
||||
|
||||
template<typename A, int N = 2> using SameExprs = std::array<Expr<A>, N>;
|
||||
|
@ -225,6 +238,15 @@ using ConvertRealOperandsResult =
|
|||
ConvertRealOperandsResult ConvertRealOperands(
|
||||
parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
|
||||
|
||||
// Per F'2018 R718, if both components are INTEGER, they are both converted
|
||||
// to default REAL and the result is default COMPLEX. Otherwise, the
|
||||
// kind of the result is the kind of most precise REAL component, and the other
|
||||
// component is converted if necessary to its type.
|
||||
std::optional<Expr<SomeComplex>> ConstructComplex(
|
||||
parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
|
||||
std::optional<Expr<SomeComplex>> ConstructComplex(parser::ContextualMessages &,
|
||||
std::optional<Expr<SomeType>> &&, std::optional<Expr<SomeType>> &&);
|
||||
|
||||
template<typename A> Expr<TypeOf<A>> ScalarConstantToExpr(const A &x) {
|
||||
using Ty = TypeOf<A>;
|
||||
static_assert(
|
||||
|
|
|
@ -104,8 +104,6 @@ struct ExprAnalyzer {
|
|||
MaybeExpr Analyze(const parser::Expr::DefinedBinary &); // TODO
|
||||
// TODO more remain
|
||||
|
||||
std::optional<Expr<SomeComplex>> ConstructComplex(MaybeExpr &&, MaybeExpr &&);
|
||||
|
||||
FoldingContext &context;
|
||||
const semantics::IntrinsicTypeDefaultKinds &defaults;
|
||||
};
|
||||
|
@ -337,32 +335,9 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::ComplexPart &x) {
|
|||
return AnalyzeHelper(*this, x.u);
|
||||
}
|
||||
|
||||
// Per F'2018 R718, if both components are INTEGER, they are both converted
|
||||
// to default REAL and the result is default COMPLEX. Otherwise, the
|
||||
// kind of the result is the kind of most precise REAL component, and the other
|
||||
// component is converted if necessary to its type.
|
||||
std::optional<Expr<SomeComplex>> ExprAnalyzer::ConstructComplex(
|
||||
MaybeExpr &&real, MaybeExpr &&imaginary) {
|
||||
if (auto parts{common::AllPresent(std::move(real), std::move(imaginary))}) {
|
||||
if (auto converted{ConvertRealOperands(context.messages,
|
||||
std::move(std::get<0>(*parts)), std::move(std::get<1>(*parts)))}) {
|
||||
return {std::visit(
|
||||
[](auto &&pair) -> std::optional<Expr<SomeComplex>> {
|
||||
using realType = ResultType<decltype(pair[0])>;
|
||||
using zType = SameKind<TypeCategory::Complex, realType>;
|
||||
auto cmplx{ComplexConstructor<zType::kind>{
|
||||
std::move(pair[0]), std::move(pair[1])}};
|
||||
return {AsCategoryExpr(AsExpr(std::move(cmplx)))};
|
||||
},
|
||||
std::move(*converted))};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::ComplexLiteralConstant &z) {
|
||||
return AsMaybeExpr(
|
||||
ConstructComplex(Analyze(std::get<0>(z.t)), Analyze(std::get<1>(z.t))));
|
||||
return AsMaybeExpr(ConstructComplex(
|
||||
context.messages, Analyze(std::get<0>(z.t)), Analyze(std::get<1>(z.t))));
|
||||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
|
||||
|
@ -486,7 +461,8 @@ MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::Divide &x) {
|
|||
}
|
||||
|
||||
MaybeExpr ExprAnalyzer::Analyze(const parser::Expr::ComplexConstructor &x) {
|
||||
return AsMaybeExpr(ConstructComplex(AnalyzeHelper(*this, *std::get<0>(x.t)),
|
||||
return AsMaybeExpr(ConstructComplex(context.messages,
|
||||
AnalyzeHelper(*this, *std::get<0>(x.t)),
|
||||
AnalyzeHelper(*this, *std::get<1>(x.t))));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue