[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}
This commit is contained in:
parent
2f3a42f9a1
commit
a6940f7aa3
@ -1271,62 +1271,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
ArmOperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 4 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 3 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 0 &&
|
||||
size_t lookup_space_cost = 3 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 0 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
index_operand = g.TempRegister();
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1443,62 +1443,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
Arm64OperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 4 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 3 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 0 &&
|
||||
size_t lookup_space_cost = 3 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 0 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
index_operand = g.TempRegister();
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -991,62 +991,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
IA32OperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 4 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 3 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 4 &&
|
||||
size_t lookup_space_cost = 3 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 4 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
index_operand = g.TempRegister();
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,6 +15,17 @@ namespace v8 {
|
||||
namespace internal {
|
||||
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
|
||||
// Operands. This class implements a base for architecture-specific helpers.
|
||||
class OperandGenerator {
|
||||
|
@ -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.
|
||||
|
@ -22,6 +22,7 @@ class BasicBlock;
|
||||
struct CallBuffer; // TODO(bmeurer): Remove this.
|
||||
class FlagsContinuation;
|
||||
class Linkage;
|
||||
struct SwitchInfo;
|
||||
|
||||
typedef ZoneVector<InstructionOperand> InstructionOperandVector;
|
||||
|
||||
@ -134,6 +135,10 @@ class InstructionSelector FINAL {
|
||||
private:
|
||||
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.
|
||||
void MarkAsDefined(Node* node);
|
||||
|
||||
@ -201,9 +206,7 @@ class InstructionSelector FINAL {
|
||||
void VisitCall(Node* call, BasicBlock* handler);
|
||||
void VisitGoto(BasicBlock* target);
|
||||
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
|
||||
void VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches, int32_t* case_values,
|
||||
size_t case_count, int32_t min_value, int32_t max_value);
|
||||
void VisitSwitch(Node* node, const SwitchInfo& sw);
|
||||
void VisitDeoptimize(Node* value);
|
||||
void VisitReturn(Node* value);
|
||||
void VisitThrow(Node* value);
|
||||
|
@ -771,61 +771,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
MipsOperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 9 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 2 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 0 &&
|
||||
size_t lookup_space_cost = 2 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 0 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -955,62 +955,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
Mips64OperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 10 + 2 * sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 2 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 0 &&
|
||||
size_t lookup_space_cost = 2 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 0 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
index_operand = g.TempRegister();
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1249,62 +1249,31 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
PPCOperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 4 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 3 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 0 &&
|
||||
size_t lookup_space_cost = 3 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 0 &&
|
||||
table_space_cost + 3 * table_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;
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
index_operand = g.TempRegister();
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1220,65 +1220,34 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitSwitch(Node* node, BasicBlock* default_branch,
|
||||
BasicBlock** case_branches,
|
||||
int32_t* case_values, size_t case_count,
|
||||
int32_t min_value, int32_t max_value) {
|
||||
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
|
||||
X64OperandGenerator g(this);
|
||||
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}
|
||||
// is 2^31-1, so don't assume that it's non-zero below.
|
||||
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;
|
||||
// Emit either ArchTableSwitch or ArchLookupSwitch.
|
||||
size_t table_space_cost = 4 + sw.value_range;
|
||||
size_t table_time_cost = 3;
|
||||
size_t lookup_space_cost = 3 + 2 * case_count;
|
||||
size_t lookup_time_cost = case_count;
|
||||
if (case_count > 4 &&
|
||||
size_t lookup_space_cost = 3 + 2 * sw.case_count;
|
||||
size_t lookup_time_cost = sw.case_count;
|
||||
if (sw.case_count > 4 &&
|
||||
table_space_cost + 3 * table_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();
|
||||
if (min_value) {
|
||||
if (sw.min_value) {
|
||||
// The leal automatically zero extends, so result is a valid 64-bit index.
|
||||
Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), index_operand,
|
||||
value_operand, g.TempImmediate(-min_value));
|
||||
value_operand, g.TempImmediate(-sw.min_value));
|
||||
} else {
|
||||
// Zero extend, because we use it as 64-bit index into the jump table.
|
||||
Emit(kX64Movl, index_operand, value_operand);
|
||||
}
|
||||
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);
|
||||
return;
|
||||
// Generate a table lookup.
|
||||
return EmitTableSwitch(sw, index_operand);
|
||||
}
|
||||
|
||||
// Generate a sequence of conditional jumps.
|
||||
size_t input_count = 2 + case_count * 2;
|
||||
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);
|
||||
return EmitLookupSwitch(sw, value_operand);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user