• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
26     static constexpr TypeFlag NARROWABLE_TO_FLOAT = TypeFlag::DOUBLE;
27     static constexpr TypeFlag NARROWABLE_TO_LONG = TypeFlag::FLOAT | NARROWABLE_TO_FLOAT;
28     static constexpr TypeFlag NARROWABLE_TO_INT = TypeFlag::LONG | NARROWABLE_TO_LONG;
29     static constexpr TypeFlag NARROWABLE_TO_CHAR = TypeFlag::SHORT | TypeFlag::INT | NARROWABLE_TO_INT;
30     static constexpr TypeFlag NARROWABLE_TO_SHORT = TypeFlag::CHAR | TypeFlag::INT | NARROWABLE_TO_INT;
31     static constexpr TypeFlag NARROWABLE_TO_BYTE = TypeFlag::CHAR | NARROWABLE_TO_CHAR;
32 
NarrowingConverter(ETSChecker * checker,TypeRelation * relation,Type * target,Type * source)33     explicit NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source)
34         : TypeConverter(checker, relation, target, source)
35     {
36         if (!relation->ApplyNarrowing()) {
37             return;
38         }
39 
40         ASSERT(relation->GetNode());
41 
42         switch (ETSChecker::ETSChecker::ETSType(target)) {
43             case TypeFlag::BYTE: {
44                 ApplyNarrowing<ByteType>(NARROWABLE_TO_BYTE);
45                 break;
46             }
47             case TypeFlag::CHAR: {
48                 ApplyNarrowing<CharType>(NARROWABLE_TO_CHAR);
49                 break;
50             }
51             case TypeFlag::SHORT: {
52                 ApplyNarrowing<ShortType>(NARROWABLE_TO_SHORT);
53                 break;
54             }
55             case TypeFlag::INT: {
56                 ApplyNarrowing<IntType>(NARROWABLE_TO_INT);
57                 break;
58             }
59             case TypeFlag::LONG: {
60                 ApplyNarrowing<LongType>(NARROWABLE_TO_LONG);
61                 break;
62             }
63             case TypeFlag::FLOAT: {
64                 ApplyNarrowing<FloatType>(NARROWABLE_TO_FLOAT);
65                 break;
66             }
67 
68             default: {
69                 break;
70             }
71         }
72     }
73 
74 private:
75     template <typename TargetType>
ApplyNarrowing(TypeFlag flag)76     void ApplyNarrowing(TypeFlag flag)
77     {
78         if (!Source()->HasTypeFlag(flag)) {
79             return;
80         }
81 
82         switch (ETSChecker::ETSChecker::ETSType(Source())) {
83             case TypeFlag::CHAR: {
84                 ApplyNarrowing<TargetType, CharType>();
85                 break;
86             }
87             case TypeFlag::SHORT: {
88                 ApplyNarrowing<TargetType, ShortType>();
89                 break;
90             }
91             case TypeFlag::INT: {
92                 ApplyNarrowing<TargetType, IntType>();
93                 break;
94             }
95             case TypeFlag::LONG: {
96                 ApplyNarrowing<TargetType, LongType>();
97                 break;
98             }
99             case TypeFlag::FLOAT: {
100                 ApplyNarrowing<TargetType, FloatType>();
101                 break;
102             }
103             case TypeFlag::DOUBLE: {
104                 ApplyNarrowing<TargetType, DoubleType>();
105                 break;
106             }
107             default: {
108                 break;
109             }
110         }
111     }
112 
113     template <typename From, typename To>
CastFloatingPointToIntOrLong(From value)114     To CastFloatingPointToIntOrLong(From value)
115     {
116         if (std::isinf(value)) {
117             if (std::signbit(value)) {
118                 return std::numeric_limits<To>::min();
119             }
120             return std::numeric_limits<To>::max();
121         }
122         ASSERT(std::is_floating_point_v<From>);
123         ASSERT(std::is_integral_v<To>);
124         To minInt = std::numeric_limits<To>::min();
125         To maxInt = std::numeric_limits<To>::max();
126         auto floatMinInt = static_cast<From>(minInt);
127         auto floatMaxInt = static_cast<From>(maxInt);
128 
129         if (value > floatMinInt) {
130             if (value < floatMaxInt) {
131                 return static_cast<To>(value);
132             }
133             return maxInt;
134         }
135         if (std::isnan(value)) {
136             return 0;
137         }
138         return minInt;
139     }
140 
141     template <typename TType, typename SType>
CalculateNarrowedValue(Type * target,Type * source,SType value)142     TType CalculateNarrowedValue(Type *target, Type *source, SType value)
143     {
144         switch (ETSChecker::ETSChecker::ETSType(target)) {
145             case TypeFlag::BYTE:
146             case TypeFlag::CHAR:
147             case TypeFlag::SHORT: {
148                 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) {
149                     return static_cast<TType>(CastFloatingPointToIntOrLong<SType, int32_t>(value));
150                 }
151                 return static_cast<TType>(value);
152             }
153             case TypeFlag::INT:
154             case TypeFlag::LONG: {
155                 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) {
156                     return CastFloatingPointToIntOrLong<SType, TType>(value);
157                 }
158                 return static_cast<TType>(value);
159             }
160             case TypeFlag::FLOAT:
161             case TypeFlag::DOUBLE: {
162                 return static_cast<TType>(value);
163             }
164             default: {
165                 UNREACHABLE();
166             }
167         }
168     }
169 
170     template <typename TargetType, typename SourceType>
ApplyNarrowing()171     void ApplyNarrowing()
172     {
173         using SType = typename SourceType::UType;
174         using TType = typename TargetType::UType;
175 
176         if (Source()->HasTypeFlag(TypeFlag::CONSTANT)) {
177             SType value = reinterpret_cast<SourceType *>(Source())->GetValue();
178             if (!Relation()->InCastingContext() && Source()->HasTypeFlag(TypeFlag::ETS_FLOATING_POINT) &&
179                 Target()->HasTypeFlag(TypeFlag::ETS_INTEGRAL)) {
180                 auto narrowedValue = CalculateNarrowedValue<TType, SType>(Target(), Source(), value);
181                 if (narrowedValue != value) {
182                     Relation()->Result(RelationResult::ERROR);
183                     return;
184                 }
185             }
186 
187             if (Relation()->InCastingContext() || util::Helpers::IsTargetFitInSourceRange<TType, SType>(value)) {
188                 auto narrowedValue = CalculateNarrowedValue<TType, SType>(Target(), Source(), value);
189                 TargetType *newType = Checker()->Allocator()->New<TargetType>(narrowedValue);
190                 Relation()->GetNode()->SetTsType(newType);
191                 Relation()->Result(true);
192                 return;
193             }
194 
195             Relation()->Result(RelationResult::ERROR);
196             return;
197         }
198 
199         Relation()->Result(true);
200     }
201 };
202 }  // namespace ark::es2panda::checker
203 
204 #endif
205