[flang] Rearrange code to eliminate dependence cycles between f18 library binaries

Original-commit: flang-compiler/f18@88651eecae
Reviewed-on: https://github.com/flang-compiler/f18/pull/265
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-01-18 15:53:11 -08:00
parent f9d6c0a338
commit e7b93436c3
11 changed files with 190 additions and 199 deletions

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2018-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.
@ -31,5 +31,5 @@ add_library(FortranEvaluate
target_link_libraries(FortranEvaluate
FortranCommon
FortranSemantics
FortranParser
)

View File

@ -15,6 +15,7 @@
#include "type.h"
#include "fold.h"
#include "../common/idioms.h"
#include "../semantics/scope.h"
#include "../semantics/symbol.h"
#include "../semantics/type.h"
#include <algorithm>
@ -23,6 +24,66 @@
using namespace std::literals::string_literals;
// IsDescriptor() predicate
namespace Fortran::semantics {
static bool IsDescriptor(const ObjectEntityDetails &details) {
if (const auto *type{details.type()}) {
if (const IntrinsicTypeSpec * typeSpec{type->AsIntrinsic()}) {
if (typeSpec->category() == TypeCategory::Character) {
// TODO maybe character lengths won't be in descriptors
return true;
}
} else if (const DerivedTypeSpec * typeSpec{type->AsDerived()}) {
if (details.isDummy()) {
return true;
}
// Any length type parameter?
if (const Scope * scope{typeSpec->scope()}) {
if (const Symbol * symbol{scope->symbol()}) {
if (const auto *details{symbol->detailsIf<DerivedTypeDetails>()}) {
for (const Symbol *param : details->paramDecls()) {
if (const auto *details{param->detailsIf<TypeParamDetails>()}) {
if (details->attr() == common::TypeParamAttr::Len) {
return true;
}
}
}
}
}
}
} else if (type->category() == DeclTypeSpec::Category::TypeStar ||
type->category() == DeclTypeSpec::Category::ClassStar) {
return true;
}
}
if (details.IsAssumedShape() || details.IsDeferredShape() ||
details.IsAssumedRank()) {
return true;
}
// TODO: Explicit shape component array dependent on length parameter
// TODO: Automatic (adjustable) arrays
return false;
}
static bool IsDescriptor(const ProcEntityDetails &details) {
// A procedure pointer or dummy procedure must be a descriptor if
// and only if it requires a static link.
return details.HasExplicitInterface();
}
static bool IsDescriptor(const Symbol &symbol) {
if (const auto *objectDetails{symbol.detailsIf<ObjectEntityDetails>()}) {
return IsDescriptor(*objectDetails);
} else if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) {
if (symbol.attrs().test(Attr::POINTER) ||
symbol.attrs().test(Attr::EXTERNAL)) {
return IsDescriptor(*procDetails);
}
}
return false;
}
}
namespace Fortran::evaluate {
bool DynamicType::operator==(const DynamicType &that) const {
@ -38,7 +99,7 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol *symbol) {
TypeCategory category{intrinsic->category()};
if (IsValidKindOfIntrinsicType(category, *kind)) {
DynamicType dyType{category, static_cast<int>(*kind)};
if (symbol->IsDescriptor()) {
if (semantics::IsDescriptor(*symbol)) {
dyType.descriptor = symbol;
}
return std::make_optional(std::move(dyType));
@ -46,7 +107,7 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol *symbol) {
}
} else if (const auto *derived{type->AsDerived()}) {
DynamicType dyType{TypeCategory::Derived, 0, derived};
if (symbol->IsDescriptor()) {
if (semantics::IsDescriptor(*symbol)) {
dyType.descriptor = symbol;
}
return std::make_optional(std::move(dyType));

View File

@ -32,5 +32,6 @@ add_library(FortranSemantics
target_link_libraries(FortranSemantics
FortranCommon
FortranEvaluate
clangBasic
)

View File

@ -35,9 +35,6 @@ Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
Scope::iterator Scope::find(const SourceName &name) {
return symbols_.find(name);
}
Scope::const_iterator Scope::find(const SourceName &name) const {
return symbols_.find(name);
}
Scope::size_type Scope::erase(const SourceName &name) {
auto it{symbols_.find(name)};
if (it != end()) {

View File

@ -91,7 +91,9 @@ public:
const_iterator cend() const { return symbols_.cend(); }
iterator find(const SourceName &name);
const_iterator find(const SourceName &name) const;
const_iterator find(const SourceName &name) const {
return symbols_.find(name);
}
size_type erase(const SourceName &);
size_type size() const { return symbols_.size(); }
bool empty() const { return symbols_.empty(); }

View File

@ -83,54 +83,12 @@ void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
}
}
bool ObjectEntityDetails::IsDescriptor() const {
if (const auto *type{this->type()}) {
if (const IntrinsicTypeSpec * typeSpec{type->AsIntrinsic()}) {
if (typeSpec->category() == TypeCategory::Character) {
// TODO maybe character lengths won't be in descriptors
return true;
}
} else if (const DerivedTypeSpec * typeSpec{type->AsDerived()}) {
if (isDummy()) {
return true;
}
// Any length type parameter?
if (const Scope * scope{typeSpec->scope()}) {
if (const Symbol * symbol{scope->symbol()}) {
if (const auto *details{symbol->detailsIf<DerivedTypeDetails>()}) {
for (const Symbol *param : details->paramDecls()) {
if (const auto *details{param->detailsIf<TypeParamDetails>()}) {
if (details->attr() == common::TypeParamAttr::Len) {
return true;
}
}
}
}
}
}
} else if (type->category() == DeclTypeSpec::Category::TypeStar ||
type->category() == DeclTypeSpec::Category::ClassStar) {
return true;
}
}
if (IsAssumedShape() || IsDeferredShape() || IsAssumedRank()) {
return true;
}
// TODO: Explicit shape component array dependent on length parameter
// TODO: Automatic (adjustable) arrays
return false;
}
ProcEntityDetails::ProcEntityDetails(EntityDetails &&d) : EntityDetails(d) {
if (type()) {
interface_.set_type(*type());
}
}
// A procedure pointer or dummy procedure must be a descriptor if
// and only if it requires a static link.
bool ProcEntityDetails::IsDescriptor() const { return HasExplicitInterface(); }
const Symbol &UseDetails::module() const {
// owner is a module so it must have a symbol:
return *symbol_->owner().symbol();
@ -229,7 +187,7 @@ bool Symbol::CanReplaceDetails(const Details &details) const {
}
Symbol &Symbol::GetUltimate() {
return const_cast<Symbol &>(static_cast<const Symbol *>(this)->GetUltimate());
return const_cast<Symbol &>(const_cast<const Symbol *>(this)->GetUltimate());
}
const Symbol &Symbol::GetUltimate() const {
if (const auto *details{detailsIf<UseDetails>()}) {
@ -241,24 +199,6 @@ const Symbol &Symbol::GetUltimate() const {
}
}
DeclTypeSpec *Symbol::GetType() {
return const_cast<DeclTypeSpec *>(
const_cast<const Symbol *>(this)->GetType());
}
const DeclTypeSpec *Symbol::GetType() const {
return std::visit(
common::visitors{
[](const EntityDetails &x) { return x.type(); },
[](const ObjectEntityDetails &x) { return x.type(); },
[](const AssocEntityDetails &x) { return x.type(); },
[](const ProcEntityDetails &x) { return x.interface().type(); },
[](const TypeParamDetails &x) { return x.type(); },
[](const auto &) -> const DeclTypeSpec * { return nullptr; },
},
details_);
}
void Symbol::SetType(const DeclTypeSpec &type) {
std::visit(
common::visitors{
@ -284,18 +224,6 @@ bool Symbol::IsSubprogram() const {
details_);
}
bool Symbol::HasExplicitInterface() const {
return std::visit(
common::visitors{
[](const SubprogramDetails &) { return true; },
[](const SubprogramNameDetails &) { return true; },
[](const ProcEntityDetails &x) { return x.HasExplicitInterface(); },
[](const UseDetails &x) { return x.symbol().HasExplicitInterface(); },
[](const auto &) { return false; },
},
details_);
}
bool Symbol::IsSeparateModuleProc() const {
if (attrs().test(Attr::MODULE)) {
if (auto *details{detailsIf<SubprogramDetails>()}) {
@ -305,40 +233,6 @@ bool Symbol::IsSeparateModuleProc() const {
return false;
}
bool Symbol::IsDescriptor() const {
if (const auto *objectDetails{detailsIf<ObjectEntityDetails>()}) {
return objectDetails->IsDescriptor();
} else if (const auto *procDetails{detailsIf<ProcEntityDetails>()}) {
if (attrs_.test(Attr::POINTER) || attrs_.test(Attr::EXTERNAL)) {
return procDetails->IsDescriptor();
}
}
return false;
}
int Symbol::Rank() const {
return std::visit(
common::visitors{
[](const SubprogramDetails &sd) {
if (sd.isFunction()) {
return sd.result().Rank();
} else {
return 0;
}
},
[](const GenericDetails &) {
return 0; /*TODO*/
},
[](const UseDetails &x) { return x.symbol().Rank(); },
[](const HostAssocDetails &x) { return x.symbol().Rank(); },
[](const ObjectEntityDetails &oed) {
return static_cast<int>(oed.shape().size());
},
[](const auto &) { return 0; },
},
details_);
}
ObjectEntityDetails::ObjectEntityDetails(EntityDetails &&d)
: EntityDetails(d) {}
@ -374,13 +268,6 @@ std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) {
return os;
}
bool ProcEntityDetails::HasExplicitInterface() const {
if (auto *symbol{interface_.symbol()}) {
return symbol->HasExplicitInterface();
}
return false;
}
std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
if (auto *symbol{x.interface_.symbol()}) {
os << ' ' << symbol->name();

View File

@ -168,7 +168,6 @@ public:
return isDummy() && IsArray() && shape_.back().ubound().isAssumed() &&
shape_.back().lbound().isAssumed();
}
bool IsDescriptor() const;
private:
MaybeExpr init_;
@ -185,10 +184,9 @@ public:
const ProcInterface &interface() const { return interface_; }
ProcInterface &interface() { return interface_; }
void set_interface(const ProcInterface &interface) { interface_ = interface; }
bool HasExplicitInterface() const;
bool IsDescriptor() const;
const std::optional<SourceName> &passName() const { return passName_; }
void set_passName(const SourceName &passName) { passName_ = passName; }
inline bool HasExplicitInterface() const;
private:
ProcInterface interface_;
@ -403,15 +401,12 @@ public:
// Return a reference to the details which must be of type D.
template<typename D> D &get() {
return const_cast<D &>(static_cast<const Symbol *>(this)->get<D>());
return const_cast<D &>(const_cast<const Symbol *>(this)->get<D>());
}
template<typename D> const D &get() const {
if (const auto p{detailsIf<D>()}) {
return *p;
} else {
common::die("unexpected %s details at %s(%d)", GetDetailsName().c_str(),
__FILE__, __LINE__);
}
const auto *p{detailsIf<D>()};
CHECK(p != nullptr);
return *p;
}
Details &details() { return details_; }
@ -427,19 +422,67 @@ public:
Symbol &GetUltimate();
const Symbol &GetUltimate() const;
DeclTypeSpec *GetType();
const DeclTypeSpec *GetType() const;
DeclTypeSpec *GetType() {
return const_cast<DeclTypeSpec *>(
const_cast<const Symbol *>(this)->GetType());
}
const DeclTypeSpec *GetType() const {
return std::visit(
common::visitors{
[](const EntityDetails &x) { return x.type(); },
[](const ObjectEntityDetails &x) { return x.type(); },
[](const AssocEntityDetails &x) { return x.type(); },
[](const ProcEntityDetails &x) { return x.interface().type(); },
[](const TypeParamDetails &x) { return x.type(); },
[](const auto &) -> const DeclTypeSpec * { return nullptr; },
},
details_);
}
void SetType(const DeclTypeSpec &);
bool IsSubprogram() const;
bool HasExplicitInterface() const;
bool IsSeparateModuleProc() const;
bool IsDescriptor() const;
bool HasExplicitInterface() const {
return std::visit(
common::visitors{
[](const SubprogramDetails &) { return true; },
[](const SubprogramNameDetails &) { return true; },
[](const ProcEntityDetails &x) { return x.HasExplicitInterface(); },
[](const UseDetails &x) {
return x.symbol().HasExplicitInterface();
},
[](const auto &) { return false; },
},
details_);
}
bool operator==(const Symbol &that) const { return this == &that; }
bool operator!=(const Symbol &that) const { return this != &that; }
int Rank() const;
int Rank() const {
return std::visit(
common::visitors{
[](const SubprogramDetails &sd) {
if (sd.isFunction()) {
return sd.result().Rank();
} else {
return 0;
}
},
[](const GenericDetails &) {
return 0; /*TODO*/
},
[](const UseDetails &x) { return x.symbol().Rank(); },
[](const HostAssocDetails &x) { return x.symbol().Rank(); },
[](const ObjectEntityDetails &oed) {
return static_cast<int>(oed.shape().size());
},
[](const auto &) { return 0; },
},
details_);
}
// Clones the Symbol in the context of a parameterized derived type instance
Symbol &Instantiate(Scope &, evaluate::FoldingContext &) const;
@ -506,5 +549,16 @@ private:
return result;
}
};
// Define a few member functions here in the header so that they
// can be used by lib/evaluate without inducing a dependence cycle
// between the two shared libraries.
inline bool ProcEntityDetails::HasExplicitInterface() const {
if (auto *symbol{interface_.symbol()}) {
return symbol->HasExplicitInterface();
}
return false;
}
}
#endif // FORTRAN_SEMANTICS_SYMBOL_H_

View File

@ -50,21 +50,8 @@ ParamValue &DerivedTypeSpec::AddParamValue(
}
ParamValue *DerivedTypeSpec::FindParameter(SourceName target) {
auto iter{parameters_.find(target)};
if (iter != parameters_.end()) {
return &iter->second;
} else {
return nullptr;
}
}
const ParamValue *DerivedTypeSpec::FindParameter(SourceName target) const {
auto iter{parameters_.find(target)};
if (iter != parameters_.end()) {
return &iter->second;
} else {
return nullptr;
}
return const_cast<ParamValue *>(
const_cast<const DerivedTypeSpec *>(this)->FindParameter(target));
}
void DerivedTypeSpec::FoldParameterExpressions(
@ -278,27 +265,8 @@ bool DeclTypeSpec::IsNumeric(TypeCategory tc) const {
return category_ == Numeric && numericTypeSpec().category() == tc;
}
IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() {
switch (category_) {
case Numeric: return &std::get<NumericTypeSpec>(typeSpec_);
case Logical: return &std::get<LogicalTypeSpec>(typeSpec_);
case Character: return &std::get<CharacterTypeSpec>(typeSpec_);
default: return nullptr;
}
}
const IntrinsicTypeSpec *DeclTypeSpec::AsIntrinsic() const {
switch (category_) {
case Numeric: return &std::get<NumericTypeSpec>(typeSpec_);
case Logical: return &std::get<LogicalTypeSpec>(typeSpec_);
case Character: return &std::get<CharacterTypeSpec>(typeSpec_);
default: return nullptr;
}
}
const DerivedTypeSpec *DeclTypeSpec::AsDerived() const {
switch (category_) {
case TypeDerived:
case ClassDerived: return &std::get<DerivedTypeSpec>(typeSpec_);
default: return nullptr;
}
return const_cast<IntrinsicTypeSpec *>(
const_cast<const DeclTypeSpec *>(this)->AsIntrinsic());
}
const NumericTypeSpec &DeclTypeSpec::numericTypeSpec() const {
CHECK(category_ == Numeric);

View File

@ -229,7 +229,14 @@ public:
bool HasActualParameters() const { return !parameters_.empty(); }
ParamValue &AddParamValue(SourceName, ParamValue &&);
ParamValue *FindParameter(SourceName);
const ParamValue *FindParameter(SourceName) const;
const ParamValue *FindParameter(SourceName target) const {
auto iter{parameters_.find(target)};
if (iter != parameters_.end()) {
return &iter->second;
} else {
return nullptr;
}
}
void FoldParameterExpressions(evaluate::FoldingContext &);
void Instantiate(Scope &, evaluate::FoldingContext &);
bool operator==(const DerivedTypeSpec &) const; // for std::find()
@ -271,15 +278,30 @@ public:
Category category() const { return category_; }
void set_category(Category category) { category_ = category; }
bool IsNumeric(TypeCategory) const;
IntrinsicTypeSpec *AsIntrinsic();
const IntrinsicTypeSpec *AsIntrinsic() const;
const DerivedTypeSpec *AsDerived() const;
const NumericTypeSpec &numericTypeSpec() const;
const LogicalTypeSpec &logicalTypeSpec() const;
const CharacterTypeSpec &characterTypeSpec() const;
const DerivedTypeSpec &derivedTypeSpec() const;
DerivedTypeSpec &derivedTypeSpec();
IntrinsicTypeSpec *AsIntrinsic();
const IntrinsicTypeSpec *AsIntrinsic() const {
switch (category_) {
case Numeric: return &std::get<NumericTypeSpec>(typeSpec_);
case Logical: return &std::get<LogicalTypeSpec>(typeSpec_);
case Character: return &std::get<CharacterTypeSpec>(typeSpec_);
default: return nullptr;
}
}
const DerivedTypeSpec *AsDerived() const {
switch (category_) {
case TypeDerived:
case ClassDerived: return &std::get<DerivedTypeSpec>(typeSpec_);
default: return nullptr;
}
}
private:
Category category_;
std::variant<std::monostate, NumericTypeSpec, LogicalTypeSpec,

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2018-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.
@ -22,8 +22,8 @@ add_executable(leading-zero-bit-count-test
)
target_link_libraries(leading-zero-bit-count-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
)
add_executable(bit-population-count-test
@ -31,8 +31,8 @@ add_executable(bit-population-count-test
)
target_link_libraries(bit-population-count-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
)
add_executable(expression-test
@ -41,10 +41,9 @@ add_executable(expression-test
target_link_libraries(expression-test
FortranEvaluateTesting
FortranEvaluate
FortranParser
FortranSemantics
FortranEvaluate
FortranParser
)
add_executable(integer-test
@ -52,8 +51,8 @@ add_executable(integer-test
)
target_link_libraries(integer-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
)
add_executable(intrinsics-test
@ -62,9 +61,9 @@ add_executable(intrinsics-test
target_link_libraries(intrinsics-test
FortranEvaluateTesting
FortranSemantics
FortranEvaluate
FortranParser
FortranSemantics
FortranRuntime
)
@ -73,8 +72,8 @@ add_executable(logical-test
)
target_link_libraries(logical-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
)
add_executable(real-test
@ -82,8 +81,8 @@ add_executable(real-test
)
target_link_libraries(real-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
m
)
@ -92,9 +91,9 @@ add_executable(reshape-test
)
target_link_libraries(reshape-test
FortranEvaluateTesting
FortranSemantics
FortranEvaluate
FortranEvaluateTesting
FortranRuntime
)
@ -103,17 +102,17 @@ add_executable(ISO-Fortran-binding-test
)
target_link_libraries(ISO-Fortran-binding-test
FortranEvaluate
FortranEvaluateTesting
FortranEvaluate
FortranRuntime
)
add_test(NAME Expression COMMAND expression-test)
add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
add_test(NAME PopPar COMMAND bit-population-count-test)
add_test(NAME Integer COMMAND integer-test)
add_test(NAME Intrinsics COMMAND intrinsics-test)
add_test(NAME Logical COMMAND logical-test)
add_test(NAME Real COMMAND real-test)
add_test(NAME RESHAPE COMMAND reshape-test)
add_test(NAME ISO-Fortran-binding COMMAND ISO-Fortran-binding-test)
add_test(Expression expression-test)
add_test(Leadz leading-zero-bit-count-test)
add_test(PopPar bit-population-count-test)
add_test(Integer integer-test)
add_test(Intrinsics intrinsics-test)
add_test(Logical logical-test)
add_test(Real real-test)
add_test(RESHAPE reshape-test)
add_test(ISO-binding ISO-Fortran-binding-test)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2018-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.
@ -19,6 +19,6 @@ add_executable(f18
target_link_libraries(f18
FortranParser
FortranSemantics
FortranEvaluate
FortranSemantics
)