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