49 return x.IsWord32And();
53 return x.IsWord32Shl();
57 return x.IsWord32Shr();
61 return x.IsWord32Sar();
64 return op->
opcode() == IrOpcode::kWord32Sar &&
69 return x.IsWord32Xor();
73 return x.IsInt32Add();
77 return x.IsInt32Mul();
81 return machine->Int32Add();
84 return machine->Word32Equal();
119 template <
typename T>
121 return x.IsWord64And();
123 template <
typename T>
125 return x.IsWord64Shl();
127 template <
typename T>
129 return x.IsWord64Shr();
131 template <
typename T>
133 return x.IsWord64Sar();
136 return op->
opcode() == IrOpcode::kWord64Sar &&
139 template <
typename T>
141 return x.IsWord64Xor();
143 template <
typename T>
145 return x.IsInt64Add();
147 template <
typename T>
149 return x.IsInt64Mul();
153 return machine->Int64Add();
156 return machine->Word64Equal();
164 return r_->NoChange();
197 signalling_nan_propagation_(signalling_nan_propagation) {}
225 graph()->NewNode(
machine()->Float64LessThanOrEqual(), value,
235 return reduction.Changed() ? reduction.replacement() :
node;
239 if (rhs == 0)
return lhs;
244 if (rhs == 0)
return lhs;
249 if (rhs == 0)
return lhs;
254 if (rhs == 0)
return lhs;
269 return reduction.Changed() ? reduction.replacement() :
node;
275 return reduction.Changed() ? reduction.replacement() :
node;
281 return reduction.Changed() ? reduction.replacement() :
node;
287 return reduction.Changed() ? reduction.replacement() :
node;
293 return reduction.Changed() ? reduction.replacement() :
node;
306 DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
307 base::MagicNumbersForDivision<uint32_t>
const mag =
312 quotient =
Int32Add(quotient, dividend);
314 quotient =
Int32Sub(quotient, dividend);
321 DCHECK_NE(std::numeric_limits<int64_t>::min(), divisor);
322 base::MagicNumbersForDivision<uint64_t>
const mag =
327 quotient =
Int64Add(quotient, dividend);
329 quotient =
Int64Sub(quotient, dividend);
342 base::MagicNumbersForDivision<uint32_t>
const mag =
352 quotient =
Word32Shr(quotient, mag.shift);
365 base::MagicNumbersForDivision<uint64_t>
const mag =
375 quotient =
Word64Shr(quotient, mag.shift);
383 return reduction.Changed() ? reduction.replacement() :
node;
392 switch (node->opcode()) {
393 case IrOpcode::kProjection:
395 case IrOpcode::kWord32And:
397 case IrOpcode::kWord64And:
399 case IrOpcode::kWord32Or:
401 case IrOpcode::kWord64Or:
403 case IrOpcode::kWord32Xor:
405 case IrOpcode::kWord64Xor:
407 case IrOpcode::kWord32Shl:
409 case IrOpcode::kWord64Shl:
411 case IrOpcode::kWord32Shr:
413 case IrOpcode::kWord64Shr:
415 case IrOpcode::kWord32Sar:
417 case IrOpcode::kWord64Sar:
419 case IrOpcode::kWord32Ror: {
421 if (
m.right().Is(0))
return Replace(
m.left().node());
422 if (
m.IsFoldable()) {
424 m.left().ResolvedValue(),
m.right().ResolvedValue() & 31));
428 case IrOpcode::kWord32Equal:
430 case IrOpcode::kWord64Equal:
432 case IrOpcode::kInt32Add:
434 case IrOpcode::kInt64Add:
436 case IrOpcode::kInt32Sub:
438 case IrOpcode::kInt64Sub:
440 case IrOpcode::kInt32Mul: {
442 if (
m.right().Is(0))
return Replace(
m.right().node());
443 if (
m.right().Is(1))
return Replace(
m.left().node());
444 if (
m.IsFoldable()) {
446 m.right().ResolvedValue()));
448 if (
m.right().Is(-1)) {
450 node->ReplaceInput(1,
m.left().node());
452 return Changed(node);
454 if (
m.right().IsPowerOf2()) {
456 m.right().ResolvedValue())));
461 if (
m.right().HasResolvedValue() &&
m.left().IsInt32Mul()) {
463 if (n.right().HasResolvedValue() &&
m.OwnsInput(
m.left().node())) {
466 m.right().ResolvedValue(), n.right().ResolvedValue())));
467 node->ReplaceInput(0, n.left().node());
468 return Changed(node);
473 case IrOpcode::kInt32MulWithOverflow: {
475 if (
m.right().Is(2)) {
476 node->ReplaceInput(1,
m.left().node());
478 return Changed(node);
480 if (
m.right().Is(-1)) {
482 node->ReplaceInput(1,
m.left().node());
484 return Changed(node);
488 case IrOpcode::kInt64Mul:
490 case IrOpcode::kInt32Div:
492 case IrOpcode::kInt64Div:
494 case IrOpcode::kUint32Div:
496 case IrOpcode::kUint64Div:
498 case IrOpcode::kInt32Mod:
500 case IrOpcode::kInt64Mod:
502 case IrOpcode::kUint32Mod:
504 case IrOpcode::kUint64Mod:
506 case IrOpcode::kInt32LessThan: {
508 if (
m.IsFoldable()) {
510 m.right().ResolvedValue());
513 if (
m.left().IsWord32Or() &&
m.right().Is(0)) {
516 if (mleftmatcher.
left().IsNegative() ||
517 mleftmatcher.
right().IsNegative()) {
523 case IrOpcode::kInt32LessThanOrEqual: {
525 if (
m.IsFoldable()) {
527 m.right().ResolvedValue());
532 case IrOpcode::kUint32LessThan: {
536 if (
m.IsFoldable()) {
538 m.right().ResolvedValue());
541 if (
m.left().IsWord32Sar() &&
m.right().HasResolvedValue()) {
543 if (mleft.
right().HasResolvedValue()) {
546 const uint32_t c =
m.right().ResolvedValue();
547 const uint32_t k = mleft.
right().ResolvedValue() & 0x1F;
548 if (c <
static_cast<uint32_t
>(
kMaxInt >> k)) {
549 node->ReplaceInput(0, mleft.
left().node());
551 return Changed(node);
558 case IrOpcode::kUint32LessThanOrEqual: {
561 case IrOpcode::kFloat32Sub: {
565 (std::copysign(1.0,
m.right().ResolvedValue()) > 0)) {
566 return Replace(
m.left().node());
568 if (
m.right().IsNaN()) {
571 if (
m.left().IsNaN()) {
574 if (
m.IsFoldable()) {
576 m.right().ResolvedValue());
579 m.left().IsMinusZero()) {
581 if (
machine()->Float32RoundUp().IsSupported() &&
582 m.right().IsFloat32RoundDown()) {
583 if (
m.right().InputAt(0)->opcode() == IrOpcode::kFloat32Sub) {
585 if (mright0.
left().IsMinusZero()) {
586 return Replace(
graph()->NewNode(
machine()->Float32RoundUp().op(),
587 mright0.
right().node()));
592 node->RemoveInput(0);
594 return Changed(node);
598 case IrOpcode::kFloat64Add: {
600 if (
m.right().IsNaN()) {
603 if (
m.left().IsNaN()) {
606 if (
m.IsFoldable()) {
608 m.right().ResolvedValue());
612 case IrOpcode::kFloat64Sub: {
617 return Replace(
m.left().node());
619 if (
m.right().IsNaN()) {
622 if (
m.left().IsNaN()) {
625 if (
m.IsFoldable()) {
627 m.right().ResolvedValue());
630 m.left().IsMinusZero()) {
632 if (
machine()->Float64RoundUp().IsSupported() &&
633 m.right().IsFloat64RoundDown()) {
634 if (
m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub) {
636 if (mright0.
left().IsMinusZero()) {
637 return Replace(
graph()->NewNode(
machine()->Float64RoundUp().op(),
638 mright0.
right().node()));
643 node->RemoveInput(0);
645 return Changed(node);
649 case IrOpcode::kFloat64Mul: {
653 return Replace(
m.left().node());
654 if (
m.right().Is(-1)) {
656 node->ReplaceInput(1,
m.left().node());
658 return Changed(node);
660 if (
m.right().IsNaN()) {
663 if (
m.IsFoldable()) {
665 m.right().ResolvedValue());
667 if (
m.right().Is(2)) {
668 node->ReplaceInput(1,
m.left().node());
670 return Changed(node);
674 case IrOpcode::kFloat64Div: {
678 return Replace(
m.left().node());
680 if (
m.right().IsNaN()) {
683 if (
m.left().IsNaN()) {
686 if (
m.IsFoldable()) {
688 base::Divide(
m.left().ResolvedValue(),
m.right().ResolvedValue()));
692 node->RemoveInput(1);
694 return Changed(node);
696 if (
m.right().IsNormal() &&
m.right().IsPositiveOrNegativePowerOf2()) {
702 return Changed(node);
706 case IrOpcode::kFloat64Mod: {
708 if (
m.right().Is(0)) {
711 if (
m.right().IsNaN()) {
714 if (
m.left().IsNaN()) {
717 if (
m.IsFoldable()) {
719 Modulo(
m.left().ResolvedValue(),
m.right().ResolvedValue()));
723 case IrOpcode::kFloat64Acos: {
725 if (
m.HasResolvedValue())
729 case IrOpcode::kFloat64Acosh: {
731 if (
m.HasResolvedValue())
735 case IrOpcode::kFloat64Asin: {
737 if (
m.HasResolvedValue())
741 case IrOpcode::kFloat64Asinh: {
743 if (
m.HasResolvedValue())
747 case IrOpcode::kFloat64Atan: {
749 if (
m.HasResolvedValue())
753 case IrOpcode::kFloat64Atanh: {
755 if (
m.HasResolvedValue())
759 case IrOpcode::kFloat64Atan2: {
761 if (
m.right().IsNaN()) {
764 if (
m.left().IsNaN()) {
767 if (
m.IsFoldable()) {
769 m.right().ResolvedValue()));
773 case IrOpcode::kFloat64Cbrt: {
775 if (
m.HasResolvedValue())
779 case IrOpcode::kFloat64Cos: {
781 if (
m.HasResolvedValue())
785 case IrOpcode::kFloat64Cosh: {
787 if (
m.HasResolvedValue())
791 case IrOpcode::kFloat64Exp: {
793 if (
m.HasResolvedValue())
797 case IrOpcode::kFloat64Expm1: {
799 if (
m.HasResolvedValue())
803 case IrOpcode::kFloat64Log: {
805 if (
m.HasResolvedValue())
809 case IrOpcode::kFloat64Log1p: {
811 if (
m.HasResolvedValue())
815 case IrOpcode::kFloat64Log10: {
817 if (
m.HasResolvedValue())
821 case IrOpcode::kFloat64Log2: {
823 if (
m.HasResolvedValue())
827 case IrOpcode::kFloat64Pow: {
829 if (
m.IsFoldable()) {
831 math::pow(
m.left().ResolvedValue(),
m.right().ResolvedValue()));
832 }
else if (
m.right().Is(0.0)) {
834 }
else if (
m.right().Is(2.0)) {
835 node->ReplaceInput(1,
m.left().node());
837 return Changed(node);
838 }
else if (
m.right().Is(0.5)) {
844 case IrOpcode::kFloat64Sin: {
846 if (
m.HasResolvedValue())
850 case IrOpcode::kFloat64Sinh: {
852 if (
m.HasResolvedValue())
856 case IrOpcode::kFloat64Tan: {
858 if (
m.HasResolvedValue())
862 case IrOpcode::kFloat64Tanh: {
864 if (
m.HasResolvedValue())
868 case IrOpcode::kChangeFloat32ToFloat64: {
870 if (
m.HasResolvedValue()) {
872 std::isnan(
m.ResolvedValue())) {
879 case IrOpcode::kChangeFloat64ToInt32: {
881 if (
m.HasResolvedValue())
883 if (
m.IsChangeInt32ToFloat64())
return Replace(
m.node()->InputAt(0));
886 case IrOpcode::kChangeFloat64ToInt64: {
888 if (
m.HasResolvedValue())
889 return ReplaceInt64(
static_cast<int64_t
>(
m.ResolvedValue()));
890 if (
m.IsChangeInt64ToFloat64())
return Replace(
m.node()->InputAt(0));
893 case IrOpcode::kChangeFloat64ToUint32: {
895 if (
m.HasResolvedValue())
897 if (
m.IsChangeUint32ToFloat64())
return Replace(
m.node()->InputAt(0));
900 case IrOpcode::kChangeInt32ToFloat64: {
902 if (
m.HasResolvedValue())
906 case IrOpcode::kBitcastWord32ToWord64: {
910 if (
m.IsTruncateInt64ToInt32())
return Replace(
m.node()->InputAt(0));
913 case IrOpcode::kChangeInt32ToInt64: {
918 case IrOpcode::kChangeInt64ToFloat64: {
920 if (
m.HasResolvedValue())
922 if (
m.IsChangeFloat64ToInt64())
return Replace(
m.node()->InputAt(0));
925 case IrOpcode::kChangeUint32ToFloat64: {
927 if (
m.HasResolvedValue())
931 case IrOpcode::kChangeUint32ToUint64: {
933 if (
m.HasResolvedValue())
934 return ReplaceInt64(
static_cast<uint64_t
>(
m.ResolvedValue()));
937 case IrOpcode::kTruncateFloat64ToWord32: {
939 if (
m.HasResolvedValue())
941 if (
m.IsChangeInt32ToFloat64())
return Replace(
m.node()->InputAt(0));
944 case IrOpcode::kTruncateInt64ToInt32:
946 case IrOpcode::kTruncateFloat64ToFloat32: {
948 if (
m.HasResolvedValue()) {
955 m.IsChangeFloat32ToFloat64())
956 return Replace(
m.node()->InputAt(0));
959 case IrOpcode::kRoundFloat64ToInt32: {
961 if (
m.HasResolvedValue()) {
964 if (
m.IsChangeInt32ToFloat64())
return Replace(
m.node()->InputAt(0));
967 case IrOpcode::kFloat64InsertLowWord32:
969 case IrOpcode::kFloat64InsertHighWord32:
971 case IrOpcode::kStore:
972 case IrOpcode::kUnalignedStore:
974 case IrOpcode::kFloat64Equal:
975 case IrOpcode::kFloat64LessThan:
976 case IrOpcode::kFloat64LessThanOrEqual:
978 case IrOpcode::kFloat64RoundDown:
980 case IrOpcode::kBitcastTaggedToWord:
981 case IrOpcode::kBitcastTaggedToWordForTagAndSmiBits: {
983 if (
m.IsBitcastWordToTaggedSigned()) {
984 RelaxEffectsAndControls(node);
985 return Replace(
m.InputAt(0));
989 case IrOpcode::kBranch:
990 case IrOpcode::kDeoptimizeIf:
991 case IrOpcode::kDeoptimizeUnless:
992#if V8_ENABLE_WEBASSEMBLY
993 case IrOpcode::kTrapIf:
994 case IrOpcode::kTrapUnless:
997 case IrOpcode::kInt64LessThan: {
999 if (
m.IsFoldable()) {
1001 m.right().ResolvedValue());
1005 case IrOpcode::kInt64LessThanOrEqual: {
1007 if (
m.IsFoldable()) {
1009 m.right().ResolvedValue());
1013 case IrOpcode::kUint64LessThan: {
1015 if (
m.IsFoldable()) {
1017 m.right().ResolvedValue());
1021 case IrOpcode::kUint64LessThanOrEqual: {
1024 case IrOpcode::kFloat32Select:
1025 case IrOpcode::kFloat64Select:
1026 case IrOpcode::kWord32Select:
1027 case IrOpcode::kWord64Select: {
1031 return Replace(node->InputAt(2));
1033 return Replace(node->InputAt(1));
1038 case IrOpcode::kLoad:
1039 case IrOpcode::kProtectedLoad:
1040 case IrOpcode::kLoadTrapOnNull: {
1043 if (input0->
opcode() == IrOpcode::kInt64Add) {
1045 if (
m.right().HasResolvedValue()) {
1046 int64_t value =
m.right().ResolvedValue();
1047 node->ReplaceInput(0,
m.left().node());
1049 node->ReplaceInput(1, new_node);
1050 return Changed(node);
1063 if (
m.HasResolvedValue())
1064 return ReplaceInt32(
static_cast<int32_t
>(
m.ResolvedValue()));
1065 if (
m.IsChangeInt32ToInt64() ||
m.IsChangeUint32ToUint64())
1066 return Replace(
m.node()->InputAt(0));
1070 if (
m.IsBitcastTaggedToWordForTagAndSmiBits() &&
m.node()->UseCount() == 1) {
1072 if (input->opcode() == IrOpcode::kLoad ||
1073 input->opcode() == IrOpcode::kLoadImmutable) {
1078 int value_edges = 0;
1079 for (
Edge edge : input->use_edges()) {
1082 if (value_edges == 1) {
1086 m.node()->RemoveInput(0);
1089 input->opcode() == IrOpcode::kLoad
1092 return Replace(input);
1101 DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
1103 if (
m.right().Is(0))
return Replace(
m.left().node());
1104 if (
m.IsFoldable()) {
1105 return ReplaceInt32(base::AddWithWraparound(
m.left().ResolvedValue(),
1106 m.right().ResolvedValue()));
1108 if (
m.left().IsInt32Sub()) {
1110 if (mleft.
left().Is(0)) {
1111 node->ReplaceInput(0,
m.right().node());
1112 node->ReplaceInput(1, mleft.
right().node());
1117 if (
m.right().IsInt32Sub()) {
1119 if (mright.
left().Is(0)) {
1120 node->ReplaceInput(1, mright.
right().node());
1126 if (
m.right().HasResolvedValue() &&
m.left().IsInt32Add()) {
1128 if (n.right().HasResolvedValue() &&
m.OwnsInput(
m.left().node())) {
1130 1,
Int32Constant(base::AddWithWraparound(
m.right().ResolvedValue(),
1131 n.right().ResolvedValue())));
1132 node->ReplaceInput(0, n.left().node());
1133 return Changed(node);
1141 DCHECK_EQ(IrOpcode::kInt64Add, node->opcode());
1143 if (
m.right().Is(0))
return Replace(
m.left().node());
1144 if (
m.IsFoldable()) {
1145 return ReplaceInt64(base::AddWithWraparound(
m.left().ResolvedValue(),
1146 m.right().ResolvedValue()));
1149 if (
m.right().HasResolvedValue() &&
m.left().IsInt64Add()) {
1151 if (n.right().HasResolvedValue() &&
m.OwnsInput(
m.left().node())) {
1153 1,
Int64Constant(base::AddWithWraparound(
m.right().ResolvedValue(),
1154 n.right().ResolvedValue())));
1155 node->ReplaceInput(0, n.left().node());
1156 return Changed(node);
1163 DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
1165 if (
m.right().Is(0))
return Replace(
m.left().node());
1166 if (
m.IsFoldable()) {
1167 return ReplaceInt32(base::SubWithWraparound(
m.left().ResolvedValue(),
1168 m.right().ResolvedValue()));
1171 if (
m.right().HasResolvedValue()) {
1182 DCHECK_EQ(IrOpcode::kInt64Sub, node->opcode());
1184 if (
m.right().Is(0))
return Replace(
m.left().node());
1185 if (
m.IsFoldable()) {
1186 return ReplaceInt64(base::SubWithWraparound(
m.left().ResolvedValue(),
1187 m.right().ResolvedValue()));
1190 if (
m.right().HasResolvedValue()) {
1201 DCHECK_EQ(IrOpcode::kInt64Mul, node->opcode());
1203 if (
m.right().Is(0))
return Replace(
m.right().node());
1204 if (
m.right().Is(1))
return Replace(
m.left().node());
1205 if (
m.IsFoldable()) {
1207 m.right().ResolvedValue()));
1209 if (
m.right().Is(-1)) {
1211 node->ReplaceInput(1,
m.left().node());
1213 return Changed(node);
1215 if (
m.right().IsPowerOf2()) {
1223 if (
m.right().HasResolvedValue() &&
m.left().IsInt64Mul()) {
1225 if (n.right().HasResolvedValue() &&
m.OwnsInput(
m.left().node())) {
1228 n.right().ResolvedValue())));
1229 node->ReplaceInput(0, n.left().node());
1230 return Changed(node);
1238 if (
m.left().Is(0))
return Replace(
m.left().node());
1239 if (
m.right().Is(0))
return Replace(
m.right().node());
1240 if (
m.right().Is(1))
return Replace(
m.left().node());
1241 if (
m.IsFoldable()) {
1243 m.right().ResolvedValue()));
1245 if (
m.LeftEqualsRight()) {
1249 if (
m.right().Is(-1)) {
1251 node->ReplaceInput(1,
m.left().node());
1252 node->TrimInputCount(2);
1254 return Changed(node);
1256 if (
m.right().HasResolvedValue()) {
1257 int32_t
const divisor =
m.right().ResolvedValue();
1258 Node*
const dividend =
m.left().node();
1259 Node* quotient = dividend;
1273 node->ReplaceInput(1, quotient);
1274 node->TrimInputCount(2);
1276 return Changed(node);
1278 return Replace(quotient);
1285 if (
m.left().Is(0))
return Replace(
m.left().node());
1286 if (
m.right().Is(0))
return Replace(
m.right().node());
1287 if (
m.right().Is(1))
return Replace(
m.left().node());
1288 if (
m.IsFoldable()) {
1290 m.right().ResolvedValue()));
1292 if (
m.LeftEqualsRight()) {
1299 if (
m.right().Is(-1)) {
1301 node->ReplaceInput(1,
m.left().node());
1302 node->TrimInputCount(2);
1304 return Changed(node);
1306 if (
m.right().HasResolvedValue()) {
1307 int64_t
const divisor =
m.right().ResolvedValue();
1308 Node*
const dividend =
m.left().node();
1309 Node* quotient = dividend;
1323 node->ReplaceInput(1, quotient);
1324 node->TrimInputCount(2);
1326 return Changed(node);
1328 return Replace(quotient);
1335 if (
m.left().Is(0))
return Replace(
m.left().node());
1336 if (
m.right().Is(0))
return Replace(
m.right().node());
1337 if (
m.right().Is(1))
return Replace(
m.left().node());
1338 if (
m.IsFoldable()) {
1340 m.right().ResolvedValue()));
1342 if (
m.LeftEqualsRight()) {
1346 if (
m.right().HasResolvedValue()) {
1347 Node*
const dividend =
m.left().node();
1348 uint32_t
const divisor =
m.right().ResolvedValue();
1351 m.right().ResolvedValue())));
1352 node->TrimInputCount(2);
1354 return Changed(node);
1356 return Replace(
Uint32Div(dividend, divisor));
1364 if (
m.left().Is(0))
return Replace(
m.left().node());
1365 if (
m.right().Is(0))
return Replace(
m.right().node());
1366 if (
m.right().Is(1))
return Replace(
m.left().node());
1367 if (
m.IsFoldable()) {
1369 m.right().ResolvedValue()));
1371 if (
m.LeftEqualsRight()) {
1378 if (
m.right().HasResolvedValue()) {
1379 Node*
const dividend =
m.left().node();
1380 uint64_t
const divisor =
m.right().ResolvedValue();
1383 m.right().ResolvedValue())));
1384 node->TrimInputCount(2);
1386 return Changed(node);
1388 return Replace(
Uint64Div(dividend, divisor));
1396 if (
m.left().Is(0))
return Replace(
m.left().node());
1397 if (
m.right().Is(0))
return Replace(
m.right().node());
1401 if (
m.IsFoldable()) {
1403 m.right().ResolvedValue()));
1405 if (
m.right().HasResolvedValue()) {
1406 Node*
const dividend =
m.left().node();
1407 uint32_t
const divisor =
Abs(
m.right().ResolvedValue());
1409 uint32_t
const mask = divisor - 1;
1412 graph()->NewNode(
machine()->Int32LessThan(), dividend, zero),
1422 node->TrimInputCount(2);
1425 return Changed(node);
1432 if (
m.left().Is(0))
return Replace(
m.left().node());
1433 if (
m.right().Is(0))
return Replace(
m.right().node());
1437 if (
m.IsFoldable()) {
1439 m.right().ResolvedValue()));
1441 if (
m.right().HasResolvedValue()) {
1442 Node*
const dividend =
m.left().node();
1443 uint64_t
const divisor =
Abs(
m.right().ResolvedValue());
1445 uint64_t
const mask = divisor - 1;
1448 graph()->NewNode(
machine()->Int64LessThan(), dividend, zero),
1458 node->TrimInputCount(2);
1461 return Changed(node);
1468 if (
m.left().Is(0))
return Replace(
m.left().node());
1469 if (
m.right().Is(0))
return Replace(
m.right().node());
1472 if (
m.IsFoldable()) {
1474 m.right().ResolvedValue()));
1476 if (
m.right().HasResolvedValue()) {
1477 Node*
const dividend =
m.left().node();
1478 uint32_t
const divisor =
m.right().ResolvedValue();
1481 node->TrimInputCount(2);
1487 node->TrimInputCount(2);
1490 return Changed(node);
1497 if (
m.left().Is(0))
return Replace(
m.left().node());
1498 if (
m.right().Is(0))
return Replace(
m.right().node());
1501 if (
m.IsFoldable()) {
1503 m.right().ResolvedValue()));
1505 if (
m.right().HasResolvedValue()) {
1506 Node*
const dividend =
m.left().node();
1507 uint64_t
const divisor =
m.right().ResolvedValue();
1510 node->TrimInputCount(2);
1516 node->TrimInputCount(2);
1519 return Changed(node);
1526 DCHECK(nm.IsStore() || nm.IsUnalignedStore());
1531 const int value_input = 2;
1534 switch (value->opcode()) {
1535 case IrOpcode::kWord32And: {
1537 if (
m.right().HasResolvedValue() &&
1539 (
m.right().ResolvedValue() & 0xFF) == 0xFF) ||
1541 (
m.right().ResolvedValue() & 0xFFFF) == 0xFFFF))) {
1542 node->ReplaceInput(value_input,
m.left().node());
1543 return Changed(node);
1547 case IrOpcode::kWord32Sar: {
1550 m.right().IsInRange(1, 24)) ||
1552 m.right().IsInRange(1, 16)))) {
1554 if (mleft.
right().Is(
m.right().ResolvedValue())) {
1555 node->ReplaceInput(value_input, mleft.
left().node());
1556 return Changed(node);
1568 switch (node->opcode()) {
1569 case IrOpcode::kInt32AddWithOverflow: {
1570 DCHECK(index == 0 || index == 1);
1572 if (
m.IsFoldable()) {
1575 m.left().ResolvedValue(),
m.right().ResolvedValue(), &val);
1578 if (
m.right().Is(0)) {
1579 return Replace(index == 0 ?
m.left().node() :
m.right().node());
1583 case IrOpcode::kInt32SubWithOverflow: {
1584 DCHECK(index == 0 || index == 1);
1586 if (
m.IsFoldable()) {
1589 m.left().ResolvedValue(),
m.right().ResolvedValue(), &val);
1592 if (
m.right().Is(0)) {
1593 return Replace(index == 0 ?
m.left().node() :
m.right().node());
1597 case IrOpcode::kInt32MulWithOverflow: {
1598 DCHECK(index == 0 || index == 1);
1600 if (
m.IsFoldable()) {
1603 m.left().ResolvedValue(),
m.right().ResolvedValue(), &val);
1606 if (
m.right().Is(0)) {
1607 return Replace(
m.right().node());
1609 if (
m.right().Is(1)) {
1610 return index == 0 ? Replace(
m.left().node()) :
ReplaceInt32(0);
1626template <
typename T>
1627bool CanRevertLeftShiftWithRightShift(T value, T shift) {
1628 using unsigned_T = std::make_unsigned_t<T>;
1629 if (shift < 0 || shift >= std::numeric_limits<T>::digits + 1) {
1633 if (
static_cast<T
>(
static_cast<unsigned_T
>(value) << shift) >> shift !=
1634 static_cast<T
>(value)) {
1640bool CanTruncate(int64_t value) {
1641 return value >= std::numeric_limits<int32_t>::min() &&
1642 value <= std::numeric_limits<int32_t>::max();
1648 DCHECK(node->opcode() == IrOpcode::kInt32LessThan ||
1649 node->opcode() == IrOpcode::kInt32LessThanOrEqual ||
1650 node->opcode() == IrOpcode::kUint32LessThan ||
1651 node->opcode() == IrOpcode::kUint32LessThanOrEqual);
1654 if (
m.left().op() == machine()->Word32SarShiftOutZeros() &&
1655 m.right().op() == machine()->Word32SarShiftOutZeros()) {
1658 if (mleft.
right().HasResolvedValue() &&
1659 mright.
right().Is(mleft.
right().ResolvedValue())) {
1660 node->ReplaceInput(0, mleft.
left().node());
1661 node->ReplaceInput(1, mright.
left().node());
1662 return Changed(node);
1667 if (
m.right().HasResolvedValue() &&
1668 m.left().op() == machine()->Word32SarShiftOutZeros() &&
1669 m.left().node()->UseCount() == 1) {
1670 uint32_t right =
m.right().ResolvedValue();
1672 if (mleft.
right().HasResolvedValue()) {
1673 auto shift = mleft.
right().ResolvedValue();
1674 if (CanRevertLeftShiftWithRightShift<int32_t>(right, shift)) {
1675 node->ReplaceInput(0, mleft.
left().node());
1677 return Changed(node);
1683 if (
m.left().HasResolvedValue() &&
1684 m.right().op() == machine()->Word32SarShiftOutZeros() &&
1685 m.right().node()->UseCount() == 1) {
1686 uint32_t left =
m.left().ResolvedValue();
1688 if (mright.
right().HasResolvedValue()) {
1689 auto shift = mright.
right().ResolvedValue();
1690 if (CanRevertLeftShiftWithRightShift<int32_t>(left, shift)) {
1692 node->ReplaceInput(1, mright.
left().node());
1693 return Changed(node);
1701 const Operator* op,
bool sign_extended) {
1703 case IrOpcode::kInt64LessThan:
1706 case IrOpcode::kInt64LessThanOrEqual:
1709 case IrOpcode::kUint64LessThan:
1711 case IrOpcode::kUint64LessThanOrEqual:
1719 DCHECK(node->opcode() == IrOpcode::kInt64LessThan ||
1720 node->opcode() == IrOpcode::kInt64LessThanOrEqual ||
1721 node->opcode() == IrOpcode::kUint64LessThan ||
1722 node->opcode() == IrOpcode::kUint64LessThanOrEqual);
1725 bool sign_extended =
1726 m.left().IsChangeInt32ToInt64() &&
m.right().IsChangeInt32ToInt64();
1727 if (sign_extended || (
m.left().IsChangeUint32ToUint64() &&
1728 m.right().IsChangeUint32ToUint64())) {
1733 return Changed(node).FollowedBy(
Reduce(node));
1738 if (
m.left().op() == machine()->Word64SarShiftOutZeros() &&
1739 m.right().op() == machine()->Word64SarShiftOutZeros()) {
1742 if (mleft.
right().HasResolvedValue() &&
1743 mright.
right().Is(mleft.
right().ResolvedValue())) {
1744 node->ReplaceInput(0, mleft.
left().node());
1745 node->ReplaceInput(1, mright.
left().node());
1746 return Changed(node);
1752 if (
m.right().HasResolvedValue() &&
1753 m.left().op() == machine()->Word64SarShiftOutZeros() &&
1754 m.left().node()->UseCount() == 1) {
1756 uint64_t right =
m.right().ResolvedValue();
1757 if (mleft.
right().HasResolvedValue()) {
1758 auto shift = mleft.
right().ResolvedValue();
1759 if (CanRevertLeftShiftWithRightShift<int64_t>(right, shift)) {
1760 sign_extended = mleft.
left().IsChangeInt32ToInt64();
1761 uint64_t value = right << shift;
1763 if ((sign_extended || mleft.
left().IsChangeUint32ToUint64()) &&
1764 CanTruncate(
static_cast<int64_t
>(value))) {
1767 node->ReplaceInput(0, mleft.
left().node()->InputAt(0));
1768 node->ReplaceInput(1,
Int32Constant(
static_cast<int32_t
>(value)));
1769 return Changed(node).FollowedBy(
Reduce(node));
1771 node->ReplaceInput(0, mleft.
left().node());
1773 return Changed(node);
1780 if (
m.left().HasResolvedValue() &&
1781 m.right().op() == machine()->Word64SarShiftOutZeros() &&
1782 m.right().node()->UseCount() == 1) {
1783 uint64_t left =
m.left().ResolvedValue();
1785 if (mright.
right().HasResolvedValue()) {
1786 auto shift = mright.
right().ResolvedValue();
1787 if (CanRevertLeftShiftWithRightShift<int64_t>(left, shift)) {
1788 sign_extended = mright.
left().IsChangeInt32ToInt64();
1789 uint64_t value = left << shift;
1791 if ((sign_extended || mright.
left().IsChangeUint32ToUint64()) &&
1792 CanTruncate(
static_cast<int64_t
>(value))) {
1795 node->ReplaceInput(0,
Int32Constant(
static_cast<int32_t
>(value)));
1796 node->ReplaceInput(1, mright.
left().node()->InputAt(0));
1797 return Changed(node).FollowedBy(
Reduce(node));
1800 node->ReplaceInput(1, mright.
left().node());
1801 return Changed(node);
1814 if (node->opcode() == IrOpcode::kInt64LessThan ||
1815 node->opcode() == IrOpcode::kInt64LessThanOrEqual) {
1817 if (
m.left().IsChangeInt32ToInt64() &&
m.right().HasResolvedValue()) {
1818 int64_t right_value =
static_cast<int64_t
>(
m.right().ResolvedValue());
1820 if (right_value ==
static_cast<int32_t
>(right_value)) {
1823 if (node->opcode() == IrOpcode::kInt64LessThan) {
1829 node->ReplaceInput(0,
m.left().InputAt(0));
1830 node->ReplaceInput(1,
Int32Constant(
static_cast<int32_t
>(right_value)));
1831 return Changed(node);
1832 }
else if (right_value < std::numeric_limits<int32_t>::min()) {
1834 node->TrimInputCount(0);
1836 return Changed(node);
1837 }
else if (right_value > std::numeric_limits<int32_t>::max()) {
1839 node->TrimInputCount(0);
1841 return Changed(node);
1845 if (
m.right().IsChangeInt32ToInt64() &&
m.left().HasResolvedValue()) {
1846 int64_t left_value =
static_cast<int64_t
>(
m.left().ResolvedValue());
1848 if (left_value ==
static_cast<int32_t
>(left_value)) {
1851 if (node->opcode() == IrOpcode::kInt64LessThan) {
1857 node->ReplaceInput(1,
m.right().InputAt(0));
1858 node->ReplaceInput(0,
Int32Constant(
static_cast<int32_t
>(left_value)));
1859 return Changed(node);
1860 }
else if (left_value < std::numeric_limits<int32_t>::min()) {
1862 node->TrimInputCount(0);
1864 return Changed(node);
1865 }
else if (left_value > std::numeric_limits<int32_t>::max()) {
1867 node->TrimInputCount(0);
1869 return Changed(node);
1882 if (node->opcode() == IrOpcode::kUint64LessThan ||
1883 node->opcode() == IrOpcode::kUint64LessThanOrEqual) {
1885 if (
m.left().IsChangeUint32ToUint64() &&
m.right().HasResolvedValue()) {
1886 uint64_t right_value =
static_cast<uint64_t
>(
m.right().ResolvedValue());
1888 if (right_value ==
static_cast<uint32_t
>(right_value)) {
1891 if (node->opcode() == IrOpcode::kUint64LessThan) {
1897 node->ReplaceInput(0,
m.left().InputAt(0));
1898 node->ReplaceInput(1,
1900 return Changed(node);
1903 node->TrimInputCount(0);
1905 return Changed(node);
1909 if (
m.right().IsChangeUint32ToUint64() &&
m.left().HasResolvedValue()) {
1910 uint64_t left_value =
static_cast<uint64_t
>(
m.left().ResolvedValue());
1912 if (left_value ==
static_cast<uint32_t
>(left_value)) {
1914 if (node->opcode() == IrOpcode::kUint64LessThan) {
1920 node->ReplaceInput(1,
m.right().InputAt(0));
1921 node->ReplaceInput(0,
1923 return Changed(node);
1926 node->TrimInputCount(0);
1928 return Changed(node);
1936 DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
1937 (node->opcode() == IrOpcode::kWord32Shr) ||
1938 (node->opcode() == IrOpcode::kWord32Sar));
1939 if (
machine()->Word32ShiftIsSafe()) {
1943 if (
m.right().IsWord32And()) {
1945 if (mright.
right().Is(0x1F)) {
1946 node->ReplaceInput(1, mright.
left().node());
1947 return Changed(node);
1955 DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
1957 if (
m.right().Is(0))
return Replace(
m.left().node());
1958 if (
m.IsFoldable()) {
1960 m.right().ResolvedValue()));
1962 if (
m.right().IsInRange(1, 31)) {
1963 if (
m.left().IsWord32Sar() ||
m.left().IsWord32Shr()) {
1972 if (mleft.
op() == machine()->Word32SarShiftOutZeros() &&
1973 mleft.
right().IsInRange(1, 31)) {
1975 int k = mleft.
right().ResolvedValue();
1976 int l =
m.right().ResolvedValue();
1980 node->ReplaceInput(0,
x);
1986 node->ReplaceInput(0,
x);
1988 return Changed(node);
1994 if (mleft.
right().Is(
m.right().ResolvedValue())) {
1995 node->ReplaceInput(0, mleft.
left().node());
1996 node->ReplaceInput(1,
1998 <<
m.right().ResolvedValue()));
2008 DCHECK_EQ(IrOpcode::kWord64Shl, node->opcode());
2010 if (
m.right().Is(0))
return Replace(
m.left().node());
2011 if (
m.IsFoldable()) {
2013 m.right().ResolvedValue()));
2015 if (
m.right().IsInRange(1, 63) &&
2016 (
m.left().IsWord64Sar() ||
m.left().IsWord64Shr())) {
2025 if (mleft.
op() == machine()->Word64SarShiftOutZeros() &&
2026 mleft.
right().IsInRange(1, 63)) {
2028 int64_t k = mleft.
right().ResolvedValue();
2029 int64_t l =
m.right().ResolvedValue();
2033 node->ReplaceInput(0,
x);
2039 node->ReplaceInput(0,
x);
2041 return Changed(node);
2047 if (mleft.
right().Is(
m.right().ResolvedValue())) {
2048 node->ReplaceInput(0, mleft.
left().node());
2049 node->ReplaceInput(1,
Uint64Constant(std::numeric_limits<uint64_t>::max()
2050 <<
m.right().ResolvedValue()));
2060 if (
m.right().Is(0))
return Replace(
m.left().node());
2061 if (
m.IsFoldable()) {
2063 (
m.right().ResolvedValue() & 31));
2065 if (
m.left().IsWord32And() &&
m.right().HasResolvedValue()) {
2067 if (mleft.
right().HasResolvedValue()) {
2068 uint32_t shift =
m.right().ResolvedValue() & 31;
2069 uint32_t
mask = mleft.
right().ResolvedValue();
2070 if ((
mask >> shift) == 0) {
2080 DCHECK_EQ(IrOpcode::kWord64Shr, node->opcode());
2082 if (
m.right().Is(0))
return Replace(
m.left().node());
2083 if (
m.IsFoldable()) {
2085 (
m.right().ResolvedValue() & 63));
2092 if (
m.right().Is(0))
return Replace(
m.left().node());
2093 if (
m.IsFoldable()) {
2095 (
m.right().ResolvedValue() & 31));
2097 if (
m.left().IsWord32Shl()) {
2099 if (mleft.
left().IsComparison()) {
2100 if (
m.right().Is(31) && mleft.
right().Is(31)) {
2103 node->ReplaceInput(1, mleft.
left().node());
2107 }
else if (mleft.
left().IsLoad()) {
2110 if (
m.right().Is(24) && mleft.
right().Is(24) &&
2113 return Replace(mleft.
left().node());
2115 if (
m.right().Is(16) && mleft.
right().Is(16) &&
2118 return Replace(mleft.
left().node());
2127 if (
m.right().Is(0))
return Replace(
m.left().node());
2128 if (
m.IsFoldable()) {
2130 (
m.right().ResolvedValue() & 63));
2135template <
typename WordNAdapter>
2137 using A = WordNAdapter;
2140 typename A::IntNBinopMatcher
m(node);
2141 if (
m.right().Is(0))
return Replace(
m.right().node());
2142 if (
m.right().Is(-1))
return Replace(
m.left().node());
2143 if (
m.right().Is(1)) {
2145 Node* left =
m.left().node();
2146 while (left->
opcode() == IrOpcode::kTruncateInt64ToInt32 ||
2147 left->
opcode() == IrOpcode::kChangeInt32ToInt64 ||
2148 left->
opcode() == IrOpcode::kChangeUint32ToUint64) {
2151 if ((left->
opcode() == IrOpcode::kInt32Add ||
2152 left->
opcode() == IrOpcode::kInt64Add) &&
2154 return a.ReplaceIntN(0);
2157 if (
m.left().IsComparison() &&
m.right().Is(1)) {
2158 return Replace(
m.left().node());
2160 if (
m.IsFoldable()) {
2161 return a.ReplaceIntN(
m.left().ResolvedValue() &
m.right().ResolvedValue());
2163 if (
m.LeftEqualsRight())
return Replace(
m.left().node());
2164 if (A::IsWordNAnd(
m.left()) &&
m.right().HasResolvedValue()) {
2165 typename A::IntNBinopMatcher mleft(
m.left().node());
2166 if (mleft.right().HasResolvedValue()) {
2167 node->ReplaceInput(0, mleft.left().node());
2168 node->ReplaceInput(1, a.IntNConstant(
m.right().ResolvedValue() &
2169 mleft.right().ResolvedValue()));
2170 return Changed(node).FollowedBy(a.ReduceWordNAnd(node));
2173 if (
m.right().IsNegativePowerOf2()) {
2174 typename A::intN_t
const mask =
m.right().ResolvedValue();
2176 if (A::IsWordNShl(
m.left())) {
2177 typename A::UintNBinopMatcher mleft(
m.left().node());
2178 if (mleft.right().HasResolvedValue() &&
2179 (mleft.right().ResolvedValue() & (A::WORD_SIZE - 1)) >=
2182 return Replace(mleft.node());
2184 }
else if (A::IsIntNAdd(
m.left())) {
2185 typename A::IntNBinopMatcher mleft(
m.left().node());
2186 if (mleft.right().HasResolvedValue() &&
2187 (mleft.right().ResolvedValue() &
mask) ==
2188 mleft.right().ResolvedValue()) {
2190 node->ReplaceInput(0,
2191 a.WordNAnd(mleft.left().node(),
m.right().node()));
2192 node->ReplaceInput(1, mleft.right().node());
2194 return Changed(node).FollowedBy(a.ReduceIntNAdd(node));
2196 if (A::IsIntNMul(mleft.left())) {
2197 typename A::IntNBinopMatcher mleftleft(mleft.left().node());
2198 if (mleftleft.right().IsMultipleOf(neg_mask)) {
2201 0, a.WordNAnd(mleft.right().node(),
m.right().node()));
2202 node->ReplaceInput(1, mleftleft.node());
2204 return Changed(node).FollowedBy(a.ReduceIntNAdd(node));
2207 if (A::IsIntNMul(mleft.right())) {
2208 typename A::IntNBinopMatcher mleftright(mleft.right().node());
2209 if (mleftright.right().IsMultipleOf(neg_mask)) {
2211 node->ReplaceInput(0,
2212 a.WordNAnd(mleft.left().node(),
m.right().node()));
2213 node->ReplaceInput(1, mleftright.node());
2215 return Changed(node).FollowedBy(a.ReduceIntNAdd(node));
2218 if (A::IsWordNShl(mleft.left())) {
2219 typename A::IntNBinopMatcher mleftleft(mleft.left().node());
2223 0, a.WordNAnd(mleft.right().node(),
m.right().node()));
2224 node->ReplaceInput(1, mleftleft.node());
2226 return Changed(node).FollowedBy(a.ReduceIntNAdd(node));
2229 if (A::IsWordNShl(mleft.right())) {
2230 typename A::IntNBinopMatcher mleftright(mleft.right().node());
2233 node->ReplaceInput(0,
2234 a.WordNAnd(mleft.left().node(),
m.right().node()));
2235 node->ReplaceInput(1, mleftright.node());
2237 return Changed(node).FollowedBy(a.ReduceIntNAdd(node));
2240 }
else if (A::IsIntNMul(
m.left())) {
2241 typename A::IntNBinopMatcher mleft(
m.left().node());
2242 if (mleft.right().IsMultipleOf(neg_mask)) {
2244 return Replace(mleft.node());
2251template <
typename WordNAdapter>
2253 using A = WordNAdapter;
2256 typename A::UintNBinopMatcher
m(node);
2257 typename A::uintN_t kMaxUIntN =
2258 std::numeric_limits<typename A::uintN_t>::max();
2261 if (
m.IsFoldable()) {
2262 return ReplaceBool(
m.left().ResolvedValue() <=
m.right().ResolvedValue());
2265 if (
m.right().Is(0)) {
2267 return Changed(node);
2269 return a.ReduceWordNComparisons(node);
2276struct BitfieldCheck {
2282 BitfieldCheck(Node* source, uint32_t mask, uint32_t masked_value,
2283 bool truncate_from_64_bit)
2291 static std::optional<BitfieldCheck> Detect(Node* node) {
2299 if (node->opcode() == IrOpcode::kWord32Equal) {
2301 if (
eq.left().IsWord32And()) {
2303 if (mand.right().HasResolvedValue() &&
eq.right().HasResolvedValue()) {
2304 uint32_t
mask = mand.right().ResolvedValue();
2306 if ((masked_value & ~mask) != 0)
return {};
2307 if (mand.left().IsTruncateInt64ToInt32()) {
2308 return BitfieldCheck(
2310 masked_value,
true);
2312 return BitfieldCheck(mand.left().node(), mask, masked_value,
false);
2317 if (node->opcode() == IrOpcode::kTruncateInt64ToInt32) {
2318 return TryDetectShiftAndMaskOneBit<Word64Adapter>(
2321 return TryDetectShiftAndMaskOneBit<Word32Adapter>(node);
2327 std::optional<BitfieldCheck> TryCombine(
const BitfieldCheck& other) {
2328 if (source != other.source ||
2329 truncate_from_64_bit != other.truncate_from_64_bit) {
2332 uint32_t overlapping_bits =
mask & other.mask;
2336 if ((masked_value & overlapping_bits) !=
2337 (other.masked_value & overlapping_bits)) {
2340 return BitfieldCheck{source,
mask | other.mask,
2346 template <
typename WordNAdapter>
2347 static std::optional<BitfieldCheck> TryDetectShiftAndMaskOneBit(Node* node) {
2349 if (WordNAdapter::IsWordNAnd(NodeMatcher(node))) {
2350 typename WordNAdapter::IntNBinopMatcher mand(node);
2351 if (mand.right().HasResolvedValue() &&
2352 mand.right().ResolvedValue() == 1) {
2353 if (WordNAdapter::IsWordNShr(mand.left()) ||
2354 WordNAdapter::IsWordNSar(mand.left())) {
2355 typename WordNAdapter::UintNBinopMatcher shift(mand.left().node());
2356 if (shift.right().HasResolvedValue() &&
2357 shift.right().ResolvedValue() < 32u) {
2358 uint32_t
mask = 1 << shift.right().ResolvedValue();
2359 return BitfieldCheck{shift.left().node(),
mask,
mask,
2360 WordNAdapter::WORD_SIZE == 64};
2363 return BitfieldCheck{mand.left().node(), 1, 1,
2364 WordNAdapter::WORD_SIZE == 64};
2374 DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
2376 if (reduction.Changed()) {
2383 if (
auto right_bitfield = BitfieldCheck::Detect(
m.right().node())) {
2384 if (
auto left_bitfield = BitfieldCheck::Detect(
m.left().node())) {
2385 if (
auto combined_bitfield = left_bitfield->TryCombine(*right_bitfield)) {
2386 Node* source = combined_bitfield->source;
2387 if (combined_bitfield->truncate_from_64_bit) {
2391 node->ReplaceInput(1,
Int32Constant(combined_bitfield->masked_value));
2402 DCHECK_EQ(IrOpcode::kWord64And, node->opcode());
2416 DCHECK(IrOpcode::kWord32Or == node->opcode() ||
2417 IrOpcode::kWord32Xor == node->opcode());
2419 Node* shl =
nullptr;
2421 if (
m.left().IsWord32Shl() &&
m.right().IsWord32Shr()) {
2422 shl =
m.left().node();
2423 shr =
m.right().node();
2424 }
else if (
m.left().IsWord32Shr() &&
m.right().IsWord32Shl()) {
2425 shl =
m.right().node();
2426 shr =
m.left().node();
2433 if (mshl.
left().node() != mshr.
left().node())
return NoChange();
2435 if (mshl.
right().HasResolvedValue() && mshr.
right().HasResolvedValue()) {
2437 if (mshl.
right().ResolvedValue() + mshr.
right().ResolvedValue() != 32) {
2440 if (node->opcode() == IrOpcode::kWord32Xor &&
2441 (mshl.
right().ResolvedValue() & 31) == 0) {
2445 Node* sub =
nullptr;
2447 if (mshl.
right().IsInt32Sub()) {
2448 sub = mshl.
right().node();
2450 }
else if (mshr.
right().IsInt32Sub()) {
2451 sub = mshr.
right().node();
2458 if (!msub.
left().Is(32) || msub.
right().node() !=
y)
return NoChange();
2459 if (node->opcode() == IrOpcode::kWord32Xor) {
2464 node->ReplaceInput(0, mshl.
left().node());
2465 node->ReplaceInput(1, mshr.
right().node());
2467 return Changed(node);
2470template <
typename WordNAdapter>
2472 using A = WordNAdapter;
2475 typename A::IntNBinopMatcher
m(node);
2476 if (
m.right().Is(0))
return Replace(
m.left().node());
2477 if (
m.right().Is(-1))
return Replace(
m.right().node());
2478 if (
m.IsFoldable()) {
2479 return a.ReplaceIntN(
m.left().ResolvedValue() |
m.right().ResolvedValue());
2481 if (
m.LeftEqualsRight())
return Replace(
m.left().node());
2485 if (
m.right().HasResolvedValue()) {
2486 if (A::IsWordNAnd(
m.left())) {
2487 typename A::IntNBinopMatcher mand(
m.left().node());
2488 if (mand.right().HasResolvedValue()) {
2489 if ((
m.right().ResolvedValue() | mand.right().ResolvedValue()) == -1) {
2490 node->ReplaceInput(0, mand.left().node());
2491 return Changed(node);
2497 return a.TryMatchWordNRor(node);
2501 DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
2506 DCHECK_EQ(IrOpcode::kWord64Or, node->opcode());
2510template <
typename WordNAdapter>
2512 using A = WordNAdapter;
2515 typename A::IntNBinopMatcher
m(node);
2516 if (
m.right().Is(0))
return Replace(
m.left().node());
2517 if (
m.IsFoldable()) {
2518 return a.ReplaceIntN(
m.left().ResolvedValue() ^
m.right().ResolvedValue());
2520 if (
m.LeftEqualsRight())
return Replace(a.IntNConstant(0));
2521 if (A::IsWordNXor(
m.left()) &&
m.right().Is(-1)) {
2522 typename A::IntNBinopMatcher mleft(
m.left().node());
2523 if (mleft.right().Is(-1)) {
2524 return Replace(mleft.left().node());
2528 return a.TryMatchWordNRor(node);
2532 DCHECK_EQ(IrOpcode::kWord32Xor, node->opcode());
2534 if (
m.right().IsWord32Equal() &&
m.left().Is(1)) {
2541 DCHECK_EQ(IrOpcode::kWord64Xor, node->opcode());
2547 if (
m.IsFoldable()) {
2548 return ReplaceBool(
m.left().ResolvedValue() ==
m.right().ResolvedValue());
2550 if (
m.left().IsInt32Sub() &&
m.right().Is(0)) {
2552 node->ReplaceInput(0, msub.
left().node());
2553 node->ReplaceInput(1, msub.
right().node());
2554 return Changed(node);
2558 if (
m.right().HasResolvedValue()) {
2559 std::optional<std::pair<Node*, uint32_t>> replacements;
2560 if (
m.left().IsTruncateInt64ToInt32()) {
2563 static_cast<uint32_t
>(
m.right().ResolvedValue()));
2566 m.left().node(),
static_cast<uint32_t
>(
m.right().ResolvedValue()));
2569 node->ReplaceInput(0, replacements->first);
2571 return Changed(node);
2575 if (
m.left().IsInt32Add() &&
m.right().IsInt32Constant()) {
2577 if (m_add.
right().IsInt32Constant()) {
2578 int32_t lte_right =
m.right().ResolvedValue();
2579 int32_t add_right = m_add.
right().ResolvedValue();
2581 node->ReplaceInput(0, m_add.
left().node());
2582 node->ReplaceInput(1,
Int32Constant(
static_cast<uint32_t
>(lte_right) -
2583 static_cast<uint32_t
>(add_right)));
2584 return Changed(node);
2594 if (
m.IsFoldable()) {
2595 return ReplaceBool(
m.left().ResolvedValue() ==
m.right().ResolvedValue());
2597 if (
m.left().IsInt64Sub() &&
m.right().Is(0)) {
2599 node->ReplaceInput(0, msub.
left().node());
2600 node->ReplaceInput(1, msub.
right().node());
2601 return Changed(node);
2605 if (
m.right().HasResolvedValue()) {
2606 std::optional<std::pair<Node*, uint64_t>> replacements =
2608 m.left().node(),
static_cast<uint64_t
>(
m.right().ResolvedValue()));
2610 node->ReplaceInput(0, replacements->first);
2612 return Changed(node);
2616 if (
m.left().IsInt64Add() &&
m.right().IsInt64Constant()) {
2618 if (m_add.
right().IsInt64Constant()) {
2619 int64_t lte_right =
m.right().ResolvedValue();
2620 int64_t add_right = m_add.
right().ResolvedValue();
2622 node->ReplaceInput(0, m_add.
left().node());
2623 node->ReplaceInput(1,
Int64Constant(
static_cast<uint64_t
>(lte_right) -
2624 static_cast<uint64_t
>(add_right)));
2625 return Changed(node);
2637 if (
m.left().IsChangeInt32ToInt64()) {
2638 int64_t right_value =
m.right().ResolvedValue();
2640 if (right_value ==
static_cast<int32_t
>(right_value)) {
2642 node->ReplaceInput(0,
m.left().InputAt(0));
2643 node->ReplaceInput(1,
Int32Constant(
static_cast<int32_t
>(right_value)));
2644 return Changed(node);
2647 node->TrimInputCount(0);
2649 return Changed(node);
2658 DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
2664 uint64_t{0xFFFFFFFF00000000}) |
2671 DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
2677 uint64_t{0xFFFFFFFF}) |
2686 if (
m.HasResolvedValue()) {
2687 double v =
m.ResolvedValue();
2696 DCHECK(IrOpcode::kFloat64Equal == node->opcode() ||
2697 IrOpcode::kFloat64LessThan == node->opcode() ||
2698 IrOpcode::kFloat64LessThanOrEqual == node->opcode());
2700 if (
m.IsFoldable()) {
2701 switch (node->opcode()) {
2702 case IrOpcode::kFloat64Equal:
2704 m.right().ResolvedValue());
2705 case IrOpcode::kFloat64LessThan:
2707 m.right().ResolvedValue());
2708 case IrOpcode::kFloat64LessThanOrEqual:
2710 m.right().ResolvedValue());
2714 }
else if ((
m.left().IsChangeFloat32ToFloat64() &&
2715 m.right().IsChangeFloat32ToFloat64()) ||
2716 (
m.left().IsChangeFloat32ToFloat64() &&
2717 IsFloat64RepresentableAsFloat32(
m.right())) ||
2718 (IsFloat64RepresentableAsFloat32(
m.left()) &&
2719 m.right().IsChangeFloat32ToFloat64())) {
2725 switch (node->opcode()) {
2726 case IrOpcode::kFloat64Equal:
2729 case IrOpcode::kFloat64LessThan:
2732 case IrOpcode::kFloat64LessThanOrEqual:
2739 0,
m.left().HasResolvedValue()
2743 1,
m.right().HasResolvedValue()
2746 return Changed(node);
2752 DCHECK_EQ(IrOpcode::kFloat64RoundDown, node->opcode());
2754 if (
m.HasResolvedValue()) {
2764 switch (node->opcode()) {
2765#define CASE_IS_ZERO(opcode, matcher) \
2766 case IrOpcode::opcode: { \
2781std::optional<Node*> TryGetInvertedCondition(Node* cond) {
2782 if (cond->opcode() == IrOpcode::kWord32Equal) {
2784 if (
IsZero(
m.right().node())) {
2785 return m.left().node();
2788 return std::nullopt;
2791struct SimplifiedCondition {
2801std::optional<SimplifiedCondition> TrySimplifyCompareZero(Node* cond) {
2803 bool changed =
false;
2804 std::optional<Node*> new_cond;
2805 while ((new_cond = TryGetInvertedCondition(cond)).has_value()) {
2841Node* TrySimplifyCompareForTestBit(Node* cond) {
2842 if (cond->opcode() != IrOpcode::kWord32Equal) {
2845 Node* word_equal_left = cond->InputAt(0);
2846 Node* word_equal_right = cond->InputAt(1);
2848 if (word_equal_left->opcode() != IrOpcode::kWord32And ||
2849 word_equal_right->opcode() != IrOpcode::kInt32Constant) {
2853 Node* word_and_right = word_equal_left->InputAt(1);
2854 if (word_and_right->opcode() != IrOpcode::kInt32Constant) {
2862 DCHECK_EQ(word_equal_left->opcode(), IrOpcode::kWord32And);
2863 return word_equal_left;
2869 DCHECK_EQ(node->opcode(), IrOpcode::kBranch);
2870 for (
Node*
const use : node->
uses()) {
2871 switch (use->opcode()) {
2872 case IrOpcode::kIfTrue:
2875 case IrOpcode::kIfFalse:
2889 if (
auto simplified = TrySimplifyCompareZero(cond)) {
2890 node->ReplaceInput(0, simplified->condition);
2891 if (simplified->is_inverted) {
2892 switch (node->opcode()) {
2893 case IrOpcode::kBranch:
2896#if V8_ENABLE_WEBASSEMBLY
2897 case IrOpcode::kTrapIf: {
2898 const bool has_frame_state = node->op()->ValueInputCount() > 1;
2901 common()->TrapUnless(TrapIdOf(node->op()), has_frame_state));
2904 case IrOpcode::kTrapUnless: {
2905 const bool has_frame_state = node->op()->ValueInputCount() > 1;
2907 node,
common()->TrapIf(TrapIdOf(node->op()), has_frame_state));
2911 case IrOpcode::kDeoptimizeIf: {
2917 case IrOpcode::kDeoptimizeUnless: {
2928 return Changed(node);
2929 }
else if (
auto new_cond = TrySimplifyCompareForTestBit(cond)) {
2930 node->ReplaceInput(0, new_cond);
2931 return Changed(node);
2937 DCHECK(node->opcode() == IrOpcode::kBranch ||
2938 node->opcode() == IrOpcode::kDeoptimizeIf ||
2939 node->opcode() == IrOpcode::kDeoptimizeUnless ||
2940 node->opcode() == IrOpcode::kTrapIf ||
2941 node->opcode() == IrOpcode::kTrapUnless);
2947 if (
condition.IsTruncateInt64ToInt32()) {
2948 if (
auto replacement =
2951 reduction = Changed(node);
2955 reduction = Changed(node);
2960template <
typename WordNAdapter>
2969 if (replacements && replacements->second == 0)
return replacements->first;
2973template <
typename WordNAdapter,
typename u
intN_t,
typename intN_t>
2974std::optional<std::pair<Node*, uintN_t>>
2977 typename WordNAdapter::UintNBinopMatcher mand(lhs);
2978 if ((WordNAdapter::IsWordNShr(mand.left()) ||
2979 WordNAdapter::IsWordNSar(mand.left())) &&
2980 mand.right().HasResolvedValue()) {
2981 typename WordNAdapter::UintNBinopMatcher mshift(mand.left().node());
2983 if (mshift.right().HasResolvedValue()) {
2984 auto shift_bits = mshift.right().ResolvedValue();
2985 auto mask = mand.right().ResolvedValue();
2990 (std::is_same_v<uintN_t, uint64_t> ||
2992 Node* new_input = mshift.left().node();
2995 if (std::is_same_v<uintN_t, uint32_t> &&
2996 WordNAdapter::WORD_SIZE == 64) {
2999 return std::make_pair(
Word32And(new_input, new_mask), new_rhs);
3001 WordNAdapter
a(
this);
3002 return std::make_pair(
3003 a.WordNAnd(new_input, a.UintNConstant(new_mask)), new_rhs);
3011 if (std::is_same_v<intN_t, typename WordNAdapter::intN_t> &&
3012 WordNAdapter::IsWordNSarShiftOutZeros(lhs->
op()) &&
3014 typename WordNAdapter::UintNBinopMatcher mshift(lhs);
3015 if (mshift.right().HasResolvedValue()) {
3016 intN_t shift =
static_cast<intN_t
>(mshift.right().ResolvedValue());
3017 if (CanRevertLeftShiftWithRightShift<intN_t>(rhs, shift)) {
3018 return std::make_pair(mshift.left().node(), rhs << shift);
constexpr int Sign() const
constexpr MachineRepresentation representation() const
static constexpr MachineType Int32()
static constexpr MachineType Int16()
static constexpr MachineType Int8()
DeoptimizeReason reason() const
const FeedbackSource & feedback() const
Node * Float64Constant(double value)
CommonOperatorBuilder * common() const
MachineOperatorBuilder * machine() const
Node * Int32Constant(int32_t value)
const Operator * Int32LessThan()
const Operator * Uint32LessThan()
const Operator * Uint32LessThanOrEqual()
const Operator * Int32LessThanOrEqual()
Reduction ReduceWord64Sar(Node *node)
MachineOperatorBuilder * machine() const
Reduction ReduceWord32Sar(Node *node)
Node * Word64And(Node *lhs, Node *rhs)
Reduction ReduceWord64Or(Node *node)
Reduction ReduceWordNOr(Node *node)
Node * Int32Constant(int32_t value)
void SwapBranches(Node *node)
Reduction ReduceWordNXor(Node *node)
Reduction ReduceWord64Comparisons(Node *node)
Node * Uint32Div(Node *dividend, uint32_t divisor)
Reduction ReduceInt64Sub(Node *node)
Reduction ReduceWord32Or(Node *node)
Reduction ReduceStore(Node *node)
Node * Int32Sub(Node *lhs, Node *rhs)
Reduction ReplaceFloat32(float value)
Reduction ReduceWord32Shl(Node *node)
std::optional< Node * > ReduceConditionalN(Node *node)
Reduction ReduceWord32And(Node *node)
Reduction ReplaceInt32(int32_t value)
Reduction ReplaceBool(bool value)
Node * Int64Div(Node *dividend, int64_t divisor)
Reduction ReduceWord32Equal(Node *node)
Reduction ReduceWord64Equal(Node *node)
Node * Int32Mul(Node *lhs, Node *rhs)
Reduction ReduceInt32Sub(Node *node)
Node * Int64Sub(Node *lhs, Node *rhs)
Reduction ReduceFloat64Compare(Node *node)
CommonOperatorBuilder * common() const
Reduction ReduceFloat64InsertLowWord32(Node *node)
Reduction ReplaceUint32(uint32_t value)
MachineOperatorReducer(Editor *editor, MachineGraph *mcgraph, SignallingNanPropagation signalling_nan_propagation)
Node * Int32Add(Node *lhs, Node *rhs)
Reduction ReduceUint32Mod(Node *node)
Reduction ReduceInt64Mod(Node *node)
Reduction ReduceInt32Div(Node *node)
Node * Int64Mul(Node *lhs, Node *rhs)
Node * Word64Equal(Node *lhs, Node *rhs)
Reduction ReduceUint32Div(Node *node)
Reduction ReduceUintNLessThanOrEqual(Node *node)
Reduction TryMatchWord32Ror(Node *node)
Reduction ReduceInt64Add(Node *node)
Reduction ReduceConditional(Node *node)
Node * Uint64Div(Node *dividend, uint64_t divisor)
Reduction ReduceWord64Xor(Node *node)
~MachineOperatorReducer() override
Reduction ReplaceUint64(uint64_t value)
SignallingNanPropagation signalling_nan_propagation_
Node * Word64Shr(Node *lhs, uint32_t rhs)
Node * TruncateInt64ToInt32(Node *value)
Node * Word32Equal(Node *lhs, Node *rhs)
Node * Word32Sar(Node *lhs, uint32_t rhs)
Reduction ReduceInt64Div(Node *node)
Reduction ReplaceFloat64(double value)
Reduction ReduceWord64And(Node *node)
MachineGraph * mcgraph() const
Reduction ReduceFloat64RoundDown(Node *node)
Node * Float64PowHalf(Node *value)
Reduction ReduceUint64Mod(Node *node)
Node * Float32Constant(float value)
Reduction ReduceWord32Comparisons(Node *node)
Node * Int64Add(Node *lhs, Node *rhs)
Node * Uint64Constant(uint64_t value)
Node * Float64Constant(double value)
Node * ChangeInt32ToInt64(Node *value)
Reduction ReduceTruncateInt64ToInt32(Node *node)
Reduction Reduce(Node *node) override
Reduction ReduceWord32Shr(Node *node)
Node * Word32Shr(Node *lhs, uint32_t rhs)
Reduction ReduceWord64Shr(Node *node)
Reduction ReduceInt32Add(Node *node)
Node * Word32And(Node *lhs, Node *rhs)
Reduction ReduceWord32Xor(Node *node)
Reduction ReduceFloat64InsertHighWord32(Node *node)
Reduction ReduceWordNAnd(Node *node)
Node * Uint32Constant(uint32_t value)
Reduction SimplifyBranch(Node *node)
Node * Int32Div(Node *dividend, int32_t divisor)
Reduction ReduceInt32Mod(Node *node)
Node * Int64Constant(int64_t value)
Reduction ReduceUint64Div(Node *node)
@ kPropagateSignallingNan
Reduction ReduceInt64Mul(Node *node)
Node * Word64Sar(Node *lhs, uint32_t rhs)
const Operator * Map64To32Comparison(const Operator *op, bool sign_extended)
Node * Float64Mul(Node *lhs, Node *rhs)
Reduction ReduceWord64Shl(Node *node)
Reduction ReduceProjection(size_t index, Node *node)
Reduction ReplaceInt64(int64_t value)
std::optional< std::pair< Node *, uintN_t > > ReduceWordEqualForConstantRhs(Node *lhs, uintN_t rhs)
Reduction ReduceWord32Shifts(Node *node)
static void ChangeOp(Node *node, const Operator *new_op)
static bool IsValueEdge(Edge edge)
static Node * GetValueInput(Node *node, int index)
static void ReplaceValueInput(Node *node, Node *value, int index)
constexpr IrOpcode::Value opcode() const
const Operator * op() const
void ReplaceInput(int index, Node *new_to)
Node * InputAt(int index) const
constexpr Opcode opcode() const
MachineRepresentation representation() const
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
Reduction ReplaceIntN(int32_t value)
static constexpr std::size_t WORD_SIZE
static const Operator * WordNEqual(MachineOperatorBuilder *machine)
static bool IsIntNAdd(const T &x)
Word32Adapter(MachineOperatorReducer *reducer)
static bool IsWordNXor(const T &x)
Reduction ReduceIntNAdd(Node *node)
static bool IsIntNMul(const T &x)
Node * IntNConstant(int32_t value)
Reduction ReduceWordNAnd(Node *node)
Node * WordNAnd(Node *lhs, Node *rhs)
static bool IsWordNShr(const T &x)
MachineOperatorReducer * r_
Node * UintNConstant(uint32_t value)
static bool IsWordNAnd(const T &x)
static bool IsWordNSar(const T &x)
static bool IsWordNSarShiftOutZeros(const Operator *op)
const Operator * IntNAdd(MachineOperatorBuilder *machine)
Reduction ReduceWordNComparisons(Node *node)
Reduction TryMatchWordNRor(Node *node)
static bool IsWordNShl(const T &x)
Node * WordNAnd(Node *lhs, Node *rhs)
static bool IsWordNAnd(const T &x)
MachineOperatorReducer * r_
static bool IsIntNAdd(const T &x)
Reduction ReduceWordNAnd(Node *node)
static bool IsWordNXor(const T &x)
Node * UintNConstant(uint64_t value)
static constexpr std::size_t WORD_SIZE
static bool IsWordNShl(const T &x)
static bool IsWordNSarShiftOutZeros(const Operator *op)
static bool IsIntNMul(const T &x)
Reduction ReduceIntNAdd(Node *node)
Reduction TryMatchWordNRor(Node *node)
Reduction ReplaceIntN(int64_t value)
Reduction ReduceWordNComparisons(Node *node)
static const Operator * WordNEqual(MachineOperatorBuilder *machine)
static bool IsWordNShr(const T &x)
static const Operator * IntNAdd(MachineOperatorBuilder *machine)
Node * IntNConstant(int64_t value)
Word64Adapter(MachineOperatorReducer *reducer)
static bool IsWordNSar(const T &x)
std::optional< TNode< JSArray > > a
bool const truncate_from_64_bit
uint32_t const masked_value
#define CASE_IS_ZERO(opcode, matcher)
constexpr unsigned CountLeadingZeros(T value)
int32_t SignedDiv32(int32_t lhs, int32_t rhs)
int64_t SignedDiv64(int64_t lhs, int64_t rhs)
constexpr unsigned CountTrailingZeros(T value)
constexpr bool IsPowerOfTwo(T value)
uint32_t UnsignedDiv32(uint32_t lhs, uint32_t rhs)
uint32_t UnsignedMod32(uint32_t lhs, uint32_t rhs)
constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift)
int64_t SignedMod64(int64_t lhs, int64_t rhs)
uint64_t UnsignedDiv64(uint64_t lhs, uint64_t rhs)
bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
uint64_t UnsignedMod64(uint64_t lhs, uint64_t rhs)
int32_t SignedMod32(int32_t lhs, int32_t rhs)
bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
constexpr int WhichPowerOfTwo(T value)
double atan2(double y, double x)
int16_t MulWithWraparound(int16_t a, int16_t b)
MagicNumbersForDivision< T > UnsignedDivisionByConstant(T d, unsigned leading_zeros)
signed_type NegateWithWraparound(signed_type a)
V8_INLINE Dest bit_cast(Source const &source)
signed_type ShlWithWraparound(signed_type a, signed_type b)
MagicNumbersForDivision< T > SignedDivisionByConstant(T d)
BinopMatcher< Int32Matcher, Int32Matcher, MachineRepresentation::kWord32 > Int32BinopMatcher
size_t ProjectionIndexOf(const Operator *const op)
BinopMatcher< Int64Matcher, Int64Matcher, MachineRepresentation::kWord64 > Int64BinopMatcher
BranchHint BranchHintOf(const Operator *const op)
StoreRepresentation const & StoreRepresentationOf(Operator const *op)
BranchHint NegateBranchHint(BranchHint hint)
TNode< Float64T > Float64Add(TNode< Float64T > a, TNode< Float64T > b)
DeoptimizeParameters const & DeoptimizeParametersOf(Operator const *const op)
LoadRepresentation LoadRepresentationOf(Operator const *op)
BinopMatcher< Uint32Matcher, Uint32Matcher, MachineRepresentation::kWord32 > Uint32BinopMatcher
T const & OpParameter(const Operator *op)
UnalignedStoreRepresentation const & UnalignedStoreRepresentationOf(Operator const *op)
BinopMatcher< Uint64Matcher, Uint64Matcher, MachineRepresentation::kWord64 > Uint64BinopMatcher
double pow(double x, double y)
std::make_unsigned< T >::type Abs(T a)
double Modulo(double x, double y)
unsigned int FastD2UI(double x)
int32_t DoubleToInt32(double x)
V8_EXPORT_PRIVATE constexpr int ElementSizeLog2Of(MachineRepresentation)
float DoubleToFloat32(double x)
double FastUI2D(unsigned x)
int FastD2IChecked(double x)
constexpr uint32_t kMaxUInt32
static bool IsZero(const Operand &rt)
i::Address Load(i::Address address)
#define DCHECK_LE(v1, v2)
#define DCHECK_NE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
const Left & left() const
const Right & right() const
bool Is(const T &value) const
const Operator * op() const
const T & ResolvedValue() const
bool HasResolvedValue() const