From 00a757fabdef480d0647f3836532501fc598b02f Mon Sep 17 00:00:00 2001 From: Seth Brenith Date: Mon, 13 Dec 2021 12:30:27 -0800 Subject: [PATCH] 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 Commit-Queue: Seth Brenith Cr-Commit-Position: refs/heads/main@{#78376} --- .../backend/arm/code-generator-arm.cc | 4 ++-- .../backend/arm64/code-generator-arm64.cc | 4 ++-- src/compiler/backend/code-generator.cc | 24 +++++++++++++++---- src/compiler/backend/code-generator.h | 8 ++++--- .../backend/ia32/code-generator-ia32.cc | 4 ++-- .../backend/loong64/code-generator-loong64.cc | 4 ++-- .../backend/mips/code-generator-mips.cc | 4 ++-- .../backend/mips64/code-generator-mips64.cc | 4 ++-- .../backend/ppc/code-generator-ppc.cc | 4 ++-- .../backend/riscv64/code-generator-riscv64.cc | 4 ++-- .../backend/s390/code-generator-s390.cc | 4 ++-- .../backend/x64/code-generator-x64.cc | 4 ++-- 12 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/compiler/backend/arm/code-generator-arm.cc b/src/compiler/backend/arm/code-generator-arm.cc index 1323121fb0..745fd1d288 100644 --- a/src/compiler/backend/arm/code-generator-arm.cc +++ b/src/compiler/backend/arm/code-generator-arm.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/arm64/code-generator-arm64.cc b/src/compiler/backend/arm64/code-generator-arm64.cc index ecde0ce926..0cc6e5bafe 100644 --- a/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/src/compiler/backend/arm64/code-generator-arm64.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc index db96ea0ab5..9eba86132e 100644 --- a/src/compiler/backend/code-generator.cc +++ b/src/compiler/backend/code-generator.cc @@ -491,11 +491,23 @@ void CodeGenerator::AssembleCode() { } void CodeGenerator::AssembleArchBinarySearchSwitchRange( - Register input, RpoNumber def_block, std::pair* begin, - std::pair* end) { + Register input, RpoNumber def_block, std::pair* begin, + std::pair* 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) { diff --git a/src/compiler/backend/code-generator.h b/src/compiler/backend/code-generator.h index 2cb3969900..af5e30363e 100644 --- a/src/compiler/backend/code-generator.h +++ b/src/compiler/backend/code-generator.h @@ -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* begin, - std::pair* end); + void AssembleArchBinarySearchSwitchRange( + Register input, RpoNumber def_block, std::pair* begin, + std::pair* end, + int32_t min_possible_value = std::numeric_limits::min(), + int32_t max_possible_value = std::numeric_limits::max()); void AssembleArchBinarySearchSwitch(Instruction* instr); void AssembleArchTableSwitch(Instruction* instr); diff --git a/src/compiler/backend/ia32/code-generator-ia32.cc b/src/compiler/backend/ia32/code-generator-ia32.cc index 5d615b06b9..171e90e5dc 100644 --- a/src/compiler/backend/ia32/code-generator-ia32.cc +++ b/src/compiler/backend/ia32/code-generator-ia32.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/loong64/code-generator-loong64.cc b/src/compiler/backend/loong64/code-generator-loong64.cc index 5fbb5dd4ad..7e90c78fef 100644 --- a/src/compiler/backend/loong64/code-generator-loong64.cc +++ b/src/compiler/backend/loong64/code-generator-loong64.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/mips/code-generator-mips.cc b/src/compiler/backend/mips/code-generator-mips.cc index 2e29db30cb..558e98f743 100644 --- a/src/compiler/backend/mips/code-generator-mips.cc +++ b/src/compiler/backend/mips/code-generator-mips.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/mips64/code-generator-mips64.cc b/src/compiler/backend/mips64/code-generator-mips64.cc index e82e8ae7d6..aa1c1bfe7d 100644 --- a/src/compiler/backend/mips64/code-generator-mips64.cc +++ b/src/compiler/backend/mips64/code-generator-mips64.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/ppc/code-generator-ppc.cc b/src/compiler/backend/ppc/code-generator-ppc.cc index 0bcca4b040..e35d690813 100644 --- a/src/compiler/backend/ppc/code-generator-ppc.cc +++ b/src/compiler/backend/ppc/code-generator-ppc.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/riscv64/code-generator-riscv64.cc b/src/compiler/backend/riscv64/code-generator-riscv64.cc index 4f30213e9d..02c88ebe62 100644 --- a/src/compiler/backend/riscv64/code-generator-riscv64.cc +++ b/src/compiler/backend/riscv64/code-generator-riscv64.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/s390/code-generator-s390.cc b/src/compiler/backend/s390/code-generator-s390.cc index 11de1d0764..c197a311f2 100644 --- a/src/compiler/backend/s390/code-generator-s390.cc +++ b/src/compiler/backend/s390/code-generator-s390.cc @@ -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> cases; + std::vector> 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()); diff --git a/src/compiler/backend/x64/code-generator-x64.cc b/src/compiler/backend/x64/code-generator-x64.cc index 02c2b224c9..ab9e1833a4 100644 --- a/src/compiler/backend/x64/code-generator-x64.cc +++ b/src/compiler/backend/x64/code-generator-x64.cc @@ -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> cases; + std::vector> 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());