14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_NUMBER_GATE_INFO_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_NUMBER_GATE_INFO_H 184514f5e3Sopenharmony_ci#include "ecmascript/compiler/gate_accessor.h" 194514f5e3Sopenharmony_ci#include "ecmascript/js_hclass.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_typed_array.h" 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu { 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_cienum class TypeInfo { 254514f5e3Sopenharmony_ci NONE, 264514f5e3Sopenharmony_ci INT1, 274514f5e3Sopenharmony_ci INT32, 284514f5e3Sopenharmony_ci UINT32, 294514f5e3Sopenharmony_ci FLOAT64, 304514f5e3Sopenharmony_ci TAGGED, 314514f5e3Sopenharmony_ci CHAR, 324514f5e3Sopenharmony_ci HOLE_INT, 334514f5e3Sopenharmony_ci HOLE_DOUBLE, 344514f5e3Sopenharmony_ci}; 354514f5e3Sopenharmony_ci 364514f5e3Sopenharmony_ciclass UseInfo { 374514f5e3Sopenharmony_cipublic: 384514f5e3Sopenharmony_ci UseInfo(uint8_t tag) : tag_(tag) {} 394514f5e3Sopenharmony_ci static constexpr uint8_t UNUSED = 0; 404514f5e3Sopenharmony_ci static constexpr uint8_t BOOL = 1 << 0; 414514f5e3Sopenharmony_ci static constexpr uint8_t INT32 = 1 << 1; 424514f5e3Sopenharmony_ci static constexpr uint8_t FLOAT64 = 1 << 2; 434514f5e3Sopenharmony_ci static constexpr uint8_t NATIVE = BOOL | INT32 | FLOAT64; 444514f5e3Sopenharmony_ci static constexpr uint8_t TAGGED = 1 << 3; 454514f5e3Sopenharmony_ci bool AddUse(const UseInfo &UseInfo) 464514f5e3Sopenharmony_ci { 474514f5e3Sopenharmony_ci uint8_t oldTag = tag_; 484514f5e3Sopenharmony_ci tag_ |= UseInfo.tag_; 494514f5e3Sopenharmony_ci return oldTag != tag_; 504514f5e3Sopenharmony_ci } 514514f5e3Sopenharmony_ci bool UsedAsBool() const 524514f5e3Sopenharmony_ci { 534514f5e3Sopenharmony_ci return ((tag_ & BOOL) == BOOL); 544514f5e3Sopenharmony_ci } 554514f5e3Sopenharmony_ci bool UsedAsFloat64() const 564514f5e3Sopenharmony_ci { 574514f5e3Sopenharmony_ci return ((tag_ & FLOAT64) == FLOAT64); 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci bool UsedAsNative() const 604514f5e3Sopenharmony_ci { 614514f5e3Sopenharmony_ci return ((tag_ & NATIVE) != 0); 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci bool UsedAsTagged() const 644514f5e3Sopenharmony_ci { 654514f5e3Sopenharmony_ci return ((tag_ & TAGGED) != 0); 664514f5e3Sopenharmony_ci } 674514f5e3Sopenharmony_ci static UseInfo UnUsed() 684514f5e3Sopenharmony_ci { 694514f5e3Sopenharmony_ci return UseInfo(UNUSED); 704514f5e3Sopenharmony_ci } 714514f5e3Sopenharmony_ci static UseInfo BoolUse() 724514f5e3Sopenharmony_ci { 734514f5e3Sopenharmony_ci return UseInfo(BOOL); 744514f5e3Sopenharmony_ci } 754514f5e3Sopenharmony_ci static UseInfo Int32Use() 764514f5e3Sopenharmony_ci { 774514f5e3Sopenharmony_ci return UseInfo(INT32); 784514f5e3Sopenharmony_ci } 794514f5e3Sopenharmony_ci static UseInfo Float64Use() 804514f5e3Sopenharmony_ci { 814514f5e3Sopenharmony_ci return UseInfo(FLOAT64); 824514f5e3Sopenharmony_ci } 834514f5e3Sopenharmony_ci static UseInfo TaggedUse() 844514f5e3Sopenharmony_ci { 854514f5e3Sopenharmony_ci return UseInfo(TAGGED); 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ciprivate: 884514f5e3Sopenharmony_ci uint8_t tag_ {0}; 894514f5e3Sopenharmony_ci}; 904514f5e3Sopenharmony_ci 914514f5e3Sopenharmony_ciclass RangeInfo { 924514f5e3Sopenharmony_cipublic: 934514f5e3Sopenharmony_ci RangeInfo() {} 944514f5e3Sopenharmony_ci RangeInfo(int32_t value) : min_(value), max_(value) {} 954514f5e3Sopenharmony_ci RangeInfo(int32_t min, int32_t max) 964514f5e3Sopenharmony_ci { 974514f5e3Sopenharmony_ci if (min == max) { 984514f5e3Sopenharmony_ci min_ = max_ = min; 994514f5e3Sopenharmony_ci } else { 1004514f5e3Sopenharmony_ci auto it = std::upper_bound(rangeBounds_.begin(), rangeBounds_.end(), min); 1014514f5e3Sopenharmony_ci ASSERT(it != rangeBounds_.begin()); 1024514f5e3Sopenharmony_ci it--; 1034514f5e3Sopenharmony_ci min_ = *it; 1044514f5e3Sopenharmony_ci max_ = *std::lower_bound(rangeBounds_.begin(), rangeBounds_.end(), max); 1054514f5e3Sopenharmony_ci } 1064514f5e3Sopenharmony_ci } 1074514f5e3Sopenharmony_ci 1084514f5e3Sopenharmony_ci static constexpr int32_t UINT30_MAX = 0x3fffffff; 1094514f5e3Sopenharmony_ci static constexpr int32_t TYPED_ARRAY_ONHEAP_MAX = JSTypedArray::MAX_ONHEAP_LENGTH; 1104514f5e3Sopenharmony_ci static constexpr int32_t UINT18_MAX = (1 << 18) - 1; 1114514f5e3Sopenharmony_ci static const inline std::vector<int32_t> rangeBounds_ = {INT32_MIN, INT32_MIN + 1, 1124514f5e3Sopenharmony_ci -UINT18_MAX, -TYPED_ARRAY_ONHEAP_MAX, -1, 0, 1, TYPED_ARRAY_ONHEAP_MAX - 1, 1134514f5e3Sopenharmony_ci TYPED_ARRAY_ONHEAP_MAX, TYPED_ARRAY_ONHEAP_MAX + 1, TYPED_ARRAY_ONHEAP_MAX * 3, 1144514f5e3Sopenharmony_ci UINT18_MAX, UINT30_MAX, UINT30_MAX + 1, INT32_MAX - 1, INT32_MAX }; 1154514f5e3Sopenharmony_ci 1164514f5e3Sopenharmony_ci static RangeInfo NONE() 1174514f5e3Sopenharmony_ci { 1184514f5e3Sopenharmony_ci return RangeInfo(INT32_MAX, INT32_MIN); 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci 1214514f5e3Sopenharmony_ci static RangeInfo ANY() 1224514f5e3Sopenharmony_ci { 1234514f5e3Sopenharmony_ci return RangeInfo(INT32_MIN, INT32_MAX); 1244514f5e3Sopenharmony_ci } 1254514f5e3Sopenharmony_ci 1264514f5e3Sopenharmony_ci int32_t GetMin() const 1274514f5e3Sopenharmony_ci { 1284514f5e3Sopenharmony_ci return min_; 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci 1314514f5e3Sopenharmony_ci int32_t GetMax() const 1324514f5e3Sopenharmony_ci { 1334514f5e3Sopenharmony_ci return max_; 1344514f5e3Sopenharmony_ci } 1354514f5e3Sopenharmony_ci 1364514f5e3Sopenharmony_ci RangeInfo operator~() const 1374514f5e3Sopenharmony_ci { 1384514f5e3Sopenharmony_ci return RangeInfo(~ max_, ~ min_); 1394514f5e3Sopenharmony_ci } 1404514f5e3Sopenharmony_ci 1414514f5e3Sopenharmony_ci RangeInfo Union(const RangeInfo &rhs) const 1424514f5e3Sopenharmony_ci { 1434514f5e3Sopenharmony_ci return RangeInfo(std::min(min_, rhs.min_), std::max(max_, rhs.max_)); 1444514f5e3Sopenharmony_ci } 1454514f5e3Sopenharmony_ci 1464514f5e3Sopenharmony_ci RangeInfo intersection(const RangeInfo &rhs) const 1474514f5e3Sopenharmony_ci { 1484514f5e3Sopenharmony_ci return RangeInfo(std::max(min_, rhs.min_), std::min(max_, rhs.max_)); 1494514f5e3Sopenharmony_ci } 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ci bool MaybeAddOverflow(const RangeInfo &rhs) const 1524514f5e3Sopenharmony_ci { 1534514f5e3Sopenharmony_ci return (rhs.max_ > 0) && (max_ > INT32_MAX - rhs.max_); 1544514f5e3Sopenharmony_ci } 1554514f5e3Sopenharmony_ci 1564514f5e3Sopenharmony_ci bool MaybeAddUnderflow(const RangeInfo &rhs) const 1574514f5e3Sopenharmony_ci { 1584514f5e3Sopenharmony_ci return (rhs.min_ < 0) && (min_ < INT32_MIN - rhs.min_); 1594514f5e3Sopenharmony_ci } 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_ci bool MaybeAddOverflowOrUnderflow(const RangeInfo &rhs) const 1624514f5e3Sopenharmony_ci { 1634514f5e3Sopenharmony_ci return MaybeAddOverflow(rhs) || MaybeAddUnderflow(rhs); 1644514f5e3Sopenharmony_ci } 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci RangeInfo operator+ (const RangeInfo &rhs) const 1674514f5e3Sopenharmony_ci { 1684514f5e3Sopenharmony_ci ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 1694514f5e3Sopenharmony_ci int32_t nmax = MaybeAddOverflow(rhs) ? INT32_MAX : max_ + rhs.max_; 1704514f5e3Sopenharmony_ci int32_t nmin = MaybeAddUnderflow(rhs) ? INT32_MIN : min_ + rhs.min_; 1714514f5e3Sopenharmony_ci return RangeInfo(nmin, nmax); 1724514f5e3Sopenharmony_ci } 1734514f5e3Sopenharmony_ci 1744514f5e3Sopenharmony_ci RangeInfo operator% (const RangeInfo &rhs) const 1754514f5e3Sopenharmony_ci { 1764514f5e3Sopenharmony_ci ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 1774514f5e3Sopenharmony_ci RangeInfo result = RangeInfo(0, 0); 1784514f5e3Sopenharmony_ci int32_t nmax = std::max(std::abs(rhs.min_), std::abs(rhs.max_)); 1794514f5e3Sopenharmony_ci if (nmax == 0) { 1804514f5e3Sopenharmony_ci return ANY(); 1814514f5e3Sopenharmony_ci } 1824514f5e3Sopenharmony_ci if (max_ > 0) result = result.Union(RangeInfo(0, nmax - 1)); 1834514f5e3Sopenharmony_ci if (min_ < 0) result = result.Union(RangeInfo(-nmax + 1, 0)); 1844514f5e3Sopenharmony_ci return result; 1854514f5e3Sopenharmony_ci } 1864514f5e3Sopenharmony_ci 1874514f5e3Sopenharmony_ci bool MaybeZero() const 1884514f5e3Sopenharmony_ci { 1894514f5e3Sopenharmony_ci return min_ <= 0 && max_ >= 0; 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ci 1924514f5e3Sopenharmony_ci bool MaybeNegative() const 1934514f5e3Sopenharmony_ci { 1944514f5e3Sopenharmony_ci return min_ < 0; 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci 1974514f5e3Sopenharmony_ci RangeInfo operator* (const RangeInfo &rhs) const 1984514f5e3Sopenharmony_ci { 1994514f5e3Sopenharmony_ci ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 2004514f5e3Sopenharmony_ci int32_t nmax = GetMaxMulResult(rhs); 2014514f5e3Sopenharmony_ci int32_t nmin = GetMinMulResult(rhs); 2024514f5e3Sopenharmony_ci return RangeInfo(nmin, nmax); 2034514f5e3Sopenharmony_ci } 2044514f5e3Sopenharmony_ci 2054514f5e3Sopenharmony_ci int32_t GetMaxMulResult(const RangeInfo &rhs) const 2064514f5e3Sopenharmony_ci { 2074514f5e3Sopenharmony_ci return std::max({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 2084514f5e3Sopenharmony_ci TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 2094514f5e3Sopenharmony_ci } 2104514f5e3Sopenharmony_ci 2114514f5e3Sopenharmony_ci int32_t GetMinMulResult(const RangeInfo &rhs) const 2124514f5e3Sopenharmony_ci { 2134514f5e3Sopenharmony_ci return std::min({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 2144514f5e3Sopenharmony_ci TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci 2174514f5e3Sopenharmony_ci int32_t TryMul(int32_t lhs, int32_t rhs) const 2184514f5e3Sopenharmony_ci { 2194514f5e3Sopenharmony_ci if (MaybeMulOverflow(lhs, rhs)) { 2204514f5e3Sopenharmony_ci return INT32_MAX; 2214514f5e3Sopenharmony_ci } 2224514f5e3Sopenharmony_ci if (MaybeMulUnderflow(lhs, rhs)) { 2234514f5e3Sopenharmony_ci return INT32_MIN; 2244514f5e3Sopenharmony_ci } 2254514f5e3Sopenharmony_ci return lhs * rhs; 2264514f5e3Sopenharmony_ci } 2274514f5e3Sopenharmony_ci 2284514f5e3Sopenharmony_ci bool MaybeMulOverflowOrUnderflow(const RangeInfo &rhs) const 2294514f5e3Sopenharmony_ci { 2304514f5e3Sopenharmony_ci return MaybeMulOverflow(rhs) || MaybeMulUnderflow(rhs); 2314514f5e3Sopenharmony_ci } 2324514f5e3Sopenharmony_ci 2334514f5e3Sopenharmony_ci bool MaybeMulUnderflow(const RangeInfo &rhs) const 2344514f5e3Sopenharmony_ci { 2354514f5e3Sopenharmony_ci return MaybeMulUnderflow(min_, rhs.max_) || MaybeMulUnderflow(max_, rhs.min_); 2364514f5e3Sopenharmony_ci } 2374514f5e3Sopenharmony_ci 2384514f5e3Sopenharmony_ci bool MaybeMulOverflow(const RangeInfo &rhs) const 2394514f5e3Sopenharmony_ci { 2404514f5e3Sopenharmony_ci return MaybeMulOverflow(max_, rhs.max_) || MaybeMulOverflow(min_, rhs.min_); 2414514f5e3Sopenharmony_ci } 2424514f5e3Sopenharmony_ci 2434514f5e3Sopenharmony_ci bool MaybeMulUnderflow(int32_t lhs, int32_t rhs) const 2444514f5e3Sopenharmony_ci { 2454514f5e3Sopenharmony_ci return (lhs > 0 && rhs < 0 && rhs < INT32_MIN / lhs) || (lhs < 0 && rhs > 0 && lhs < INT32_MIN / rhs); 2464514f5e3Sopenharmony_ci } 2474514f5e3Sopenharmony_ci 2484514f5e3Sopenharmony_ci bool MaybeMulOverflow(int32_t lhs, int32_t rhs) const 2494514f5e3Sopenharmony_ci { 2504514f5e3Sopenharmony_ci return (lhs > 0 && rhs > 0 && lhs > INT32_MAX / rhs) || (lhs < 0 && rhs < 0 && lhs < INT32_MAX / rhs); 2514514f5e3Sopenharmony_ci } 2524514f5e3Sopenharmony_ci 2534514f5e3Sopenharmony_ci bool MaybeSubOverflow(const RangeInfo &rhs) const 2544514f5e3Sopenharmony_ci { 2554514f5e3Sopenharmony_ci return (rhs.min_ < 0) && (max_ > INT32_MAX + rhs.min_); 2564514f5e3Sopenharmony_ci } 2574514f5e3Sopenharmony_ci 2584514f5e3Sopenharmony_ci bool MaybeSubUnderflow(const RangeInfo &rhs) const 2594514f5e3Sopenharmony_ci { 2604514f5e3Sopenharmony_ci return (rhs.max_ > 0) && (min_ < INT32_MIN + rhs.max_); 2614514f5e3Sopenharmony_ci } 2624514f5e3Sopenharmony_ci 2634514f5e3Sopenharmony_ci bool MaybeSubOverflowOrUnderflow(const RangeInfo &rhs) const 2644514f5e3Sopenharmony_ci { 2654514f5e3Sopenharmony_ci return MaybeSubOverflow(rhs) || MaybeSubUnderflow(rhs); 2664514f5e3Sopenharmony_ci } 2674514f5e3Sopenharmony_ci 2684514f5e3Sopenharmony_ci RangeInfo operator- (const RangeInfo &rhs) const 2694514f5e3Sopenharmony_ci { 2704514f5e3Sopenharmony_ci ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 2714514f5e3Sopenharmony_ci int32_t nmax = MaybeSubOverflow(rhs) ? INT32_MAX : max_ - rhs.min_; 2724514f5e3Sopenharmony_ci int32_t nmin = MaybeSubUnderflow(rhs) ? INT32_MIN : min_ - rhs.max_; 2734514f5e3Sopenharmony_ci return RangeInfo(nmin, nmax); 2744514f5e3Sopenharmony_ci } 2754514f5e3Sopenharmony_ci 2764514f5e3Sopenharmony_ci bool MaybeShrOverflow(const RangeInfo &rhs) const 2774514f5e3Sopenharmony_ci { 2784514f5e3Sopenharmony_ci if (rhs.max_ != rhs.min_) { 2794514f5e3Sopenharmony_ci return true; 2804514f5e3Sopenharmony_ci } 2814514f5e3Sopenharmony_ci return ((static_cast<uint32_t>(rhs.max_) & 0x1f) == 0) && (min_< 0); // 0x1f : shift bits 2824514f5e3Sopenharmony_ci } 2834514f5e3Sopenharmony_ci 2844514f5e3Sopenharmony_ci RangeInfo SHR(const RangeInfo &rhs) const 2854514f5e3Sopenharmony_ci { 2864514f5e3Sopenharmony_ci ASSERT(min_ <= max_); 2874514f5e3Sopenharmony_ci ASSERT(rhs.max_ == rhs.min_); 2884514f5e3Sopenharmony_ci if (MaybeShrOverflow(rhs)) { 2894514f5e3Sopenharmony_ci // assume no overflow occurs since overflow will lead to deopt 2904514f5e3Sopenharmony_ci return RangeInfo(0, std::max(0, GetMax())); 2914514f5e3Sopenharmony_ci } 2924514f5e3Sopenharmony_ci int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 2934514f5e3Sopenharmony_ci uint32_t tempMin = bit_cast<uint32_t>((max_ >= 0) ? std::max(0, min_) : min_); 2944514f5e3Sopenharmony_ci uint32_t tempMax = bit_cast<uint32_t>((min_ < 0) ? std::min(-1, max_) : max_); 2954514f5e3Sopenharmony_ci int32_t nmin = bit_cast<int32_t>(tempMin >> shift); 2964514f5e3Sopenharmony_ci int32_t nmax = bit_cast<int32_t>(tempMax >> shift); 2974514f5e3Sopenharmony_ci return RangeInfo(nmin, nmax); 2984514f5e3Sopenharmony_ci } 2994514f5e3Sopenharmony_ci 3004514f5e3Sopenharmony_ci RangeInfo ASHR(const RangeInfo &rhs) const 3014514f5e3Sopenharmony_ci { 3024514f5e3Sopenharmony_ci ASSERT(min_ <= max_); 3034514f5e3Sopenharmony_ci ASSERT(rhs.max_ == rhs.min_); 3044514f5e3Sopenharmony_ci int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 3054514f5e3Sopenharmony_ci int32_t nmin = min_ >> shift; 3064514f5e3Sopenharmony_ci int32_t nmax = max_ >> shift; 3074514f5e3Sopenharmony_ci return RangeInfo(nmin, nmax); 3084514f5e3Sopenharmony_ci } 3094514f5e3Sopenharmony_ci 3104514f5e3Sopenharmony_ci bool operator== (const RangeInfo &rhs) const 3114514f5e3Sopenharmony_ci { 3124514f5e3Sopenharmony_ci return (min_ == rhs.min_) && (max_ == rhs.max_); 3134514f5e3Sopenharmony_ci } 3144514f5e3Sopenharmony_ci 3154514f5e3Sopenharmony_ci bool operator!= (const RangeInfo &rhs) const 3164514f5e3Sopenharmony_ci { 3174514f5e3Sopenharmony_ci return (min_ != rhs.min_) || (max_ != rhs.max_); 3184514f5e3Sopenharmony_ci } 3194514f5e3Sopenharmony_ci 3204514f5e3Sopenharmony_ci bool IsNone() const 3214514f5e3Sopenharmony_ci { 3224514f5e3Sopenharmony_ci return (min_ == INT32_MAX) && (max_ == INT32_MIN); 3234514f5e3Sopenharmony_ci } 3244514f5e3Sopenharmony_ci 3254514f5e3Sopenharmony_ciprivate: 3264514f5e3Sopenharmony_ci int32_t min_ {INT32_MIN}; 3274514f5e3Sopenharmony_ci int32_t max_ {INT32_MAX}; 3284514f5e3Sopenharmony_ci}; 3294514f5e3Sopenharmony_ci} // panda::ecmascript::kungfu 3304514f5e3Sopenharmony_ci#endif // ECMASCRIPT_COMPILER_NUMBER_GATE_INFO_H 331