| //===-- lib/Semantics/target.cpp ------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "flang/Evaluate/target.h" |
| #include "flang/Common/template.h" |
| #include "flang/Evaluate/common.h" |
| #include "flang/Evaluate/type.h" |
| |
| namespace Fortran::evaluate { |
| |
| Rounding TargetCharacteristics::defaultRounding; |
| |
| TargetCharacteristics::TargetCharacteristics() { |
| auto enableCategoryKinds{[this](TypeCategory category) { |
| for (int kind{0}; kind < maxKind; ++kind) { |
| if (CanSupportType(category, kind)) { |
| auto byteSize{static_cast<std::size_t>(kind)}; |
| if (category == TypeCategory::Real || |
| category == TypeCategory::Complex) { |
| if (kind == 3) { |
| // non-IEEE 16-bit format (truncated 32-bit) |
| byteSize = 2; |
| } else if (kind == 10) { |
| // x87 floating-point |
| // Follow gcc precedent for "long double" |
| byteSize = 16; |
| } |
| } |
| std::size_t align{byteSize}; |
| if (category == TypeCategory::Complex) { |
| byteSize = 2 * byteSize; |
| } |
| EnableType(category, kind, byteSize, align); |
| } |
| } |
| }}; |
| enableCategoryKinds(TypeCategory::Integer); |
| enableCategoryKinds(TypeCategory::Real); |
| enableCategoryKinds(TypeCategory::Complex); |
| enableCategoryKinds(TypeCategory::Character); |
| enableCategoryKinds(TypeCategory::Logical); |
| |
| isBigEndian_ = !isHostLittleEndian; |
| |
| areSubnormalsFlushedToZero_ = false; |
| } |
| |
| bool TargetCharacteristics::CanSupportType( |
| TypeCategory category, std::int64_t kind) { |
| return IsValidKindOfIntrinsicType(category, kind); |
| } |
| |
| bool TargetCharacteristics::EnableType(common::TypeCategory category, |
| std::int64_t kind, std::size_t byteSize, std::size_t align) { |
| if (CanSupportType(category, kind)) { |
| byteSize_[static_cast<int>(category)][kind] = byteSize; |
| align_[static_cast<int>(category)][kind] = align; |
| maxByteSize_ = std::max(maxByteSize_, byteSize); |
| maxAlignment_ = std::max(maxAlignment_, align); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| void TargetCharacteristics::DisableType( |
| common::TypeCategory category, std::int64_t kind) { |
| if (kind >= 0 && kind < maxKind) { |
| align_[static_cast<int>(category)][kind] = 0; |
| } |
| } |
| |
| std::size_t TargetCharacteristics::GetByteSize( |
| common::TypeCategory category, std::int64_t kind) const { |
| if (kind >= 0 && kind < maxKind) { |
| return byteSize_[static_cast<int>(category)][kind]; |
| } else { |
| return 0; |
| } |
| } |
| |
| std::size_t TargetCharacteristics::GetAlignment( |
| common::TypeCategory category, std::int64_t kind) const { |
| if (kind >= 0 && kind < maxKind) { |
| return align_[static_cast<int>(category)][kind]; |
| } else { |
| return 0; |
| } |
| } |
| |
| bool TargetCharacteristics::IsTypeEnabled( |
| common::TypeCategory category, std::int64_t kind) const { |
| return GetAlignment(category, kind) > 0; |
| } |
| |
| void TargetCharacteristics::set_isBigEndian(bool isBig) { |
| isBigEndian_ = isBig; |
| } |
| |
| void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; } |
| |
| void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { |
| areSubnormalsFlushedToZero_ = yes; |
| } |
| |
| void TargetCharacteristics::set_roundingMode(Rounding rounding) { |
| roundingMode_ = rounding; |
| } |
| |
| // SELECTED_INT_KIND() -- F'2018 16.9.169 |
| class SelectedIntKindVisitor { |
| public: |
| SelectedIntKindVisitor( |
| const TargetCharacteristics &targetCharacteristics, std::int64_t p) |
| : targetCharacteristics_{targetCharacteristics}, precision_{p} {} |
| using Result = std::optional<int>; |
| using Types = IntegerTypes; |
| template <typename T> Result Test() const { |
| if (Scalar<T>::RANGE >= precision_ && |
| targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
| return T::kind; |
| } else { |
| return std::nullopt; |
| } |
| } |
| |
| private: |
| const TargetCharacteristics &targetCharacteristics_; |
| std::int64_t precision_; |
| }; |
| |
| int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const { |
| if (auto kind{ |
| common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) { |
| return *kind; |
| } else { |
| return -1; |
| } |
| } |
| |
| // SELECTED_LOGICAL_KIND() -- F'2023 16.9.182 |
| class SelectedLogicalKindVisitor { |
| public: |
| SelectedLogicalKindVisitor( |
| const TargetCharacteristics &targetCharacteristics, std::int64_t bits) |
| : targetCharacteristics_{targetCharacteristics}, bits_{bits} {} |
| using Result = std::optional<int>; |
| using Types = LogicalTypes; |
| template <typename T> Result Test() const { |
| if (Scalar<T>::bits >= bits_ && |
| targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
| return T::kind; |
| } else { |
| return std::nullopt; |
| } |
| } |
| |
| private: |
| const TargetCharacteristics &targetCharacteristics_; |
| std::int64_t bits_; |
| }; |
| |
| int TargetCharacteristics::SelectedLogicalKind(std::int64_t bits) const { |
| if (auto kind{common::SearchTypes(SelectedLogicalKindVisitor{*this, bits})}) { |
| return *kind; |
| } else { |
| return -1; |
| } |
| } |
| |
| // SELECTED_REAL_KIND() -- F'2018 16.9.170 |
| class SelectedRealKindVisitor { |
| public: |
| SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics, |
| std::int64_t p, std::int64_t r) |
| : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{ |
| r} {} |
| using Result = std::optional<int>; |
| using Types = RealTypes; |
| template <typename T> Result Test() const { |
| if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ && |
| targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
| return {T::kind}; |
| } else { |
| return std::nullopt; |
| } |
| } |
| |
| private: |
| const TargetCharacteristics &targetCharacteristics_; |
| std::int64_t precision_, range_; |
| }; |
| |
| int TargetCharacteristics::SelectedRealKind( |
| std::int64_t precision, std::int64_t range, std::int64_t radix) const { |
| if (radix != 2) { |
| return -5; |
| } |
| if (auto kind{common::SearchTypes( |
| SelectedRealKindVisitor{*this, precision, range})}) { |
| return *kind; |
| } |
| // No kind has both sufficient precision and sufficient range. |
| // The negative return value encodes whether any kinds exist that |
| // could satisfy either constraint independently. |
| bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})}; |
| bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})}; |
| if (pOK) { |
| if (rOK) { |
| return -4; |
| } else { |
| return -2; |
| } |
| } else { |
| if (rOK) { |
| return -1; |
| } else { |
| return -3; |
| } |
| } |
| } |
| |
| } // namespace Fortran::evaluate |