From: peter klausler Date: Wed, 6 Mar 2019 00:57:18 +0000 (-0800) Subject: [flang] Add Expression traversal framework, use it to reimplement IsConstantExpr() X-Git-Tag: llvmorg-12-init~9537^2~1671 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dbed3cebdc62e2479c14ace3699a8ac1cf729bc7;p=platform%2Fupstream%2Fllvm.git [flang] Add Expression traversal framework, use it to reimplement IsConstantExpr() Original-commit: flang-compiler/f18@f5d39159354a994cdeb5ab1d4cbfea188c14e681 Reviewed-on: https://github.com/flang-compiler/f18/pull/316 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 491313d..cd84212 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -18,6 +18,7 @@ #include "expression.h" #include "int-power.h" #include "tools.h" +#include "traversal.h" #include "type.h" #include "../common/indirection.h" #include "../common/template.h" @@ -27,7 +28,6 @@ #include "../semantics/symbol.h" #include #include -#include #include #include @@ -799,221 +799,45 @@ FOR_EACH_TYPE_AND_KIND(template class ExpressionBase) // able to fold it (yet) into a known constant value; specifically, // the expression may reference derived type kind parameters whose values // are not yet known. -// -// The implementation uses mutually recursive helper function overloadings and -// templates. -struct ConstExprContext { - std::set constantNames; -}; +class IsConstantExprVisitor : public virtual TraversalBase { +public: + using Base = TraversalBase; + using Base::Handle, Base::Pre, Base::Post; -// Base cases -bool IsConstExpr(ConstExprContext &, const BOZLiteralConstant &) { - return true; -} -bool IsConstExpr(ConstExprContext &, const NullPointer &) { return true; } -template bool IsConstExpr(ConstExprContext &, const Constant &) { - return true; -} -bool IsConstExpr(ConstExprContext &, const StaticDataObject::Pointer) { - return true; -} -template -bool IsConstExpr(ConstExprContext &, const TypeParamInquiry &inquiry) { - return inquiry.parameter() - .template get() - .attr() == common::TypeParamAttr::Kind; -} -bool IsConstExpr(ConstExprContext &, const Symbol *symbol) { - return symbol->attrs().test(semantics::Attr::PARAMETER); -} -bool IsConstExpr(ConstExprContext &, const CoarrayRef &) { return false; } -bool IsConstExpr(ConstExprContext &, const ImpliedDoIndex &) { - return true; // only tested when bounds are constant -} + explicit IsConstantExprVisitor(std::nullptr_t) {} -// Prototypes for mutual recursion -template -bool IsConstExpr(ConstExprContext &, const Operation &); -template -bool IsConstExpr(ConstExprContext &, const Operation &); -template bool IsConstExpr(ConstExprContext &, const ImpliedDo &); -template -bool IsConstExpr(ConstExprContext &, const ArrayConstructorValue &); -template -bool IsConstExpr(ConstExprContext &, const ArrayConstructorValues &); -template -bool IsConstExpr(ConstExprContext &, const ArrayConstructor &); -bool IsConstExpr(ConstExprContext &, const semantics::DerivedTypeSpec &); -bool IsConstExpr(ConstExprContext &, const StructureConstructor &); -bool IsConstExpr(ConstExprContext &, const BaseObject &); -bool IsConstExpr(ConstExprContext &, const Component &); -bool IsConstExpr(ConstExprContext &, const Triplet &); -bool IsConstExpr(ConstExprContext &, const Subscript &); -bool IsConstExpr(ConstExprContext &, const ArrayRef &); -bool IsConstExpr(ConstExprContext &, const DataRef &); -bool IsConstExpr(ConstExprContext &, const Substring &); -bool IsConstExpr(ConstExprContext &, const ComplexPart &); -template -bool IsConstExpr(ConstExprContext &, const Designator &); -bool IsConstExpr(ConstExprContext &, const ActualArgument &); -template -bool IsConstExpr(ConstExprContext &, const FunctionRef &); -template bool IsConstExpr(ConstExprContext &, const Expr &); -template -bool IsConstExpr(ConstExprContext &, const CopyableIndirection &); -template -bool IsConstExpr(ConstExprContext &, const std::optional &); -template -bool IsConstExpr(ConstExprContext &, const std::vector &); -template -bool IsConstExpr(ConstExprContext &, const std::variant &); -bool IsConstExpr(ConstExprContext &, const Relational &); - -template -bool IsConstExpr( - ConstExprContext &context, const Operation &operation) { - return IsConstExpr(context, operation.left()); -} -template -bool IsConstExpr( - ConstExprContext &context, const Operation &operation) { - return IsConstExpr(context, operation.left()) && - IsConstExpr(context, operation.right()); -} -template -bool IsConstExpr(ConstExprContext &context, const ImpliedDo &impliedDo) { - if (!IsConstExpr(context, impliedDo.lower()) || - !IsConstExpr(context, impliedDo.upper()) || - !IsConstExpr(context, impliedDo.stride())) { - return false; + template void Handle(const TypeParamInquiry &inq) { + Check(inq.parameter().template get().attr() == + common::TypeParamAttr::Kind); } - ConstExprContext newContext{context}; - newContext.constantNames.insert(impliedDo.name()); - return IsConstExpr(newContext, impliedDo.values()); -} -template -bool IsConstExpr( - ConstExprContext &context, const ArrayConstructorValue &value) { - return IsConstExpr(context, value.u); -} -template -bool IsConstExpr( - ConstExprContext &context, const ArrayConstructorValues &values) { - return IsConstExpr(context, values.values()); -} -template -bool IsConstExpr(ConstExprContext &context, const ArrayConstructor &array) { - const typename ArrayConstructor::Base &base{array}; - return IsConstExpr(context, base); -} -bool IsConstExpr( - ConstExprContext &context, const semantics::DerivedTypeSpec &spec) { - for (const auto &nameValue : spec.parameters()) { - const auto &value{nameValue.second}; - if (!value.isExplicit() || !value.GetExplicit().has_value() || - !IsConstExpr(context, *value.GetExplicit())) { - return false; - } - } - return true; -} -bool IsConstExpr( - ConstExprContext &context, const StructureConstructor &structure) { - if (!IsConstExpr(context, structure.derivedTypeSpec())) { - return false; - } - for (const auto &symbolExpr : structure.values()) { - if (!IsConstExpr(context, symbolExpr.second)) { - return false; - } + void Handle(const semantics::Symbol &symbol) { + Check(symbol.attrs().test(semantics::Attr::PARAMETER)); } - return true; -} -bool IsConstExpr(ConstExprContext &context, const BaseObject &base) { - return IsConstExpr(context, base.u); -} -bool IsConstExpr(ConstExprContext &context, const Component &component) { - return IsConstExpr(context, component.base()); -} -bool IsConstExpr(ConstExprContext &context, const Triplet &triplet) { - return IsConstExpr(context, triplet.lower()) && - IsConstExpr(context, triplet.upper()) && - IsConstExpr(context, triplet.stride()); -} -bool IsConstExpr(ConstExprContext &context, const Subscript &subscript) { - return IsConstExpr(context, subscript.u); -} -bool IsConstExpr(ConstExprContext &context, const ArrayRef &arrayRef) { - return IsConstExpr(context, arrayRef.base()) && - IsConstExpr(context, arrayRef.subscript()); -} -bool IsConstExpr(ConstExprContext &context, const DataRef &dataRef) { - return IsConstExpr(context, dataRef.u); -} -bool IsConstExpr(ConstExprContext &context, const Substring &substring) { - if (const auto *dataRef{substring.GetParentIf()}) { - if (!IsConstExpr(context, *dataRef)) { - return false; - } - } - return IsConstExpr(context, substring.lower()) && - IsConstExpr(context, substring.upper()); -} -bool IsConstExpr(ConstExprContext &context, const ComplexPart &complexPart) { - return IsConstExpr(context, complexPart.complex()); -} -template -bool IsConstExpr(ConstExprContext &context, const Designator &designator) { - return IsConstExpr(context, designator.u); -} -bool IsConstExpr(ConstExprContext &context, const ActualArgument &arg) { - return IsConstExpr(context, arg.value()); -} -template -bool IsConstExpr(ConstExprContext &context, const FunctionRef &funcRef) { - if (const auto *intrinsic{ - std::get_if(&funcRef.proc().u)}) { - if (intrinsic->name == "kind") { - return true; + void Handle(const CoarrayRef &) { NotConstant(); } + void Pre(const semantics::ParamValue ¶m) { Check(param.isExplicit()); } + template void Pre(const FunctionRef &call) { + if (const auto *intrinsic{std::get_if(&call.proc().u)}) { + Check(intrinsic->name == "kind"); + // TODO: Obviously many other intrinsics can be allowed + } else { + NotConstant(); } - // TODO: This is a placeholder with obvious false positives - return IsConstExpr(context, funcRef.arguments()); } - return false; -} -template -bool IsConstExpr(ConstExprContext &context, const Expr &expr) { - return IsConstExpr(context, expr.u); -} -template -bool IsConstExpr(ConstExprContext &context, const CopyableIndirection &x) { - return IsConstExpr(context, x.value()); -} -template -bool IsConstExpr(ConstExprContext &context, const std::optional &maybe) { - return !maybe.has_value() || IsConstExpr(context, *maybe); -} -template -bool IsConstExpr(ConstExprContext &context, const std::vector &v) { - for (const auto &x : v) { - if (!IsConstExpr(context, x)) { - return false; + +private: + void NotConstant() { Return(false); } + + void Check(bool ok) { + if (!ok) { + NotConstant(); } } - return true; -} -template -bool IsConstExpr(ConstExprContext &context, const std::variant &u) { - return std::visit([&](const auto &x) { return IsConstExpr(context, x); }, u); -} -bool IsConstExpr(ConstExprContext &context, const Relational &rel) { - return IsConstExpr(context, rel.u); -} +}; bool IsConstantExpr(const Expr &expr) { - ConstExprContext context; - return IsConstExpr(context, expr); + Traversal traverser{nullptr}; + return !traverser.Traverse(expr).has_value(); // only no news is good news } std::optional ToInt64(const Expr &expr) { diff --git a/flang/lib/evaluate/traversal.h b/flang/lib/evaluate/traversal.h new file mode 100644 index 0000000..49a2872 --- /dev/null +++ b/flang/lib/evaluate/traversal.h @@ -0,0 +1,189 @@ +// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FORTRAN_EVALUATE_TRAVERSAL_H_ +#define FORTRAN_EVALUATE_TRAVERSAL_H_ + +#include "expression.h" + +// Implements an expression traversal utility framework. +namespace Fortran::evaluate { + +template +class TraversalBase { +public: + using Result = RESULT; + template void Handle(const A &) { defaultHandle_ = true; } + template void Pre(const A &) {} + template void Post(const A &) {} + template void Return(A &&...x) { + result_.emplace(std::move(x)...); + } +protected: + std::optional result_; + bool defaultHandle_{false}; +}; + +// Descend() is a helper function template for Traversal::Visit(). +// Do not use directly. +namespace descend { +template void Descend(VISITOR &, const EXPR &) {} +template void Descend(V &visitor, const A *p) { + if (p != nullptr) { + visitor.Visit(*p); + } +} +template void Descend(V &visitor, const std::optional *o) { + if (o.has_value()) { + visitor.Visit(*o); + } +} +template void Descend(V &visitor, const CopyableIndirection &p) { + visitor.Visit(p.value()); +} +template void Descend(V &visitor, const std::variant &u) { + std::visit([&](const auto &x){ visitor.Visit(x); }, u); +} +template void Descend(V &visitor, const std::vector &xs) { + for (const auto &x : xs) { + visitor.Visit(x); + } +} +template void Descend(V &visitor, const Expr &expr) { + visitor.Visit(expr.u); +} +template +void Descend(V &visitor, const Operation &op) { + visitor.Visit(op.left()); + if constexpr (op.operands > 1) { + visitor.Visit(op.right()); + } +} +template void Descend(V &visitor, const ImpliedDo &ido) { + visitor.Visit(ido.lower()); + visitor.Visit(ido.upper()); + visitor.Visit(ido.stride()); + visitor.Visit(ido.values()); +} +template void Descend(V &visitor, const ArrayConstructorValue &av) { + visitor.Visit(av.u); +} +template void Descend(V &visitor, const ArrayConstructorValues &avs) { + visitor.Visit(avs.values()); +} +template void Descend(V &visitor, const ArrayConstructor> &ac) { + visitor.Visit(static_cast>>(ac)); + visitor.Visit(ac.LEN()); +} +template void Descend(V &visitor, const semantics::ParamValue ¶m) { + visitor.Visit(param.GetExplicit()); +} +template void Descend(V &visitor, const semantics::DerivedTypeSpec &derived) { + for (const auto &pair : derived.parameters()) { + visitor.Visit(pair.second); + } +} +template void Descend(V &visitor, const StructureConstructor &sc) { + visitor.Visit(sc.derivedTypeSpec()); + for (const auto &pair : sc.values()) { + visitor.Visit(pair.second); + } +} +template void Descend(V &visitor, const BaseObject &object) { + visitor.Visit(object.u); +} +template void Descend(V &visitor, const Component &component) { + visitor.Visit(component.base()); + visitor.Visit(component.GetLastSymbol()); +} +template void Descend(V &visitor, const TypeParamInquiry &inq) { + visitor.Visit(inq.base()); + visitor.Visit(inq.parameter()); +} +template void Descend(V &visitor, const Triplet &triplet) { + visitor.Visit(triplet.lower()); + visitor.Visit(triplet.upper()); + visitor.Visit(triplet.stride()); +} +template void Descend(V &visitor, const Subscript &sscript) { + visitor.Visit(sscript.u); +} +template void Descend(V &visitor, const ArrayRef &aref) { + visitor.Visit(aref.base()); + visitor.Visit(aref.subscript()); +} +template void Descend(V &visitor, const CoarrayRef &caref) { + visitor.Visit(caref.base()); + visitor.Visit(caref.subscript()); + visitor.Visit(caref.cosubscript()); + visitor.Visit(caref.stat()); + visitor.Visit(caref.team()); +} +template void Descend(V &visitor, const DataRef &data) { + visitor.Visit(data.u); +} +template void Descend(V &visitor, const ComplexPart &z) { + visitor.Visit(z.complex()); +} +template void Descend(V &visitor, const Designator &designator) { + visitor.Visit(designator.u); +} +template void Descend(V &visitor, const Variable &var) { + visitor.Visit(var.u); +} +template void Descend(V &visitor, const ActualArgument &arg) { + visitor.Visit(arg.value()); +} +template void Descend(V &visitor, const ProcedureDesignator &p) { + visitor.Visit(p.u); +} +template void Descend(V &visitor, const ProcedureRef &call) { + visitor.Visit(call.proc()); + visitor.Visit(call.arguments()); +} +} + +template +class Traversal : public virtual TraversalBase, public virtual A... { +public: + using Result = RESULT; + using A::Handle..., A::Pre..., A::Post...; +private: + using TraversalBase::result_, TraversalBase::defaultHandle_; +public: + template Traversal(B... x) : A{x}... {} + template std::optional Traverse(const B &x) { + Visit(x); + return std::move(result_); + } + + // TODO: make private, make Descend instances friends + template void Visit(const B &x) { + if (!result_.has_value()) { + defaultHandle_ = false; + Handle(x); + if (defaultHandle_) { + Pre(x); + if (!result_.has_value()) { + descend::Descend(*this, x); + if (!result_.has_value()) { + Post(x); + } + } + } + } + } +}; +} +#endif // FORTRAN_EVALUATE_TRAVERSAL_H_ diff --git a/flang/lib/evaluate/variable.h b/flang/lib/evaluate/variable.h index ef280e1..a572f30 100644 --- a/flang/lib/evaluate/variable.h +++ b/flang/lib/evaluate/variable.h @@ -356,8 +356,8 @@ public: FOR_EACH_CHARACTER_KIND(extern template class Designator) -template struct Variable { - using Result = A; +template struct Variable { + using Result = T; static_assert(IsSpecificIntrinsicType || std::is_same_v>); EVALUATE_UNION_CLASS_BOILERPLATE(Variable)