Index: src/compiler/instruction-selector.cc |
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc |
index 3eb46db828ee5773a7ea688ddfb8135c319d6ef1..7604cf8d3b78af518a60a94677613bc521c5b62e 100644 |
--- a/src/compiler/instruction-selector.cc |
+++ b/src/compiler/instruction-selector.cc |
@@ -522,27 +522,32 @@ void InstructionSelector::VisitControl(BasicBlock* block) { |
} |
case BasicBlock::kSwitch: { |
DCHECK_EQ(IrOpcode::kSwitch, input->opcode()); |
+ SwitchInfo sw; |
// Last successor must be Default. |
- BasicBlock* default_branch = block->successors().back(); |
- DCHECK_EQ(IrOpcode::kIfDefault, default_branch->front()->opcode()); |
+ sw.default_branch = block->successors().back(); |
+ DCHECK_EQ(IrOpcode::kIfDefault, sw.default_branch->front()->opcode()); |
// All other successors must be cases. |
- size_t case_count = block->SuccessorCount() - 1; |
- DCHECK_LE(1u, case_count); |
- BasicBlock** case_branches = &block->successors().front(); |
+ sw.case_count = block->SuccessorCount() - 1; |
+ DCHECK_LE(1u, sw.case_count); |
+ sw.case_branches = &block->successors().front(); |
// Determine case values and their min/max. |
- int32_t* case_values = zone()->NewArray<int32_t>(case_count); |
- int32_t min_value = std::numeric_limits<int32_t>::max(); |
- int32_t max_value = std::numeric_limits<int32_t>::min(); |
- for (size_t index = 0; index < case_count; ++index) { |
- BasicBlock* branch = case_branches[index]; |
+ sw.case_values = zone()->NewArray<int32_t>(sw.case_count); |
+ sw.min_value = std::numeric_limits<int32_t>::max(); |
+ sw.max_value = std::numeric_limits<int32_t>::min(); |
+ for (size_t index = 0; index < sw.case_count; ++index) { |
+ BasicBlock* branch = sw.case_branches[index]; |
int32_t value = OpParameter<int32_t>(branch->front()->op()); |
- case_values[index] = value; |
- if (min_value > value) min_value = value; |
- if (max_value < value) max_value = value; |
+ sw.case_values[index] = value; |
+ if (sw.min_value > value) sw.min_value = value; |
+ if (sw.max_value < value) sw.max_value = value; |
} |
- DCHECK_LE(min_value, max_value); |
- return VisitSwitch(input, default_branch, case_branches, case_values, |
- case_count, min_value, max_value); |
+ DCHECK_LE(sw.min_value, sw.max_value); |
+ // Note that {value_range} can be 0 if {min_value} is -2^31 and |
+ // {max_value} |
+ // is 2^31-1, so don't assume that it's non-zero below. |
+ sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - |
+ bit_cast<uint32_t>(sw.min_value); |
+ return VisitSwitch(input, sw); |
} |
case BasicBlock::kReturn: { |
// If the result itself is a return, return its input. |
@@ -813,6 +818,43 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) { |
Emit(kArchStackPointer, g.DefineAsRegister(node)); |
} |
+ |
+void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw, |
+ InstructionOperand& index_operand) { |
+ OperandGenerator g(this); |
+ size_t input_count = 2 + sw.value_range; |
+ auto* inputs = zone()->NewArray<InstructionOperand>(input_count); |
+ inputs[0] = index_operand; |
+ InstructionOperand default_operand = g.Label(sw.default_branch); |
+ std::fill(&inputs[1], &inputs[input_count], default_operand); |
+ for (size_t index = 0; index < sw.case_count; ++index) { |
+ size_t value = sw.case_values[index] - sw.min_value; |
+ BasicBlock* branch = sw.case_branches[index]; |
+ DCHECK_LE(0u, value); |
+ DCHECK_LT(value + 2, input_count); |
+ inputs[value + 2] = g.Label(branch); |
+ } |
+ Emit(kArchTableSwitch, 0, nullptr, input_count, inputs, 0, nullptr); |
+} |
+ |
+ |
+void InstructionSelector::EmitLookupSwitch(const SwitchInfo& sw, |
+ InstructionOperand& value_operand) { |
+ OperandGenerator g(this); |
+ size_t input_count = 2 + sw.case_count * 2; |
+ auto* inputs = zone()->NewArray<InstructionOperand>(input_count); |
+ inputs[0] = value_operand; |
+ inputs[1] = g.Label(sw.default_branch); |
+ for (size_t index = 0; index < sw.case_count; ++index) { |
+ int32_t value = sw.case_values[index]; |
+ BasicBlock* branch = sw.case_branches[index]; |
+ inputs[index * 2 + 2 + 0] = g.TempImmediate(value); |
+ inputs[index * 2 + 2 + 1] = g.Label(branch); |
+ } |
+ Emit(kArchLookupSwitch, 0, nullptr, input_count, inputs, 0, nullptr); |
+} |
+ |
+ |
#endif // V8_TURBOFAN_BACKEND |
// 32 bit targets do not implement the following instructions. |