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