| 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/compiler/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 #include "src/compiler/node-properties.h" | 7 #include "src/compiler/node-properties.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 outputs[output_count++] = g.DefineAsRegister(node); | 242 outputs[output_count++] = g.DefineAsRegister(node); |
| 243 if (cont->IsSet()) { | 243 if (cont->IsSet()) { |
| 244 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 244 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
| 245 } | 245 } |
| 246 | 246 |
| 247 DCHECK_NE(0u, input_count); | 247 DCHECK_NE(0u, input_count); |
| 248 DCHECK_NE(0u, output_count); | 248 DCHECK_NE(0u, output_count); |
| 249 DCHECK_GE(arraysize(inputs), input_count); | 249 DCHECK_GE(arraysize(inputs), input_count); |
| 250 DCHECK_GE(arraysize(outputs), output_count); | 250 DCHECK_GE(arraysize(outputs), output_count); |
| 251 | 251 |
| 252 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, | 252 selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, |
| 253 outputs, input_count, inputs); | 253 inputs); |
| 254 if (cont->IsBranch()) instr->MarkAsControl(); | |
| 255 } | 254 } |
| 256 | 255 |
| 257 | 256 |
| 258 // Shared routine for multiple binary operations. | 257 // Shared routine for multiple binary operations. |
| 259 template <typename Matcher> | 258 template <typename Matcher> |
| 260 static void VisitBinop(InstructionSelector* selector, Node* node, | 259 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 261 ArchOpcode opcode, ImmediateMode operand_mode) { | 260 ArchOpcode opcode, ImmediateMode operand_mode) { |
| 262 FlagsContinuation cont; | 261 FlagsContinuation cont; |
| 263 VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont); | 262 VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont); |
| 264 } | 263 } |
| (...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1223 | 1222 |
| 1224 | 1223 |
| 1225 // Shared routine for multiple compare operations. | 1224 // Shared routine for multiple compare operations. |
| 1226 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 1225 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 1227 InstructionOperand left, InstructionOperand right, | 1226 InstructionOperand left, InstructionOperand right, |
| 1228 FlagsContinuation* cont) { | 1227 FlagsContinuation* cont) { |
| 1229 Arm64OperandGenerator g(selector); | 1228 Arm64OperandGenerator g(selector); |
| 1230 opcode = cont->Encode(opcode); | 1229 opcode = cont->Encode(opcode); |
| 1231 if (cont->IsBranch()) { | 1230 if (cont->IsBranch()) { |
| 1232 selector->Emit(opcode, g.NoOutput(), left, right, | 1231 selector->Emit(opcode, g.NoOutput(), left, right, |
| 1233 g.Label(cont->true_block()), | 1232 g.Label(cont->true_block()), g.Label(cont->false_block())); |
| 1234 g.Label(cont->false_block()))->MarkAsControl(); | |
| 1235 } else { | 1233 } else { |
| 1236 DCHECK(cont->IsSet()); | 1234 DCHECK(cont->IsSet()); |
| 1237 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); | 1235 selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); |
| 1238 } | 1236 } |
| 1239 } | 1237 } |
| 1240 | 1238 |
| 1241 | 1239 |
| 1242 // Shared routine for multiple word compare operations. | 1240 // Shared routine for multiple word compare operations. |
| 1243 static void VisitWordCompare(InstructionSelector* selector, Node* node, | 1241 static void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 1244 InstructionCode opcode, FlagsContinuation* cont, | 1242 InstructionCode opcode, FlagsContinuation* cont, |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 Int32BinopMatcher m(value); | 1401 Int32BinopMatcher m(value); |
| 1404 if (m.right().HasValue() && | 1402 if (m.right().HasValue() && |
| 1405 (base::bits::CountPopulation32(m.right().Value()) == 1)) { | 1403 (base::bits::CountPopulation32(m.right().Value()) == 1)) { |
| 1406 // If the mask has only one bit set, we can use tbz/tbnz. | 1404 // If the mask has only one bit set, we can use tbz/tbnz. |
| 1407 DCHECK((cont.condition() == kEqual) || | 1405 DCHECK((cont.condition() == kEqual) || |
| 1408 (cont.condition() == kNotEqual)); | 1406 (cont.condition() == kNotEqual)); |
| 1409 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), | 1407 Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), |
| 1410 g.UseRegister(m.left().node()), | 1408 g.UseRegister(m.left().node()), |
| 1411 g.TempImmediate( | 1409 g.TempImmediate( |
| 1412 base::bits::CountTrailingZeros32(m.right().Value())), | 1410 base::bits::CountTrailingZeros32(m.right().Value())), |
| 1413 g.Label(cont.true_block()), | 1411 g.Label(cont.true_block()), g.Label(cont.false_block())); |
| 1414 g.Label(cont.false_block()))->MarkAsControl(); | |
| 1415 return; | 1412 return; |
| 1416 } | 1413 } |
| 1417 return VisitWordCompare(this, value, kArm64Tst32, &cont, true, | 1414 return VisitWordCompare(this, value, kArm64Tst32, &cont, true, |
| 1418 kLogical32Imm); | 1415 kLogical32Imm); |
| 1419 } | 1416 } |
| 1420 case IrOpcode::kWord64And: { | 1417 case IrOpcode::kWord64And: { |
| 1421 Int64BinopMatcher m(value); | 1418 Int64BinopMatcher m(value); |
| 1422 if (m.right().HasValue() && | 1419 if (m.right().HasValue() && |
| 1423 (base::bits::CountPopulation64(m.right().Value()) == 1)) { | 1420 (base::bits::CountPopulation64(m.right().Value()) == 1)) { |
| 1424 // If the mask has only one bit set, we can use tbz/tbnz. | 1421 // If the mask has only one bit set, we can use tbz/tbnz. |
| 1425 DCHECK((cont.condition() == kEqual) || | 1422 DCHECK((cont.condition() == kEqual) || |
| 1426 (cont.condition() == kNotEqual)); | 1423 (cont.condition() == kNotEqual)); |
| 1427 Emit(cont.Encode(kArm64TestAndBranch), g.NoOutput(), | 1424 Emit(cont.Encode(kArm64TestAndBranch), g.NoOutput(), |
| 1428 g.UseRegister(m.left().node()), | 1425 g.UseRegister(m.left().node()), |
| 1429 g.TempImmediate( | 1426 g.TempImmediate( |
| 1430 base::bits::CountTrailingZeros64(m.right().Value())), | 1427 base::bits::CountTrailingZeros64(m.right().Value())), |
| 1431 g.Label(cont.true_block()), | 1428 g.Label(cont.true_block()), g.Label(cont.false_block())); |
| 1432 g.Label(cont.false_block()))->MarkAsControl(); | |
| 1433 return; | 1429 return; |
| 1434 } | 1430 } |
| 1435 return VisitWordCompare(this, value, kArm64Tst, &cont, true, | 1431 return VisitWordCompare(this, value, kArm64Tst, &cont, true, |
| 1436 kLogical64Imm); | 1432 kLogical64Imm); |
| 1437 } | 1433 } |
| 1438 default: | 1434 default: |
| 1439 break; | 1435 break; |
| 1440 } | 1436 } |
| 1441 } | 1437 } |
| 1442 | 1438 |
| 1443 // Branch could not be combined with a compare, compare against 0 and branch. | 1439 // Branch could not be combined with a compare, compare against 0 and branch. |
| 1444 Emit(cont.Encode(kArm64CompareAndBranch32), g.NoOutput(), | 1440 Emit(cont.Encode(kArm64CompareAndBranch32), g.NoOutput(), |
| 1445 g.UseRegister(value), g.Label(cont.true_block()), | 1441 g.UseRegister(value), g.Label(cont.true_block()), |
| 1446 g.Label(cont.false_block()))->MarkAsControl(); | 1442 g.Label(cont.false_block())); |
| 1447 } | 1443 } |
| 1448 | 1444 |
| 1449 | 1445 |
| 1450 void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, | 1446 void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, |
| 1451 BasicBlock** case_branches, | 1447 BasicBlock** case_branches, |
| 1452 int32_t* case_values, size_t case_count, | 1448 int32_t* case_values, size_t case_count, |
| 1453 int32_t min_value, int32_t max_value) { | 1449 int32_t min_value, int32_t max_value) { |
| 1454 Arm64OperandGenerator g(this); | 1450 Arm64OperandGenerator g(this); |
| 1455 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); | 1451 InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); |
| 1456 InstructionOperand default_operand = g.Label(default_branch); | 1452 InstructionOperand default_operand = g.Label(default_branch); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1480 auto* inputs = zone()->NewArray<InstructionOperand>(input_count); | 1476 auto* inputs = zone()->NewArray<InstructionOperand>(input_count); |
| 1481 inputs[0] = index_operand; | 1477 inputs[0] = index_operand; |
| 1482 std::fill(&inputs[1], &inputs[input_count], default_operand); | 1478 std::fill(&inputs[1], &inputs[input_count], default_operand); |
| 1483 for (size_t index = 0; index < case_count; ++index) { | 1479 for (size_t index = 0; index < case_count; ++index) { |
| 1484 size_t value = case_values[index] - min_value; | 1480 size_t value = case_values[index] - min_value; |
| 1485 BasicBlock* branch = case_branches[index]; | 1481 BasicBlock* branch = case_branches[index]; |
| 1486 DCHECK_LE(0u, value); | 1482 DCHECK_LE(0u, value); |
| 1487 DCHECK_LT(value + 2, input_count); | 1483 DCHECK_LT(value + 2, input_count); |
| 1488 inputs[value + 2] = g.Label(branch); | 1484 inputs[value + 2] = g.Label(branch); |
| 1489 } | 1485 } |
| 1490 Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr) | 1486 Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr); |
| 1491 ->MarkAsControl(); | |
| 1492 return; | 1487 return; |
| 1493 } | 1488 } |
| 1494 | 1489 |
| 1495 // Generate a sequence of conditional jumps. | 1490 // Generate a sequence of conditional jumps. |
| 1496 size_t input_count = 2 + case_count * 2; | 1491 size_t input_count = 2 + case_count * 2; |
| 1497 auto* inputs = zone()->NewArray<InstructionOperand>(input_count); | 1492 auto* inputs = zone()->NewArray<InstructionOperand>(input_count); |
| 1498 inputs[0] = value_operand; | 1493 inputs[0] = value_operand; |
| 1499 inputs[1] = default_operand; | 1494 inputs[1] = default_operand; |
| 1500 for (size_t index = 0; index < case_count; ++index) { | 1495 for (size_t index = 0; index < case_count; ++index) { |
| 1501 int32_t value = case_values[index]; | 1496 int32_t value = case_values[index]; |
| 1502 BasicBlock* branch = case_branches[index]; | 1497 BasicBlock* branch = case_branches[index]; |
| 1503 inputs[index * 2 + 2 + 0] = g.TempImmediate(value); | 1498 inputs[index * 2 + 2 + 0] = g.TempImmediate(value); |
| 1504 inputs[index * 2 + 2 + 1] = g.Label(branch); | 1499 inputs[index * 2 + 2 + 1] = g.Label(branch); |
| 1505 } | 1500 } |
| 1506 Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr) | 1501 Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr); |
| 1507 ->MarkAsControl(); | |
| 1508 } | 1502 } |
| 1509 | 1503 |
| 1510 | 1504 |
| 1511 void InstructionSelector::VisitWord32Equal(Node* const node) { | 1505 void InstructionSelector::VisitWord32Equal(Node* const node) { |
| 1512 Node* const user = node; | 1506 Node* const user = node; |
| 1513 FlagsContinuation cont(kEqual, node); | 1507 FlagsContinuation cont(kEqual, node); |
| 1514 Int32BinopMatcher m(user); | 1508 Int32BinopMatcher m(user); |
| 1515 if (m.right().Is(0)) { | 1509 if (m.right().Is(0)) { |
| 1516 Node* const value = m.left().node(); | 1510 Node* const value = m.left().node(); |
| 1517 if (CanCover(user, value)) { | 1511 if (CanCover(user, value)) { |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1696 MachineOperatorBuilder::kFloat64Max | | 1690 MachineOperatorBuilder::kFloat64Max | |
| 1697 MachineOperatorBuilder::kFloat64Min | | 1691 MachineOperatorBuilder::kFloat64Min | |
| 1698 MachineOperatorBuilder::kWord32ShiftIsSafe | | 1692 MachineOperatorBuilder::kWord32ShiftIsSafe | |
| 1699 MachineOperatorBuilder::kInt32DivIsSafe | | 1693 MachineOperatorBuilder::kInt32DivIsSafe | |
| 1700 MachineOperatorBuilder::kUint32DivIsSafe; | 1694 MachineOperatorBuilder::kUint32DivIsSafe; |
| 1701 } | 1695 } |
| 1702 | 1696 |
| 1703 } // namespace compiler | 1697 } // namespace compiler |
| 1704 } // namespace internal | 1698 } // namespace internal |
| 1705 } // namespace v8 | 1699 } // namespace v8 |
| OLD | NEW |