13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H
173af6ab5fSopenharmony_ci#define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H
183af6ab5fSopenharmony_ci
193af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
203af6ab5fSopenharmony_ci
213af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
223af6ab5fSopenharmony_ci
233af6ab5fSopenharmony_citemplate <typename TargetType>
243af6ab5fSopenharmony_citypename TargetType::UType ETSChecker::GetOperand(Type *type)
253af6ab5fSopenharmony_ci{
263af6ab5fSopenharmony_ci    switch (ETSType(type)) {
273af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
283af6ab5fSopenharmony_ci            return type->AsByteType()->GetValue();
293af6ab5fSopenharmony_ci        }
303af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
313af6ab5fSopenharmony_ci            return type->AsCharType()->GetValue();
323af6ab5fSopenharmony_ci        }
333af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
343af6ab5fSopenharmony_ci            return type->AsShortType()->GetValue();
353af6ab5fSopenharmony_ci        }
363af6ab5fSopenharmony_ci        case TypeFlag::INT: {
373af6ab5fSopenharmony_ci            return type->AsIntType()->GetValue();
383af6ab5fSopenharmony_ci        }
393af6ab5fSopenharmony_ci        case TypeFlag::LONG: {
403af6ab5fSopenharmony_ci            return type->AsLongType()->GetValue();
413af6ab5fSopenharmony_ci        }
423af6ab5fSopenharmony_ci        case TypeFlag::FLOAT: {
433af6ab5fSopenharmony_ci            return type->AsFloatType()->GetValue();
443af6ab5fSopenharmony_ci        }
453af6ab5fSopenharmony_ci        case TypeFlag::DOUBLE: {
463af6ab5fSopenharmony_ci            return type->AsDoubleType()->GetValue();
473af6ab5fSopenharmony_ci        }
483af6ab5fSopenharmony_ci        case TypeFlag::ETS_BOOLEAN: {
493af6ab5fSopenharmony_ci            return type->AsETSBooleanType()->GetValue();
503af6ab5fSopenharmony_ci        }
513af6ab5fSopenharmony_ci        default: {
523af6ab5fSopenharmony_ci            UNREACHABLE();
533af6ab5fSopenharmony_ci        }
543af6ab5fSopenharmony_ci    }
553af6ab5fSopenharmony_ci}
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_citemplate <typename TargetType>
583af6ab5fSopenharmony_ciType *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
593af6ab5fSopenharmony_ci{
603af6ab5fSopenharmony_ci    using UType = typename TargetType::UType;
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_ci    UType leftValue = GetOperand<TargetType>(left);
633af6ab5fSopenharmony_ci    UType rightValue = GetOperand<TargetType>(right);
643af6ab5fSopenharmony_ci
653af6ab5fSopenharmony_ci    bool result {};
663af6ab5fSopenharmony_ci    switch (operationType) {
673af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
683af6ab5fSopenharmony_ci            result = leftValue < rightValue;
693af6ab5fSopenharmony_ci            break;
703af6ab5fSopenharmony_ci        }
713af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
723af6ab5fSopenharmony_ci            result = leftValue <= rightValue;
733af6ab5fSopenharmony_ci            break;
743af6ab5fSopenharmony_ci        }
753af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
763af6ab5fSopenharmony_ci            result = leftValue > rightValue;
773af6ab5fSopenharmony_ci            break;
783af6ab5fSopenharmony_ci        }
793af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
803af6ab5fSopenharmony_ci            result = leftValue >= rightValue;
813af6ab5fSopenharmony_ci            break;
823af6ab5fSopenharmony_ci        }
833af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EQUAL: {
843af6ab5fSopenharmony_ci            result = leftValue == rightValue;
853af6ab5fSopenharmony_ci            break;
863af6ab5fSopenharmony_ci        }
873af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
883af6ab5fSopenharmony_ci            result = leftValue != rightValue;
893af6ab5fSopenharmony_ci            break;
903af6ab5fSopenharmony_ci        }
913af6ab5fSopenharmony_ci        default: {
923af6ab5fSopenharmony_ci            UNREACHABLE();
933af6ab5fSopenharmony_ci        }
943af6ab5fSopenharmony_ci    }
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_ci    return CreateETSBooleanType(result);
973af6ab5fSopenharmony_ci}
983af6ab5fSopenharmony_ci
993af6ab5fSopenharmony_citemplate <typename TargetType>
1003af6ab5fSopenharmony_ciType *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
1013af6ab5fSopenharmony_ci{
1023af6ab5fSopenharmony_ci    using UType = typename TargetType::UType;
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_ci    UType leftValue = GetOperand<TargetType>(left);
1053af6ab5fSopenharmony_ci    UType rightValue = GetOperand<TargetType>(right);
1063af6ab5fSopenharmony_ci    auto result = leftValue;
1073af6ab5fSopenharmony_ci    auto isForbiddenZeroDivision = [&rightValue]() { return std::is_integral<UType>::value && rightValue == 0; };
1083af6ab5fSopenharmony_ci
1093af6ab5fSopenharmony_ci    switch (operationType) {
1103af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS:
1113af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
1123af6ab5fSopenharmony_ci            result = leftValue + rightValue;
1133af6ab5fSopenharmony_ci            break;
1143af6ab5fSopenharmony_ci        }
1153af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS:
1163af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: {
1173af6ab5fSopenharmony_ci            result = leftValue - rightValue;
1183af6ab5fSopenharmony_ci            break;
1193af6ab5fSopenharmony_ci        }
1203af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE:
1213af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
1223af6ab5fSopenharmony_ci            if (isForbiddenZeroDivision()) {
1233af6ab5fSopenharmony_ci                return nullptr;
1243af6ab5fSopenharmony_ci            }
1253af6ab5fSopenharmony_ci            result = leftValue / rightValue;
1263af6ab5fSopenharmony_ci            break;
1273af6ab5fSopenharmony_ci        }
1283af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY:
1293af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: {
1303af6ab5fSopenharmony_ci            result = leftValue * rightValue;
1313af6ab5fSopenharmony_ci            break;
1323af6ab5fSopenharmony_ci        }
1333af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD:
1343af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: {
1353af6ab5fSopenharmony_ci            if (isForbiddenZeroDivision()) {
1363af6ab5fSopenharmony_ci                return nullptr;
1373af6ab5fSopenharmony_ci            }
1383af6ab5fSopenharmony_ci            result = HandleModulo<UType>(leftValue, rightValue);
1393af6ab5fSopenharmony_ci            break;
1403af6ab5fSopenharmony_ci        }
1413af6ab5fSopenharmony_ci        default: {
1423af6ab5fSopenharmony_ci            UNREACHABLE();
1433af6ab5fSopenharmony_ci        }
1443af6ab5fSopenharmony_ci    }
1453af6ab5fSopenharmony_ci
1463af6ab5fSopenharmony_ci    return Allocator()->New<TargetType>(result);
1473af6ab5fSopenharmony_ci}
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_citemplate <>
1503af6ab5fSopenharmony_ciinline IntType::UType ark::es2panda::checker::ETSChecker::HandleModulo<IntType::UType>(IntType::UType leftValue,
1513af6ab5fSopenharmony_ci                                                                                       IntType::UType rightValue)
1523af6ab5fSopenharmony_ci{
1533af6ab5fSopenharmony_ci    ASSERT(rightValue != 0);
1543af6ab5fSopenharmony_ci    return leftValue % rightValue;
1553af6ab5fSopenharmony_ci}
1563af6ab5fSopenharmony_ci
1573af6ab5fSopenharmony_citemplate <>
1583af6ab5fSopenharmony_ciinline LongType::UType ark::es2panda::checker::ETSChecker::HandleModulo<LongType::UType>(LongType::UType leftValue,
1593af6ab5fSopenharmony_ci                                                                                         LongType::UType rightValue)
1603af6ab5fSopenharmony_ci{
1613af6ab5fSopenharmony_ci    ASSERT(rightValue != 0);
1623af6ab5fSopenharmony_ci    return leftValue % rightValue;
1633af6ab5fSopenharmony_ci}
1643af6ab5fSopenharmony_ci
1653af6ab5fSopenharmony_citemplate <>
1663af6ab5fSopenharmony_ciinline FloatType::UType ark::es2panda::checker::ETSChecker::HandleModulo<FloatType::UType>(FloatType::UType leftValue,
1673af6ab5fSopenharmony_ci                                                                                           FloatType::UType rightValue)
1683af6ab5fSopenharmony_ci{
1693af6ab5fSopenharmony_ci    return std::fmod(leftValue, rightValue);
1703af6ab5fSopenharmony_ci}
1713af6ab5fSopenharmony_ci
1723af6ab5fSopenharmony_citemplate <>
1733af6ab5fSopenharmony_ciinline DoubleType::UType ark::es2panda::checker::ETSChecker::HandleModulo<DoubleType::UType>(
1743af6ab5fSopenharmony_ci    DoubleType::UType leftValue, DoubleType::UType rightValue)
1753af6ab5fSopenharmony_ci{
1763af6ab5fSopenharmony_ci    return std::fmod(leftValue, rightValue);
1773af6ab5fSopenharmony_ci}
1783af6ab5fSopenharmony_ci
1793af6ab5fSopenharmony_citemplate <typename IntegerUType, typename FloatOrIntegerUType>
1803af6ab5fSopenharmony_ciinline IntegerUType CastIfFloat(FloatOrIntegerUType num)
1813af6ab5fSopenharmony_ci{
1823af6ab5fSopenharmony_ci    if constexpr (std::is_floating_point_v<FloatOrIntegerUType>) {
1833af6ab5fSopenharmony_ci        return CastFloatToInt<FloatOrIntegerUType, IntegerUType>(num);
1843af6ab5fSopenharmony_ci    } else {
1853af6ab5fSopenharmony_ci        return num;
1863af6ab5fSopenharmony_ci    }
1873af6ab5fSopenharmony_ci}
1883af6ab5fSopenharmony_ci
1893af6ab5fSopenharmony_citemplate <typename FloatOrIntegerType, typename IntegerType>
1903af6ab5fSopenharmony_ciType *ETSChecker::HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operationType)
1913af6ab5fSopenharmony_ci{
1923af6ab5fSopenharmony_ci    using IntegerUType = typename IntegerType::UType;
1933af6ab5fSopenharmony_ci    using UnsignedUType = std::make_unsigned_t<IntegerUType>;
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci    UnsignedUType result = 0;
1963af6ab5fSopenharmony_ci    UnsignedUType unsignedLeftValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(left));
1973af6ab5fSopenharmony_ci    UnsignedUType unsignedRightValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(right));
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_ci    auto mask = std::numeric_limits<UnsignedUType>::digits - 1U;
2003af6ab5fSopenharmony_ci    auto shift = unsignedRightValue & mask;
2013af6ab5fSopenharmony_ci
2023af6ab5fSopenharmony_ci    switch (operationType) {
2033af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
2043af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: {
2053af6ab5fSopenharmony_ci            result = unsignedLeftValue & unsignedRightValue;
2063af6ab5fSopenharmony_ci            break;
2073af6ab5fSopenharmony_ci        }
2083af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
2093af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
2103af6ab5fSopenharmony_ci            result = unsignedLeftValue | unsignedRightValue;
2113af6ab5fSopenharmony_ci            break;
2123af6ab5fSopenharmony_ci        }
2133af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
2143af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: {
2153af6ab5fSopenharmony_ci            result = unsignedLeftValue ^ unsignedRightValue;
2163af6ab5fSopenharmony_ci            break;
2173af6ab5fSopenharmony_ci        }
2183af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
2193af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: {
2203af6ab5fSopenharmony_ci            static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
2213af6ab5fSopenharmony_ci            result = unsignedLeftValue << shift;
2223af6ab5fSopenharmony_ci            break;
2233af6ab5fSopenharmony_ci        }
2243af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
2253af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: {
2263af6ab5fSopenharmony_ci            static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8);
2273af6ab5fSopenharmony_ci            result = static_cast<IntegerUType>(unsignedLeftValue) >> shift;  // NOLINT(hicpp-signed-bitwise)
2283af6ab5fSopenharmony_ci            break;
2293af6ab5fSopenharmony_ci        }
2303af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
2313af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: {
2323af6ab5fSopenharmony_ci            static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
2333af6ab5fSopenharmony_ci            result = unsignedLeftValue >> shift;
2343af6ab5fSopenharmony_ci            break;
2353af6ab5fSopenharmony_ci        }
2363af6ab5fSopenharmony_ci        default: {
2373af6ab5fSopenharmony_ci            UNREACHABLE();
2383af6ab5fSopenharmony_ci        }
2393af6ab5fSopenharmony_ci    }
2403af6ab5fSopenharmony_ci
2413af6ab5fSopenharmony_ci    return Allocator()->New<IntegerType>(result);
2423af6ab5fSopenharmony_ci}
2433af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
2443af6ab5fSopenharmony_ci
2453af6ab5fSopenharmony_ci#endif
246