xref: /llvm-project/flang/lib/Evaluate/target.cpp (revision ff862d6de92f478253a332ec48cfc2c2add76bb3)
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