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