• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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