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