[liftoff] Materialize constants before conditional branches

The number of constants stored in locals and the merge region can be
arbitrarily big, thus generating arbitrarily long code for a single
`br_if`. This happened in particular for unoptimized code.

This CL solves this by materializing all constants (in registers or on
the stack) before doing a conditional branch. This ensures that in a
series of `br_if`s, each constant is only spilled once instead of on
each single branch.

For the linked bug, this reduces the total generated code size by ~36%.

R=thibaudm@chromium.org

Bug: chromium:1117033
Change-Id: I84ea2ea9ba4d3de9b042ceb223af15c3d73dc5b8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2364498
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69485}
This commit is contained in:
Clemens Backes 2020-08-19 16:11:38 +02:00 committed by Commit Bot
parent 1096e03159
commit 1a911e6cbe
3 changed files with 32 additions and 0 deletions

View File

@ -578,6 +578,28 @@ void LiftoffAssembler::PrepareLoopArgs(int num) {
}
}
void LiftoffAssembler::MaterializeMergedConstants(uint32_t arity) {
// Materialize constants on top of the stack ({arity} many), and locals.
VarState* stack_base = cache_state_.stack_state.data();
for (auto slots :
{VectorOf(stack_base + cache_state_.stack_state.size() - arity, arity),
VectorOf(stack_base, num_locals())}) {
for (VarState& slot : slots) {
if (!slot.is_const()) continue;
RegClass rc = reg_class_for(slot.type());
if (cache_state_.has_unused_register(rc)) {
LiftoffRegister reg = cache_state_.unused_register(rc);
LoadConstant(reg, slot.constant());
cache_state_.inc_used(reg);
slot.MakeRegister(reg);
} else {
Spill(slot.offset(), slot.constant());
slot.MakeStack();
}
}
}
}
void LiftoffAssembler::MergeFullStackWith(const CacheState& target,
const CacheState& source) {
DCHECK_EQ(source.stack_height(), target.stack_height());

View File

@ -381,6 +381,8 @@ class LiftoffAssembler : public TurboAssembler {
return SpillOneRegister(candidates, pinned);
}
void MaterializeMergedConstants(uint32_t arity);
void MergeFullStackWith(const CacheState& target, const CacheState& source);
void MergeStackWith(const CacheState& target, uint32_t arity);

View File

@ -1840,6 +1840,14 @@ class LiftoffCompiler {
}
void BrIf(FullDecoder* decoder, const Value& /* cond */, uint32_t depth) {
// Before branching, materialize all constants. This avoids repeatedly
// materializing them for each conditional branch.
// TODO(clemensb): Do the same for br_table.
if (depth != decoder->control_depth() - 1) {
__ MaterializeMergedConstants(
decoder->control_at(depth)->br_merge()->arity);
}
Label cont_false;
Register value = __ PopToRegister().gp();