diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc index 5515843612..541718cf89 100644 --- a/src/compiler/register-allocator.cc +++ b/src/compiler/register-allocator.cc @@ -3278,8 +3278,32 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { register_use->pos())) { SpillBetween(current, current->Start(), register_use->pos()); } else { - SetLiveRangeAssignedRegister(current, reg); - SplitAndSpillIntersecting(current); + // We can't spill up to the first register use, because there is no gap + // where the fill before the register use may happen. This happens when + // there is high register pressure, we are at the beginning of an + // instruction, we are the input to that instruction, and we can't hold + // on to the register past the instruction (we likely lose due to an + // output or a temp). + // We give the `reg` register to this range, but then we need to spill + // until the next register use, if any. + LifetimePosition after_this_reg_use = register_use->pos().NextFullStart(); + if (after_this_reg_use >= current->End()) { + // The range ends at this instruction, since the end is at or before + // the next gap. It should follow that there is no other use either. + DCHECK_NULL(register_use->next()); + SetLiveRangeAssignedRegister(current, reg); + } else { + const UsePosition* next_reg_pos = register_use->next(); + for (; next_reg_pos != nullptr; next_reg_pos = next_reg_pos->next()) { + if (next_reg_pos->type() == UsePositionType::kRequiresRegister) break; + } + SetLiveRangeAssignedRegister(current, reg); + if (next_reg_pos == nullptr) { + SpillAfter(current, after_this_reg_use); + } else { + SpillBetween(current, after_this_reg_use, next_reg_pos->pos()); + } + } } return; } diff --git a/test/mjsunit/regress/regress-5888.js b/test/mjsunit/regress/regress-5888.js new file mode 100644 index 0000000000..0725ac4285 --- /dev/null +++ b/test/mjsunit/regress/regress-5888.js @@ -0,0 +1,76 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +load("test/mjsunit/wasm/wasm-constants.js"); +load("test/mjsunit/wasm/wasm-module-builder.js"); + +(function() { + var builder = new WasmModuleBuilder(); + builder.addMemory(32, 32, false); + builder.addFunction("test", kSig_i_iii) + .addBodyWithEnd([ +// body: +kExprI64Const, 0xb4, 0x42, +kExprI64Const, 0x7a, +kExprI64Const, 0x42, +kExprI64Const, 0x7a, +kExprI64Ior, +kExprI64Ctz, +kExprI64Ctz, +kExprI64Shl, +kExprI64Mul, +kExprI64Const, 0x41, +kExprI64Ctz, +kExprI64Ctz, +kExprI64Shl, +kExprF32SConvertI64, +kExprI64Const, 0x42, +kExprI64Const, 0x02, +kExprI64Const, 0x7a, +kExprI64Mul, +kExprI64Const, 0x42, +kExprI64Ctz, +kExprI64Shl, +kExprI64Const, 0x7a, +kExprI64Ctz, +kExprI64Shl, +kExprI64Mul, +kExprI64Const, 0x41, +kExprI64Ctz, +kExprI64Ctz, +kExprI64Shl, +kExprF32SConvertI64, +kExprUnreachable, +kExprEnd, // @65 + ]) + .exportFunc(); + var module = new WebAssembly.Module(builder.toBuffer()); +})(); + +(function() { + var builder = new WasmModuleBuilder(); + builder.addMemory(16, 32, false); + builder.addFunction("test", kSig_i_iii) + .addBodyWithEnd([ + // body: + kExprI64Const, 0x42, + kExprI64Const, 0x7a, + kExprI64Ctz, + kExprI64Mul, + kExprI64Ctz, + kExprI64Const, 0x41, + kExprI64Ctz, + kExprI64Ctz, + kExprI64Shl, + kExprI64Const, 0x41, + kExprI64Ctz, + kExprI64Ctz, + kExprI64Shl, + kExprF32SConvertI64, + kExprUnreachable, + kExprEnd, // @20 + ]) + .exportFunc(); + var module = new WebAssembly.Module(builder.toBuffer()); +})();