1 /* 2 * Copyright (c) 2023 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 ECMASCRIPT_NUMBER_GATE_INFO_H 17 #define ECMASCRIPT_NUMBER_GATE_INFO_H 18 #include "ecmascript/compiler/gate_accessor.h" 19 #include "ecmascript/js_hclass.h" 20 #include "ecmascript/js_typed_array.h" 21 22 namespace panda::ecmascript::kungfu { 23 24 enum class TypeInfo { 25 NONE, 26 INT1, 27 INT32, 28 UINT32, 29 FLOAT64, 30 TAGGED, 31 CHAR, 32 }; 33 34 class UseInfo { 35 public: UseInfo(uint8_t tag)36 UseInfo(uint8_t tag) : tag_(tag) {} 37 static constexpr uint8_t UNUSED = 0; 38 static constexpr uint8_t BOOL = 1 << 0; 39 static constexpr uint8_t INT32 = 1 << 1; 40 static constexpr uint8_t FLOAT64 = 1 << 2; 41 static constexpr uint8_t NATIVE = BOOL | INT32 | FLOAT64; 42 static constexpr uint8_t TAGGED = 1 << 3; AddUse(const UseInfo & UseInfo)43 bool AddUse(const UseInfo &UseInfo) 44 { 45 uint8_t oldTag = tag_; 46 tag_ |= UseInfo.tag_; 47 return oldTag != tag_; 48 } UsedAsBool()49 bool UsedAsBool() const 50 { 51 return ((tag_ & BOOL) == BOOL); 52 } UsedAsFloat64()53 bool UsedAsFloat64() const 54 { 55 return ((tag_ & FLOAT64) == FLOAT64); 56 } UsedAsNative()57 bool UsedAsNative() const 58 { 59 return ((tag_ & NATIVE) != 0); 60 } UsedAsTagged()61 bool UsedAsTagged() const 62 { 63 return ((tag_ & TAGGED) != 0); 64 } UnUsed()65 static UseInfo UnUsed() 66 { 67 return UseInfo(UNUSED); 68 } BoolUse()69 static UseInfo BoolUse() 70 { 71 return UseInfo(BOOL); 72 } Int32Use()73 static UseInfo Int32Use() 74 { 75 return UseInfo(INT32); 76 } Float64Use()77 static UseInfo Float64Use() 78 { 79 return UseInfo(FLOAT64); 80 } TaggedUse()81 static UseInfo TaggedUse() 82 { 83 return UseInfo(TAGGED); 84 } 85 private: 86 uint8_t tag_ {0}; 87 }; 88 89 class RangeInfo { 90 public: RangeInfo()91 RangeInfo() {} RangeInfo(int32_t value)92 RangeInfo(int32_t value) : min_(value), max_(value) {} RangeInfo(int32_t min,int32_t max)93 RangeInfo(int32_t min, int32_t max) 94 { 95 if (min == max) { 96 min_ = max_ = min; 97 } else { 98 auto it = std::upper_bound(rangeBounds_.begin(), rangeBounds_.end(), min); 99 ASSERT(it != rangeBounds_.begin()); 100 it--; 101 min_ = *it; 102 max_ = *std::lower_bound(rangeBounds_.begin(), rangeBounds_.end(), max); 103 } 104 } 105 106 static constexpr int32_t UINT30_MAX = 0x3fffffff; 107 static constexpr int32_t TYPED_ARRAY_ONHEAP_MAX = JSTypedArray::MAX_ONHEAP_LENGTH; 108 static constexpr int32_t UINT18_MAX = (1 << 18) - 1; 109 static const inline std::vector<int32_t> rangeBounds_ = {INT32_MIN, INT32_MIN + 1, 110 -UINT18_MAX, -TYPED_ARRAY_ONHEAP_MAX, -1, 0, 1, TYPED_ARRAY_ONHEAP_MAX - 1, 111 TYPED_ARRAY_ONHEAP_MAX, TYPED_ARRAY_ONHEAP_MAX + 1, TYPED_ARRAY_ONHEAP_MAX * 3, 112 UINT18_MAX, UINT30_MAX, UINT30_MAX + 1, INT32_MAX - 1, INT32_MAX }; 113 NONE()114 static RangeInfo NONE() 115 { 116 return RangeInfo(INT32_MAX, INT32_MIN); 117 } 118 ANY()119 static RangeInfo ANY() 120 { 121 return RangeInfo(INT32_MIN, INT32_MAX); 122 } 123 GetMin()124 int32_t GetMin() const 125 { 126 return min_; 127 } 128 GetMax()129 int32_t GetMax() const 130 { 131 return max_; 132 } 133 134 RangeInfo operator~() const 135 { 136 return RangeInfo(~ max_, ~ min_); 137 } 138 Union(const RangeInfo & rhs)139 RangeInfo Union(const RangeInfo &rhs) const 140 { 141 return RangeInfo(std::min(min_, rhs.min_), std::max(max_, rhs.max_)); 142 } 143 intersection(const RangeInfo & rhs)144 RangeInfo intersection(const RangeInfo &rhs) const 145 { 146 return RangeInfo(std::max(min_, rhs.min_), std::min(max_, rhs.max_)); 147 } 148 MaybeAddOverflow(const RangeInfo & rhs)149 bool MaybeAddOverflow(const RangeInfo &rhs) const 150 { 151 return (rhs.max_ > 0) && (max_ > INT32_MAX - rhs.max_); 152 } 153 MaybeAddUnderflow(const RangeInfo & rhs)154 bool MaybeAddUnderflow(const RangeInfo &rhs) const 155 { 156 return (rhs.min_ < 0) && (min_ < INT32_MIN - rhs.min_); 157 } 158 MaybeAddOverflowOrUnderflow(const RangeInfo & rhs)159 bool MaybeAddOverflowOrUnderflow(const RangeInfo &rhs) const 160 { 161 return MaybeAddOverflow(rhs) || MaybeAddUnderflow(rhs); 162 } 163 164 RangeInfo operator+ (const RangeInfo &rhs) const 165 { 166 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 167 int32_t nmax = MaybeAddOverflow(rhs) ? INT32_MAX : max_ + rhs.max_; 168 int32_t nmin = MaybeAddUnderflow(rhs) ? INT32_MIN : min_ + rhs.min_; 169 return RangeInfo(nmin, nmax); 170 } 171 172 RangeInfo operator% (const RangeInfo &rhs) const 173 { 174 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 175 RangeInfo result = RangeInfo(0, 0); 176 int32_t nmax = std::max(std::abs(rhs.min_), std::abs(rhs.max_)); 177 if (nmax == 0) { 178 return ANY(); 179 } 180 if (max_ > 0) result = result.Union(RangeInfo(0, nmax - 1)); 181 if (min_ < 0) result = result.Union(RangeInfo(-nmax + 1, 0)); 182 return result; 183 } 184 MaybeZero()185 bool MaybeZero() const 186 { 187 return min_ <= 0 && max_ >= 0; 188 } 189 MaybeNegative()190 bool MaybeNegative() const 191 { 192 return min_ < 0; 193 } 194 195 RangeInfo operator* (const RangeInfo &rhs) const 196 { 197 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 198 int32_t nmax = GetMaxMulResult(rhs); 199 int32_t nmin = GetMinMulResult(rhs); 200 return RangeInfo(nmin, nmax); 201 } 202 GetMaxMulResult(const RangeInfo & rhs)203 int32_t GetMaxMulResult(const RangeInfo &rhs) const 204 { 205 return std::max({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 206 TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 207 } 208 GetMinMulResult(const RangeInfo & rhs)209 int32_t GetMinMulResult(const RangeInfo &rhs) const 210 { 211 return std::min({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 212 TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 213 } 214 TryMul(int32_t lhs,int32_t rhs)215 int32_t TryMul(int32_t lhs, int32_t rhs) const 216 { 217 if (MaybeMulOverflow(lhs, rhs)) { 218 return INT32_MAX; 219 } 220 if (MaybeMulUnderflow(lhs, rhs)) { 221 return INT32_MIN; 222 } 223 return lhs * rhs; 224 } 225 MaybeMulOverflowOrUnderflow(const RangeInfo & rhs)226 bool MaybeMulOverflowOrUnderflow(const RangeInfo &rhs) const 227 { 228 return MaybeMulOverflow(rhs) || MaybeMulUnderflow(rhs); 229 } 230 MaybeMulUnderflow(const RangeInfo & rhs)231 bool MaybeMulUnderflow(const RangeInfo &rhs) const 232 { 233 return MaybeMulUnderflow(min_, rhs.max_) || MaybeMulUnderflow(max_, rhs.min_); 234 } 235 MaybeMulOverflow(const RangeInfo & rhs)236 bool MaybeMulOverflow(const RangeInfo &rhs) const 237 { 238 return MaybeMulOverflow(max_, rhs.max_) || MaybeMulOverflow(min_, rhs.min_); 239 } 240 MaybeMulUnderflow(int32_t lhs,int32_t rhs)241 bool MaybeMulUnderflow(int32_t lhs, int32_t rhs) const 242 { 243 return (lhs > 0 && rhs < 0 && rhs < INT32_MIN / lhs) || (lhs < 0 && rhs > 0 && lhs < INT32_MIN / rhs); 244 } 245 MaybeMulOverflow(int32_t lhs,int32_t rhs)246 bool MaybeMulOverflow(int32_t lhs, int32_t rhs) const 247 { 248 return (lhs > 0 && rhs > 0 && lhs > INT32_MAX / rhs) || (lhs < 0 && rhs < 0 && lhs < INT32_MAX / rhs); 249 } 250 MaybeSubOverflow(const RangeInfo & rhs)251 bool MaybeSubOverflow(const RangeInfo &rhs) const 252 { 253 return (rhs.min_ < 0) && (max_ > INT32_MAX + rhs.min_); 254 } 255 MaybeSubUnderflow(const RangeInfo & rhs)256 bool MaybeSubUnderflow(const RangeInfo &rhs) const 257 { 258 return (rhs.max_ > 0) && (min_ < INT32_MIN + rhs.max_); 259 } 260 MaybeSubOverflowOrUnderflow(const RangeInfo & rhs)261 bool MaybeSubOverflowOrUnderflow(const RangeInfo &rhs) const 262 { 263 return MaybeSubOverflow(rhs) || MaybeSubUnderflow(rhs); 264 } 265 266 RangeInfo operator- (const RangeInfo &rhs) const 267 { 268 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 269 int32_t nmax = MaybeSubOverflow(rhs) ? INT32_MAX : max_ - rhs.min_; 270 int32_t nmin = MaybeSubUnderflow(rhs) ? INT32_MIN : min_ - rhs.max_; 271 return RangeInfo(nmin, nmax); 272 } 273 MaybeShrOverflow(const RangeInfo & rhs)274 bool MaybeShrOverflow(const RangeInfo &rhs) const 275 { 276 if (rhs.max_ != rhs.min_) { 277 return true; 278 } 279 return ((static_cast<uint32_t>(rhs.max_) & 0x1f) == 0) && (min_< 0); // 0x1f : shift bits 280 } 281 SHR(const RangeInfo & rhs)282 RangeInfo SHR(const RangeInfo &rhs) const 283 { 284 ASSERT(min_ <= max_); 285 ASSERT(rhs.max_ == rhs.min_); 286 if (MaybeShrOverflow(rhs)) { 287 // assume no overflow occurs since overflow will lead to deopt 288 return RangeInfo(0, std::max(0, GetMax())); 289 } 290 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 291 uint32_t tempMin = bit_cast<uint32_t>((max_ >= 0) ? std::max(0, min_) : min_); 292 uint32_t tempMax = bit_cast<uint32_t>((min_ < 0) ? std::min(-1, max_) : max_); 293 int32_t nmin = bit_cast<int32_t>(tempMin >> shift); 294 int32_t nmax = bit_cast<int32_t>(tempMax >> shift); 295 return RangeInfo(nmin, nmax); 296 } 297 ASHR(const RangeInfo & rhs)298 RangeInfo ASHR(const RangeInfo &rhs) const 299 { 300 ASSERT(min_ <= max_); 301 ASSERT(rhs.max_ == rhs.min_); 302 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 303 int32_t nmin = min_ >> shift; 304 int32_t nmax = max_ >> shift; 305 return RangeInfo(nmin, nmax); 306 } 307 308 bool operator== (const RangeInfo &rhs) const 309 { 310 return (min_ == rhs.min_) && (max_ == rhs.max_); 311 } 312 313 bool operator!= (const RangeInfo &rhs) const 314 { 315 return (min_ != rhs.min_) || (max_ != rhs.max_); 316 } 317 IsNone()318 bool IsNone() const 319 { 320 return (min_ == INT32_MAX) && (max_ == INT32_MIN); 321 } 322 323 private: 324 int32_t min_ {INT32_MIN}; 325 int32_t max_ {INT32_MAX}; 326 }; 327 } // panda::ecmascript::kungfu 328 #endif // ECMASCRIPT_COMPILER_NUMBER_GATE_INFO_H 329