From 710d635cad0c2a9e137d3257c5b680e5166d1a38 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Wed, 5 Sep 2018 17:12:03 -0700 Subject: [PATCH] [flang] mixed Complex; removed BOZConstant in favor of converting in place Original-commit: flang-compiler/f18@17a18ddd223d8a91687d59f0299dbbf35f771f72 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false --- flang/lib/common/interval.h | 17 +++++++ flang/lib/evaluate/common.h | 2 +- flang/lib/evaluate/expression.cc | 6 +-- flang/lib/evaluate/expression.h | 33 +++++--------- flang/lib/evaluate/logical.cc | 1 - flang/lib/evaluate/logical.h | 1 - flang/lib/evaluate/tools.cc | 96 +++++++++++++++++++++++++++++++--------- flang/lib/evaluate/tools.h | 28 +++++++++--- flang/lib/evaluate/type.h | 1 + flang/lib/parser/features.h | 3 +- 10 files changed, 130 insertions(+), 58 deletions(-) diff --git a/flang/lib/common/interval.h b/flang/lib/common/interval.h index 0f90100..caffcd7 100644 --- a/flang/lib/common/interval.h +++ b/flang/lib/common/interval.h @@ -53,6 +53,9 @@ public: constexpr bool Contains(const Interval &that) const { return Contains(that.start_) && Contains(that.start_ + (that.size_ - 1)); } + constexpr bool IsDisjointWith(const Interval &that) const { + return that.NextAfter() <= start_ || NextAfter() <= that.start_; + } constexpr bool ImmediatelyPrecedes(const Interval &that) const { return NextAfter() == that.start_; } @@ -86,6 +89,20 @@ public: return {start_ + n, size_ - n}; } + constexpr Interval Intersection(const Interval &that) const { + if (start_ >= that.NextAfter()) { + return {}; + } else if (start_ >= that.start_) { + auto skip{start_ - that.start_}; + return {start_, std::min(size_, that.size_ - skip)}; + } else if (NextAfter() <= that.start_) { + return {}; + } else { + auto skip{that.start_ - start_}; + return {that.start_, std::min(that.size_ - size_ - skip)}; + } + } + private: A start_; std::size_t size_{0}; diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index a7afead..89b75ea 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -70,7 +70,7 @@ static constexpr Relation Reverse(Relation relation) { ENUM_CLASS( RealFlag, Overflow, DivideByZero, InvalidArgument, Underflow, Inexact) -using RealFlags = common::EnumSet; +using RealFlags = common::EnumSet; template struct ValueWithRealFlags { A AccumulateFlags(RealFlags &f) { diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 79762ef..531dd34 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -33,7 +33,6 @@ namespace Fortran::evaluate { template auto Operation::Fold(FoldingContext &context) -> std::optional> { - // TODO pmk: generalize auto c0{operand<0>().Fold(context)}; if constexpr (operands() == 1) { if (c0.has_value()) { @@ -42,6 +41,7 @@ auto Operation::Fold(FoldingContext &context) } } } else { + static_assert(operands() == 2); // TODO: generalize to N operands? auto c1{operand<1>().Fold(context)}; if (c0.has_value() && c1.has_value()) { if (auto scalar{derived().FoldScalar(context, c0->value, c1->value)}) { @@ -446,10 +446,6 @@ template std::ostream &Constant::Dump(std::ostream &o) const { } } -template std::ostream &BOZConstant::Dump(std::ostream &o) const { - return o << "Z'" << value.Hexadecimal() << "'"; -} - template std::ostream &ExpressionBase::Dump(std::ostream &o) const { std::visit( diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index caa1ced..090619e 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -69,21 +69,10 @@ template struct Constant { }; // 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<8 * 2 * DefaultComplex::kind>; - -// "Typeless" operands to INTEGER, REAL, and COMPLEX operations. -template struct BOZConstant { - using Result = T; - using Value = BOZLiteralConstant; - CLASS_BOILERPLATE(BOZConstant) - BOZConstant(const BOZLiteralConstant &x) : value{x} {} - BOZConstant(BOZLiteralConstant &&x) : value{std::move(x)} {} - std::ostream &Dump(std::ostream &) const; - Value value; -}; +// value of any supported kind of INTEGER or REAL. They must also be +// distinguishable from other integer constants, since they are permitted +// to be used in only a few situations. +using BOZLiteralConstant = typename LargestReal::Scalar::Word; // These wrappers around data and function references expose their resolved // types. @@ -414,8 +403,8 @@ private: using Operations = std::variant, Negate, Add, Subtract, Multiply, Divide, Power, Extremum>; - using Others = std::variant, BOZConstant, - DataReference, FunctionReference>; + using Others = std::variant, DataReference, + FunctionReference>; public: common::CombineVariants u; @@ -445,8 +434,8 @@ private: using Operations = std::variant, Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, RealToIntPower, Extremum>; - using Others = std::variant, BOZConstant, - DataReference, FunctionReference>; + using Others = std::variant, DataReference, + FunctionReference>; public: common::CombineVariants u; @@ -466,11 +455,13 @@ public: Expr(const DataRef &x) : u{DataReference{x}} {} Expr(const FunctionRef &x) : u{FunctionReference{x}} {} + // TODO pmk: Remove Negate, Add, Subtract in favor of component-wise + // operations. using Operations = std::variant, Negate, Add, Subtract, Multiply, Divide, Power, RealToIntPower, ComplexConstructor>; - using Others = std::variant, BOZConstant, - DataReference, FunctionReference>; + using Others = std::variant, DataReference, + FunctionReference>; public: common::CombineVariants u; diff --git a/flang/lib/evaluate/logical.cc b/flang/lib/evaluate/logical.cc index 2beb748..da7f34b 100644 --- a/flang/lib/evaluate/logical.cc +++ b/flang/lib/evaluate/logical.cc @@ -20,6 +20,5 @@ template class Logical<8>; template class Logical<16>; template class Logical<32>; template class Logical<64>; -template class Logical<128>; } // namespace Fortran::evaluate::value diff --git a/flang/lib/evaluate/logical.h b/flang/lib/evaluate/logical.h index df39768..cfab07f 100644 --- a/flang/lib/evaluate/logical.h +++ b/flang/lib/evaluate/logical.h @@ -57,6 +57,5 @@ extern template class Logical<8>; extern template class Logical<16>; extern template class Logical<32>; extern template class Logical<64>; -extern template class Logical<128>; } // namespace Fortran::evaluate::value #endif // FORTRAN_EVALUATE_LOGICAL_H_ diff --git a/flang/lib/evaluate/tools.cc b/flang/lib/evaluate/tools.cc index 09988bce..20bed09 100644 --- a/flang/lib/evaluate/tools.cc +++ b/flang/lib/evaluate/tools.cc @@ -104,42 +104,82 @@ Expr GetComplexPart(const Expr &z, bool isImaginary) { z.u); } -template class OPR> -std::optional> MixedComplex(parser::ContextualMessages &messages, - Expr &&zx, Expr &&iry) { +// Handle mixed COMPLEX+REAL (or INTEGER) operations in a smarter way +// than just converting the second operand to COMPLEX and performing the +// corresponding COMPLEX+COMPLEX operation. +template class OPR, TypeCategory RCAT> +std::optional> MixedComplexLeft( + parser::ContextualMessages &messages, Expr &&zx, + Expr> &&iry) { Expr zr{GetComplexPart(zx, false)}; Expr zi{GetComplexPart(zx, true)}; if constexpr (std::is_same_v, Add> || std::is_same_v, Subtract>) { - // 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> rr{ - NumericOperation(messages, std::move(zr), std::move(iry))}) { - return Package(ConstructComplex(messages, AsGenericExpr(std::move(*rr)), - AsGenericExpr(std::move(zi)))); + // (a,b) + x -> (a+x, b) + // (a,b) - x -> (a-x, b) + if (std::optional> rr{NumericOperation(messages, + AsGenericExpr(std::move(zr)), AsGenericExpr(std::move(iry)))}) { + return Package(ConstructComplex( + messages, std::move(*rr), AsGenericExpr(std::move(zi)))); } } else if constexpr (std::is_same_v, Multiply> || std::is_same_v, Divide>) { - // 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) + // (a,b) * x -> (a*x, b*x) + // (a,b) / x -> (a/x, b/x) auto copy{iry}; - auto rr{NumericOperation(messages, std::move(zr), std::move(iry))}; - auto ri{NumericOperation(messages, std::move(zi), std::move(copy))}; + auto rr{NumericOperation( + messages, AsGenericExpr(std::move(zr)), AsGenericExpr(std::move(iry)))}; + auto ri{NumericOperation(messages, AsGenericExpr(std::move(zi)), + AsGenericExpr(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)))); } + } else { + // (a,b) ? x -> (a,b) ? (x,0) + Expr zy{ConvertTo(zx, std::move(iry))}; + return Package(PromoteAndCombine(std::move(zx), std::move(zy))); + } + return std::nullopt; +} + +// Mixed COMPLEX operations with the COMPLEX operand on the right. +// x + (a,b) -> (x+a, b) +// x - (a,b) -> (x-a, -b) +// x * (a,b) -> (x*a, x*b) +// x / (a,b) -> (x,0) / (a,b) +template class OPR, TypeCategory LCAT> +std::optional> MixedComplexRight( + parser::ContextualMessages &messages, Expr> &&irx, + Expr &&zy) { + if constexpr (std::is_same_v, Add> || + std::is_same_v, Multiply>) { + // x + (a,b) -> (a,b) + x -> (a+x, b) + // x * (a,b) -> (a,b) * x -> (a*x, b*x) + return MixedComplexLeft(messages, std::move(zy), std::move(irx)); + } else if constexpr (std::is_same_v, + Subtract>) { + // x - (a,b) -> (x-a, -b) + Expr zr{GetComplexPart(zy, false)}; + Expr zi{GetComplexPart(zy, true)}; + if (std::optional> rr{NumericOperation(messages, + AsGenericExpr(std::move(irx)), AsGenericExpr(std::move(zr)))}) { + return Package(ConstructComplex( + messages, std::move(*rr), AsGenericExpr(-std::move(zi)))); + } + } else { + // x / (a,b) -> (x,0) / (a,b) and any other operators that make it here + Expr zx{ConvertTo(zy, std::move(irx))}; + return Package(PromoteAndCombine(std::move(zx), std::move(zy))); } 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 -// and kind of the other operand. +// the operands to a dyadic operation, it assumes the type and kind of the +// other operand. +// TODO pmk: add Power, RealToIntPower, &c. template class OPR> std::optional> NumericOperation( parser::ContextualMessages &messages, Expr &&x, @@ -154,6 +194,7 @@ std::optional> NumericOperation( return Package(PromoteAndCombine( std::move(rx), std::move(ry))); }, + // Mixed INTEGER/REAL operations [](Expr &&rx, Expr &&iy) { return Package(std::visit( [&](auto &&rxk) -> Expr { @@ -173,18 +214,28 @@ std::optional> NumericOperation( }, std::move(ry.u))); }, + // Homogenous and mixed COMPLEX operations [](Expr &&zx, Expr &&zy) { return Package(PromoteAndCombine( std::move(zx), std::move(zy))); }, [&](Expr &&zx, Expr &&zy) { - return MixedComplex(messages, std::move(zx), std::move(zy)); + return MixedComplexLeft( + messages, std::move(zx), std::move(zy)); }, [&](Expr &&zx, Expr &&zy) { - return MixedComplex(messages, std::move(zx), std::move(zy)); + return MixedComplexLeft( + messages, std::move(zx), std::move(zy)); + }, + [&](Expr &&zx, Expr &&zy) { + return MixedComplexRight( + messages, std::move(zx), std::move(zy)); + }, + [&](Expr &&zx, Expr &&zy) { + return MixedComplexRight( + 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? + // Operations with one typeless operand [&](BOZLiteralConstant &&bx, Expr &&iy) { return NumericOperation( messages, ConvertTo(iy, std::move(bx)), std::move(y)); @@ -201,6 +252,7 @@ std::optional> NumericOperation( return NumericOperation( messages, std::move(x), ConvertTo(rx, std::move(by))); }, + // Default case [&](auto &&, auto &&) { messages.Say("non-numeric operands to numeric operation"_err_en_US); return std::optional>{std::nullopt}; diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index 2a614cd..88d9738 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -107,8 +107,16 @@ template Expr ConvertToType(Expr> &&x) { static_assert(TO::isSpecificType); if constexpr (FROMCAT != TO::category) { - return {Convert{std::move(x)}}; + if constexpr (TO::category == TypeCategory::Complex) { + using Part = typename TO::Part; + Scalar zero; + return {ComplexConstructor{ + ConvertToType(std::move(x)), Expr{Constant{zero}}}}; + } else { + return {Convert{std::move(x)}}; + } } else { + // Same type category if (auto already{common::GetIf>(x.u)}) { return std::move(*already); } @@ -134,10 +142,15 @@ Expr ConvertToType(Expr> &&x) { } template Expr ConvertToType(BOZLiteralConstant &&x) { - // TODO: check rank == 0 - // TODO: pmk: truncation warnings static_assert(TO::isSpecificType); - return Expr{BOZConstant{std::move(x)}}; + using Value = typename Constant::Value; + if constexpr (TO::category == TypeCategory::Integer) { + return Expr{Constant{Value::ConvertUnsigned(std::move(x)).value}}; + } else { + static_assert(TO::category == TypeCategory::Real); + using Word = typename Value::Word; + return Expr{Constant{Word::ConvertUnsigned(std::move(x)).value}}; + } } template @@ -256,8 +269,8 @@ template Expr> ScalarConstantToExpr(const A &x) { // Given two expressions of arbitrary kind in the same intrinsic type // category, convert one of them if necessary to the larger kind of the -// other, then combine them with a operation and return a new expression -// in the same type category. +// other, then combine the resulting homogenized operands with a given +// operation, returning a new expression in the same type category. template class OPR, TypeCategory CAT> Expr> PromoteAndCombine( Expr> &&x, Expr> &&y) { @@ -287,6 +300,9 @@ extern template std::optional> NumericOperation( parser::ContextualMessages &, Expr &&, Expr &&); // Convenience functions and operator overloadings for expression construction. +// These interfaces are defined only for those situations that cannot possibly +// need to emit any messages. Use the more general NumericOperation<> +// template (above) in other situations. template Expr> operator-(Expr> &&x) { diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 2add276..ab7e8f3 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -129,6 +129,7 @@ using DefaultCharacter = Type; using SubscriptInteger = Type; using LogicalResult = Type; +using LargestReal = Type; // For an intrinsic type category CAT, CategoryTypes is an instantiation // of std::tuple> over each supported kind K in that category. diff --git a/flang/lib/parser/features.h b/flang/lib/parser/features.h index bf5ed6e..82cd2cd 100644 --- a/flang/lib/parser/features.h +++ b/flang/lib/parser/features.h @@ -31,7 +31,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, ProgramParentheses, PercentRefAndVal, OmitFunctionDummies, CrayPointer, Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenMP) -using LanguageFeatures = common::EnumSet; +using LanguageFeatures = + common::EnumSet; class LanguageFeatureControl { public: -- 2.7.4