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_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; } |
106 | |
107 | void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { |
108 | areSubnormalsFlushedToZero_ = yes; |
109 | } |
110 | |
111 | void TargetCharacteristics::set_roundingMode(Rounding rounding) { |
112 | roundingMode_ = rounding; |
113 | } |
114 | |
115 | // SELECTED_INT_KIND() -- F'2018 16.9.169 |
116 | class SelectedIntKindVisitor { |
117 | public: |
118 | SelectedIntKindVisitor( |
119 | const TargetCharacteristics &targetCharacteristics, std::int64_t p) |
120 | : targetCharacteristics_{targetCharacteristics}, precision_{p} {} |
121 | using Result = std::optional<int>; |
122 | using Types = IntegerTypes; |
123 | template <typename T> Result Test() const { |
124 | if (Scalar<T>::RANGE >= precision_ && |
125 | targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
126 | return T::kind; |
127 | } else { |
128 | return std::nullopt; |
129 | } |
130 | } |
131 | |
132 | private: |
133 | const TargetCharacteristics &targetCharacteristics_; |
134 | std::int64_t precision_; |
135 | }; |
136 | |
137 | int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const { |
138 | if (auto kind{ |
139 | common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) { |
140 | return *kind; |
141 | } else { |
142 | return -1; |
143 | } |
144 | } |
145 | |
146 | // SELECTED_LOGICAL_KIND() -- F'2023 16.9.182 |
147 | class SelectedLogicalKindVisitor { |
148 | public: |
149 | SelectedLogicalKindVisitor( |
150 | const TargetCharacteristics &targetCharacteristics, std::int64_t bits) |
151 | : targetCharacteristics_{targetCharacteristics}, bits_{bits} {} |
152 | using Result = std::optional<int>; |
153 | using Types = LogicalTypes; |
154 | template <typename T> Result Test() const { |
155 | if (Scalar<T>::bits >= bits_ && |
156 | targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
157 | return T::kind; |
158 | } else { |
159 | return std::nullopt; |
160 | } |
161 | } |
162 | |
163 | private: |
164 | const TargetCharacteristics &targetCharacteristics_; |
165 | std::int64_t bits_; |
166 | }; |
167 | |
168 | int TargetCharacteristics::SelectedLogicalKind(std::int64_t bits) const { |
169 | if (auto kind{common::SearchTypes(SelectedLogicalKindVisitor{*this, bits})}) { |
170 | return *kind; |
171 | } else { |
172 | return -1; |
173 | } |
174 | } |
175 | |
176 | // SELECTED_REAL_KIND() -- F'2018 16.9.170 |
177 | class SelectedRealKindVisitor { |
178 | public: |
179 | SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics, |
180 | std::int64_t p, std::int64_t r) |
181 | : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{ |
182 | r} {} |
183 | using Result = std::optional<int>; |
184 | using Types = RealTypes; |
185 | template <typename T> Result Test() const { |
186 | if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ && |
187 | targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) { |
188 | return {T::kind}; |
189 | } else { |
190 | return std::nullopt; |
191 | } |
192 | } |
193 | |
194 | private: |
195 | const TargetCharacteristics &targetCharacteristics_; |
196 | std::int64_t precision_, range_; |
197 | }; |
198 | |
199 | int TargetCharacteristics::SelectedRealKind( |
200 | std::int64_t precision, std::int64_t range, std::int64_t radix) const { |
201 | if (radix != 2) { |
202 | return -5; |
203 | } |
204 | if (auto kind{common::SearchTypes( |
205 | SelectedRealKindVisitor{*this, precision, range})}) { |
206 | return *kind; |
207 | } |
208 | // No kind has both sufficient precision and sufficient range. |
209 | // The negative return value encodes whether any kinds exist that |
210 | // could satisfy either constraint independently. |
211 | bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})}; |
212 | bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})}; |
213 | if (pOK) { |
214 | if (rOK) { |
215 | return -4; |
216 | } else { |
217 | return -2; |
218 | } |
219 | } else { |
220 | if (rOK) { |
221 | return -1; |
222 | } else { |
223 | return -3; |
224 | } |
225 | } |
226 | } |
227 | |
228 | } // namespace Fortran::evaluate |
229 | |