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 HOLE_INT, 33 HOLE_DOUBLE, 34 }; 35 36 class UseInfo { 37 public: UseInfo(uint8_t tag)38 UseInfo(uint8_t tag) : tag_(tag) {} 39 static constexpr uint8_t UNUSED = 0; 40 static constexpr uint8_t BOOL = 1 << 0; 41 static constexpr uint8_t INT32 = 1 << 1; 42 static constexpr uint8_t FLOAT64 = 1 << 2; 43 static constexpr uint8_t NATIVE = BOOL | INT32 | FLOAT64; 44 static constexpr uint8_t TAGGED = 1 << 3; AddUse(const UseInfo &UseInfo)45 bool AddUse(const UseInfo &UseInfo) 46 { 47 uint8_t oldTag = tag_; 48 tag_ |= UseInfo.tag_; 49 return oldTag != tag_; 50 } UsedAsBool() const51 bool UsedAsBool() const 52 { 53 return ((tag_ & BOOL) == BOOL); 54 } UsedAsFloat64() const55 bool UsedAsFloat64() const 56 { 57 return ((tag_ & FLOAT64) == FLOAT64); 58 } UsedAsNative() const59 bool UsedAsNative() const 60 { 61 return ((tag_ & NATIVE) != 0); 62 } UsedAsTagged() const63 bool UsedAsTagged() const 64 { 65 return ((tag_ & TAGGED) != 0); 66 } UnUsed()67 static UseInfo UnUsed() 68 { 69 return UseInfo(UNUSED); 70 } BoolUse()71 static UseInfo BoolUse() 72 { 73 return UseInfo(BOOL); 74 } Int32Use()75 static UseInfo Int32Use() 76 { 77 return UseInfo(INT32); 78 } Float64Use()79 static UseInfo Float64Use() 80 { 81 return UseInfo(FLOAT64); 82 } TaggedUse()83 static UseInfo TaggedUse() 84 { 85 return UseInfo(TAGGED); 86 } 87 private: 88 uint8_t tag_ {0}; 89 }; 90 91 class RangeInfo { 92 public: RangeInfo()93 RangeInfo() {} RangeInfo(int32_t value)94 RangeInfo(int32_t value) : min_(value), max_(value) {} RangeInfo(int32_t min, int32_t max)95 RangeInfo(int32_t min, int32_t max) 96 { 97 if (min == max) { 98 min_ = max_ = min; 99 } else { 100 auto it = std::upper_bound(rangeBounds_.begin(), rangeBounds_.end(), min); 101 ASSERT(it != rangeBounds_.begin()); 102 it--; 103 min_ = *it; 104 max_ = *std::lower_bound(rangeBounds_.begin(), rangeBounds_.end(), max); 105 } 106 } 107 108 static constexpr int32_t UINT30_MAX = 0x3fffffff; 109 static constexpr int32_t TYPED_ARRAY_ONHEAP_MAX = JSTypedArray::MAX_ONHEAP_LENGTH; 110 static constexpr int32_t UINT18_MAX = (1 << 18) - 1; 111 static const inline std::vector<int32_t> rangeBounds_ = {INT32_MIN, INT32_MIN + 1, 112 -UINT18_MAX, -TYPED_ARRAY_ONHEAP_MAX, -1, 0, 1, TYPED_ARRAY_ONHEAP_MAX - 1, 113 TYPED_ARRAY_ONHEAP_MAX, TYPED_ARRAY_ONHEAP_MAX + 1, TYPED_ARRAY_ONHEAP_MAX * 3, 114 UINT18_MAX, UINT30_MAX, UINT30_MAX + 1, INT32_MAX - 1, INT32_MAX }; 115 NONE()116 static RangeInfo NONE() 117 { 118 return RangeInfo(INT32_MAX, INT32_MIN); 119 } 120 ANY()121 static RangeInfo ANY() 122 { 123 return RangeInfo(INT32_MIN, INT32_MAX); 124 } 125 GetMin() const126 int32_t GetMin() const 127 { 128 return min_; 129 } 130 GetMax() const131 int32_t GetMax() const 132 { 133 return max_; 134 } 135 operator ~() const136 RangeInfo operator~() const 137 { 138 return RangeInfo(~ max_, ~ min_); 139 } 140 Union(const RangeInfo &rhs) const141 RangeInfo Union(const RangeInfo &rhs) const 142 { 143 return RangeInfo(std::min(min_, rhs.min_), std::max(max_, rhs.max_)); 144 } 145 intersection(const RangeInfo &rhs) const146 RangeInfo intersection(const RangeInfo &rhs) const 147 { 148 return RangeInfo(std::max(min_, rhs.min_), std::min(max_, rhs.max_)); 149 } 150 MaybeAddOverflow(const RangeInfo &rhs) const151 bool MaybeAddOverflow(const RangeInfo &rhs) const 152 { 153 return (rhs.max_ > 0) && (max_ > INT32_MAX - rhs.max_); 154 } 155 MaybeAddUnderflow(const RangeInfo &rhs) const156 bool MaybeAddUnderflow(const RangeInfo &rhs) const 157 { 158 return (rhs.min_ < 0) && (min_ < INT32_MIN - rhs.min_); 159 } 160 MaybeAddOverflowOrUnderflow(const RangeInfo &rhs) const161 bool MaybeAddOverflowOrUnderflow(const RangeInfo &rhs) const 162 { 163 return MaybeAddOverflow(rhs) || MaybeAddUnderflow(rhs); 164 } 165 operator +(const RangeInfo &rhs) const166 RangeInfo operator+ (const RangeInfo &rhs) const 167 { 168 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 169 int32_t nmax = MaybeAddOverflow(rhs) ? INT32_MAX : max_ + rhs.max_; 170 int32_t nmin = MaybeAddUnderflow(rhs) ? INT32_MIN : min_ + rhs.min_; 171 return RangeInfo(nmin, nmax); 172 } 173 operator %(const RangeInfo &rhs) const174 RangeInfo operator% (const RangeInfo &rhs) const 175 { 176 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 177 RangeInfo result = RangeInfo(0, 0); 178 int32_t nmax = std::max(std::abs(rhs.min_), std::abs(rhs.max_)); 179 if (nmax == 0) { 180 return ANY(); 181 } 182 if (max_ > 0) result = result.Union(RangeInfo(0, nmax - 1)); 183 if (min_ < 0) result = result.Union(RangeInfo(-nmax + 1, 0)); 184 return result; 185 } 186 MaybeZero() const187 bool MaybeZero() const 188 { 189 return min_ <= 0 && max_ >= 0; 190 } 191 MaybeNegative() const192 bool MaybeNegative() const 193 { 194 return min_ < 0; 195 } 196 operator *(const RangeInfo &rhs) const197 RangeInfo operator* (const RangeInfo &rhs) const 198 { 199 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 200 int32_t nmax = GetMaxMulResult(rhs); 201 int32_t nmin = GetMinMulResult(rhs); 202 return RangeInfo(nmin, nmax); 203 } 204 GetMaxMulResult(const RangeInfo &rhs) const205 int32_t GetMaxMulResult(const RangeInfo &rhs) const 206 { 207 return std::max({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 208 TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 209 } 210 GetMinMulResult(const RangeInfo &rhs) const211 int32_t GetMinMulResult(const RangeInfo &rhs) const 212 { 213 return std::min({ TryMul(min_, rhs.min_), TryMul(min_, rhs.max_), 214 TryMul(max_, rhs.min_), TryMul(max_, rhs.max_) }); 215 } 216 TryMul(int32_t lhs, int32_t rhs) const217 int32_t TryMul(int32_t lhs, int32_t rhs) const 218 { 219 if (MaybeMulOverflow(lhs, rhs)) { 220 return INT32_MAX; 221 } 222 if (MaybeMulUnderflow(lhs, rhs)) { 223 return INT32_MIN; 224 } 225 return lhs * rhs; 226 } 227 MaybeMulOverflowOrUnderflow(const RangeInfo &rhs) const228 bool MaybeMulOverflowOrUnderflow(const RangeInfo &rhs) const 229 { 230 return MaybeMulOverflow(rhs) || MaybeMulUnderflow(rhs); 231 } 232 MaybeMulUnderflow(const RangeInfo &rhs) const233 bool MaybeMulUnderflow(const RangeInfo &rhs) const 234 { 235 return MaybeMulUnderflow(min_, rhs.max_) || MaybeMulUnderflow(max_, rhs.min_); 236 } 237 MaybeMulOverflow(const RangeInfo &rhs) const238 bool MaybeMulOverflow(const RangeInfo &rhs) const 239 { 240 return MaybeMulOverflow(max_, rhs.max_) || MaybeMulOverflow(min_, rhs.min_); 241 } 242 MaybeMulUnderflow(int32_t lhs, int32_t rhs) const243 bool MaybeMulUnderflow(int32_t lhs, int32_t rhs) const 244 { 245 return (lhs > 0 && rhs < 0 && rhs < INT32_MIN / lhs) || (lhs < 0 && rhs > 0 && lhs < INT32_MIN / rhs); 246 } 247 MaybeMulOverflow(int32_t lhs, int32_t rhs) const248 bool MaybeMulOverflow(int32_t lhs, int32_t rhs) const 249 { 250 return (lhs > 0 && rhs > 0 && lhs > INT32_MAX / rhs) || (lhs < 0 && rhs < 0 && lhs < INT32_MAX / rhs); 251 } 252 MaybeSubOverflow(const RangeInfo &rhs) const253 bool MaybeSubOverflow(const RangeInfo &rhs) const 254 { 255 return (rhs.min_ < 0) && (max_ > INT32_MAX + rhs.min_); 256 } 257 MaybeSubUnderflow(const RangeInfo &rhs) const258 bool MaybeSubUnderflow(const RangeInfo &rhs) const 259 { 260 return (rhs.max_ > 0) && (min_ < INT32_MIN + rhs.max_); 261 } 262 MaybeSubOverflowOrUnderflow(const RangeInfo &rhs) const263 bool MaybeSubOverflowOrUnderflow(const RangeInfo &rhs) const 264 { 265 return MaybeSubOverflow(rhs) || MaybeSubUnderflow(rhs); 266 } 267 operator -(const RangeInfo &rhs) const268 RangeInfo operator- (const RangeInfo &rhs) const 269 { 270 ASSERT(min_ <= max_ && rhs.min_ <= rhs.max_); 271 int32_t nmax = MaybeSubOverflow(rhs) ? INT32_MAX : max_ - rhs.min_; 272 int32_t nmin = MaybeSubUnderflow(rhs) ? INT32_MIN : min_ - rhs.max_; 273 return RangeInfo(nmin, nmax); 274 } 275 MaybeShrOverflow(const RangeInfo &rhs) const276 bool MaybeShrOverflow(const RangeInfo &rhs) const 277 { 278 if (rhs.max_ != rhs.min_) { 279 return true; 280 } 281 return ((static_cast<uint32_t>(rhs.max_) & 0x1f) == 0) && (min_< 0); // 0x1f : shift bits 282 } 283 SHR(const RangeInfo &rhs) const284 RangeInfo SHR(const RangeInfo &rhs) const 285 { 286 ASSERT(min_ <= max_); 287 ASSERT(rhs.max_ == rhs.min_); 288 if (MaybeShrOverflow(rhs)) { 289 // assume no overflow occurs since overflow will lead to deopt 290 return RangeInfo(0, std::max(0, GetMax())); 291 } 292 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 293 uint32_t tempMin = bit_cast<uint32_t>((max_ >= 0) ? std::max(0, min_) : min_); 294 uint32_t tempMax = bit_cast<uint32_t>((min_ < 0) ? std::min(-1, max_) : max_); 295 int32_t nmin = bit_cast<int32_t>(tempMin >> shift); 296 int32_t nmax = bit_cast<int32_t>(tempMax >> shift); 297 return RangeInfo(nmin, nmax); 298 } 299 ASHR(const RangeInfo &rhs) const300 RangeInfo ASHR(const RangeInfo &rhs) const 301 { 302 ASSERT(min_ <= max_); 303 ASSERT(rhs.max_ == rhs.min_); 304 int32_t shift = rhs.max_ & 0x1f; // 0x1f : shift bits 305 int32_t nmin = min_ >> shift; 306 int32_t nmax = max_ >> shift; 307 return RangeInfo(nmin, nmax); 308 } 309 operator ==(const RangeInfo &rhs) const310 bool operator== (const RangeInfo &rhs) const 311 { 312 return (min_ == rhs.min_) && (max_ == rhs.max_); 313 } 314 operator !=(const RangeInfo &rhs) const315 bool operator!= (const RangeInfo &rhs) const 316 { 317 return (min_ != rhs.min_) || (max_ != rhs.max_); 318 } 319 IsNone() const320 bool IsNone() const 321 { 322 return (min_ == INT32_MAX) && (max_ == INT32_MIN); 323 } 324 325 private: 326 int32_t min_ {INT32_MIN}; 327 int32_t max_ {INT32_MAX}; 328 }; 329 } // panda::ecmascript::kungfu 330 #endif // ECMASCRIPT_COMPILER_NUMBER_GATE_INFO_H 331