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