[turbofan] Fix 32-to-64 bit spill slot moves
Other optimizations can create a situation where it is valid to treat a stack slot as either 32-bit (which is what its value was created as) or 64-bit value (to which it was implicitly zero-extended). So when moving such a value to a register, we cannot use a 32-bit move instruction just because the source was annotated as such; we must also take the target slot's representation into account. Fixed: chromium:1407594 Bug: chromium:1356461 Change-Id: I00d850c11a020b055e90f6107b604cdd267d9b6c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4197349 Auto-Submit: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Maya Lekova <mslekova@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#85501}
This commit is contained in:
parent
83e2bce929
commit
9ec4e9095a
@ -5220,6 +5220,18 @@ void CodeGenerator::SetPendingMove(MoveOperands* move) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool Is32BitOperand(InstructionOperand* operand) {
|
||||||
|
DCHECK(operand->IsStackSlot() || operand->IsRegister());
|
||||||
|
MachineRepresentation mr = LocationOperand::cast(operand)->representation();
|
||||||
|
return mr == MachineRepresentation::kWord32 ||
|
||||||
|
mr == MachineRepresentation::kCompressed ||
|
||||||
|
mr == MachineRepresentation::kCompressedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||||
InstructionOperand* destination) {
|
InstructionOperand* destination) {
|
||||||
X64OperandConverter g(this, nullptr);
|
X64OperandConverter g(this, nullptr);
|
||||||
@ -5343,18 +5355,18 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
|||||||
case MoveType::kStackToRegister: {
|
case MoveType::kStackToRegister: {
|
||||||
Operand src = g.ToOperand(source);
|
Operand src = g.ToOperand(source);
|
||||||
if (source->IsStackSlot()) {
|
if (source->IsStackSlot()) {
|
||||||
MachineRepresentation mr =
|
|
||||||
LocationOperand::cast(source)->representation();
|
|
||||||
const bool is_32_bit = mr == MachineRepresentation::kWord32 ||
|
|
||||||
mr == MachineRepresentation::kCompressed ||
|
|
||||||
mr == MachineRepresentation::kCompressedPointer;
|
|
||||||
// TODO(13581): Fix this for other code kinds (see
|
// TODO(13581): Fix this for other code kinds (see
|
||||||
// https://crbug.com/1356461).
|
// https://crbug.com/1356461).
|
||||||
if (code_kind() == CodeKind::WASM_FUNCTION && is_32_bit) {
|
if (code_kind() == CodeKind::WASM_FUNCTION && Is32BitOperand(source) &&
|
||||||
|
Is32BitOperand(destination)) {
|
||||||
// When we need only 32 bits, move only 32 bits. Benefits:
|
// When we need only 32 bits, move only 32 bits. Benefits:
|
||||||
// - Save a byte here and there (depending on the destination
|
// - Save a byte here and there (depending on the destination
|
||||||
// register; "movl eax, ..." is smaller than "movq rax, ...").
|
// register; "movl eax, ..." is smaller than "movq rax, ...").
|
||||||
// - Safeguard against accidental decompression of compressed slots.
|
// - Safeguard against accidental decompression of compressed slots.
|
||||||
|
// We must check both {source} and {destination} to be 32-bit values,
|
||||||
|
// because treating 32-bit sources as 64-bit values can be perfectly
|
||||||
|
// fine as a result of virtual register renaming (to avoid redundant
|
||||||
|
// explicit zero-extensions that also happen implicitly).
|
||||||
__ movl(g.ToRegister(destination), src);
|
__ movl(g.ToRegister(destination), src);
|
||||||
} else {
|
} else {
|
||||||
__ movq(g.ToRegister(destination), src);
|
__ movq(g.ToRegister(destination), src);
|
||||||
|
64
test/mjsunit/regress/wasm/regress-crbug-1407594.js
Normal file
64
test/mjsunit/regress/wasm/regress-crbug-1407594.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2023 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.
|
||||||
|
|
||||||
|
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
|
||||||
|
|
||||||
|
let builder = new WasmModuleBuilder();
|
||||||
|
builder.addMemory(1, 1, false);
|
||||||
|
builder.addDataSegment(0, [0x78, 0x56, 0x34, 0x12]);
|
||||||
|
|
||||||
|
let spiller = builder.addFunction('spiller', kSig_v_v).addBody([]);
|
||||||
|
|
||||||
|
builder.addFunction('main', kSig_l_v)
|
||||||
|
.exportFunc()
|
||||||
|
.addLocals(kWasmI64, 1)
|
||||||
|
.addBody([
|
||||||
|
// Initialize {var0} to 0x12345678 via a zero-extended 32-bit load.
|
||||||
|
kExprI32Const, 0,
|
||||||
|
kExprI64LoadMem32U, 2, 0,
|
||||||
|
kExprLocalSet, 0,
|
||||||
|
kExprCallFunction, spiller.index,
|
||||||
|
// The observable effect of this loop is that {var0} is left-shifted
|
||||||
|
// until it ends in 0x..000000. The details are specifically crafted
|
||||||
|
// to recreate a particular pattern of spill slot moves.
|
||||||
|
kExprLoop, kWasmVoid,
|
||||||
|
kExprI32Const, 0,
|
||||||
|
kExprI32LoadMem, 2, 0,
|
||||||
|
kExprI32Eqz,
|
||||||
|
// This block is never taken; it only serves to influence register
|
||||||
|
// allocator choices.
|
||||||
|
kExprIf, kWasmVoid,
|
||||||
|
kExprLocalGet, 0,
|
||||||
|
kExprI64Const, 1,
|
||||||
|
kExprI64And,
|
||||||
|
kExprLocalSet, 0,
|
||||||
|
kExprEnd, // if
|
||||||
|
kExprLocalGet, 0,
|
||||||
|
kExprI64Const, 1,
|
||||||
|
kExprI64And,
|
||||||
|
kExprI64Eqz,
|
||||||
|
// This block is always taken; it is conditional in order to influence
|
||||||
|
// register allocator choices.
|
||||||
|
kExprIf, kWasmVoid,
|
||||||
|
kExprLocalGet, 0,
|
||||||
|
kExprI64Const, 8,
|
||||||
|
kExprI64Shl,
|
||||||
|
kExprLocalSet, 0,
|
||||||
|
kExprEnd, // if
|
||||||
|
kExprBlock, kWasmVoid,
|
||||||
|
kExprLocalGet, 0,
|
||||||
|
...wasmI64Const(0xFFFFFF),
|
||||||
|
kExprI64And,
|
||||||
|
kExprI64Eqz,
|
||||||
|
kExprI32Eqz,
|
||||||
|
kExprCallFunction, spiller.index,
|
||||||
|
kExprBrIf, 1,
|
||||||
|
kExprEnd, // block
|
||||||
|
kExprCallFunction, spiller.index,
|
||||||
|
kExprEnd, // loop
|
||||||
|
kExprLocalGet, 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let instance = builder.instantiate();
|
||||||
|
assertEquals("12345678000000", instance.exports.main().toString(16));
|
Loading…
Reference in New Issue
Block a user