1 //===-- lib/Semantics/target.cpp ------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "flang/Evaluate/target.h" 10 #include "flang/Common/template.h" 11 #include "flang/Evaluate/common.h" 12 #include "flang/Evaluate/type.h" 13 14 namespace Fortran::evaluate { 15 16 Rounding TargetCharacteristics::defaultRounding; 17 18 TargetCharacteristics::TargetCharacteristics() { 19 auto enableCategoryKinds{[this](TypeCategory category) { 20 for (int kind{0}; kind < maxKind; ++kind) { 21 if (CanSupportType(category, kind)) { 22 auto byteSize{static_cast<std::size_t>(kind)}; 23 if (category == TypeCategory::Real || 24 category == TypeCategory::Complex) { 25 if (kind == 3) { 26 // non-IEEE 16-bit format (truncated 32-bit) 27 byteSize = 2; 28 } else if (kind == 10) { 29 // x87 floating-point 30 // Follow gcc precedent for "long double" 31 byteSize = 16; 32 } 33 } 34 std::size_t align{byteSize}; 35 if (category == TypeCategory::Complex) { 36 byteSize = 2 * byteSize; 37 } 38 EnableType(category, kind, byteSize, align); 39 } 40 } 41 }}; 42 enableCategoryKinds(TypeCategory::Integer); 43 enableCategoryKinds(TypeCategory::Real); 44 enableCategoryKinds(TypeCategory::Complex); 45 enableCategoryKinds(TypeCategory::Character); 46 enableCategoryKinds(TypeCategory::Logical); 47 48 isBigEndian_ = !isHostLittleEndian; 49 50 areSubnormalsFlushedToZero_ = false; 51 } 52 53 bool TargetCharacteristics::CanSupportType( 54 TypeCategory category, std::int64_t kind) { 55 return IsValidKindOfIntrinsicType(category, kind); 56 } 57 58 bool TargetCharacteristics::EnableType(common::TypeCategory category, 59 std::int64_t kind, std::size_t byteSize, std::size_t align) { 60 if (CanSupportType(category, kind)) { 61 byteSize_[static_cast<int>(category)][kind] = byteSize; 62 align_[static_cast<int>(category)][kind] = align; 63 maxByteSize_ = std::max(maxByteSize_, byteSize); 64 maxAlignment_ = std::max(maxAlignment_, align); 65 return true; 66 } else { 67 return false; 68 } 69 } 70 71 void TargetCharacteristics::DisableType( 72 common::TypeCategory category, std::int64_t kind) { 73 if (kind >= 0 && kind < maxKind) { 74 align_[static_cast<int>(category)][kind] = 0; 75 } 76 } 77 78 std::size_t TargetCharacteristics::GetByteSize( 79 common::TypeCategory category, std::int64_t kind) const { 80 if (kind >= 0 && kind < maxKind) { 81 return byteSize_[static_cast<int>(category)][kind]; 82 } else { 83 return 0; 84 } 85 } 86 87 std::size_t TargetCharacteristics::GetAlignment( 88 common::TypeCategory category, std::int64_t kind) const { 89 if (kind >= 0 && kind < maxKind) { 90 return align_[static_cast<int>(category)][kind]; 91 } else { 92 return 0; 93 } 94 } 95 96 bool TargetCharacteristics::IsTypeEnabled( 97 common::TypeCategory category, std::int64_t kind) const { 98 return GetAlignment(category, kind) > 0; 99 } 100 101 void TargetCharacteristics::set_isBigEndian(bool isBig) { 102 isBigEndian_ = isBig; 103 } 104 105 void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { 106 areSubnormalsFlushedToZero_ = yes; 107 } 108 109 void TargetCharacteristics::set_roundingMode(Rounding rounding) { 110 roundingMode_ = rounding; 111 } 112 113 // SELECTED_INT_KIND() -- F'2018 16.9.169 114 class SelectedIntKindVisitor { 115 public: 116 SelectedIntKindVisitor( 117 const TargetCharacteristics &targetCharacteristics, std::int64_t p) 118 : targetCharacteristics_{targetCharacteristics}, precision_{p} {} 119 using Result = std::optional<int>; 120 using Types = IntegerTypes; 121 template <typename T> Result Test() const { 122 if (Scalar<T>::RANGE >= precision_ && 123 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 124 return T::kind; 125 } else { 126 return std::nullopt; 127 } 128 } 129 130 private: 131 const TargetCharacteristics &targetCharacteristics_; 132 std::int64_t precision_; 133 }; 134 135 int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const { 136 if (auto kind{ 137 common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) { 138 return *kind; 139 } else { 140 return -1; 141 } 142 } 143 144 // SELECTED_REAL_KIND() -- F'2018 16.9.170 145 class SelectedRealKindVisitor { 146 public: 147 SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics, 148 std::int64_t p, std::int64_t r) 149 : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{ 150 r} {} 151 using Result = std::optional<int>; 152 using Types = RealTypes; 153 template <typename T> Result Test() const { 154 if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ && 155 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 156 return {T::kind}; 157 } else { 158 return std::nullopt; 159 } 160 } 161 162 private: 163 const TargetCharacteristics &targetCharacteristics_; 164 std::int64_t precision_, range_; 165 }; 166 167 int TargetCharacteristics::SelectedRealKind( 168 std::int64_t precision, std::int64_t range, std::int64_t radix) const { 169 if (radix != 2) { 170 return -5; 171 } 172 if (auto kind{common::SearchTypes( 173 SelectedRealKindVisitor{*this, precision, range})}) { 174 return *kind; 175 } 176 // No kind has both sufficient precision and sufficient range. 177 // The negative return value encodes whether any kinds exist that 178 // could satisfy either constraint independently. 179 bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})}; 180 bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})}; 181 if (pOK) { 182 if (rOK) { 183 return -4; 184 } else { 185 return -2; 186 } 187 } else { 188 if (rOK) { 189 return -1; 190 } else { 191 return -3; 192 } 193 } 194 } 195 196 } // namespace Fortran::evaluate 197