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 
TargetCharacteristics()18 TargetCharacteristics::TargetCharacteristics() {
19   // TODO: Fill in the type information from command-line targeting information.
20   auto enableCategoryKinds{[this](TypeCategory category) {
21     for (int kind{0}; kind < maxKind; ++kind) {
22       if (CanSupportType(category, kind)) {
23         auto byteSize{static_cast<std::size_t>(kind)};
24         if (category == TypeCategory::Real ||
25             category == TypeCategory::Complex) {
26           if (kind == 3) {
27             // non-IEEE 16-bit format (truncated 32-bit)
28             byteSize = 2;
29           } else if (kind == 10) {
30             // x87 floating-point
31             // Follow gcc precedent for "long double"
32             byteSize = 16;
33           }
34         }
35         std::size_t align{byteSize};
36         if (category == TypeCategory::Complex) {
37           byteSize = 2 * byteSize;
38         }
39         EnableType(category, kind, byteSize, align);
40       }
41     }
42   }};
43   enableCategoryKinds(TypeCategory::Integer);
44   enableCategoryKinds(TypeCategory::Real);
45   enableCategoryKinds(TypeCategory::Complex);
46   enableCategoryKinds(TypeCategory::Character);
47   enableCategoryKinds(TypeCategory::Logical);
48 
49   isBigEndian_ = !isHostLittleEndian;
50 
51   areSubnormalsFlushedToZero_ = false;
52 }
53 
CanSupportType(TypeCategory category,std::int64_t kind)54 bool TargetCharacteristics::CanSupportType(
55     TypeCategory category, std::int64_t kind) {
56   return IsValidKindOfIntrinsicType(category, kind);
57 }
58 
EnableType(common::TypeCategory category,std::int64_t kind,std::size_t byteSize,std::size_t align)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 
DisableType(common::TypeCategory category,std::int64_t kind)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 
GetByteSize(common::TypeCategory category,std::int64_t kind) const79 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 
GetAlignment(common::TypeCategory category,std::int64_t kind) const88 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 
IsTypeEnabled(common::TypeCategory category,std::int64_t kind) const97 bool TargetCharacteristics::IsTypeEnabled(
98     common::TypeCategory category, std::int64_t kind) const {
99   return GetAlignment(category, kind) > 0;
100 }
101 
set_isBigEndian(bool isBig)102 void TargetCharacteristics::set_isBigEndian(bool isBig) {
103   isBigEndian_ = isBig;
104 }
105 
set_areSubnormalsFlushedToZero(bool yes)106 void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) {
107   areSubnormalsFlushedToZero_ = yes;
108 }
109 
set_roundingMode(Rounding rounding)110 void TargetCharacteristics::set_roundingMode(Rounding rounding) {
111   roundingMode_ = rounding;
112 }
113 
114 // SELECTED_INT_KIND() -- F'2018 16.9.169
115 class SelectedIntKindVisitor {
116 public:
SelectedIntKindVisitor(const TargetCharacteristics & targetCharacteristics,std::int64_t p)117   SelectedIntKindVisitor(
118       const TargetCharacteristics &targetCharacteristics, std::int64_t p)
119       : targetCharacteristics_{targetCharacteristics}, precision_{p} {}
120   using Result = std::optional<int>;
121   using Types = IntegerTypes;
Test() const122   template <typename T> Result Test() const {
123     if (Scalar<T>::RANGE >= precision_ &&
124         targetCharacteristics_.IsTypeEnabled(T::category, T::kind)) {
125       return T::kind;
126     } else {
127       return std::nullopt;
128     }
129   }
130 
131 private:
132   const TargetCharacteristics &targetCharacteristics_;
133   std::int64_t precision_;
134 };
135 
SelectedIntKind(std::int64_t precision) const136 int TargetCharacteristics::SelectedIntKind(std::int64_t precision) const {
137   if (auto kind{
138           common::SearchTypes(SelectedIntKindVisitor{*this, precision})}) {
139     return *kind;
140   } else {
141     return -1;
142   }
143 }
144 
145 // SELECTED_REAL_KIND() -- F'2018 16.9.170
146 class SelectedRealKindVisitor {
147 public:
SelectedRealKindVisitor(const TargetCharacteristics & targetCharacteristics,std::int64_t p,std::int64_t r)148   SelectedRealKindVisitor(const TargetCharacteristics &targetCharacteristics,
149       std::int64_t p, std::int64_t r)
150       : targetCharacteristics_{targetCharacteristics}, precision_{p}, range_{
151                                                                           r} {}
152   using Result = std::optional<int>;
153   using Types = RealTypes;
Test() const154   template <typename T> Result Test() const {
155     if (Scalar<T>::PRECISION >= precision_ && Scalar<T>::RANGE >= range_ &&
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 precision_, range_;
166 };
167 
SelectedRealKind(std::int64_t precision,std::int64_t range,std::int64_t radix) const168 int TargetCharacteristics::SelectedRealKind(
169     std::int64_t precision, std::int64_t range, std::int64_t radix) const {
170   if (radix != 2) {
171     return -5;
172   }
173   if (auto kind{common::SearchTypes(
174           SelectedRealKindVisitor{*this, precision, range})}) {
175     return *kind;
176   }
177   // No kind has both sufficient precision and sufficient range.
178   // The negative return value encodes whether any kinds exist that
179   // could satisfy either constraint independently.
180   bool pOK{common::SearchTypes(SelectedRealKindVisitor{*this, precision, 0})};
181   bool rOK{common::SearchTypes(SelectedRealKindVisitor{*this, 0, range})};
182   if (pOK) {
183     if (rOK) {
184       return -4;
185     } else {
186       return -2;
187     }
188   } else {
189     if (rOK) {
190       return -1;
191     } else {
192       return -3;
193     }
194   }
195 }
196 
197 } // namespace Fortran::evaluate
198