271 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Evaluate/target.h"10#include "flang/Common/template.h"11#include "flang/Common/type-kinds.h"12#include "flang/Evaluate/common.h"13#include "flang/Evaluate/type.h"14 15namespace Fortran::evaluate {16 17Rounding TargetCharacteristics::defaultRounding;18 19TargetCharacteristics::TargetCharacteristics() {20 auto enableCategoryKinds{[this](TypeCategory category) {21 for (int kind{1}; kind <= maxKind; ++kind) {22 if (CanSupportType(category, kind)) {23 auto byteSize{24 static_cast<std::size_t>(common::TypeSizeInBytes(category, kind))};25 std::size_t align{byteSize};26 if (category == TypeCategory::Complex) {27 align /= 2;28 }29 EnableType(category, kind, byteSize, align);30 }31 }32 }};33 enableCategoryKinds(TypeCategory::Integer);34 enableCategoryKinds(TypeCategory::Real);35 enableCategoryKinds(TypeCategory::Complex);36 enableCategoryKinds(TypeCategory::Character);37 enableCategoryKinds(TypeCategory::Logical);38 enableCategoryKinds(TypeCategory::Unsigned);39 40 isBigEndian_ = !isHostLittleEndian;41 42 areSubnormalsFlushedToZero_ = false;43}44 45bool TargetCharacteristics::CanSupportType(46 TypeCategory category, std::int64_t kind) {47 return common::IsValidKindOfIntrinsicType(category, kind);48}49 50bool TargetCharacteristics::EnableType(common::TypeCategory category,51 std::int64_t kind, std::size_t byteSize, std::size_t align) {52 if (CanSupportType(category, kind)) {53 byteSize_[static_cast<int>(category)][kind] = byteSize;54 align_[static_cast<int>(category)][kind] = align;55 maxByteSize_ = std::max(maxByteSize_, byteSize);56 maxAlignment_ = std::max(maxAlignment_, align);57 return true;58 } else {59 return false;60 }61}62 63void TargetCharacteristics::DisableType(64 common::TypeCategory category, std::int64_t kind) {65 if (kind > 0 && kind <= maxKind) {66 align_[static_cast<int>(category)][kind] = 0;67 }68}69 70std::size_t TargetCharacteristics::GetByteSize(71 common::TypeCategory category, std::int64_t kind) const {72 if (kind > 0 && kind <= maxKind) {73 return byteSize_[static_cast<int>(category)][kind];74 } else {75 return 0;76 }77}78 79std::size_t TargetCharacteristics::GetAlignment(80 common::TypeCategory category, std::int64_t kind) const {81 if (kind > 0 && kind <= maxKind) {82 return align_[static_cast<int>(category)][kind];83 } else {84 return 0;85 }86}87 88bool TargetCharacteristics::IsTypeEnabled(89 common::TypeCategory category, std::int64_t kind) const {90 return GetAlignment(category, kind) > 0;91}92 93void TargetCharacteristics::set_isBigEndian(bool isBig) {94 isBigEndian_ = isBig;95}96 97void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; }98void TargetCharacteristics::set_isSPARC(bool isSPARC) { isSPARC_ = isSPARC; }99 100void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) {101 areSubnormalsFlushedToZero_ = yes;102}103 104// Check if a given real kind has flushing control.105bool TargetCharacteristics::hasSubnormalFlushingControl(int kind) const {106 CHECK(kind > 0 && kind <= maxKind);107 CHECK(CanSupportType(TypeCategory::Real, kind));108 return hasSubnormalFlushingControl_[kind];109}110 111// Check if any or all real kinds have flushing control.112bool TargetCharacteristics::hasSubnormalFlushingControl(bool any) const {113 for (int kind{1}; kind <= maxKind; ++kind) {114 if (CanSupportType(TypeCategory::Real, kind) &&115 hasSubnormalFlushingControl_[kind] == any) {116 return any;117 }118 }119 return !any;120}121 122void TargetCharacteristics::set_hasSubnormalFlushingControl(123 int kind, bool yes) {124 CHECK(kind > 0 && kind <= maxKind);125 hasSubnormalFlushingControl_[kind] = yes;126}127 128// Check if a given real kind has (nonstandard) ieee_denorm exception control.129bool TargetCharacteristics::hasSubnormalExceptionSupport(int kind) const {130 CHECK(kind > 0 && kind <= maxKind);131 CHECK(CanSupportType(TypeCategory::Real, kind));132 return hasSubnormalExceptionSupport_[kind];133}134 135// Check if all real kinds have support for the ieee_denorm exception.136bool TargetCharacteristics::hasSubnormalExceptionSupport() const {137 for (int kind{1}; kind <= maxKind; ++kind) {138 if (CanSupportType(TypeCategory::Real, kind) &&139 !hasSubnormalExceptionSupport_[kind]) {140 return false;141 }142 }143 return true;144}145 146void TargetCharacteristics::set_hasSubnormalExceptionSupport(147 int kind, bool yes) {148 CHECK(kind > 0 && kind <= maxKind);149 hasSubnormalExceptionSupport_[kind] = yes;150}151 152void TargetCharacteristics::set_roundingMode(Rounding rounding) {153 roundingMode_ = rounding;154}155 156// SELECTED_INT_KIND() -- F'2018 16.9.169157// and SELECTED_UNSIGNED_KIND() extension (same results)158class SelectedIntKindVisitor {159public:160 SelectedIntKindVisitor(161 const TargetCharacteristics &targetCharacteristics, std::int64_t p)162 : targetCharacteristics_{targetCharacteristics}, precision_{p} {}163 using Result = std::optional<int>;164 using Types = IntegerTypes;165 template <typename T> Result Test() const {166 if (Scalar<T>::RANGE >= precision_ &&167 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) {168 return T::kind;169 } else {170 return std::nullopt;171 }172 }173 174private:175 const TargetCharacteristics &targetCharacteristics_;176 std::int64_t precision_;177};178 179int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const {180 if (auto kind{181 common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) {182 return *kind;183 } else {184 return -1;185 }186}187 188// SELECTED_LOGICAL_KIND() -- F'2023 16.9.182189class SelectedLogicalKindVisitor {190public:191 SelectedLogicalKindVisitor(192 const TargetCharacteristics &targetCharacteristics, std::int64_t bits)193 : targetCharacteristics_{targetCharacteristics}, bits_{bits} {}194 using Result = std::optional<int>;195 using Types = LogicalTypes;196 template <typename T> Result Test() const {197 if (Scalar<T>::bits >= bits_ &&198 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) {199 return T::kind;200 } else {201 return std::nullopt;202 }203 }204 205private:206 const TargetCharacteristics &targetCharacteristics_;207 std::int64_t bits_;208};209 210int TargetCharacteristics::SelectedLogicalKind(std::int64_t bits) const {211 if (auto kind{common::SearchTypes(SelectedLogicalKindVisitor{*this, bits})}) {212 return *kind;213 } else {214 return -1;215 }216}217 218// SELECTED_REAL_KIND() -- F'2018 16.9.170219class SelectedRealKindVisitor {220public:221 SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics,222 std::int64_t p, std::int64_t r)223 : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{224 r} {}225 using Result = std::optional<int>;226 using Types = RealTypes;227 template <typename T> Result Test() const {228 if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ &&229 targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) {230 return {T::kind};231 } else {232 return std::nullopt;233 }234 }235 236private:237 const TargetCharacteristics &targetCharacteristics_;238 std::int64_t precision_, range_;239};240 241int TargetCharacteristics::SelectedRealKind(242 std::int64_t precision, std::int64_t range, std::int64_t radix) const {243 if (radix != 2) {244 return -5;245 }246 if (auto kind{common::SearchTypes(247 SelectedRealKindVisitor{*this, precision, range})}) {248 return *kind;249 }250 // No kind has both sufficient precision and sufficient range.251 // The negative return value encodes whether any kinds exist that252 // could satisfy either constraint independently.253 bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})};254 bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})};255 if (pOK) {256 if (rOK) {257 return -4;258 } else {259 return -2;260 }261 } else {262 if (rOK) {263 return -1;264 } else {265 return -3;266 }267 }268}269 270} // namespace Fortran::evaluate271