[flang-commits] [flang] df62afd - [flang] Unsplit COMPLEX operations
peter klausler via flang-commits
flang-commits at lists.llvm.org
Mon Nov 16 09:39:14 PST 2020
Author: peter klausler
Date: 2020-11-16T09:39:03-08:00
New Revision: df62afd559d4899a968cb72ad2ddc98b27412fa6
URL: https://github.com/llvm/llvm-project/commit/df62afd559d4899a968cb72ad2ddc98b27412fa6
DIFF: https://github.com/llvm/llvm-project/commit/df62afd559d4899a968cb72ad2ddc98b27412fa6.diff
LOG: [flang] Unsplit COMPLEX operations
COMPLEX negation, addition, subtraction, conversions of kind, and
equality/inequality were represented as component-wise REAL
operations. It turns out to be easier for lowering if we
do not split and recombine these COMPLEX operations, and it
avoids a potential problem with COMPLEX valued function calls
in these contexts. So add this suite of operations to the
typed expression representation in place of the component-wise
transformations, and support them in folding.
Differential revision: https://reviews.llvm.org/D91443
Added:
Modified:
flang/include/flang/Evaluate/expression.h
flang/include/flang/Evaluate/tools.h
flang/lib/Evaluate/fold-implementation.h
flang/lib/Evaluate/fold-logical.cpp
flang/lib/Evaluate/formatting.cpp
flang/lib/Evaluate/tools.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h
index f0ce375da015..8fdeb45024d8 100644
--- a/flang/include/flang/Evaluate/expression.h
+++ b/flang/include/flang/Evaluate/expression.h
@@ -202,15 +202,11 @@ template <typename TO, TypeCategory FROMCAT = TO::category>
struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> {
// Fortran doesn't have conversions between kinds of CHARACTER apart from
// assignments, and in those the data must be convertible to/from 7-bit ASCII.
- // Conversions between kinds of COMPLEX are represented piecewise.
static_assert(((TO::category == TypeCategory::Integer ||
TO::category == TypeCategory::Real) &&
(FROMCAT == TypeCategory::Integer ||
FROMCAT == TypeCategory::Real)) ||
- (TO::category == TypeCategory::Character &&
- FROMCAT == TypeCategory::Character) ||
- (TO::category == TypeCategory::Logical &&
- FROMCAT == TypeCategory::Logical));
+ TO::category == FROMCAT);
using Result = TO;
using Operand = SomeKind<FROMCAT>;
using Base = Operation<Convert, Result, Operand>;
@@ -542,8 +538,7 @@ class Expr<Type<TypeCategory::Real, KIND>>
private:
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
- // and part access operations (resp.). Conversions between kinds of
- // Complex are done via decomposition to Real and reconstruction.
+ // and part access operations (resp.).
using Conversions = std::variant<Convert<Result, TypeCategory::Integer>,
Convert<Result, TypeCategory::Real>>;
using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>,
@@ -563,12 +558,10 @@ class Expr<Type<TypeCategory::Complex, KIND>>
using Result = Type<TypeCategory::Complex, KIND>;
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
-
- // Note that many COMPLEX operations are represented as REAL operations
- // over their components (viz., conversions, negation, add, and subtract).
- using Operations =
- std::variant<Parentheses<Result>, Multiply<Result>, Divide<Result>,
- Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
+ using Operations = std::variant<Parentheses<Result>, Negate<Result>,
+ Convert<Result, TypeCategory::Complex>, Add<Result>, Subtract<Result>,
+ Multiply<Result>, Divide<Result>, Power<Result>, RealToIntPower<Result>,
+ ComplexConstructor<KIND>>;
using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
Designator<Result>, FunctionRef<Result>>;
@@ -614,6 +607,7 @@ struct Relational : public Operation<Relational<T>, LogicalResult, T, T> {
using Operand = typename Base::template Operand<0>;
static_assert(Operand::category == TypeCategory::Integer ||
Operand::category == TypeCategory::Real ||
+ Operand::category == TypeCategory::Complex ||
Operand::category == TypeCategory::Character);
CLASS_BOILERPLATE(Relational)
Relational(
@@ -625,9 +619,8 @@ struct Relational : public Operation<Relational<T>, LogicalResult, T, T> {
};
template <> class Relational<SomeType> {
- // COMPLEX data are compared piecewise.
- using DirectlyComparableTypes =
- common::CombineTuples<IntegerTypes, RealTypes, CharacterTypes>;
+ using DirectlyComparableTypes = common::CombineTuples<IntegerTypes, RealTypes,
+ ComplexTypes, CharacterTypes>;
public:
using Result = LogicalResult;
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 4ae85b9c0d56..7df91e13dc58 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -331,49 +331,29 @@ template <typename A> const Symbol *GetFirstSymbol(const A &x) {
template <typename TO, TypeCategory FROMCAT>
Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
static_assert(IsSpecificIntrinsicType<TO>);
- if constexpr (FROMCAT != TO::category) {
- if constexpr (TO::category == TypeCategory::Complex) {
- using Part = typename TO::Part;
- Scalar<Part> zero;
- return Expr<TO>{ComplexConstructor<TO::kind>{
- ConvertToType<Part>(std::move(x)), Expr<Part>{Constant<Part>{zero}}}};
- } else if constexpr (FROMCAT == TypeCategory::Complex) {
- // Extract and convert the real component of a complex value
- return std::visit(
- [&](auto &&z) {
- using ZType = ResultType<decltype(z)>;
- using Part = typename ZType::Part;
- return ConvertToType<TO, TypeCategory::Real>(Expr<SomeReal>{
- Expr<Part>{ComplexComponent<Part::kind>{false, std::move(z)}}});
- },
- std::move(x.u));
- } else {
- return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
- }
- } else {
- // Same type category
+ if constexpr (FROMCAT == TO::category) {
if (auto *already{std::get_if<Expr<TO>>(&x.u)}) {
return std::move(*already);
- }
- if constexpr (TO::category == TypeCategory::Complex) {
- // Extract, convert, and recombine the components.
- return Expr<TO>{std::visit(
- [](auto &z) {
- using FromType = ResultType<decltype(z)>;
- using FromPart = typename FromType::Part;
- using FromGeneric = SomeKind<TypeCategory::Real>;
- using ToPart = typename TO::Part;
- Convert<ToPart, TypeCategory::Real> re{Expr<FromGeneric>{
- Expr<FromPart>{ComplexComponent<FromType::kind>{false, z}}}};
- Convert<ToPart, TypeCategory::Real> im{Expr<FromGeneric>{
- Expr<FromPart>{ComplexComponent<FromType::kind>{true, z}}}};
- return ComplexConstructor<TO::kind>{
- AsExpr(std::move(re)), AsExpr(std::move(im))};
- },
- x.u)};
} else {
- return Expr<TO>{Convert<TO, TO::category>{std::move(x)}};
+ return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
}
+ } else if constexpr (TO::category == TypeCategory::Complex) {
+ using Part = typename TO::Part;
+ Scalar<Part> zero;
+ return Expr<TO>{ComplexConstructor<TO::kind>{
+ ConvertToType<Part>(std::move(x)), Expr<Part>{Constant<Part>{zero}}}};
+ } else if constexpr (FROMCAT == TypeCategory::Complex) {
+ // Extract and convert the real component of a complex value
+ return std::visit(
+ [&](auto &&z) {
+ using ZType = ResultType<decltype(z)>;
+ using Part = typename ZType::Part;
+ return ConvertToType<TO, TypeCategory::Real>(Expr<SomeReal>{
+ Expr<Part>{ComplexComponent<Part::kind>{false, std::move(z)}}});
+ },
+ std::move(x.u));
+ } else {
+ return Expr<TO>{Convert<TO, FROMCAT>{std::move(x)}};
}
}
@@ -523,24 +503,11 @@ template <typename A> Expr<TypeOf<A>> ScalarConstantToExpr(const A &x) {
}
// Combine two expressions of the same specific numeric type with an operation
-// to produce a new expression. Implements piecewise addition and subtraction
-// for COMPLEX.
+// to produce a new expression.
template <template <typename> class OPR, typename SPECIFIC>
Expr<SPECIFIC> Combine(Expr<SPECIFIC> &&x, Expr<SPECIFIC> &&y) {
static_assert(IsSpecificIntrinsicType<SPECIFIC>);
- if constexpr (SPECIFIC::category == TypeCategory::Complex &&
- (std::is_same_v<OPR<LargestReal>, Add<LargestReal>> ||
- std::is_same_v<OPR<LargestReal>, Subtract<LargestReal>>)) {
- static constexpr int kind{SPECIFIC::kind};
- using Part = Type<TypeCategory::Real, kind>;
- return AsExpr(ComplexConstructor<kind>{
- AsExpr(OPR<Part>{AsExpr(ComplexComponent<kind>{false, x}),
- AsExpr(ComplexComponent<kind>{false, y})}),
- AsExpr(OPR<Part>{AsExpr(ComplexComponent<kind>{true, x}),
- AsExpr(ComplexComponent<kind>{true, y})})});
- } else {
- return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
- }
+ return AsExpr(OPR<SPECIFIC>{std::move(x), std::move(y)});
}
// Given two expressions of arbitrary kind in the same intrinsic type
@@ -620,15 +587,6 @@ Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
return AsExpr(Negate<Type<C, K>>{std::move(x)});
}
-template <int K>
-Expr<Type<TypeCategory::Complex, K>> operator-(
- Expr<Type<TypeCategory::Complex, K>> &&x) {
- using Part = Type<TypeCategory::Real, K>;
- return AsExpr(ComplexConstructor<K>{
- AsExpr(Negate<Part>{AsExpr(ComplexComponent<K>{false, x})}),
- AsExpr(Negate<Part>{AsExpr(ComplexComponent<K>{true, x})})});
-}
-
template <TypeCategory C, int K>
Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return AsExpr(Combine<Add, Type<C, K>>(std::move(x), std::move(y)));
diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index ee3aaa3f9124..4b22a593df91 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -1236,6 +1236,15 @@ Expr<TO> FoldOperation(
}
return ScalarConstantToExpr(std::move(converted.value));
}
+ } else if constexpr (TO::category == TypeCategory::Complex) {
+ if constexpr (Operand::category == 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()})})});
+ }
} else if constexpr (TO::category == TypeCategory::Character &&
Operand::category == TypeCategory::Character) {
if (auto converted{ConvertString<Scalar<TO>>(std::move(*value))}) {
diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index bf283c4f9206..b22c742b0ea6 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -134,11 +134,13 @@ Expr<LogicalResult> FoldOperation(
Satisfies(relation.opr, folded->first.CompareSigned(folded->second));
} else if constexpr (T::category == TypeCategory::Real) {
result = Satisfies(relation.opr, folded->first.Compare(folded->second));
+ } else if constexpr (T::category == TypeCategory::Complex) {
+ result = (relation.opr == RelationalOperator::EQ) ==
+ folded->first.Equals(folded->second);
} else if constexpr (T::category == TypeCategory::Character) {
result = Satisfies(relation.opr, Compare(folded->first, folded->second));
} else {
- static_assert(T::category != TypeCategory::Complex &&
- T::category != TypeCategory::Logical);
+ static_assert(T::category != TypeCategory::Logical);
}
return Expr<LogicalResult>{Constant<LogicalResult>{result}};
}
diff --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index bed7fc4efee7..e59e79873f4c 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -349,6 +349,7 @@ template <typename TO, TypeCategory FROMCAT>
llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
static_assert(TO::category == TypeCategory::Integer ||
TO::category == TypeCategory::Real ||
+ TO::category == TypeCategory::Complex ||
TO::category == TypeCategory::Character ||
TO::category == TypeCategory::Logical,
"Convert<> to bad category!");
@@ -358,6 +359,8 @@ llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
this->left().AsFortran(o << "int(");
} else if constexpr (TO::category == TypeCategory::Real) {
this->left().AsFortran(o << "real(");
+ } else if constexpr (TO::category == TypeCategory::Complex) {
+ this->left().AsFortran(o << "cmplx(");
} else {
this->left().AsFortran(o << "logical(");
}
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 22b881a98a7f..afad30271c1c 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -69,7 +69,7 @@ auto IsVariableHelper::operator()(const ProcedureDesignator &x) const
return symbol && symbol->attrs().test(semantics::Attr::POINTER);
}
-// Conversions of complex component expressions to REAL.
+// Conversions of COMPLEX component expressions to REAL.
ConvertRealOperandsResult ConvertRealOperands(
parser::ContextualMessages &messages, Expr<SomeType> &&x,
Expr<SomeType> &&y, int defaultRealKind) {
@@ -498,31 +498,14 @@ std::optional<Expr<LogicalResult>> Relate(parser::ContextualMessages &messages,
},
[&](Expr<SomeComplex> &&zx,
Expr<SomeComplex> &&zy) -> std::optional<Expr<LogicalResult>> {
- if (opr != RelationalOperator::EQ &&
- opr != RelationalOperator::NE) {
+ if (opr == RelationalOperator::EQ ||
+ opr == RelationalOperator::NE) {
+ return PromoteAndRelate(opr, std::move(zx), std::move(zy));
+ } else {
messages.Say(
"COMPLEX data may be compared only for equality"_err_en_US);
- } else {
- auto rr{Relate(messages, opr,
- AsGenericExpr(GetComplexPart(zx, false)),
- AsGenericExpr(GetComplexPart(zy, false)))};
- auto ri{
- Relate(messages, opr, AsGenericExpr(GetComplexPart(zx, true)),
- AsGenericExpr(GetComplexPart(zy, true)))};
- if (auto parts{
- common::AllPresent(std::move(rr), std::move(ri))}) {
- // (a,b)==(c,d) -> (a==c) .AND. (b==d)
- // (a,b)/=(c,d) -> (a/=c) .OR. (b/=d)
- LogicalOperator combine{opr == RelationalOperator::EQ
- ? LogicalOperator::And
- : LogicalOperator::Or};
- return Expr<LogicalResult>{
- LogicalOperation<LogicalResult::kind>{combine,
- std::get<0>(std::move(*parts)),
- std::get<1>(std::move(*parts))}};
- }
+ return std::nullopt;
}
- return std::nullopt;
},
[&](Expr<SomeComplex> &&zx, Expr<SomeInteger> &&iy) {
return Relate(messages, opr, std::move(x),
More information about the flang-commits
mailing list