123c2bedfSPeter Klausler //===-- lib/Semantics/target.cpp ------------------------------------------===// 223c2bedfSPeter Klausler // 323c2bedfSPeter Klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 423c2bedfSPeter Klausler // See https://llvm.org/LICENSE.txt for license information. 523c2bedfSPeter Klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 623c2bedfSPeter Klausler // 723c2bedfSPeter Klausler //===----------------------------------------------------------------------===// 823c2bedfSPeter Klausler 923c2bedfSPeter Klausler #include "flang/Evaluate/target.h" 1023c2bedfSPeter Klausler #include "flang/Common/template.h" 1123c2bedfSPeter Klausler #include "flang/Evaluate/common.h" 1223c2bedfSPeter Klausler #include "flang/Evaluate/type.h" 1323c2bedfSPeter Klausler 1423c2bedfSPeter Klausler namespace Fortran::evaluate { 1523c2bedfSPeter Klausler 1623c2bedfSPeter Klausler Rounding TargetCharacteristics::defaultRounding; 1723c2bedfSPeter Klausler 1823c2bedfSPeter Klausler TargetCharacteristics::TargetCharacteristics() { 1923c2bedfSPeter Klausler auto enableCategoryKinds{[this](TypeCategory category) { 206003be7eSvdonaldson for (int kind{1}; kind <= maxKind; ++kind) { 2123c2bedfSPeter Klausler if (CanSupportType(category, kind)) { 2223c2bedfSPeter Klausler auto byteSize{static_cast<std::size_t>(kind)}; 2323c2bedfSPeter Klausler if (category == TypeCategory::Real || 2423c2bedfSPeter Klausler category == TypeCategory::Complex) { 2523c2bedfSPeter Klausler if (kind == 3) { 2623c2bedfSPeter Klausler // non-IEEE 16-bit format (truncated 32-bit) 2723c2bedfSPeter Klausler byteSize = 2; 2823c2bedfSPeter Klausler } else if (kind == 10) { 2923c2bedfSPeter Klausler // x87 floating-point 3023c2bedfSPeter Klausler // Follow gcc precedent for "long double" 3123c2bedfSPeter Klausler byteSize = 16; 3223c2bedfSPeter Klausler } 3323c2bedfSPeter Klausler } 3423c2bedfSPeter Klausler std::size_t align{byteSize}; 3523c2bedfSPeter Klausler if (category == TypeCategory::Complex) { 3623c2bedfSPeter Klausler byteSize = 2 * byteSize; 3723c2bedfSPeter Klausler } 3823c2bedfSPeter Klausler EnableType(category, kind, byteSize, align); 3923c2bedfSPeter Klausler } 4023c2bedfSPeter Klausler } 4123c2bedfSPeter Klausler }}; 4223c2bedfSPeter Klausler enableCategoryKinds(TypeCategory::Integer); 4323c2bedfSPeter Klausler enableCategoryKinds(TypeCategory::Real); 4423c2bedfSPeter Klausler enableCategoryKinds(TypeCategory::Complex); 4523c2bedfSPeter Klausler enableCategoryKinds(TypeCategory::Character); 4623c2bedfSPeter Klausler enableCategoryKinds(TypeCategory::Logical); 47fc97d2e6SPeter Klausler enableCategoryKinds(TypeCategory::Unsigned); 4823c2bedfSPeter Klausler 4923c2bedfSPeter Klausler isBigEndian_ = !isHostLittleEndian; 5023c2bedfSPeter Klausler 5123c2bedfSPeter Klausler areSubnormalsFlushedToZero_ = false; 5223c2bedfSPeter Klausler } 5323c2bedfSPeter Klausler 5423c2bedfSPeter Klausler bool TargetCharacteristics::CanSupportType( 5523c2bedfSPeter Klausler TypeCategory category, std::int64_t kind) { 5623c2bedfSPeter Klausler return IsValidKindOfIntrinsicType(category, kind); 5723c2bedfSPeter Klausler } 5823c2bedfSPeter Klausler 5923c2bedfSPeter Klausler bool TargetCharacteristics::EnableType(common::TypeCategory category, 6023c2bedfSPeter Klausler std::int64_t kind, std::size_t byteSize, std::size_t align) { 6123c2bedfSPeter Klausler if (CanSupportType(category, kind)) { 6223c2bedfSPeter Klausler byteSize_[static_cast<int>(category)][kind] = byteSize; 6323c2bedfSPeter Klausler align_[static_cast<int>(category)][kind] = align; 6423c2bedfSPeter Klausler maxByteSize_ = std::max(maxByteSize_, byteSize); 6523c2bedfSPeter Klausler maxAlignment_ = std::max(maxAlignment_, align); 6623c2bedfSPeter Klausler return true; 6723c2bedfSPeter Klausler } else { 6823c2bedfSPeter Klausler return false; 6923c2bedfSPeter Klausler } 7023c2bedfSPeter Klausler } 7123c2bedfSPeter Klausler 7223c2bedfSPeter Klausler void TargetCharacteristics::DisableType( 7323c2bedfSPeter Klausler common::TypeCategory category, std::int64_t kind) { 746003be7eSvdonaldson if (kind > 0 && kind <= maxKind) { 7523c2bedfSPeter Klausler align_[static_cast<int>(category)][kind] = 0; 7623c2bedfSPeter Klausler } 7723c2bedfSPeter Klausler } 7823c2bedfSPeter Klausler 7923c2bedfSPeter Klausler std::size_t TargetCharacteristics::GetByteSize( 8023c2bedfSPeter Klausler common::TypeCategory category, std::int64_t kind) const { 816003be7eSvdonaldson if (kind > 0 && kind <= maxKind) { 8223c2bedfSPeter Klausler return byteSize_[static_cast<int>(category)][kind]; 8323c2bedfSPeter Klausler } else { 8423c2bedfSPeter Klausler return 0; 8523c2bedfSPeter Klausler } 8623c2bedfSPeter Klausler } 8723c2bedfSPeter Klausler 8823c2bedfSPeter Klausler std::size_t TargetCharacteristics::GetAlignment( 8923c2bedfSPeter Klausler common::TypeCategory category, std::int64_t kind) const { 906003be7eSvdonaldson if (kind > 0 && kind <= maxKind) { 9123c2bedfSPeter Klausler return align_[static_cast<int>(category)][kind]; 9223c2bedfSPeter Klausler } else { 9323c2bedfSPeter Klausler return 0; 9423c2bedfSPeter Klausler } 9523c2bedfSPeter Klausler } 9623c2bedfSPeter Klausler 9723c2bedfSPeter Klausler bool TargetCharacteristics::IsTypeEnabled( 9823c2bedfSPeter Klausler common::TypeCategory category, std::int64_t kind) const { 9923c2bedfSPeter Klausler return GetAlignment(category, kind) > 0; 10023c2bedfSPeter Klausler } 10123c2bedfSPeter Klausler 10223c2bedfSPeter Klausler void TargetCharacteristics::set_isBigEndian(bool isBig) { 10323c2bedfSPeter Klausler isBigEndian_ = isBig; 10423c2bedfSPeter Klausler } 10523c2bedfSPeter Klausler 106a9e1d2e7SKelvin Li void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; } 107*ff862d6dSvdonaldson void TargetCharacteristics::set_isSPARC(bool isSPARC) { isSPARC_ = isSPARC; } 108a9e1d2e7SKelvin Li 10923c2bedfSPeter Klausler void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { 11023c2bedfSPeter Klausler areSubnormalsFlushedToZero_ = yes; 11123c2bedfSPeter Klausler } 11223c2bedfSPeter Klausler 1136003be7eSvdonaldson // Check if a given real kind has flushing control. 1146003be7eSvdonaldson bool TargetCharacteristics::hasSubnormalFlushingControl(int kind) const { 1156003be7eSvdonaldson CHECK(kind > 0 && kind <= maxKind); 1166003be7eSvdonaldson CHECK(CanSupportType(TypeCategory::Real, kind)); 1176003be7eSvdonaldson return hasSubnormalFlushingControl_[kind]; 1186003be7eSvdonaldson } 1196003be7eSvdonaldson 1206003be7eSvdonaldson // Check if any or all real kinds have flushing control. 1216003be7eSvdonaldson bool TargetCharacteristics::hasSubnormalFlushingControl(bool any) const { 1226003be7eSvdonaldson for (int kind{1}; kind <= maxKind; ++kind) { 1236003be7eSvdonaldson if (CanSupportType(TypeCategory::Real, kind) && 1246003be7eSvdonaldson hasSubnormalFlushingControl_[kind] == any) { 1256003be7eSvdonaldson return any; 1266003be7eSvdonaldson } 1276003be7eSvdonaldson } 1286003be7eSvdonaldson return !any; 1296003be7eSvdonaldson } 1306003be7eSvdonaldson 1316003be7eSvdonaldson void TargetCharacteristics::set_hasSubnormalFlushingControl( 1326003be7eSvdonaldson int kind, bool yes) { 1336003be7eSvdonaldson CHECK(kind > 0 && kind <= maxKind); 1346003be7eSvdonaldson hasSubnormalFlushingControl_[kind] = yes; 1356003be7eSvdonaldson } 1366003be7eSvdonaldson 13723c2bedfSPeter Klausler void TargetCharacteristics::set_roundingMode(Rounding rounding) { 13823c2bedfSPeter Klausler roundingMode_ = rounding; 13923c2bedfSPeter Klausler } 14023c2bedfSPeter Klausler 14123c2bedfSPeter Klausler // SELECTED_INT_KIND() -- F'2018 16.9.169 142fc97d2e6SPeter Klausler // and SELECTED_UNSIGNED_KIND() extension (same results) 14323c2bedfSPeter Klausler class SelectedIntKindVisitor { 14423c2bedfSPeter Klausler public: 14523c2bedfSPeter Klausler SelectedIntKindVisitor( 14623c2bedfSPeter Klausler const TargetCharacteristics &targetCharacteristics, std::int64_t p) 14723c2bedfSPeter Klausler : targetCharacteristics_{targetCharacteristics}, precision_{p} {} 14823c2bedfSPeter Klausler using Result = std::optional<int>; 14923c2bedfSPeter Klausler using Types = IntegerTypes; 15023c2bedfSPeter Klausler template <typename T> Result Test() const { 15123c2bedfSPeter Klausler if (Scalar<T>::RANGE >= precision_ && 15223c2bedfSPeter Klausler targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 15323c2bedfSPeter Klausler return T::kind; 15423c2bedfSPeter Klausler } else { 15523c2bedfSPeter Klausler return std::nullopt; 15623c2bedfSPeter Klausler } 15723c2bedfSPeter Klausler } 15823c2bedfSPeter Klausler 15923c2bedfSPeter Klausler private: 16023c2bedfSPeter Klausler const TargetCharacteristics &targetCharacteristics_; 16123c2bedfSPeter Klausler std::int64_t precision_; 16223c2bedfSPeter Klausler }; 16323c2bedfSPeter Klausler 16423c2bedfSPeter Klausler int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const { 16523c2bedfSPeter Klausler if (auto kind{ 16623c2bedfSPeter Klausler common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) { 16723c2bedfSPeter Klausler return *kind; 16823c2bedfSPeter Klausler } else { 16923c2bedfSPeter Klausler return -1; 17023c2bedfSPeter Klausler } 17123c2bedfSPeter Klausler } 17223c2bedfSPeter Klausler 1738383d768SPeter Klausler // SELECTED_LOGICAL_KIND() -- F'2023 16.9.182 1748383d768SPeter Klausler class SelectedLogicalKindVisitor { 1758383d768SPeter Klausler public: 1768383d768SPeter Klausler SelectedLogicalKindVisitor( 1778383d768SPeter Klausler const TargetCharacteristics &targetCharacteristics, std::int64_t bits) 1788383d768SPeter Klausler : targetCharacteristics_{targetCharacteristics}, bits_{bits} {} 1798383d768SPeter Klausler using Result = std::optional<int>; 1808383d768SPeter Klausler using Types = LogicalTypes; 1818383d768SPeter Klausler template <typename T> Result Test() const { 1828383d768SPeter Klausler if (Scalar<T>::bits >= bits_ && 1838383d768SPeter Klausler targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 1848383d768SPeter Klausler return T::kind; 1858383d768SPeter Klausler } else { 1868383d768SPeter Klausler return std::nullopt; 1878383d768SPeter Klausler } 1888383d768SPeter Klausler } 1898383d768SPeter Klausler 1908383d768SPeter Klausler private: 1918383d768SPeter Klausler const TargetCharacteristics &targetCharacteristics_; 1928383d768SPeter Klausler std::int64_t bits_; 1938383d768SPeter Klausler }; 1948383d768SPeter Klausler 1958383d768SPeter Klausler int TargetCharacteristics::SelectedLogicalKind(std::int64_t bits) const { 1968383d768SPeter Klausler if (auto kind{common::SearchTypes(SelectedLogicalKindVisitor{*this, bits})}) { 1978383d768SPeter Klausler return *kind; 1988383d768SPeter Klausler } else { 1998383d768SPeter Klausler return -1; 2008383d768SPeter Klausler } 2018383d768SPeter Klausler } 2028383d768SPeter Klausler 20323c2bedfSPeter Klausler // SELECTED_REAL_KIND() -- F'2018 16.9.170 20423c2bedfSPeter Klausler class SelectedRealKindVisitor { 20523c2bedfSPeter Klausler public: 20623c2bedfSPeter Klausler SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics, 20723c2bedfSPeter Klausler std::int64_t p, std::int64_t r) 20823c2bedfSPeter Klausler : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{ 20923c2bedfSPeter Klausler r} {} 21023c2bedfSPeter Klausler using Result = std::optional<int>; 21123c2bedfSPeter Klausler using Types = RealTypes; 21223c2bedfSPeter Klausler template <typename T> Result Test() const { 21323c2bedfSPeter Klausler if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ && 21423c2bedfSPeter Klausler targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 21523c2bedfSPeter Klausler return {T::kind}; 21623c2bedfSPeter Klausler } else { 21723c2bedfSPeter Klausler return std::nullopt; 21823c2bedfSPeter Klausler } 21923c2bedfSPeter Klausler } 22023c2bedfSPeter Klausler 22123c2bedfSPeter Klausler private: 22223c2bedfSPeter Klausler const TargetCharacteristics &targetCharacteristics_; 22323c2bedfSPeter Klausler std::int64_t precision_, range_; 22423c2bedfSPeter Klausler }; 22523c2bedfSPeter Klausler 22623c2bedfSPeter Klausler int TargetCharacteristics::SelectedRealKind( 22723c2bedfSPeter Klausler std::int64_t precision, std::int64_t range, std::int64_t radix) const { 22823c2bedfSPeter Klausler if (radix != 2) { 22923c2bedfSPeter Klausler return -5; 23023c2bedfSPeter Klausler } 23123c2bedfSPeter Klausler if (auto kind{common::SearchTypes( 23223c2bedfSPeter Klausler SelectedRealKindVisitor{*this, precision, range})}) { 23323c2bedfSPeter Klausler return *kind; 23423c2bedfSPeter Klausler } 23523c2bedfSPeter Klausler // No kind has both sufficient precision and sufficient range. 23623c2bedfSPeter Klausler // The negative return value encodes whether any kinds exist that 23723c2bedfSPeter Klausler // could satisfy either constraint independently. 23823c2bedfSPeter Klausler bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})}; 23923c2bedfSPeter Klausler bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})}; 24023c2bedfSPeter Klausler if (pOK) { 24123c2bedfSPeter Klausler if (rOK) { 24223c2bedfSPeter Klausler return -4; 24323c2bedfSPeter Klausler } else { 24423c2bedfSPeter Klausler return -2; 24523c2bedfSPeter Klausler } 24623c2bedfSPeter Klausler } else { 24723c2bedfSPeter Klausler if (rOK) { 24823c2bedfSPeter Klausler return -1; 24923c2bedfSPeter Klausler } else { 25023c2bedfSPeter Klausler return -3; 25123c2bedfSPeter Klausler } 25223c2bedfSPeter Klausler } 25323c2bedfSPeter Klausler } 25423c2bedfSPeter Klausler 25523c2bedfSPeter Klausler } // namespace Fortran::evaluate 256