• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "ecmascript/compiler/share_gate_meta_data.h"
17 #include "ecmascript/compiler/number_gate_info.h"
18 #include "ecmascript/compiler/type.h"
19 #include "ecmascript/compiler/typed_hcr_lowering.h"
20 #include "ecmascript/compiler/builtins_lowering.h"
21 #include "ecmascript/compiler/new_object_stub_builder.h"
22 #include "ecmascript/compiler/number_speculative_lowering.h"
23 #include "ecmascript/deoptimizer/deoptimizer.h"
24 #include "ecmascript/js_arraybuffer.h"
25 #include "ecmascript/js_locale.h"
26 #include "ecmascript/js_native_pointer.h"
27 #include "ecmascript/js_object.h"
28 
29 namespace panda::ecmascript::kungfu {
30 
Run()31 void NumberSpeculativeLowering::Run()
32 {
33     std::vector<GateRef> gateList;
34     acc_.GetAllGates(gateList);
35     for (auto gate : gateList) {
36         auto op = acc_.GetOpCode(gate);
37         switch (op) {
38             case OpCode::RANGE_GUARD: {
39                 rangeGuardGates_.push_back(gate);
40                 break;
41             }
42             default: {
43                 VisitGate(gate);
44             }
45         }
46     }
47     for (auto rangeGuard : rangeGuardGates_) {
48         VisitRangeGuard(rangeGuard);
49     }
50 }
51 
VisitGate(GateRef gate)52 void NumberSpeculativeLowering::VisitGate(GateRef gate)
53 {
54     OpCode op = acc_.GetOpCode(gate);
55     switch (op) {
56         case OpCode::TYPED_BINARY_OP: {
57             VisitTypedBinaryOp(gate);
58             break;
59         }
60         case OpCode::TYPED_UNARY_OP: {
61             VisitTypedUnaryOp(gate);
62             break;
63         }
64         case OpCode::TYPED_CONDITION_JUMP: {
65             VisitTypedConditionJump(gate);
66             break;
67         }
68         case OpCode::VALUE_SELECTOR: {
69             VisitPhi(gate);
70             break;
71         }
72         case OpCode::CONSTANT: {
73             VisitConstant(gate);
74             break;
75         }
76         case OpCode::LOAD_ELEMENT: {
77             VisitLoadElement(gate);
78             break;
79         }
80         case OpCode::INDEX_CHECK: {
81             VisitIndexCheck(gate);
82             break;
83         }
84         case OpCode::RANGE_CHECK_PREDICATE: {
85             VisitRangeCheckPredicate(gate);
86             break;
87         }
88         case OpCode::LOAD_ARRAY_LENGTH:
89         case OpCode::LOAD_TYPED_ARRAY_LENGTH: {
90             VisitLoadArrayLength(gate);
91             break;
92         }
93         case OpCode::LOAD_STRING_LENGTH: {
94             VisitLoadStringLength(gate);
95             break;
96         }
97         case OpCode::LOAD_MAP_SIZE: {
98             VisitLoadMapSize(gate);
99             break;
100         }
101         case OpCode::LOAD_PROPERTY: {
102             VisitLoadProperty(gate);
103             break;
104         }
105         case OpCode::MONO_LOAD_PROPERTY_ON_PROTO: {
106             VisitLoadPropertyOnProto(gate);
107             break;
108         }
109         case OpCode::MATH_ROUND: {
110             VisitRound(gate);
111             break;
112         }
113         default:
114             break;
115     }
116 }
117 
VisitTypedBinaryOp(GateRef gate)118 void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate)
119 {
120     Environment env(gate, circuit_, &builder_);
121     if (acc_.HasStringType(gate)) {
122         VisitStringBinaryOp(gate);
123         return;
124     }
125     auto op = acc_.GetTypedBinaryOp(gate);
126     switch (op) {
127         case TypedBinOp::TYPED_STRICTEQ:
128         case TypedBinOp::TYPED_STRICTNOTEQ: {
129             VisitStrictEqualOrStrictNotEqual(gate);
130             break;
131         }
132         case TypedBinOp::TYPED_EQ:
133         case TypedBinOp::TYPED_NOTEQ: {
134             VisitEqualOrNotEqual(gate);
135             break;
136         }
137         default: {
138             if (acc_.HasNumberType(gate)) {
139                 VisitNumberBinaryOp(gate);
140             }
141             break;
142         }
143     }
144 }
145 
VisitEqualOrNotEqual(GateRef gate)146 void NumberSpeculativeLowering::VisitEqualOrNotEqual(GateRef gate)
147 {
148     if (acc_.HasNumberType(gate)) {
149         VisitNumberBinaryOp(gate);
150     } else {
151         VisitUndefinedEqOrUndefinedNotEq(gate);
152     }
153 }
154 
VisitStrictEqualOrStrictNotEqual(GateRef gate)155 void NumberSpeculativeLowering::VisitStrictEqualOrStrictNotEqual(GateRef gate)
156 {
157     if (acc_.HasNumberType(gate)) {
158         VisitNumberBinaryOp(gate);
159     } else {
160         VisitUndefinedStrictEqOrUndefinedStrictNotEq(gate);
161     }
162 }
163 
VisitNumberBinaryOp(GateRef gate)164 void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate)
165 {
166     TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
167     switch (Op) {
168         case TypedBinOp::TYPED_ADD: {
169             VisitNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
170             break;
171         }
172         case TypedBinOp::TYPED_SUB: {
173             VisitNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
174             break;
175         }
176         case TypedBinOp::TYPED_MUL: {
177             VisitNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
178             break;
179         }
180         case TypedBinOp::TYPED_LESS: {
181             VisitNumberCompare<TypedBinOp::TYPED_LESS>(gate);
182             break;
183         }
184         case TypedBinOp::TYPED_LESSEQ: {
185             VisitNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
186             break;
187         }
188         case TypedBinOp::TYPED_GREATER: {
189             VisitNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
190             break;
191         }
192         case TypedBinOp::TYPED_GREATEREQ: {
193             VisitNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
194             break;
195         }
196         case TypedBinOp::TYPED_EQ: {
197             VisitNumberCompare<TypedBinOp::TYPED_EQ>(gate);
198             break;
199         }
200         case TypedBinOp::TYPED_NOTEQ: {
201             VisitNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
202             break;
203         }
204         case TypedBinOp::TYPED_STRICTEQ: {
205             VisitNumberCompare<TypedBinOp::TYPED_STRICTEQ>(gate);
206             break;
207         }
208         case TypedBinOp::TYPED_STRICTNOTEQ: {
209             VisitNumberCompare<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
210             break;
211         }
212         case TypedBinOp::TYPED_SHL: {
213             VisitNumberShift<TypedBinOp::TYPED_SHL>(gate);
214             break;
215         }
216         case TypedBinOp::TYPED_SHR: {
217             VisitNumberShift<TypedBinOp::TYPED_SHR>(gate);
218             break;
219         }
220         case TypedBinOp::TYPED_ASHR: {
221             VisitNumberShift<TypedBinOp::TYPED_ASHR>(gate);
222             break;
223         }
224         case TypedBinOp::TYPED_AND: {
225             VisitNumberLogical<TypedBinOp::TYPED_AND>(gate);
226             break;
227         }
228         case TypedBinOp::TYPED_OR: {
229             VisitNumberLogical<TypedBinOp::TYPED_OR>(gate);
230             break;
231         }
232         case TypedBinOp::TYPED_XOR: {
233             VisitNumberLogical<TypedBinOp::TYPED_XOR>(gate);
234             break;
235         }
236         case TypedBinOp::TYPED_DIV: {
237             VisitNumberDiv(gate);
238             break;
239         }
240         case TypedBinOp::TYPED_MOD: {
241             VisitNumberMod<TypedBinOp::TYPED_MOD>(gate);
242             break;
243         }
244         default:
245             break;
246     }
247 }
248 
VisitTypedUnaryOp(GateRef gate)249 void NumberSpeculativeLowering::VisitTypedUnaryOp(GateRef gate)
250 {
251     Environment env(gate, circuit_, &builder_);
252     TypedUnOp Op = acc_.GetTypedUnAccessor(gate).GetTypedUnOp();
253     switch (Op) {
254         case TypedUnOp::TYPED_INC: {
255             VisitNumberMonocular<TypedUnOp::TYPED_INC>(gate);
256             return;
257         }
258         case TypedUnOp::TYPED_DEC: {
259             VisitNumberMonocular<TypedUnOp::TYPED_DEC>(gate);
260             return;
261         }
262         case TypedUnOp::TYPED_NEG: {
263             VisitNumberMonocular<TypedUnOp::TYPED_NEG>(gate);
264             return;
265         }
266         case TypedUnOp::TYPED_ISFALSE: {
267             VisitIsTrueOrFalse(gate, false);
268             return;
269         }
270         case TypedUnOp::TYPED_ISTRUE: {
271             VisitIsTrueOrFalse(gate, true);
272             return;
273         }
274         case TypedUnOp::TYPED_NOT: {
275             VisitNumberNot(gate);
276             return;
277         }
278         default:
279             break;
280     }
281 }
282 
VisitTypedConditionJump(GateRef gate)283 void NumberSpeculativeLowering::VisitTypedConditionJump(GateRef gate)
284 {
285     Environment env(gate, circuit_, &builder_);
286     ParamType type = acc_.GetTypedJumpAccessor(gate).GetParamType();
287     if (type.IsBooleanType()) {
288         VisitBooleanJump(gate);
289     } else {
290         UNREACHABLE();
291     }
292 }
293 
294 template<TypedBinOp Op>
VisitNumberCalculate(GateRef gate)295 void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate)
296 {
297     GateRef left = acc_.GetValueIn(gate, 0);
298     GateRef right = acc_.GetValueIn(gate, 1);
299     TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
300     const ParamType paramType = accessor.GetParamType();
301     ASSERT(paramType.HasNumberType());
302     GateRef result = Circuit::NullGate();
303     if (paramType.IsIntType()) {
304         result = CalculateInts<Op>(left, right);    // int op int
305         UpdateRange(result, GetRange(gate));
306         acc_.SetMachineType(gate, MachineType::I32);
307     } else {
308         result = CalculateDoubles<Op>(left, right); // float op float
309         acc_.SetMachineType(gate, MachineType::F64);
310     }
311     acc_.SetGateType(gate, GateType::NJSValue());
312     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
313 }
314 
315 template<TypedBinOp Op>
VisitNumberCompare(GateRef gate)316 void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate)
317 {
318     GateRef left = acc_.GetValueIn(gate, 0);
319     GateRef right = acc_.GetValueIn(gate, 1);
320     TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
321     const ParamType paramType = accessor.GetParamType();
322     ASSERT(paramType.HasNumberType());
323     GateRef result = Circuit::NullGate();
324     if (paramType.IsIntType()) {
325         result = CompareInts<Op>(left, right);  // int op int
326     } else {
327         result = CompareDoubles<Op>(left, right);   // float op float
328     }
329     acc_.SetMachineType(gate, MachineType::I1);
330     acc_.SetGateType(gate, GateType::NJSValue());
331     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
332 }
333 
334 template<TypedBinOp Op>
VisitNumberShift(GateRef gate)335 void NumberSpeculativeLowering::VisitNumberShift(GateRef gate)
336 {
337     GateRef left = acc_.GetValueIn(gate, 0);
338     GateRef right = acc_.GetValueIn(gate, 1);
339     GateRef result = ShiftInts<Op>(left, right);  // int op int
340     UpdateRange(result, GetRange(gate));
341     acc_.SetMachineType(gate, MachineType::I32);
342     acc_.SetGateType(gate, GateType::NJSValue());
343     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
344 }
345 
346 template<TypedBinOp Op>
VisitNumberLogical(GateRef gate)347 void NumberSpeculativeLowering::VisitNumberLogical(GateRef gate)
348 {
349     GateRef left = acc_.GetValueIn(gate, 0);
350     GateRef right = acc_.GetValueIn(gate, 1);
351     GateRef result = LogicalInts<Op>(left, right);  // int op int
352     UpdateRange(result, GetRange(gate));
353     acc_.SetMachineType(gate, MachineType::I32);
354     acc_.SetGateType(gate, GateType::NJSValue());
355     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
356 }
357 
VisitNumberDiv(GateRef gate)358 void NumberSpeculativeLowering::VisitNumberDiv(GateRef gate)
359 {
360     GateRef left = acc_.GetValueIn(gate, 0);
361     GateRef right = acc_.GetValueIn(gate, 1);
362     TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
363     const ParamType paramType = accessor.GetParamType();
364     ASSERT(paramType.HasNumberType());
365     GateRef result = Circuit::NullGate();
366     if (paramType.IsIntType()) {
367         result = builder_.Int32DivWithCheck(left, right);
368         acc_.SetMachineType(gate, MachineType::I32);
369     } else {
370         result = builder_.BinaryArithmetic(circuit_->Fdiv(),
371             MachineType::F64, left, right, GateType::NJSValue());
372         acc_.SetMachineType(gate, MachineType::F64);
373     }
374     acc_.SetGateType(gate, GateType::NJSValue());
375     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
376 }
377 
378 template<TypedBinOp Op>
VisitNumberMod(GateRef gate)379 void NumberSpeculativeLowering::VisitNumberMod(GateRef gate)
380 {
381     GateRef left = acc_.GetValueIn(gate, 0);
382     GateRef right = acc_.GetValueIn(gate, 1);
383     TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
384     const ParamType paramType = accessor.GetParamType();
385     ASSERT(paramType.HasNumberType());
386     GateRef result = Circuit::NullGate();
387     if (paramType.IsIntType()) {
388         if (GetRange(right).MaybeZero()) {
389             builder_.Int32CheckRightIsZero(right);
390         }
391         bool isNegativeZero = (GetRange(left) % GetRange(right)).MaybeZero() && GetRange(left).MaybeNegative();
392         if (isNegativeZero) {
393             builder_.RemainderIsNegativeZero(left, right);
394         }
395         result = CalculateInts<Op>(left, right);
396         UpdateRange(result, GetRange(gate));
397         acc_.SetMachineType(gate, MachineType::I32);
398     } else {
399         GateRef glue = acc_.GetGlueFromArgList();
400         result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
401             Gate::InvalidGateRef, {left, right}, Circuit::NullGate());
402         acc_.SetMachineType(gate, MachineType::F64);
403     }
404     acc_.SetGateType(gate, GateType::NJSValue());
405     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
406 }
407 
408 template<TypedUnOp Op>
VisitNumberMonocular(GateRef gate)409 void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate)
410 {
411     TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
412     ParamType type = accessor.GetParamType();
413     ASSERT(type.HasNumberType());
414     GateRef value = acc_.GetValueIn(gate, 0);
415     GateRef result = Circuit::NullGate();
416     if (type.IsIntType()) {
417         if (Op == TypedUnOp::TYPED_NEG) {
418             builder_.ValueCheckNegOverflow(value);
419         }
420         result = MonocularInt<Op>(value);
421         UpdateRange(result, GetRange(gate));
422         acc_.SetMachineType(gate, MachineType::I32);
423     } else {
424         result = MonocularDouble<Op>(value);
425         acc_.SetMachineType(gate, MachineType::F64);
426     }
427     acc_.SetGateType(gate, GateType::NJSValue());
428     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
429 }
430 
VisitNumberNot(GateRef gate)431 void NumberSpeculativeLowering::VisitNumberNot(GateRef gate)
432 {
433     ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType());
434     GateRef value = acc_.GetValueIn(gate, 0);
435     GateRef result = builder_.Int32Not(value);
436     UpdateRange(result, GetRange(gate));
437     acc_.SetMachineType(gate, MachineType::I32);
438     acc_.SetGateType(gate, GateType::NJSValue());
439     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
440 }
441 
VisitIsTrueOrFalse(GateRef gate,bool flag)442 void NumberSpeculativeLowering::VisitIsTrueOrFalse(GateRef gate, bool flag)
443 {
444     GateRef value = acc_.GetValueIn(gate, 0);
445     GateRef result = Circuit::NullGate();
446     if (!flag) {
447         result = builder_.BoolNot(value);
448     } else {
449         result = value;
450     }
451     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
452 }
453 
VisitBooleanJump(GateRef gate)454 void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate)
455 {
456     TypedJumpAccessor jumpAcc = acc_.GetTypedJumpAccessor(gate);
457     TypedJumpOp jumpOp = jumpAcc.GetTypedJumpOp();
458     ASSERT((jumpOp == TypedJumpOp::TYPED_JEQZ) || (jumpOp == TypedJumpOp::TYPED_JNEZ));
459     GateRef condition = acc_.GetValueIn(gate, 0);
460     uint32_t trueWeight = jumpAcc.GetTrueWeight();
461     uint32_t falseWeight = jumpAcc.GetFalseWeight();
462     if (jumpOp == TypedJumpOp::TYPED_JEQZ) {
463         std::swap(trueWeight, falseWeight);
464         condition = builder_.BoolNot(condition);
465     }
466     GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition, trueWeight, falseWeight, "booleanJump");
467     acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate());
468 }
469 
VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)470 void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)
471 {
472     ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ ||
473            acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ);
474     GateRef left = acc_.GetValueIn(gate, 0);
475     GateRef right = acc_.GetValueIn(gate, 1);
476     ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
477     GateRef result = Circuit::NullGate();
478     if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) {
479         result = builder_.Equal(left, right);
480     } else {
481         result = builder_.NotEqual(left, right);
482     }
483     ASSERT(result != Circuit::NullGate());
484     acc_.SetMachineType(gate, MachineType::I1);
485     acc_.SetGateType(gate, GateType::NJSValue());
486     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
487 }
488 
VisitUndefinedEqOrUndefinedNotEq(GateRef gate)489 void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate)
490 {
491     ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ ||
492            acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ);
493     GateRef left = acc_.GetValueIn(gate, 0);
494     GateRef right = acc_.GetValueIn(gate, 1);
495     ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
496     GateRef valueGate =  acc_.IsUndefinedOrNullOrHole(left) ? right : left;
497     GateRef result = Circuit::NullGate();
498     if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) {
499         result = builder_.TaggedIsUndefinedOrNullOrHole(valueGate);
500     } else {
501         result = builder_.TaggedIsNotUndefinedAndNullAndHole(valueGate);
502     }
503     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
504 }
505 
VisitConstant(GateRef gate)506 void NumberSpeculativeLowering::VisitConstant(GateRef gate)
507 {
508     TypeInfo output = GetOutputType(gate);
509     switch (output) {
510         case TypeInfo::INT32: {
511             int value = acc_.GetInt32FromConstant(gate);
512             GateRef constGate = GetConstInt32(value);
513             acc_.UpdateAllUses(gate, constGate);
514             break;
515         }
516         case TypeInfo::FLOAT64: {
517             double value = acc_.GetFloat64FromConstant(gate);
518             acc_.UpdateAllUses(gate, builder_.Double(value));
519             break;
520         }
521         default:
522             break;
523     }
524 }
525 
VisitPhi(GateRef gate)526 void NumberSpeculativeLowering::VisitPhi(GateRef gate)
527 {
528     TypeInfo output = GetOutputType(gate);
529     switch (output) {
530         case TypeInfo::INT1: {
531             acc_.SetGateType(gate, GateType::NJSValue());
532             acc_.SetMachineType(gate, MachineType::I1);
533             break;
534         }
535         case TypeInfo::INT32:
536         case TypeInfo::UINT32: {
537             acc_.SetGateType(gate, GateType::NJSValue());
538             acc_.SetMachineType(gate, MachineType::I32);
539             break;
540         }
541         case TypeInfo::FLOAT64: {
542             acc_.SetGateType(gate, GateType::NJSValue());
543             acc_.SetMachineType(gate, MachineType::F64);
544             break;
545         }
546         case TypeInfo::CHAR: {
547             acc_.SetGateType(gate, GateType::NJSValue());
548             acc_.SetMachineType(gate, MachineType::I32);
549             break;
550         }
551         default:
552             break;
553     }
554 }
555 
VisitRangeCheckPredicate(GateRef gate)556 void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate)
557 {
558     acc_.SetGateType(gate, GateType::NJSValue());
559     acc_.SetMachineType(gate, MachineType::I32);
560 }
561 
VisitIndexCheck(GateRef gate)562 void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate)
563 {
564     acc_.SetGateType(gate, GateType::NJSValue());
565     acc_.SetMachineType(gate, MachineType::I32);
566 }
567 
VisitLoadArrayLength(GateRef gate)568 void NumberSpeculativeLowering::VisitLoadArrayLength(GateRef gate)
569 {
570     acc_.SetGateType(gate, GateType::NJSValue());
571     acc_.SetMachineType(gate, MachineType::I32);
572 }
573 
VisitLoadStringLength(GateRef gate)574 void NumberSpeculativeLowering::VisitLoadStringLength(GateRef gate)
575 {
576     acc_.SetGateType(gate, GateType::NJSValue());
577     acc_.SetMachineType(gate, MachineType::I32);
578 }
579 
VisitLoadMapSize(GateRef gate)580 void NumberSpeculativeLowering::VisitLoadMapSize(GateRef gate)
581 {
582     acc_.SetGateType(gate, GateType::NJSValue());
583     acc_.SetMachineType(gate, MachineType::I32);
584 }
585 
VisitLoadElement(GateRef gate)586 void NumberSpeculativeLowering::VisitLoadElement(GateRef gate)
587 {
588     auto op = acc_.GetTypedLoadOp(gate);
589     switch (op) {
590         case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
591         case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
592         case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
593         case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
594         case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
595         case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
596         case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
597             acc_.SetMachineType(gate, MachineType::I32);
598             acc_.SetGateType(gate, GateType::NJSValue());
599             break;
600         case TypedLoadOp::ARRAY_LOAD_HOLE_INT_ELEMENT:
601         case TypedLoadOp::ARRAY_LOAD_HOLE_DOUBLE_ELEMENT:
602             acc_.SetMachineType(gate, MachineType::I64);
603             acc_.SetGateType(gate, GateType::NJSValue());
604             break;
605         case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
606         case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
607             acc_.SetMachineType(gate, MachineType::F64);
608             acc_.SetGateType(gate, GateType::NJSValue());
609             break;
610         default:
611             break;
612     }
613 }
614 
VisitLoadProperty(GateRef gate)615 void NumberSpeculativeLowering::VisitLoadProperty(GateRef gate)
616 {
617     TypeInfo output = GetOutputType(gate);
618     if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
619         Environment env(gate, circuit_, &builder_);
620         ASSERT(acc_.GetNumValueIn(gate) == 2);  // 2: receiver, plr
621         GateRef receiver = acc_.GetValueIn(gate, 0);
622         GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
623         PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
624         ASSERT(plr.IsLocal() || plr.IsFunction());
625 
626         // Hole check?
627         GateRef result = Circuit::NullGate();
628         if (output == TypeInfo::FLOAT64) {
629             if (plr.IsInlinedProps()) {
630                 result = builder_.LoadConstOffset(VariableType::FLOAT64(), receiver, plr.GetOffset());
631             } else {
632                 auto properties =
633                     builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
634                 result = builder_.GetValueFromTaggedArray(
635                     VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
636             }
637             acc_.SetMachineType(gate, MachineType::F64);
638         } else {
639             if (plr.IsInlinedProps()) {
640                 result = builder_.LoadConstOffset(VariableType::INT32(), receiver, plr.GetOffset());
641             } else {
642                 auto properties =
643                     builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
644                 result = builder_.GetValueFromTaggedArray(
645                     VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
646             }
647             acc_.SetMachineType(gate, MachineType::I32);
648         }
649         acc_.SetGateType(gate, GateType::NJSValue());
650         acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
651     }
652 }
653 
VisitRangeGuard(GateRef gate)654 void NumberSpeculativeLowering::VisitRangeGuard(GateRef gate)
655 {
656     Environment env(gate, circuit_, &builder_);
657     GateRef inputLength = acc_.GetValueIn(gate, 0);
658     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), inputLength);
659 }
660 
661 template<TypedBinOp Op>
CalculateInts(GateRef left,GateRef right)662 GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
663 {
664     GateRef res = Circuit::NullGate();
665     RangeInfo leftRange = GetRange(left);
666     RangeInfo rightRange = GetRange(right);
667     switch (Op) {
668         case TypedBinOp::TYPED_ADD: {
669             if (!leftRange.MaybeAddOverflowOrUnderflow(rightRange)) {
670                 return builder_.Int32Add(left, right, GateType::NJSValue());
671             }
672             res = builder_.AddWithOverflow(left, right);
673             break;
674         }
675         case TypedBinOp::TYPED_SUB: {
676             if (!leftRange.MaybeSubOverflowOrUnderflow(rightRange)) {
677                 return builder_.Int32Sub(left, right, GateType::NJSValue());
678             }
679             res = builder_.SubWithOverflow(left, right);
680             break;
681         }
682         case TypedBinOp::TYPED_MUL:
683             if (!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) {
684                 return builder_.Int32Mul(left, right);
685             }
686             res = builder_.MulWithOverflow(left, right);
687             break;
688         case TypedBinOp::TYPED_MOD: {
689             return builder_.BinaryArithmetic(circuit_->Smod(),
690                 MachineType::I32, left, right, GateType::NJSValue());
691             break;
692         }
693         default:
694             break;
695     }
696     // DeoptCheckForOverFlow
697     builder_.OverflowCheck(res);
698     return builder_.ExtractValue(MachineType::I32, res, GetConstInt32(0));
699 }
700 
701 template<TypedBinOp Op>
CalculateDoubles(GateRef left,GateRef right)702 GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right)
703 {
704     GateRef res = Circuit::NullGate();
705     switch (Op) {
706         case TypedBinOp::TYPED_ADD:
707             res = builder_.DoubleAdd(left, right, GateType::NJSValue());
708             break;
709         case TypedBinOp::TYPED_SUB:
710             res = builder_.DoubleSub(left, right, GateType::NJSValue());
711             break;
712         case TypedBinOp::TYPED_MUL:
713             res = builder_.DoubleMul(left, right, GateType::NJSValue());
714             break;
715         default:
716             break;
717     }
718     return res;
719 }
720 
721 template<TypedBinOp Op>
CompareInts(GateRef left,GateRef right)722 GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right)
723 {
724     GateRef condition = Circuit::NullGate();
725     switch (Op) {
726         case TypedBinOp::TYPED_LESS:
727             condition = builder_.Int32LessThan(left, right);
728             break;
729         case TypedBinOp::TYPED_LESSEQ:
730             condition = builder_.Int32LessThanOrEqual(left, right);
731             break;
732         case TypedBinOp::TYPED_GREATER:
733             condition = builder_.Int32GreaterThan(left, right);
734             break;
735         case TypedBinOp::TYPED_GREATEREQ:
736             condition = builder_.Int32GreaterThanOrEqual(left, right);
737             break;
738         case TypedBinOp::TYPED_EQ:
739         case TypedBinOp::TYPED_STRICTEQ:
740             condition = builder_.Int32Equal(left, right);
741             break;
742         case TypedBinOp::TYPED_NOTEQ:
743         case TypedBinOp::TYPED_STRICTNOTEQ:
744             condition = builder_.Int32NotEqual(left, right);
745             break;
746         default:
747             break;
748     }
749     return condition;
750 }
751 
752 template<TypedBinOp Op>
CompareDoubles(GateRef left,GateRef right)753 GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right)
754 {
755     GateRef condition = Circuit::NullGate();
756     switch (Op) {
757         case TypedBinOp::TYPED_LESS:
758             condition = builder_.DoubleLessThan(left, right);
759             break;
760         case TypedBinOp::TYPED_LESSEQ:
761             condition = builder_.DoubleLessThanOrEqual(left, right);
762             break;
763         case TypedBinOp::TYPED_GREATER:
764             condition = builder_.DoubleGreaterThan(left, right);
765             break;
766         case TypedBinOp::TYPED_GREATEREQ:
767             condition = builder_.DoubleGreaterThanOrEqual(left, right);
768             break;
769         case TypedBinOp::TYPED_EQ:
770         case TypedBinOp::TYPED_STRICTEQ: {
771             condition = LogicAndBuilder(builder_.GetCurrentEnvironment())
772                 .And(builder_.BoolNot(builder_.DoubleIsNAN(left)))
773                 .And(builder_.BoolNot(builder_.DoubleIsNAN(right)))
774                 .And(builder_.DoubleEqual(left, right))
775                 .Done();
776             break;
777         }
778         case TypedBinOp::TYPED_NOTEQ:
779         case TypedBinOp::TYPED_STRICTNOTEQ: {
780             condition = LogicOrBuilder(builder_.GetCurrentEnvironment())
781                 .Or(builder_.DoubleIsNAN(left))
782                 .Or(builder_.DoubleIsNAN(right))
783                 .Or(builder_.DoubleNotEqual(left, right))
784                 .Done();
785             break;
786         }
787         default:
788             break;
789     }
790     return condition;
791 }
792 
793 template<TypedBinOp Op>
ShiftInts(GateRef left,GateRef right)794 GateRef NumberSpeculativeLowering::ShiftInts(GateRef left, GateRef right)
795 {
796     GateRef value = Circuit::NullGate();
797     GateRef bitmask = GetConstInt32(0x1f); // 0x1f: bit mask of shift value
798     GateRef shift = builder_.Int32And(right, bitmask, GateType::NJSValue());
799     switch (Op) {
800         case TypedBinOp::TYPED_SHL: {
801             value = builder_.Int32LSL(left, shift, GateType::NJSValue());
802             break;
803         }
804         case TypedBinOp::TYPED_SHR: {
805             value = builder_.Int32LSR(left, shift, GateType::NJSValue());
806             RangeInfo leftRange = GetRange(left);
807             RangeInfo rightRange = GetRange(right);
808             if (!leftRange.MaybeShrOverflow(rightRange)) {
809                 return value;
810             }
811             builder_.Int32UnsignedUpperBoundCheck(value, builder_.Int32(INT32_MAX));
812             break;
813         }
814         case TypedBinOp::TYPED_ASHR: {
815             value = builder_.Int32ASR(left, shift, GateType::NJSValue());
816             break;
817         }
818         default:
819             LOG_ECMA(FATAL) << "this branch is unreachable";
820             UNREACHABLE();
821             break;
822     }
823     return value;
824 }
825 
826 template<TypedBinOp Op>
LogicalInts(GateRef left,GateRef right)827 GateRef NumberSpeculativeLowering::LogicalInts(GateRef left, GateRef right)
828 {
829     GateRef value = Circuit::NullGate();
830     switch (Op) {
831         case TypedBinOp::TYPED_AND: {
832             value = builder_.Int32And(left, right, GateType::NJSValue());
833             break;
834         }
835         case TypedBinOp::TYPED_OR: {
836             value = builder_.Int32Or(left, right, GateType::NJSValue());
837             break;
838         }
839         case TypedBinOp::TYPED_XOR: {
840             value = builder_.Int32Xor(left, right, GateType::NJSValue());
841             break;
842         }
843         default:
844             LOG_ECMA(FATAL) << "this branch is unreachable";
845             UNREACHABLE();
846             break;
847     }
848     return value;
849 }
850 
851 template<TypedUnOp Op>
MonocularInt(GateRef value)852 GateRef NumberSpeculativeLowering::MonocularInt(GateRef value)
853 {
854     GateRef res = Circuit::NullGate();
855     switch (Op) {
856         case TypedUnOp::TYPED_INC:
857             res = CalculateInts<TypedBinOp::TYPED_ADD>(value, GetConstInt32(1));
858             break;
859         case TypedUnOp::TYPED_DEC:
860             res = CalculateInts<TypedBinOp::TYPED_SUB>(value, GetConstInt32(1));
861             break;
862         case TypedUnOp::TYPED_NEG:
863             res = builder_.Int32Sub(GetConstInt32(0), value, GateType::NJSValue());
864             break;
865         default:
866             break;
867     }
868     return res;
869 }
870 
871 template<TypedUnOp Op>
MonocularDouble(GateRef value)872 GateRef NumberSpeculativeLowering::MonocularDouble(GateRef value)
873 {
874     GateRef res = Circuit::NullGate();
875     switch (Op) {
876         case TypedUnOp::TYPED_INC:
877             res = CalculateDoubles<TypedBinOp::TYPED_ADD>(value, GetConstDouble(1));
878             break;
879         case TypedUnOp::TYPED_DEC:
880             res = CalculateDoubles<TypedBinOp::TYPED_SUB>(value, GetConstDouble(1));
881             break;
882         case TypedUnOp::TYPED_NEG:
883             res = CalculateDoubles<TypedBinOp::TYPED_MUL>(value, GetConstDouble(-1));
884             break;
885         default:
886             break;
887     }
888     return res;
889 }
890 
UpdateRange(GateRef gate,const RangeInfo & range)891 void NumberSpeculativeLowering::UpdateRange(GateRef gate, const RangeInfo& range)
892 {
893     auto id = acc_.GetId(gate);
894     if (id >= rangeInfos_.size()) {
895         rangeInfos_.resize(id + 1, RangeInfo::ANY());
896     }
897     rangeInfos_[id] = range;
898 }
899 
GetRange(GateRef gate) const900 RangeInfo NumberSpeculativeLowering::GetRange(GateRef gate) const
901 {
902     auto id = acc_.GetId(gate);
903     if (id >= rangeInfos_.size()) {
904         rangeInfos_.resize(id + 1, RangeInfo::ANY());
905     }
906     ASSERT(!rangeInfos_[id].IsNone());
907     return rangeInfos_[id];
908 }
909 
GetConstInt32(int32_t v)910 GateRef NumberSpeculativeLowering::GetConstInt32(int32_t v)
911 {
912     auto val = builder_.Int32(v);
913     UpdateRange(val, RangeInfo(v, v));
914     return val;
915 }
916 
GetConstDouble(double v)917 GateRef NumberSpeculativeLowering::GetConstDouble(double v)
918 {
919     auto val = builder_.Double(v);
920     UpdateRange(val, RangeInfo(v, v));
921     return val;
922 }
923 
VisitStringBinaryOp(GateRef gate)924 void NumberSpeculativeLowering::VisitStringBinaryOp(GateRef gate)
925 {
926     TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
927     switch (Op) {
928         case TypedBinOp::TYPED_EQ: {
929             VisitStringCompare<TypedBinOp::TYPED_EQ>(gate);
930             break;
931         }
932         case TypedBinOp::TYPED_ADD: {
933             VisitStringAdd<TypedBinOp::TYPED_ADD>(gate);
934             break;
935         }
936         default:
937             LOG_COMPILER(FATAL) << "this branch is unreachable";
938             UNREACHABLE();
939     }
940 }
941 
942 template<TypedBinOp Op>
VisitStringCompare(GateRef gate)943 void NumberSpeculativeLowering::VisitStringCompare(GateRef gate)
944 {
945     GateRef left = acc_.GetValueIn(gate, 0);
946     GateRef right = acc_.GetValueIn(gate, 1);
947 
948     GateRef result;
949     ASSERT(Op == TypedBinOp::TYPED_EQ);
950     result = builder_.StringEqual(left, right);
951 
952     acc_.SetMachineType(gate, MachineType::I1);
953     acc_.SetGateType(gate, GateType::NJSValue());
954     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
955 }
956 
957 template<TypedBinOp Op>
VisitStringAdd(GateRef gate)958 void NumberSpeculativeLowering::VisitStringAdd(GateRef gate)
959 {
960     GateRef left = acc_.GetValueIn(gate, 0);
961     GateRef right = acc_.GetValueIn(gate, 1);
962 
963     GateRef result;
964     ASSERT(Op == TypedBinOp::TYPED_ADD);
965     result = builder_.StringAdd(left, right);
966 
967     acc_.SetMachineType(gate, MachineType::I64);
968     acc_.SetGateType(gate, GateType::NJSValue());
969     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
970 }
971 
VisitLoadPropertyOnProto(GateRef gate)972 void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate)
973 {
974     TypeInfo output = GetOutputType(gate);
975     if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
976         Environment env(gate, circuit_, &builder_);
977         GateRef frameState = acc_.GetFrameState(gate);
978         GateRef receiver = acc_.GetValueIn(gate, 0);
979         GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
980         GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
981         GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constpool
982         PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
983         GateRef result = Circuit::NullGate();
984         ASSERT(plr.IsLocal() || plr.IsFunction());
985 
986         auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
987         auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
988 
989         auto holderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex));
990         DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
991         Label exit(&builder_);
992         Label loopHead(&builder_);
993         Label loadHolder(&builder_);
994         Label lookUpProto(&builder_);
995         builder_.Jump(&loopHead);
996 
997         builder_.LoopBegin(&loopHead);
998         builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS7);
999         auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
1000         BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1001 
1002         builder_.Bind(&lookUpProto);
1003         current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
1004         builder_.LoopEnd(&loopHead);
1005 
1006         builder_.Bind(&loadHolder);
1007         if (output == TypeInfo::FLOAT64) {
1008             if (plr.IsInlinedProps()) {
1009                 result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset());
1010             } else {
1011                 auto properties =
1012                     builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1013                 result = builder_.GetValueFromTaggedArray(
1014                     VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
1015             }
1016             acc_.SetMachineType(gate, MachineType::F64);
1017         } else {
1018             if (plr.IsInlinedProps()) {
1019                 result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset());
1020             } else {
1021                 auto properties =
1022                     builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1023                 result = builder_.GetValueFromTaggedArray(
1024                     VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
1025             }
1026             acc_.SetMachineType(gate, MachineType::I32);
1027         }
1028         builder_.Jump(&exit);
1029         builder_.Bind(&exit);
1030         acc_.SetGateType(gate, GateType::NJSValue());
1031         acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1032     }
1033 }
1034 
VisitRound(GateRef gate)1035 void NumberSpeculativeLowering::VisitRound(GateRef gate)
1036 {
1037     TypeInfo output = GetOutputType(gate);
1038     GateRef in = acc_.GetValueIn(gate, 0);
1039     if (output == TypeInfo::INT32) {
1040         acc_.ReplaceGate(gate, in);
1041     }
1042 }
1043 
1044 }  // namespace panda::ecmascript
1045