1 /*
2  * Copyright (c) 2021 - 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H
17 #define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H
18 
19 #include "checker/ets/typeConverter.h"
20 #include "checker/ETSchecker.h"
21 #include "util/helpers.h"
22 
23 namespace ark::es2panda::checker {
24 class NarrowingConverter : public TypeConverter {
25 public:
NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source)26     explicit NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source)
27         : TypeConverter(checker, relation, target, source)
28     {
29         if (!relation->ApplyNarrowing()) {
30             return;
31         }
32 
33         ASSERT(relation->GetNode());
34 
35         switch (ETSChecker::ETSChecker::ETSType(target)) {
36             case TypeFlag::BYTE: {
37                 ApplyNarrowing<ByteType>(TypeFlag::NARROWABLE_TO_BYTE);
38                 break;
39             }
40             case TypeFlag::CHAR: {
41                 ApplyNarrowing<CharType>(TypeFlag::NARROWABLE_TO_CHAR);
42                 break;
43             }
44             case TypeFlag::SHORT: {
45                 ApplyNarrowing<ShortType>(TypeFlag::NARROWABLE_TO_SHORT);
46                 break;
47             }
48             case TypeFlag::INT: {
49                 ApplyNarrowing<IntType>(TypeFlag::NARROWABLE_TO_INT);
50                 break;
51             }
52             case TypeFlag::LONG: {
53                 ApplyNarrowing<LongType>(TypeFlag::NARROWABLE_TO_LONG);
54                 break;
55             }
56             case TypeFlag::FLOAT: {
57                 ApplyNarrowing<FloatType>(TypeFlag::NARROWABLE_TO_FLOAT);
58                 break;
59             }
60 
61             default: {
62                 break;
63             }
64         }
65     }
66 
67 private:
68     template <typename TargetType>
ApplyNarrowing(TypeFlag flag)69     void ApplyNarrowing(TypeFlag flag)
70     {
71         if (!Source()->HasTypeFlag(flag)) {
72             return;
73         }
74 
75         switch (ETSChecker::ETSChecker::ETSType(Source())) {
76             case TypeFlag::CHAR: {
77                 ApplyNarrowing<TargetType, CharType>();
78                 break;
79             }
80             case TypeFlag::SHORT: {
81                 ApplyNarrowing<TargetType, ShortType>();
82                 break;
83             }
84             case TypeFlag::INT: {
85                 ApplyNarrowing<TargetType, IntType>();
86                 break;
87             }
88             case TypeFlag::LONG: {
89                 ApplyNarrowing<TargetType, LongType>();
90                 break;
91             }
92             case TypeFlag::FLOAT: {
93                 ApplyNarrowing<TargetType, FloatType>();
94                 break;
95             }
96             case TypeFlag::DOUBLE: {
97                 ApplyNarrowing<TargetType, DoubleType>();
98                 break;
99             }
100             default: {
101                 break;
102             }
103         }
104     }
105 
106     template <typename From, typename To>
CastFloatingPointToIntOrLong(From value)107     To CastFloatingPointToIntOrLong(From value)
108     {
109         if (std::isinf(value)) {
110             if (std::signbit(value)) {
111                 return std::numeric_limits<To>::min();
112             }
113             return std::numeric_limits<To>::max();
114         }
115         ASSERT(std::is_floating_point_v<From>);
116         ASSERT(std::is_integral_v<To>);
117         To minInt = std::numeric_limits<To>::min();
118         To maxInt = std::numeric_limits<To>::max();
119         auto floatMinInt = static_cast<From>(minInt);
120         auto floatMaxInt = static_cast<From>(maxInt);
121 
122         if (value > floatMinInt) {
123             if (value < floatMaxInt) {
124                 return static_cast<To>(value);
125             }
126             return maxInt;
127         }
128         if (std::isnan(value)) {
129             return 0;
130         }
131         return minInt;
132     }
133 
134     template <typename TType, typename SType>
CalculateNarrowedValue(Type *target, Type *source, SType value)135     TType CalculateNarrowedValue(Type *target, Type *source, SType value)
136     {
137         switch (ETSChecker::ETSChecker::ETSType(target)) {
138             case TypeFlag::BYTE:
139             case TypeFlag::CHAR:
140             case TypeFlag::SHORT: {
141                 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) {
142                     return static_cast<TType>(CastFloatingPointToIntOrLong<SType, int32_t>(value));
143                 }
144                 return static_cast<TType>(value);
145             }
146             case TypeFlag::INT:
147             case TypeFlag::LONG: {
148                 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) {
149                     return CastFloatingPointToIntOrLong<SType, TType>(value);
150                 }
151                 return static_cast<TType>(value);
152             }
153             case TypeFlag::FLOAT:
154             case TypeFlag::DOUBLE: {
155                 return static_cast<TType>(value);
156             }
157             default: {
158                 UNREACHABLE();
159             }
160         }
161     }
162 
163     template <typename TargetType, typename SourceType>
ApplyNarrowing()164     void ApplyNarrowing()
165     {
166         using SType = typename SourceType::UType;
167         using TType = typename TargetType::UType;
168 
169         if (Source()->HasTypeFlag(TypeFlag::CONSTANT)) {
170             SType value = reinterpret_cast<SourceType *>(Source())->GetValue();
171             if (!Relation()->InCastingContext() && Source()->HasTypeFlag(TypeFlag::ETS_FLOATING_POINT) &&
172                 Target()->HasTypeFlag(TypeFlag::ETS_INTEGRAL)) {
173                 auto narrowedValue = CalculateNarrowedValue<TType, SType>(Target(), Source(), value);
174                 if (narrowedValue != value) {
175                     Relation()->Result(RelationResult::ERROR);
176                     return;
177                 }
178             }
179 
180             if (Relation()->InCastingContext() || util::Helpers::IsTargetFitInSourceRange<TType, SType>(value)) {
181                 auto narrowedValue = CalculateNarrowedValue<TType, SType>(Target(), Source(), value);
182                 TargetType *newType = Checker()->Allocator()->New<TargetType>(narrowedValue);
183                 Relation()->GetNode()->SetTsType(newType);
184                 Relation()->Result(true);
185                 return;
186             }
187 
188             Relation()->Result(RelationResult::ERROR);
189             return;
190         }
191 
192         Relation()->Result(true);
193     }
194 };
195 }  // namespace ark::es2panda::checker
196 
197 #endif
198