Commit a6940f7a authored by titzer's avatar titzer Committed by Commit bot

[turbofan] Factor out common switch-related code in instruction selectors.

R=bmeurer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1019803005

Cr-Commit-Position: refs/heads/master@{#27468}
parent 2f3a42f9
...@@ -1271,62 +1271,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1271,62 +1271,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
ArmOperandGenerator g(this); ArmOperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 4 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 4 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 3 + 2 * case_count; size_t lookup_space_cost = 3 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 0 && if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I), Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_I),
index_operand, value_operand, g.TempImmediate(min_value)); index_operand, value_operand, g.TempImmediate(sw.min_value));
}
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -1443,62 +1443,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1443,62 +1443,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
Arm64OperandGenerator g(this); Arm64OperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 4 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 4 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 3 + 2 * case_count; size_t lookup_space_cost = 3 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 0 && if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kArm64Sub32, index_operand, value_operand, Emit(kArm64Sub32, index_operand, value_operand,
g.TempImmediate(min_value)); g.TempImmediate(sw.min_value));
}
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -991,62 +991,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -991,62 +991,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
IA32OperandGenerator g(this); IA32OperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 4 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 4 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 3 + 2 * case_count; size_t lookup_space_cost = 3 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 4 && if (sw.case_count > 4 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand, Emit(kIA32Lea | AddressingModeField::encode(kMode_MRI), index_operand,
value_operand, g.TempImmediate(-min_value)); value_operand, g.TempImmediate(-sw.min_value));
}
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -15,6 +15,17 @@ namespace v8 { ...@@ -15,6 +15,17 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
// Helper struct containing data about a table or lookup switch.
struct SwitchInfo {
int32_t min_value; // minimum value of {case_values}
int32_t max_value; // maximum value of {case_values}
size_t value_range; // |max_value - min_value| + 1
size_t case_count; // number of cases
int32_t* case_values; // actual case values, unsorted
BasicBlock** case_branches; // basic blocks corresponding to case values
BasicBlock* default_branch; // default branch target
};
// A helper class for the instruction selector that simplifies construction of // A helper class for the instruction selector that simplifies construction of
// Operands. This class implements a base for architecture-specific helpers. // Operands. This class implements a base for architecture-specific helpers.
class OperandGenerator { class OperandGenerator {
......
...@@ -522,27 +522,32 @@ void InstructionSelector::VisitControl(BasicBlock* block) { ...@@ -522,27 +522,32 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
} }
case BasicBlock::kSwitch: { case BasicBlock::kSwitch: {
DCHECK_EQ(IrOpcode::kSwitch, input->opcode()); DCHECK_EQ(IrOpcode::kSwitch, input->opcode());
SwitchInfo sw;
// Last successor must be Default. // Last successor must be Default.
BasicBlock* default_branch = block->successors().back(); sw.default_branch = block->successors().back();
DCHECK_EQ(IrOpcode::kIfDefault, default_branch->front()->opcode()); DCHECK_EQ(IrOpcode::kIfDefault, sw.default_branch->front()->opcode());
// All other successors must be cases. // All other successors must be cases.
size_t case_count = block->SuccessorCount() - 1; sw.case_count = block->SuccessorCount() - 1;
DCHECK_LE(1u, case_count); DCHECK_LE(1u, sw.case_count);
BasicBlock** case_branches = &block->successors().front(); sw.case_branches = &block->successors().front();
// Determine case values and their min/max. // Determine case values and their min/max.
int32_t* case_values = zone()->NewArray<int32_t>(case_count); sw.case_values = zone()->NewArray<int32_t>(sw.case_count);
int32_t min_value = std::numeric_limits<int32_t>::max(); sw.min_value = std::numeric_limits<int32_t>::max();
int32_t max_value = std::numeric_limits<int32_t>::min(); sw.max_value = std::numeric_limits<int32_t>::min();
for (size_t index = 0; index < case_count; ++index) { for (size_t index = 0; index < sw.case_count; ++index) {
BasicBlock* branch = case_branches[index]; BasicBlock* branch = sw.case_branches[index];
int32_t value = OpParameter<int32_t>(branch->front()->op()); int32_t value = OpParameter<int32_t>(branch->front()->op());
case_values[index] = value; sw.case_values[index] = value;
if (min_value > value) min_value = value; if (sw.min_value > value) sw.min_value = value;
if (max_value < value) max_value = value; if (sw.max_value < value) sw.max_value = value;
} }
DCHECK_LE(min_value, max_value); DCHECK_LE(sw.min_value, sw.max_value);
return VisitSwitch(input, default_branch, case_branches, case_values, // Note that {value_range} can be 0 if {min_value} is -2^31 and
case_count, min_value, max_value); // {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: { case BasicBlock::kReturn: {
// If the result itself is a return, return its input. // If the result itself is a return, return its input.
...@@ -813,6 +818,43 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) { ...@@ -813,6 +818,43 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) {
Emit(kArchStackPointer, g.DefineAsRegister(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 #endif // V8_TURBOFAN_BACKEND
// 32 bit targets do not implement the following instructions. // 32 bit targets do not implement the following instructions.
......
...@@ -22,6 +22,7 @@ class BasicBlock; ...@@ -22,6 +22,7 @@ class BasicBlock;
struct CallBuffer; // TODO(bmeurer): Remove this. struct CallBuffer; // TODO(bmeurer): Remove this.
class FlagsContinuation; class FlagsContinuation;
class Linkage; class Linkage;
struct SwitchInfo;
typedef ZoneVector<InstructionOperand> InstructionOperandVector; typedef ZoneVector<InstructionOperand> InstructionOperandVector;
...@@ -134,6 +135,10 @@ class InstructionSelector FINAL { ...@@ -134,6 +135,10 @@ class InstructionSelector FINAL {
private: private:
friend class OperandGenerator; friend class OperandGenerator;
void EmitTableSwitch(const SwitchInfo& sw, InstructionOperand& index_operand);
void EmitLookupSwitch(const SwitchInfo& sw,
InstructionOperand& value_operand);
// Inform the instruction selection that {node} was just defined. // Inform the instruction selection that {node} was just defined.
void MarkAsDefined(Node* node); void MarkAsDefined(Node* node);
...@@ -201,9 +206,7 @@ class InstructionSelector FINAL { ...@@ -201,9 +206,7 @@ class InstructionSelector FINAL {
void VisitCall(Node* call, BasicBlock* handler); void VisitCall(Node* call, BasicBlock* handler);
void VisitGoto(BasicBlock* target); void VisitGoto(BasicBlock* target);
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch); void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
void VisitSwitch(Node* node, BasicBlock* default_branch, void VisitSwitch(Node* node, const SwitchInfo& sw);
BasicBlock** case_branches, int32_t* case_values,
size_t case_count, int32_t min_value, int32_t max_value);
void VisitDeoptimize(Node* value); void VisitDeoptimize(Node* value);
void VisitReturn(Node* value); void VisitReturn(Node* value);
void VisitThrow(Node* value); void VisitThrow(Node* value);
......
...@@ -771,61 +771,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -771,61 +771,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
MipsOperandGenerator g(this); MipsOperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 9 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 9 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * case_count; size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 0 && if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kMipsSub, index_operand, value_operand, g.TempImmediate(min_value)); Emit(kMipsSub, index_operand, value_operand,
} g.TempImmediate(sw.min_value));
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -955,62 +955,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -955,62 +955,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
Mips64OperandGenerator g(this); Mips64OperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 10 + 2 * sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 10 + 2 * value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 2 + 2 * case_count; size_t lookup_space_cost = 2 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 0 && if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kMips64Sub, index_operand, value_operand, Emit(kMips64Sub, index_operand, value_operand,
g.TempImmediate(min_value)); g.TempImmediate(sw.min_value));
}
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -1249,62 +1249,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1249,62 +1249,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
PPCOperandGenerator g(this); PPCOperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 4 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 4 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 3 + 2 * case_count; size_t lookup_space_cost = 3 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 0 && if (sw.case_count > 0 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kPPC_Sub32, index_operand, value_operand, Emit(kPPC_Sub32, index_operand, value_operand,
g.TempImmediate(min_value)); g.TempImmediate(sw.min_value));
}
size_t input_count = 2 + value_range;
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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); // Generate a table lookup.
return; return EmitTableSwitch(sw, index_operand);
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
...@@ -1220,65 +1220,34 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ...@@ -1220,65 +1220,34 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
} }
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch, void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
BasicBlock** case_branches,
int32_t* case_values, size_t case_count,
int32_t min_value, int32_t max_value) {
X64OperandGenerator g(this); X64OperandGenerator g(this);
InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); InstructionOperand value_operand = g.UseRegister(node->InputAt(0));
InstructionOperand default_operand = g.Label(default_branch);
// Note that {value_range} can be 0 if {min_value} is -2^31 and {max_value} // Emit either ArchTableSwitch or ArchLookupSwitch.
// is 2^31-1, so don't assume that it's non-zero below. size_t table_space_cost = 4 + sw.value_range;
size_t value_range =
1u + bit_cast<uint32_t>(max_value) - bit_cast<uint32_t>(min_value);
// Determine whether to issue an ArchTableSwitch or an ArchLookupSwitch
// instruction.
size_t table_space_cost = 4 + value_range;
size_t table_time_cost = 3; size_t table_time_cost = 3;
size_t lookup_space_cost = 3 + 2 * case_count; size_t lookup_space_cost = 3 + 2 * sw.case_count;
size_t lookup_time_cost = case_count; size_t lookup_time_cost = sw.case_count;
if (case_count > 4 && if (sw.case_count > 4 &&
table_space_cost + 3 * table_time_cost <= table_space_cost + 3 * table_time_cost <=
lookup_space_cost + 3 * lookup_time_cost && lookup_space_cost + 3 * lookup_time_cost &&
min_value > std::numeric_limits<int32_t>::min()) { sw.min_value > std::numeric_limits<int32_t>::min()) {
InstructionOperand index_operand = g.TempRegister(); InstructionOperand index_operand = g.TempRegister();
if (min_value) { if (sw.min_value) {
// The leal automatically zero extends, so result is a valid 64-bit index. // The leal automatically zero extends, so result is a valid 64-bit index.
Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand, Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
value_operand, g.TempImmediate(-min_value)); value_operand, g.TempImmediate(-sw.min_value));
} else { } else {
// Zero extend, because we use it as 64-bit index into the jump table. // Zero extend, because we use it as 64-bit index into the jump table.
Emit(kX64Movl, index_operand, value_operand); Emit(kX64Movl, index_operand, value_operand);
} }
size_t input_count = 2 + value_range; // Generate a table lookup.
auto* inputs = zone()->NewArray<InstructionOperand>(input_count); return EmitTableSwitch(sw, index_operand);
inputs[0] = index_operand;
std::fill(&inputs[1], &inputs[input_count], default_operand);
for (size_t index = 0; index < case_count; ++index) {
size_t value = case_values[index] - min_value;
BasicBlock* branch = 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);
return;
} }
// Generate a sequence of conditional jumps. // Generate a sequence of conditional jumps.
size_t input_count = 2 + case_count * 2; return EmitLookupSwitch(sw, value_operand);
auto* inputs = zone()->NewArray<InstructionOperand>(input_count);
inputs[0] = value_operand;
inputs[1] = default_operand;
for (size_t index = 0; index < case_count; ++index) {
int32_t value = case_values[index];
BasicBlock* branch = 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);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment