• 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             VisitNumberCalculate<TypedBinOp::TYPED_MUL>(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 
368 template<TypedBinOp Op>
VisitNumberMod(GateRef gate)369 void NumberSpeculativeLowering::VisitNumberMod(GateRef gate)
370 {
371     GateRef left = acc_.GetValueIn(gate, 0);
372     GateRef right = acc_.GetValueIn(gate, 1);
373     TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
374     const ParamType paramType = accessor.GetParamType();
375     ASSERT(paramType.HasNumberType());
376     GateRef result = Circuit::NullGate();
377     if (paramType.IsIntType()) {
378         if (GetRange(right).MaybeZero()) {
379             builder_.Int32CheckRightIsZero(right);
380         }
381         bool isNegativeZero = (GetRange(left) % GetRange(right)).MaybeZero() && GetRange(left).MaybeNegative();
382         if (isNegativeZero) {
383             builder_.RemainderIsNegativeZero(left, right);
384         }
385         result = CalculateInts<Op>(left, right);
386         UpdateRange(result, GetRange(gate));
387         acc_.SetMachineType(gate, MachineType::I32);
388     } else {
389         GateRef glue = acc_.GetGlueFromArgList();
390         result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
391             Gate::InvalidGateRef, {left, right}, Circuit::NullGate());
392         acc_.SetMachineType(gate, MachineType::F64);
393     }
394     acc_.SetGateType(gate, GateType::NJSValue());
395     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
396 }
397 
398 template<TypedUnOp Op>
VisitNumberMonocular(GateRef gate)399 void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate)
400 {
401     TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
402     ParamType type = accessor.GetParamType();
403     ASSERT(type.HasNumberType());
404     GateRef value = acc_.GetValueIn(gate, 0);
405     GateRef result = Circuit::NullGate();
406     if (type.IsIntType()) {
407         if (Op == TypedUnOp::TYPED_NEG) {
408             builder_.ValueCheckNegOverflow(value);
409         }
410         result = MonocularInt<Op>(value);
411         UpdateRange(result, GetRange(gate));
412         acc_.SetMachineType(gate, MachineType::I32);
413     } else {
414         result = MonocularDouble<Op>(value);
415         acc_.SetMachineType(gate, MachineType::F64);
416     }
417     acc_.SetGateType(gate, GateType::NJSValue());
418     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
419 }
420 
VisitNumberNot(GateRef gate)421 void NumberSpeculativeLowering::VisitNumberNot(GateRef gate)
422 {
423     ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType());
424     GateRef value = acc_.GetValueIn(gate, 0);
425     GateRef result = builder_.Int32Not(value);
426     UpdateRange(result, GetRange(gate));
427     acc_.SetMachineType(gate, MachineType::I32);
428     acc_.SetGateType(gate, GateType::NJSValue());
429     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
430 }
431 
VisitIsTrueOrFalse(GateRef gate,bool flag)432 void NumberSpeculativeLowering::VisitIsTrueOrFalse(GateRef gate, bool flag)
433 {
434     GateRef value = acc_.GetValueIn(gate, 0);
435     GateRef result = Circuit::NullGate();
436     if (!flag) {
437         result = builder_.BoolNot(value);
438     } else {
439         result = value;
440     }
441     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
442 }
443 
VisitBooleanJump(GateRef gate)444 void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate)
445 {
446     TypedJumpAccessor jumpAcc = acc_.GetTypedJumpAccessor(gate);
447     TypedJumpOp jumpOp = jumpAcc.GetTypedJumpOp();
448     ASSERT((jumpOp == TypedJumpOp::TYPED_JEQZ) || (jumpOp == TypedJumpOp::TYPED_JNEZ));
449     GateRef condition = acc_.GetValueIn(gate, 0);
450     uint32_t trueWeight = jumpAcc.GetTrueWeight();
451     uint32_t falseWeight = jumpAcc.GetFalseWeight();
452     if (jumpOp == TypedJumpOp::TYPED_JEQZ) {
453         std::swap(trueWeight, falseWeight);
454         condition = builder_.BoolNot(condition);
455     }
456     GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition, trueWeight, falseWeight, "booleanJump");
457     acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate());
458 }
459 
VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)460 void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)
461 {
462     ASSERT((acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) ||
463            (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ));
464     GateRef left = acc_.GetValueIn(gate, 0);
465     GateRef right = acc_.GetValueIn(gate, 1);
466     ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
467     GateRef result = Circuit::NullGate();
468     if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) {
469         result = builder_.Equal(left, right);
470     } else {
471         result = builder_.NotEqual(left, right);
472     }
473     ASSERT(result != Circuit::NullGate());
474     acc_.SetMachineType(gate, MachineType::I1);
475     acc_.SetGateType(gate, GateType::NJSValue());
476     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
477 }
478 
VisitUndefinedEqOrUndefinedNotEq(GateRef gate)479 void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate)
480 {
481     ASSERT((acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) ||
482            (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ));
483     GateRef left = acc_.GetValueIn(gate, 0);
484     GateRef right = acc_.GetValueIn(gate, 1);
485     ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
486     GateRef valueGate =  acc_.IsUndefinedOrNullOrHole(left) ? right : left;
487     GateRef result = Circuit::NullGate();
488     if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) {
489         result = builder_.TaggedIsUndefinedOrNullOrHole(valueGate);
490     } else {
491         result = builder_.TaggedIsNotUndefinedAndNullAndHole(valueGate);
492     }
493     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
494 }
495 
VisitConstant(GateRef gate)496 void NumberSpeculativeLowering::VisitConstant(GateRef gate)
497 {
498     TypeInfo output = GetOutputType(gate);
499     switch (output) {
500         case TypeInfo::INT32: {
501             int value = acc_.GetInt32FromConstant(gate);
502             GateRef constGate = GetConstInt32(value);
503             acc_.UpdateAllUses(gate, constGate);
504             break;
505         }
506         case TypeInfo::FLOAT64: {
507             double value = acc_.GetFloat64FromConstant(gate);
508             acc_.UpdateAllUses(gate, builder_.Double(value));
509             break;
510         }
511         default:
512             break;
513     }
514 }
515 
VisitPhi(GateRef gate)516 void NumberSpeculativeLowering::VisitPhi(GateRef gate)
517 {
518     TypeInfo output = GetOutputType(gate);
519     switch (output) {
520         case TypeInfo::INT1: {
521             acc_.SetGateType(gate, GateType::NJSValue());
522             acc_.SetMachineType(gate, MachineType::I1);
523             break;
524         }
525         case TypeInfo::INT32:
526         case TypeInfo::UINT32: {
527             acc_.SetGateType(gate, GateType::NJSValue());
528             acc_.SetMachineType(gate, MachineType::I32);
529             break;
530         }
531         case TypeInfo::FLOAT64: {
532             acc_.SetGateType(gate, GateType::NJSValue());
533             acc_.SetMachineType(gate, MachineType::F64);
534             break;
535         }
536         case TypeInfo::CHAR: {
537             acc_.SetGateType(gate, GateType::NJSValue());
538             acc_.SetMachineType(gate, MachineType::I32);
539             break;
540         }
541         default:
542             break;
543     }
544 }
545 
VisitRangeCheckPredicate(GateRef gate)546 void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate)
547 {
548     acc_.SetGateType(gate, GateType::NJSValue());
549     acc_.SetMachineType(gate, MachineType::I32);
550 }
551 
VisitIndexCheck(GateRef gate)552 void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate)
553 {
554     acc_.SetGateType(gate, GateType::NJSValue());
555     acc_.SetMachineType(gate, MachineType::I32);
556 }
557 
VisitLoadArrayLength(GateRef gate)558 void NumberSpeculativeLowering::VisitLoadArrayLength(GateRef gate)
559 {
560     acc_.SetGateType(gate, GateType::NJSValue());
561     acc_.SetMachineType(gate, MachineType::I32);
562 }
563 
VisitLoadStringLength(GateRef gate)564 void NumberSpeculativeLowering::VisitLoadStringLength(GateRef gate)
565 {
566     acc_.SetGateType(gate, GateType::NJSValue());
567     acc_.SetMachineType(gate, MachineType::I32);
568 }
569 
VisitLoadMapSize(GateRef gate)570 void NumberSpeculativeLowering::VisitLoadMapSize(GateRef gate)
571 {
572     acc_.SetGateType(gate, GateType::NJSValue());
573     acc_.SetMachineType(gate, MachineType::I32);
574 }
575 
VisitLoadElement(GateRef gate)576 void NumberSpeculativeLowering::VisitLoadElement(GateRef gate)
577 {
578     auto op = acc_.GetTypedLoadOp(gate);
579     switch (op) {
580         case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
581         case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
582         case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
583         case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
584         case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
585         case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
586         case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
587             acc_.SetMachineType(gate, MachineType::I32);
588             acc_.SetGateType(gate, GateType::NJSValue());
589             break;
590         case TypedLoadOp::ARRAY_LOAD_HOLE_INT_ELEMENT:
591         case TypedLoadOp::ARRAY_LOAD_HOLE_DOUBLE_ELEMENT:
592             acc_.SetMachineType(gate, MachineType::I64);
593             acc_.SetGateType(gate, GateType::NJSValue());
594             break;
595         case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
596         case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
597             acc_.SetMachineType(gate, MachineType::F64);
598             acc_.SetGateType(gate, GateType::NJSValue());
599             break;
600         default:
601             break;
602     }
603 }
604 
VisitLoadProperty(GateRef gate)605 void NumberSpeculativeLowering::VisitLoadProperty(GateRef gate)
606 {
607     TypeInfo output = GetOutputType(gate);
608     if ((output == TypeInfo::INT32) || (output == TypeInfo::FLOAT64)) {
609         Environment env(gate, circuit_, &builder_);
610         ASSERT(acc_.GetNumValueIn(gate) == 2);  // 2: receiver, plr
611         GateRef receiver = acc_.GetValueIn(gate, 0);
612         GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
613         PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
614         ASSERT(plr.IsLocal() || plr.IsFunction());
615 
616         // Hole check?
617         GateRef result = Circuit::NullGate();
618         if (output == TypeInfo::FLOAT64) {
619             if (plr.IsInlinedProps()) {
620                 result = builder_.LoadConstOffset(VariableType::FLOAT64(), receiver, plr.GetOffset());
621             } else {
622                 auto properties =
623                     builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
624                 result = builder_.GetValueFromTaggedArray(
625                     VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
626             }
627             acc_.SetMachineType(gate, MachineType::F64);
628         } else {
629             if (plr.IsInlinedProps()) {
630                 result = builder_.LoadConstOffset(VariableType::INT32(), receiver, plr.GetOffset());
631             } else {
632                 auto properties =
633                     builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
634                 result = builder_.GetValueFromTaggedArray(
635                     VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
636             }
637             acc_.SetMachineType(gate, MachineType::I32);
638         }
639         acc_.SetGateType(gate, GateType::NJSValue());
640         acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
641     }
642 }
643 
VisitRangeGuard(GateRef gate)644 void NumberSpeculativeLowering::VisitRangeGuard(GateRef gate)
645 {
646     Environment env(gate, circuit_, &builder_);
647     GateRef inputLength = acc_.GetValueIn(gate, 0);
648     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), inputLength);
649 }
650 
651 template<TypedBinOp Op>
CalculateInts(GateRef left,GateRef right)652 GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
653 {
654     GateRef res = Circuit::NullGate();
655     RangeInfo leftRange = GetRange(left);
656     RangeInfo rightRange = GetRange(right);
657     switch (Op) {
658         case TypedBinOp::TYPED_ADD: {
659             if (!leftRange.MaybeAddOverflowOrUnderflow(rightRange)) {
660                 return builder_.Int32Add(left, right, GateType::NJSValue());
661             }
662             res = builder_.AddWithOverflow(left, right);
663             break;
664         }
665         case TypedBinOp::TYPED_SUB: {
666             if (!leftRange.MaybeSubOverflowOrUnderflow(rightRange)) {
667                 return builder_.Int32Sub(left, right, GateType::NJSValue());
668             }
669             res = builder_.SubWithOverflow(left, right);
670             break;
671         }
672         case TypedBinOp::TYPED_MUL:
673             if (!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) {
674                 return builder_.Int32Mul(left, right);
675             }
676             res = builder_.MulWithOverflow(left, right);
677             break;
678         case TypedBinOp::TYPED_MOD: {
679             return builder_.BinaryArithmetic(circuit_->Smod(),
680                 MachineType::I32, left, right, GateType::NJSValue());
681             break;
682         }
683         default:
684             break;
685     }
686     // DeoptCheckForOverFlow
687     builder_.OverflowCheck(res);
688     return builder_.ExtractValue(MachineType::I32, res, GetConstInt32(0));
689 }
690 
691 template<TypedBinOp Op>
CalculateDoubles(GateRef left,GateRef right)692 GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right)
693 {
694     GateRef res = Circuit::NullGate();
695     switch (Op) {
696         case TypedBinOp::TYPED_ADD:
697             res = builder_.DoubleAdd(left, right, GateType::NJSValue());
698             break;
699         case TypedBinOp::TYPED_SUB:
700             res = builder_.DoubleSub(left, right, GateType::NJSValue());
701             break;
702         case TypedBinOp::TYPED_MUL:
703             res = builder_.DoubleMul(left, right, GateType::NJSValue());
704             break;
705         default:
706             break;
707     }
708     return res;
709 }
710 
711 template<TypedBinOp Op>
CompareInts(GateRef left,GateRef right)712 GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right)
713 {
714     GateRef condition = Circuit::NullGate();
715     switch (Op) {
716         case TypedBinOp::TYPED_LESS:
717             condition = builder_.Int32LessThan(left, right);
718             break;
719         case TypedBinOp::TYPED_LESSEQ:
720             condition = builder_.Int32LessThanOrEqual(left, right);
721             break;
722         case TypedBinOp::TYPED_GREATER:
723             condition = builder_.Int32GreaterThan(left, right);
724             break;
725         case TypedBinOp::TYPED_GREATEREQ:
726             condition = builder_.Int32GreaterThanOrEqual(left, right);
727             break;
728         case TypedBinOp::TYPED_EQ:
729         case TypedBinOp::TYPED_STRICTEQ:
730             condition = builder_.Int32Equal(left, right);
731             break;
732         case TypedBinOp::TYPED_NOTEQ:
733         case TypedBinOp::TYPED_STRICTNOTEQ:
734             condition = builder_.Int32NotEqual(left, right);
735             break;
736         default:
737             break;
738     }
739     return condition;
740 }
741 
742 template<TypedBinOp Op>
CompareDoubles(GateRef left,GateRef right)743 GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right)
744 {
745     GateRef condition = Circuit::NullGate();
746     switch (Op) {
747         case TypedBinOp::TYPED_LESS:
748             condition = builder_.DoubleLessThan(left, right);
749             break;
750         case TypedBinOp::TYPED_LESSEQ:
751             condition = builder_.DoubleLessThanOrEqual(left, right);
752             break;
753         case TypedBinOp::TYPED_GREATER:
754             condition = builder_.DoubleGreaterThan(left, right);
755             break;
756         case TypedBinOp::TYPED_GREATEREQ:
757             condition = builder_.DoubleGreaterThanOrEqual(left, right);
758             break;
759         case TypedBinOp::TYPED_EQ:
760         case TypedBinOp::TYPED_STRICTEQ: {
761             condition = LogicAndBuilder(builder_.GetCurrentEnvironment())
762                 .And(builder_.BoolNot(builder_.DoubleIsNAN(left)))
763                 .And(builder_.BoolNot(builder_.DoubleIsNAN(right)))
764                 .And(builder_.DoubleEqual(left, right))
765                 .Done();
766             break;
767         }
768         case TypedBinOp::TYPED_NOTEQ:
769         case TypedBinOp::TYPED_STRICTNOTEQ: {
770             condition = LogicOrBuilder(builder_.GetCurrentEnvironment())
771                 .Or(builder_.DoubleIsNAN(left))
772                 .Or(builder_.DoubleIsNAN(right))
773                 .Or(builder_.DoubleNotEqual(left, right))
774                 .Done();
775             break;
776         }
777         default:
778             break;
779     }
780     return condition;
781 }
782 
783 template<TypedBinOp Op>
ShiftInts(GateRef left,GateRef right)784 GateRef NumberSpeculativeLowering::ShiftInts(GateRef left, GateRef right)
785 {
786     GateRef value = Circuit::NullGate();
787     GateRef bitmask = GetConstInt32(0x1f); // 0x1f: bit mask of shift value
788     GateRef shift = builder_.Int32And(right, bitmask, GateType::NJSValue());
789     switch (Op) {
790         case TypedBinOp::TYPED_SHL: {
791             value = builder_.Int32LSL(left, shift, GateType::NJSValue());
792             break;
793         }
794         case TypedBinOp::TYPED_SHR: {
795             value = builder_.Int32LSR(left, shift, GateType::NJSValue());
796             RangeInfo leftRange = GetRange(left);
797             RangeInfo rightRange = GetRange(right);
798             if (!leftRange.MaybeShrOverflow(rightRange)) {
799                 return value;
800             }
801             builder_.Int32UnsignedUpperBoundCheck(value, builder_.Int32(INT32_MAX));
802             break;
803         }
804         case TypedBinOp::TYPED_ASHR: {
805             value = builder_.Int32ASR(left, shift, GateType::NJSValue());
806             break;
807         }
808         default:
809             LOG_ECMA(FATAL) << "this branch is unreachable";
810             UNREACHABLE();
811             break;
812     }
813     return value;
814 }
815 
816 template<TypedBinOp Op>
LogicalInts(GateRef left,GateRef right)817 GateRef NumberSpeculativeLowering::LogicalInts(GateRef left, GateRef right)
818 {
819     GateRef value = Circuit::NullGate();
820     switch (Op) {
821         case TypedBinOp::TYPED_AND: {
822             value = builder_.Int32And(left, right, GateType::NJSValue());
823             break;
824         }
825         case TypedBinOp::TYPED_OR: {
826             value = builder_.Int32Or(left, right, GateType::NJSValue());
827             break;
828         }
829         case TypedBinOp::TYPED_XOR: {
830             value = builder_.Int32Xor(left, right, GateType::NJSValue());
831             break;
832         }
833         default:
834             LOG_ECMA(FATAL) << "this branch is unreachable";
835             UNREACHABLE();
836             break;
837     }
838     return value;
839 }
840 
841 template<TypedUnOp Op>
MonocularInt(GateRef value)842 GateRef NumberSpeculativeLowering::MonocularInt(GateRef value)
843 {
844     GateRef res = Circuit::NullGate();
845     switch (Op) {
846         case TypedUnOp::TYPED_INC:
847             res = CalculateInts<TypedBinOp::TYPED_ADD>(value, GetConstInt32(1));
848             break;
849         case TypedUnOp::TYPED_DEC:
850             res = CalculateInts<TypedBinOp::TYPED_SUB>(value, GetConstInt32(1));
851             break;
852         case TypedUnOp::TYPED_NEG:
853             res = builder_.Int32Sub(GetConstInt32(0), value, GateType::NJSValue());
854             break;
855         default:
856             break;
857     }
858     return res;
859 }
860 
861 template<TypedUnOp Op>
MonocularDouble(GateRef value)862 GateRef NumberSpeculativeLowering::MonocularDouble(GateRef value)
863 {
864     GateRef res = Circuit::NullGate();
865     switch (Op) {
866         case TypedUnOp::TYPED_INC:
867             res = CalculateDoubles<TypedBinOp::TYPED_ADD>(value, GetConstDouble(1));
868             break;
869         case TypedUnOp::TYPED_DEC:
870             res = CalculateDoubles<TypedBinOp::TYPED_SUB>(value, GetConstDouble(1));
871             break;
872         case TypedUnOp::TYPED_NEG:
873             res = CalculateDoubles<TypedBinOp::TYPED_MUL>(value, GetConstDouble(-1));
874             break;
875         default:
876             break;
877     }
878     return res;
879 }
880 
UpdateRange(GateRef gate,const RangeInfo & range)881 void NumberSpeculativeLowering::UpdateRange(GateRef gate, const RangeInfo& range)
882 {
883     auto id = acc_.GetId(gate);
884     if (id >= rangeInfos_.size()) {
885         rangeInfos_.resize(id + 1, RangeInfo::ANY());
886     }
887     rangeInfos_[id] = range;
888 }
889 
GetRange(GateRef gate) const890 RangeInfo NumberSpeculativeLowering::GetRange(GateRef gate) const
891 {
892     auto id = acc_.GetId(gate);
893     if (id >= rangeInfos_.size()) {
894         rangeInfos_.resize(id + 1, RangeInfo::ANY());
895     }
896     ASSERT(!rangeInfos_[id].IsNone());
897     return rangeInfos_[id];
898 }
899 
GetConstInt32(int32_t v)900 GateRef NumberSpeculativeLowering::GetConstInt32(int32_t v)
901 {
902     auto val = builder_.Int32(v);
903     UpdateRange(val, RangeInfo(v, v));
904     return val;
905 }
906 
GetConstDouble(double v)907 GateRef NumberSpeculativeLowering::GetConstDouble(double v)
908 {
909     auto val = builder_.Double(v);
910     UpdateRange(val, RangeInfo(v, v));
911     return val;
912 }
913 
VisitStringBinaryOp(GateRef gate)914 void NumberSpeculativeLowering::VisitStringBinaryOp(GateRef gate)
915 {
916     if (acc_.IsInternStringType(gate)) {
917         VisitInternStringBinaryOp(gate);
918         return;
919     }
920     TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
921     switch (Op) {
922         case TypedBinOp::TYPED_EQ: {
923             VisitStringCompare<TypedBinOp::TYPED_EQ>(gate);
924             break;
925         }
926         case TypedBinOp::TYPED_ADD: {
927             VisitStringAdd<TypedBinOp::TYPED_ADD>(gate);
928             break;
929         }
930         default:
931             LOG_COMPILER(FATAL) << "this branch is unreachable";
932             UNREACHABLE();
933     }
934 }
935 
VisitInternStringBinaryOp(GateRef gate)936 void NumberSpeculativeLowering::VisitInternStringBinaryOp(GateRef gate)
937 {
938     TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
939     GateRef left = acc_.GetValueIn(gate, 0);
940     GateRef right = acc_.GetValueIn(gate, 1);
941     DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.False());
942     switch (Op) {
943         case TypedBinOp::TYPED_STRICTEQ: {
944             result = builder_.Equal(left, right);
945             break;
946         }
947         case TypedBinOp::TYPED_STRICTNOTEQ: {
948             result = builder_.NotEqual(left, right);
949             break;
950         }
951         default: {
952             LOG_COMPILER(FATAL) << "this branch is unreachable";
953             UNREACHABLE();
954         }
955     }
956     acc_.SetMachineType(gate, MachineType::I1);
957     acc_.SetGateType(gate, GateType::NJSValue());
958     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
959 }
960 
961 template<TypedBinOp Op>
VisitStringCompare(GateRef gate)962 void NumberSpeculativeLowering::VisitStringCompare(GateRef gate)
963 {
964     GateRef left = acc_.GetValueIn(gate, 0);
965     GateRef right = acc_.GetValueIn(gate, 1);
966 
967     GateRef result;
968     ASSERT(Op == TypedBinOp::TYPED_EQ);
969     result = builder_.StringEqual(left, right);
970 
971     acc_.SetMachineType(gate, MachineType::I1);
972     acc_.SetGateType(gate, GateType::NJSValue());
973     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
974 }
975 
976 template<TypedBinOp Op>
VisitStringAdd(GateRef gate)977 void NumberSpeculativeLowering::VisitStringAdd(GateRef gate)
978 {
979     GateRef left = acc_.GetValueIn(gate, 0);
980     GateRef right = acc_.GetValueIn(gate, 1);
981 
982     GateRef result;
983     ASSERT(Op == TypedBinOp::TYPED_ADD);
984     result = builder_.StringAdd(left, right);
985 
986     acc_.SetMachineType(gate, MachineType::I64);
987     acc_.SetGateType(gate, GateType::NJSValue());
988     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
989 }
990 
VisitLoadPropertyOnProto(GateRef gate)991 void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate)
992 {
993     TypeInfo output = GetOutputType(gate);
994     if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
995         Environment env(gate, circuit_, &builder_);
996         GateRef frameState = acc_.GetFrameState(gate);
997         GateRef receiver = acc_.GetValueIn(gate, 0);
998         GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
999         GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
1000         GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constpool
1001         PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
1002         GateRef result = Circuit::NullGate();
1003         ASSERT(plr.IsLocal() || plr.IsFunction());
1004 
1005         auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
1006         auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
1007 
1008         auto holderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex));
1009         DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
1010         Label exit(&builder_);
1011         Label loopHead(&builder_);
1012         Label loadHolder(&builder_);
1013         Label lookUpProto(&builder_);
1014         builder_.Jump(&loopHead);
1015 
1016         builder_.LoopBegin(&loopHead);
1017         builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS7);
1018         auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
1019         BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1020 
1021         builder_.Bind(&lookUpProto);
1022         current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
1023         builder_.LoopEnd(&loopHead);
1024 
1025         builder_.Bind(&loadHolder);
1026         if (output == TypeInfo::FLOAT64) {
1027             if (plr.IsInlinedProps()) {
1028                 result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset());
1029             } else {
1030                 auto properties =
1031                     builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1032                 result = builder_.GetValueFromTaggedArray(
1033                     VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
1034             }
1035             acc_.SetMachineType(gate, MachineType::F64);
1036         } else {
1037             if (plr.IsInlinedProps()) {
1038                 result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset());
1039             } else {
1040                 auto properties =
1041                     builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1042                 result = builder_.GetValueFromTaggedArray(
1043                     VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
1044             }
1045             acc_.SetMachineType(gate, MachineType::I32);
1046         }
1047         builder_.Jump(&exit);
1048         builder_.Bind(&exit);
1049         acc_.SetGateType(gate, GateType::NJSValue());
1050         acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1051     }
1052 }
1053 
VisitRound(GateRef gate)1054 void NumberSpeculativeLowering::VisitRound(GateRef gate)
1055 {
1056     TypeInfo output = GetOutputType(gate);
1057     GateRef in = acc_.GetValueIn(gate, 0);
1058     if (output == TypeInfo::INT32) {
1059         acc_.ReplaceGate(gate, in);
1060     }
1061 }
1062 
1063 }  // namespace panda::ecmascript
1064