OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/base/bits.h" | 6 #include "src/base/bits.h" |
7 #include "src/compiler/instruction-selector-impl.h" | 7 #include "src/compiler/instruction-selector-impl.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 | 10 |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 Emit(kMipsIns, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), | 300 Emit(kMipsIns, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()), |
301 g.TempImmediate(0), g.TempImmediate(shift)); | 301 g.TempImmediate(0), g.TempImmediate(shift)); |
302 return; | 302 return; |
303 } | 303 } |
304 } | 304 } |
305 VisitBinop(this, node, kMipsAnd); | 305 VisitBinop(this, node, kMipsAnd); |
306 } | 306 } |
307 | 307 |
308 | 308 |
309 void InstructionSelector::VisitWord32Or(Node* node) { | 309 void InstructionSelector::VisitWord32Or(Node* node) { |
| 310 Int32BinopMatcher orm(node); |
| 311 |
| 312 bool unalignedMatched = false; |
| 313 bool loadSigned = false; |
| 314 |
| 315 int i = 0; |
| 316 uintptr_t prevAddress = 0; |
| 317 Node* smallestLoad = NULL; |
| 318 |
| 319 // Unligned access is simulated using combinations of |
| 320 // load byte, shift and or operations, like this |
| 321 // Result = 0 |
| 322 // Result = LoadByte (high) | Result << 8 |
| 323 // Result = LoadByte (high - 1) | Result << 8 |
| 324 // ... |
| 325 // Result = LoadByte (low) | Result << 8 |
| 326 // We are trying to match the graph that corresponds |
| 327 // to the above operations and reduce it to |
| 328 // one simple Unaligned load |
| 329 while (orm.left().IsWord32Shl() && orm.right().IsLoad()) { |
| 330 Int32BinopMatcher shl(orm.left().node()); |
| 331 LoadMatcher<PtrMatcher> load(orm.right().node()); |
| 332 |
| 333 // Verifying load address |
| 334 if (load.object().HasValue()) { |
| 335 // Assumption is that the first byte will |
| 336 // always be the most significant |
| 337 if (prevAddress == 0) { |
| 338 prevAddress = load.object().Value(); |
| 339 smallestLoad = load.node(); |
| 340 } else { |
| 341 // Verifying that load addresses are consecutive |
| 342 if (prevAddress + 1 != load.object().Value()) { |
| 343 unalignedMatched = false; |
| 344 break; |
| 345 } |
| 346 prevAddress = load.object().Value(); |
| 347 loadSigned = LoadRepresentationOf(load.node()->op()).IsSigned(); |
| 348 } |
| 349 } else { |
| 350 unalignedMatched = false; |
| 351 break; |
| 352 } |
| 353 |
| 354 if (shl.left().IsWord32Or() && shl.right().Is(8)) { |
| 355 orm = Int32BinopMatcher(shl.left().node()); |
| 356 } else if (shl.left().Is(0)) { |
| 357 unalignedMatched = true; |
| 358 break; |
| 359 } else { |
| 360 unalignedMatched = false; |
| 361 break; |
| 362 } |
| 363 |
| 364 i++; |
| 365 // Something is not right, the graph is too deep, break |
| 366 if (i > 8) { |
| 367 unalignedMatched = false; |
| 368 break; |
| 369 } |
| 370 } |
| 371 |
| 372 if (unalignedMatched) { |
| 373 MipsOperandGenerator g(this); |
| 374 ArchOpcode opcode = kArchNop; |
| 375 |
| 376 if (i == 3) { |
| 377 opcode = kMipsUlw; |
| 378 } else if (i == 1) { |
| 379 opcode = loadSigned ? kMipsUlh : kMipsUlhu; |
| 380 } else { |
| 381 unalignedMatched = false; |
| 382 } |
| 383 |
| 384 if (unalignedMatched) { |
| 385 MipsOperandGenerator g(this); |
| 386 |
| 387 DCHECK(smallestLoad != NULL); |
| 388 |
| 389 Node* base = smallestLoad->InputAt(0); |
| 390 Node* index = smallestLoad->InputAt(1); |
| 391 |
| 392 if (g.CanBeImmediate(index, opcode)) { |
| 393 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| 394 g.DefineAsRegister(node), g.UseRegister(base), |
| 395 g.UseImmediate(index)); |
| 396 } else { |
| 397 InstructionOperand addr_reg = g.TempRegister(); |
| 398 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg, |
| 399 g.UseRegister(index), g.UseRegister(base)); |
| 400 // Emit desired load opcode, using temp addr_reg. |
| 401 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| 402 g.DefineAsRegister(node), addr_reg, g.TempImmediate(0)); |
| 403 } |
| 404 return; |
| 405 } |
| 406 } |
| 407 |
310 VisitBinop(this, node, kMipsOr); | 408 VisitBinop(this, node, kMipsOr); |
311 } | 409 } |
312 | 410 |
313 | 411 |
314 void InstructionSelector::VisitWord32Xor(Node* node) { | 412 void InstructionSelector::VisitWord32Xor(Node* node) { |
315 Int32BinopMatcher m(node); | 413 Int32BinopMatcher m(node); |
316 if (m.left().IsWord32Or() && CanCover(node, m.left().node()) && | 414 if (m.left().IsWord32Or() && CanCover(node, m.left().node()) && |
317 m.right().Is(-1)) { | 415 m.right().Is(-1)) { |
318 Int32BinopMatcher mleft(m.left().node()); | 416 Int32BinopMatcher mleft(m.left().node()); |
319 if (!mleft.right().HasValue()) { | 417 if (!mleft.right().HasValue()) { |
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 } | 1063 } |
966 } | 1064 } |
967 } | 1065 } |
968 } | 1066 } |
969 | 1067 |
970 | 1068 |
971 bool InstructionSelector::IsTailCallAddressImmediate() { return false; } | 1069 bool InstructionSelector::IsTailCallAddressImmediate() { return false; } |
972 | 1070 |
973 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; } | 1071 int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 3; } |
974 | 1072 |
| 1073 void InstructionSelector::VisitUnalignedLoad(Node* node) { |
| 1074 UnalignedLoadRepresentation load_rep = |
| 1075 UnalignedLoadRepresentationOf(node->op()); |
| 1076 MipsOperandGenerator g(this); |
| 1077 Node* base = node->InputAt(0); |
| 1078 Node* index = node->InputAt(1); |
| 1079 |
| 1080 ArchOpcode opcode = kArchNop; |
| 1081 switch (load_rep.representation()) { |
| 1082 case MachineRepresentation::kBit: // Fall through. |
| 1083 case MachineRepresentation::kWord8: |
| 1084 opcode = load_rep.IsUnsigned() ? kMipsLbu : kMipsLb; |
| 1085 break; |
| 1086 case MachineRepresentation::kWord16: |
| 1087 opcode = load_rep.IsUnsigned() ? kMipsUlhu : kMipsUlh; |
| 1088 break; |
| 1089 case MachineRepresentation::kTagged: // Fall through. |
| 1090 case MachineRepresentation::kWord32: |
| 1091 opcode = kMipsUlw; |
| 1092 break; |
| 1093 case MachineRepresentation::kFloat32: |
| 1094 opcode = kMipsUlwc1; |
| 1095 break; |
| 1096 case MachineRepresentation::kFloat64: |
| 1097 opcode = kMipsUldc1; |
| 1098 break; |
| 1099 case MachineRepresentation::kWord64: // Fall through. |
| 1100 case MachineRepresentation::kSimd128: // Fall through. |
| 1101 case MachineRepresentation::kNone: |
| 1102 UNREACHABLE(); |
| 1103 return; |
| 1104 } |
| 1105 |
| 1106 if (g.CanBeImmediate(index, opcode)) { |
| 1107 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| 1108 g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index)); |
| 1109 } else { |
| 1110 InstructionOperand addr_reg = g.TempRegister(); |
| 1111 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg, |
| 1112 g.UseRegister(index), g.UseRegister(base)); |
| 1113 // Emit desired load opcode, using temp addr_reg. |
| 1114 Emit(opcode | AddressingModeField::encode(kMode_MRI), |
| 1115 g.DefineAsRegister(node), addr_reg, g.TempImmediate(0)); |
| 1116 } |
| 1117 } |
| 1118 |
| 1119 void InstructionSelector::VisitUnalignedStore(Node* node) { |
| 1120 MipsOperandGenerator g(this); |
| 1121 Node* base = node->InputAt(0); |
| 1122 Node* index = node->InputAt(1); |
| 1123 Node* value = node->InputAt(2); |
| 1124 |
| 1125 UnalignedStoreRepresentation rep = UnalignedStoreRepresentationOf(node->op()); |
| 1126 |
| 1127 // TODO(mips): I guess this could be done in a better way. |
| 1128 ArchOpcode opcode = kArchNop; |
| 1129 switch (rep) { |
| 1130 case MachineRepresentation::kFloat32: |
| 1131 opcode = kMipsUswc1; |
| 1132 break; |
| 1133 case MachineRepresentation::kFloat64: |
| 1134 opcode = kMipsUsdc1; |
| 1135 break; |
| 1136 case MachineRepresentation::kBit: // Fall through. |
| 1137 case MachineRepresentation::kWord8: |
| 1138 opcode = kMipsSb; |
| 1139 break; |
| 1140 case MachineRepresentation::kWord16: |
| 1141 opcode = kMipsUsh; |
| 1142 break; |
| 1143 case MachineRepresentation::kTagged: // Fall through. |
| 1144 case MachineRepresentation::kWord32: |
| 1145 opcode = kMipsUsw; |
| 1146 break; |
| 1147 case MachineRepresentation::kWord64: // Fall through. |
| 1148 case MachineRepresentation::kSimd128: // Fall through. |
| 1149 case MachineRepresentation::kNone: |
| 1150 UNREACHABLE(); |
| 1151 return; |
| 1152 } |
| 1153 |
| 1154 if (g.CanBeImmediate(index, opcode)) { |
| 1155 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), |
| 1156 g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value)); |
| 1157 } else { |
| 1158 InstructionOperand addr_reg = g.TempRegister(); |
| 1159 Emit(kMipsAdd | AddressingModeField::encode(kMode_None), addr_reg, |
| 1160 g.UseRegister(index), g.UseRegister(base)); |
| 1161 // Emit desired store opcode, using temp addr_reg. |
| 1162 Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), |
| 1163 addr_reg, g.TempImmediate(0), g.UseRegister(value)); |
| 1164 } |
| 1165 } |
| 1166 |
975 void InstructionSelector::VisitCheckedLoad(Node* node) { | 1167 void InstructionSelector::VisitCheckedLoad(Node* node) { |
976 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); | 1168 CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); |
977 MipsOperandGenerator g(this); | 1169 MipsOperandGenerator g(this); |
978 Node* const buffer = node->InputAt(0); | 1170 Node* const buffer = node->InputAt(0); |
979 Node* const offset = node->InputAt(1); | 1171 Node* const offset = node->InputAt(1); |
980 Node* const length = node->InputAt(2); | 1172 Node* const length = node->InputAt(2); |
981 ArchOpcode opcode = kArchNop; | 1173 ArchOpcode opcode = kArchNop; |
982 switch (load_rep.representation()) { | 1174 switch (load_rep.representation()) { |
983 case MachineRepresentation::kWord8: | 1175 case MachineRepresentation::kWord8: |
984 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8; | 1176 opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8; |
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1457 MachineOperatorBuilder::Flags | 1649 MachineOperatorBuilder::Flags |
1458 InstructionSelector::SupportedMachineOperatorFlags() { | 1650 InstructionSelector::SupportedMachineOperatorFlags() { |
1459 MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags; | 1651 MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags; |
1460 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && | 1652 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && |
1461 IsFp64Mode()) { | 1653 IsFp64Mode()) { |
1462 flags |= MachineOperatorBuilder::kFloat64RoundDown | | 1654 flags |= MachineOperatorBuilder::kFloat64RoundDown | |
1463 MachineOperatorBuilder::kFloat64RoundUp | | 1655 MachineOperatorBuilder::kFloat64RoundUp | |
1464 MachineOperatorBuilder::kFloat64RoundTruncate | | 1656 MachineOperatorBuilder::kFloat64RoundTruncate | |
1465 MachineOperatorBuilder::kFloat64RoundTiesEven; | 1657 MachineOperatorBuilder::kFloat64RoundTiesEven; |
1466 } | 1658 } |
| 1659 |
| 1660 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r1)) || |
| 1661 IsMipsArchVariant(kLoongson)) { |
| 1662 flags |= MachineOperatorBuilder::kUnalignedLoad | |
| 1663 MachineOperatorBuilder::kUnalignedStore; |
| 1664 } |
| 1665 |
1467 return flags | MachineOperatorBuilder::kWord32Ctz | | 1666 return flags | MachineOperatorBuilder::kWord32Ctz | |
1468 MachineOperatorBuilder::kWord32Popcnt | | 1667 MachineOperatorBuilder::kWord32Popcnt | |
1469 MachineOperatorBuilder::kInt32DivIsSafe | | 1668 MachineOperatorBuilder::kInt32DivIsSafe | |
1470 MachineOperatorBuilder::kUint32DivIsSafe | | 1669 MachineOperatorBuilder::kUint32DivIsSafe | |
1471 MachineOperatorBuilder::kWord32ShiftIsSafe | | 1670 MachineOperatorBuilder::kWord32ShiftIsSafe | |
1472 MachineOperatorBuilder::kFloat64Min | | 1671 MachineOperatorBuilder::kFloat64Min | |
1473 MachineOperatorBuilder::kFloat64Max | | 1672 MachineOperatorBuilder::kFloat64Max | |
1474 MachineOperatorBuilder::kFloat32Min | | 1673 MachineOperatorBuilder::kFloat32Min | |
1475 MachineOperatorBuilder::kFloat32Max | | 1674 MachineOperatorBuilder::kFloat32Max | |
1476 MachineOperatorBuilder::kFloat32RoundDown | | 1675 MachineOperatorBuilder::kFloat32RoundDown | |
1477 MachineOperatorBuilder::kFloat32RoundUp | | 1676 MachineOperatorBuilder::kFloat32RoundUp | |
1478 MachineOperatorBuilder::kFloat32RoundTruncate | | 1677 MachineOperatorBuilder::kFloat32RoundTruncate | |
1479 MachineOperatorBuilder::kFloat32RoundTiesEven; | 1678 MachineOperatorBuilder::kFloat32RoundTiesEven; |
1480 } | 1679 } |
1481 | 1680 |
1482 } // namespace compiler | 1681 } // namespace compiler |
1483 } // namespace internal | 1682 } // namespace internal |
1484 } // namespace v8 | 1683 } // namespace v8 |
OLD | NEW |