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{1}; 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 enableCategoryKinds(TypeCategory::Unsigned); 48 49 isBigEndian_ = !isHostLittleEndian; 50 51 areSubnormalsFlushedToZero_ = false; 52 } 53 54 bool TargetCharacteristics::CanSupportType( 55 TypeCategory category, std::int64_t kind) { 56 return IsValidKindOfIntrinsicType(category, kind); 57 } 58 59 bool TargetCharacteristics::EnableType(common::TypeCategory category, 60 std::int64_t kind, std::size_t byteSize, std::size_t align) { 61 if (CanSupportType(category, kind)) { 62 byteSize_[static_cast<int>(category)][kind] = byteSize; 63 align_[static_cast<int>(category)][kind] = align; 64 maxByteSize_ = std::max(maxByteSize_, byteSize); 65 maxAlignment_ = std::max(maxAlignment_, align); 66 return true; 67 } else { 68 return false; 69 } 70 } 71 72 void TargetCharacteristics::DisableType( 73 common::TypeCategory category, std::int64_t kind) { 74 if (kind > 0 && kind <= maxKind) { 75 align_[static_cast<int>(category)][kind] = 0; 76 } 77 } 78 79 std::size_t TargetCharacteristics::GetByteSize( 80 common::TypeCategory category, std::int64_t kind) const { 81 if (kind > 0 && kind <= maxKind) { 82 return byteSize_[static_cast<int>(category)][kind]; 83 } else { 84 return 0; 85 } 86 } 87 88 std::size_t TargetCharacteristics::GetAlignment( 89 common::TypeCategory category, std::int64_t kind) const { 90 if (kind > 0 && kind <= maxKind) { 91 return align_[static_cast<int>(category)][kind]; 92 } else { 93 return 0; 94 } 95 } 96 97 bool TargetCharacteristics::IsTypeEnabled( 98 common::TypeCategory category, std::int64_t kind) const { 99 return GetAlignment(category, kind) > 0; 100 } 101 102 void TargetCharacteristics::set_isBigEndian(bool isBig) { 103 isBigEndian_ = isBig; 104 } 105 106 void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; } 107 void TargetCharacteristics::set_isSPARC(bool isSPARC) { isSPARC_ = isSPARC; } 108 109 void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { 110 areSubnormalsFlushedToZero_ = yes; 111 } 112 113 // Check if a given real kind has flushing control. 114 bool TargetCharacteristics::hasSubnormalFlushingControl(int kind) const { 115 CHECK(kind > 0 && kind <= maxKind); 116 CHECK(CanSupportType(TypeCategory::Real, kind)); 117 return hasSubnormalFlushingControl_[kind]; 118 } 119 120 // Check if any or all real kinds have flushing control. 121 bool TargetCharacteristics::hasSubnormalFlushingControl(bool any) const { 122 for (int kind{1}; kind <= maxKind; ++kind) { 123 if (CanSupportType(TypeCategory::Real, kind) && 124 hasSubnormalFlushingControl_[kind] == any) { 125 return any; 126 } 127 } 128 return !any; 129 } 130 131 void TargetCharacteristics::set_hasSubnormalFlushingControl( 132 int kind, bool yes) { 133 CHECK(kind > 0 && kind <= maxKind); 134 hasSubnormalFlushingControl_[kind] = yes; 135 } 136 137 void TargetCharacteristics::set_roundingMode(Rounding rounding) { 138 roundingMode_ = rounding; 139 } 140 141 // SELECTED_INT_KIND() -- F'2018 16.9.169 142 // and SELECTED_UNSIGNED_KIND() extension (same results) 143 class SelectedIntKindVisitor { 144 public: 145 SelectedIntKindVisitor( 146 const TargetCharacteristics &targetCharacteristics, std::int64_t p) 147 : targetCharacteristics_{targetCharacteristics}, precision_{p} {} 148 using Result = std::optional<int>; 149 using Types = IntegerTypes; 150 template <typename T> Result Test() const { 151 if (Scalar<T>::RANGE >= precision_ && 152 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 153 return T::kind; 154 } else { 155 return std::nullopt; 156 } 157 } 158 159 private: 160 const TargetCharacteristics &targetCharacteristics_; 161 std::int64_t precision_; 162 }; 163 164 int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const { 165 if (auto kind{ 166 common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) { 167 return *kind; 168 } else { 169 return -1; 170 } 171 } 172 173 // SELECTED_LOGICAL_KIND() -- F'2023 16.9.182 174 class SelectedLogicalKindVisitor { 175 public: 176 SelectedLogicalKindVisitor( 177 const TargetCharacteristics &targetCharacteristics, std::int64_t bits) 178 : targetCharacteristics_{targetCharacteristics}, bits_{bits} {} 179 using Result = std::optional<int>; 180 using Types = LogicalTypes; 181 template <typename T> Result Test() const { 182 if (Scalar<T>::bits >= bits_ && 183 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 184 return T::kind; 185 } else { 186 return std::nullopt; 187 } 188 } 189 190 private: 191 const TargetCharacteristics &targetCharacteristics_; 192 std::int64_t bits_; 193 }; 194 195 int TargetCharacteristics::SelectedLogicalKind(std::int64_t bits) const { 196 if (auto kind{common::SearchTypes(SelectedLogicalKindVisitor{*this, bits})}) { 197 return *kind; 198 } else { 199 return -1; 200 } 201 } 202 203 // SELECTED_REAL_KIND() -- F'2018 16.9.170 204 class SelectedRealKindVisitor { 205 public: 206 SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics, 207 std::int64_t p, std::int64_t r) 208 : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{ 209 r} {} 210 using Result = std::optional<int>; 211 using Types = RealTypes; 212 template <typename T> Result Test() const { 213 if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ && 214 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { 215 return {T::kind}; 216 } else { 217 return std::nullopt; 218 } 219 } 220 221 private: 222 const TargetCharacteristics &targetCharacteristics_; 223 std::int64_t precision_, range_; 224 }; 225 226 int TargetCharacteristics::SelectedRealKind( 227 std::int64_t precision, std::int64_t range, std::int64_t radix) const { 228 if (radix != 2) { 229 return -5; 230 } 231 if (auto kind{common::SearchTypes( 232 SelectedRealKindVisitor{*this, precision, range})}) { 233 return *kind; 234 } 235 // No kind has both sufficient precision and sufficient range. 236 // The negative return value encodes whether any kinds exist that 237 // could satisfy either constraint independently. 238 bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})}; 239 bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})}; 240 if (pOK) { 241 if (rOK) { 242 return -4; 243 } else { 244 return -2; 245 } 246 } else { 247 if (rOK) { 248 return -1; 249 } else { 250 return -3; 251 } 252 } 253 } 254 255 } // namespace Fortran::evaluate 256