• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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_ARITHMETIC_H
17 #define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H
18 
19 #include "checker/ETSchecker.h"
20 #include "checker/ETSAnalyzer.h"
21 
22 namespace ark::es2panda::checker {
23 
24 template <typename TargetType>
GetOperand(Type * type)25 typename TargetType::UType ETSChecker::GetOperand(Type *type)
26 {
27     switch (ETSType(type)) {
28         case TypeFlag::BYTE: {
29             return type->AsByteType()->GetValue();
30         }
31         case TypeFlag::CHAR: {
32             return type->AsCharType()->GetValue();
33         }
34         case TypeFlag::SHORT: {
35             return type->AsShortType()->GetValue();
36         }
37         case TypeFlag::INT: {
38             return type->AsIntType()->GetValue();
39         }
40         case TypeFlag::LONG: {
41             return type->AsLongType()->GetValue();
42         }
43         case TypeFlag::FLOAT: {
44             return type->AsFloatType()->GetValue();
45         }
46         case TypeFlag::DOUBLE: {
47             return type->AsDoubleType()->GetValue();
48         }
49         case TypeFlag::ETS_BOOLEAN: {
50             return type->AsETSBooleanType()->GetValue();
51         }
52         default: {
53             ES2PANDA_UNREACHABLE();
54         }
55     }
56 }
57 
58 template <typename TargetType>
PerformRelationOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)59 Type *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
60 {
61     using UType = typename TargetType::UType;
62 
63     UType leftValue = GetOperand<TargetType>(left);
64     UType rightValue = GetOperand<TargetType>(right);
65 
66     bool result {};
67     switch (operationType) {
68         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
69             result = leftValue < rightValue;
70             break;
71         }
72         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
73             result = leftValue <= rightValue;
74             break;
75         }
76         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
77             result = leftValue > rightValue;
78             break;
79         }
80         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
81             result = leftValue >= rightValue;
82             break;
83         }
84         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
85         case lexer::TokenType::PUNCTUATOR_EQUAL: {
86             result = leftValue == rightValue;
87             break;
88         }
89         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
90         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
91             result = leftValue != rightValue;
92             break;
93         }
94         default: {
95             ES2PANDA_UNREACHABLE();
96         }
97     }
98 
99     return CreateETSBooleanType(result);
100 }
101 
102 template <typename TargetType>
PerformArithmeticOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)103 Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
104 {
105     using UType = typename TargetType::UType;
106 
107     UType leftValue = GetOperand<TargetType>(left);
108     UType rightValue = GetOperand<TargetType>(right);
109     auto result = leftValue;
110     auto isForbiddenZeroDivision = [&rightValue]() { return std::is_integral<UType>::value && rightValue == 0; };
111     auto isIntegralDivideResOverflow = [&rightValue, &leftValue]() {
112         // Note: Handle corner cases
113         return std::is_integral_v<UType> && leftValue == std::numeric_limits<UType>::min() && rightValue == -1;
114     };
115 
116     switch (operationType) {
117         case lexer::TokenType::PUNCTUATOR_PLUS:
118         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
119             result = leftValue + rightValue;
120             break;
121         }
122         case lexer::TokenType::PUNCTUATOR_MINUS:
123         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: {
124             result = leftValue - rightValue;
125             break;
126         }
127         case lexer::TokenType::PUNCTUATOR_DIVIDE:
128         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
129             if (isForbiddenZeroDivision()) {
130                 return nullptr;
131             }
132 
133             if (isIntegralDivideResOverflow()) {
134                 return ProgramAllocator()->New<TargetType>(std::numeric_limits<UType>::min());
135             }
136 
137             result = leftValue / rightValue;
138             break;
139         }
140         case lexer::TokenType::PUNCTUATOR_MULTIPLY:
141         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: {
142             result = leftValue * rightValue;
143             break;
144         }
145         case lexer::TokenType::PUNCTUATOR_MOD:
146         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: {
147             if (isForbiddenZeroDivision()) {
148                 return nullptr;
149             }
150             result = HandleModulo<UType>(leftValue, rightValue);
151             break;
152         }
153         default: {
154             ES2PANDA_UNREACHABLE();
155         }
156     }
157 
158     return ProgramAllocator()->New<TargetType>(result);
159 }
160 
161 template <>
162 inline IntType::UType ark::es2panda::checker::ETSChecker::HandleModulo<IntType::UType>(IntType::UType leftValue,
163                                                                                        IntType::UType rightValue)
164 {
165     ES2PANDA_ASSERT(rightValue != 0);
166     return leftValue % rightValue;
167 }
168 
169 template <>
170 inline LongType::UType ark::es2panda::checker::ETSChecker::HandleModulo<LongType::UType>(LongType::UType leftValue,
171                                                                                          LongType::UType rightValue)
172 {
173     ES2PANDA_ASSERT(rightValue != 0);
174     return leftValue % rightValue;
175 }
176 
177 template <>
178 inline FloatType::UType ark::es2panda::checker::ETSChecker::HandleModulo<FloatType::UType>(FloatType::UType leftValue,
179                                                                                            FloatType::UType rightValue)
180 {
181     return std::fmod(leftValue, rightValue);
182 }
183 
184 template <>
185 inline DoubleType::UType ark::es2panda::checker::ETSChecker::HandleModulo<DoubleType::UType>(
186     DoubleType::UType leftValue, DoubleType::UType rightValue)
187 {
188     return std::fmod(leftValue, rightValue);
189 }
190 
191 template <typename IntegerUType, typename FloatOrIntegerUType>
CastIfFloat(FloatOrIntegerUType num)192 inline IntegerUType CastIfFloat(FloatOrIntegerUType num)
193 {
194     if constexpr (std::is_floating_point_v<FloatOrIntegerUType>) {
195         return CastFloatToInt<FloatOrIntegerUType, IntegerUType>(num);
196     } else {
197         return num;
198     }
199 }
200 
201 template <typename FloatOrIntegerType, typename IntegerType>
HandleBitWiseArithmetic(Type * left,Type * right,lexer::TokenType operationType)202 Type *ETSChecker::HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operationType)
203 {
204     using IntegerUType = typename IntegerType::UType;
205     using UnsignedUType = std::make_unsigned_t<IntegerUType>;
206 
207     UnsignedUType result = 0;
208     UnsignedUType unsignedLeftValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(left));
209     UnsignedUType unsignedRightValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(right));
210 
211     auto mask = std::numeric_limits<UnsignedUType>::digits - 1U;
212     auto shift = unsignedRightValue & mask;
213 
214     switch (operationType) {
215         case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
216         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: {
217             result = unsignedLeftValue & unsignedRightValue;
218             break;
219         }
220         case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
221         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
222             result = unsignedLeftValue | unsignedRightValue;
223             break;
224         }
225         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
226         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: {
227             result = unsignedLeftValue ^ unsignedRightValue;
228             break;
229         }
230         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
231         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: {
232             static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
233             result = unsignedLeftValue << shift;
234             break;
235         }
236         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
237         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: {
238             static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8);
239             result = static_cast<IntegerUType>(unsignedLeftValue) >> shift;  // NOLINT(hicpp-signed-bitwise)
240             break;
241         }
242         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
243         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: {
244             static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
245             result = unsignedLeftValue >> shift;
246             break;
247         }
248         default: {
249             ES2PANDA_UNREACHABLE();
250         }
251     }
252 
253     return ProgramAllocator()->New<IntegerType>(result);
254 }
255 }  // namespace ark::es2panda::checker
256 
257 #endif
258