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