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