Shorten generated code for binary-search switches
On some branches of the search tree for a binary-search switch, the input value is sufficiently constrained that we could unconditionally jump to the last possible case rather than checking for value equality. This shortens some builtins by a few instructions and might speed things up, though I expect the effect to be small. Change-Id: I2313f26976e6d3c182f03bd927b338c8175b3af3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3335437 Reviewed-by: Nico Hartmann <nicohartmann@chromium.org> Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Cr-Commit-Position: refs/heads/main@{#78376}
This commit is contained in:
parent
86363753cf
commit
00a757fabd
@ -3625,9 +3625,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
ArmOperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -2959,9 +2959,9 @@ void CodeGenerator::AssembleArchSelect(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
Arm64OperandConverter i(this, instr);
|
||||
Register input = i.InputRegister32(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -491,11 +491,23 @@ void CodeGenerator::AssembleCode() {
|
||||
}
|
||||
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitchRange(
|
||||
Register input, RpoNumber def_block, std::pair<int32_t, Label*>* begin,
|
||||
std::pair<int32_t, Label*>* end) {
|
||||
Register input, RpoNumber def_block, std::pair<int32_t, RpoNumber>* begin,
|
||||
std::pair<int32_t, RpoNumber>* end, int32_t min_possible_value,
|
||||
int32_t max_possible_value) {
|
||||
if (end - begin < kBinarySearchSwitchMinimalCases) {
|
||||
while (begin != end) {
|
||||
tasm()->JumpIfEqual(input, begin->first, begin->second);
|
||||
if (min_possible_value == begin->first) {
|
||||
if (max_possible_value == begin->first) {
|
||||
// Only one value is possible, so we can jump to it unconditionally.
|
||||
DCHECK_EQ(begin + 1, end);
|
||||
def_block = begin->second;
|
||||
break;
|
||||
}
|
||||
// After emitting the branch for this case, the minimum possible value
|
||||
// is increased.
|
||||
++min_possible_value;
|
||||
}
|
||||
tasm()->JumpIfEqual(input, begin->first, GetLabel(begin->second));
|
||||
++begin;
|
||||
}
|
||||
AssembleArchJumpRegardlessOfAssemblyOrder(def_block);
|
||||
@ -504,9 +516,11 @@ void CodeGenerator::AssembleArchBinarySearchSwitchRange(
|
||||
auto middle = begin + (end - begin) / 2;
|
||||
Label less_label;
|
||||
tasm()->JumpIfLessThan(input, middle->first, &less_label);
|
||||
AssembleArchBinarySearchSwitchRange(input, def_block, middle, end);
|
||||
AssembleArchBinarySearchSwitchRange(input, def_block, middle, end,
|
||||
middle->first, max_possible_value);
|
||||
tasm()->bind(&less_label);
|
||||
AssembleArchBinarySearchSwitchRange(input, def_block, begin, middle);
|
||||
AssembleArchBinarySearchSwitchRange(input, def_block, begin, middle,
|
||||
min_possible_value, middle->first - 1);
|
||||
}
|
||||
|
||||
void CodeGenerator::AssembleArchJump(RpoNumber target) {
|
||||
|
@ -257,9 +257,11 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
void AssembleArchTrap(Instruction* instr, FlagsCondition condition);
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
void AssembleArchBinarySearchSwitchRange(Register input, RpoNumber def_block,
|
||||
std::pair<int32_t, Label*>* begin,
|
||||
std::pair<int32_t, Label*>* end);
|
||||
void AssembleArchBinarySearchSwitchRange(
|
||||
Register input, RpoNumber def_block, std::pair<int32_t, RpoNumber>* begin,
|
||||
std::pair<int32_t, RpoNumber>* end,
|
||||
int32_t min_possible_value = std::numeric_limits<int32_t>::min(),
|
||||
int32_t max_possible_value = std::numeric_limits<int32_t>::max());
|
||||
void AssembleArchBinarySearchSwitch(Instruction* instr);
|
||||
void AssembleArchTableSwitch(Instruction* instr);
|
||||
|
||||
|
@ -3841,9 +3841,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
IA32OperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -2152,9 +2152,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
Loong64OperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -3906,9 +3906,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
MipsOperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -4110,9 +4110,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
MipsOperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -3926,9 +3926,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
PPCOperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -3764,9 +3764,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
RiscvOperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -3793,9 +3793,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
S390OperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
@ -4478,9 +4478,9 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
|
||||
X64OperandConverter i(this, instr);
|
||||
Register input = i.InputRegister(0);
|
||||
std::vector<std::pair<int32_t, Label*>> cases;
|
||||
std::vector<std::pair<int32_t, RpoNumber>> cases;
|
||||
for (size_t index = 2; index < instr->InputCount(); index += 2) {
|
||||
cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
|
||||
cases.push_back({i.InputInt32(index + 0), i.InputRpo(index + 1)});
|
||||
}
|
||||
AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
|
||||
cases.data() + cases.size());
|
||||
|
Loading…
Reference in New Issue
Block a user