Skip to content

Commit 8c69870

Browse files
ngzhianCommit Bot
authored andcommitted
[wasm-simd] Fix loading fp pair registers
We were incorrectly clearing the high reg from the list of regs to load. The intention was to prevent double (and incorrect) loading - loading 128 bits from the low fp and the loading 128 bits from the high fp. But this violates the assumption that the two regs in a pair would be set or unset at the same time. The fix here is to introduce a new enum for register loads, a nop, which does nothing. The high fp of the fp pair will be tied to this nop, so as we iterate down the reglist, we load 128 bits using the low fp, then don't load anything for the high fp. Bug: chromium:1161654 Change-Id: If2ea79132b78623e5990237c60cf0883d9a8223f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2617380 Reviewed-by: Clemens Backes <[email protected]> Commit-Queue: Zhi An Ng <[email protected]> Cr-Commit-Position: refs/heads/master@{#71976}
1 parent d727c9b commit 8c69870

2 files changed

Lines changed: 67 additions & 4 deletions

File tree

src/wasm/baseline/liftoff-assembler.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class StackTransferRecipe {
3838

3939
struct RegisterLoad {
4040
enum LoadKind : uint8_t {
41+
kNop, // no-op, used for high fp of a fp pair.
4142
kConstant, // load a constant value into a register.
4243
kStack, // fill a register from a stack slot.
4344
kLowHalfStack, // fill a register from the low half of a stack slot.
@@ -64,6 +65,10 @@ class StackTransferRecipe {
6465
return {half == kLowWord ? kLowHalfStack : kHighHalfStack, kWasmI32,
6566
offset};
6667
}
68+
static RegisterLoad Nop() {
69+
// ValueType does not matter.
70+
return {kNop, kWasmI32, 0};
71+
}
6772

6873
private:
6974
RegisterLoad(LoadKind kind, ValueType type, int32_t value)
@@ -220,11 +225,11 @@ class StackTransferRecipe {
220225
RegisterLoad::HalfStack(stack_offset, kHighWord);
221226
} else if (dst.is_fp_pair()) {
222227
DCHECK_EQ(kWasmS128, type);
223-
// load_dst_regs_.set above will set both low and high fp regs.
224-
// But unlike gp_pair, we load a kWasm128 in one go in ExecuteLoads.
225-
// So unset the top fp register to skip loading it.
226-
load_dst_regs_.clear(dst.high());
228+
// Only need register_load for low_gp since we load 128 bits at one go.
229+
// Both low and high need to be set in load_dst_regs_ but when iterating
230+
// over it, both low and high will be cleared, so we won't load twice.
227231
*register_load(dst.low()) = RegisterLoad::Stack(stack_offset, type);
232+
*register_load(dst.high()) = RegisterLoad::Nop();
228233
} else {
229234
*register_load(dst) = RegisterLoad::Stack(stack_offset, type);
230235
}
@@ -321,6 +326,8 @@ class StackTransferRecipe {
321326
for (LiftoffRegister dst : load_dst_regs_) {
322327
RegisterLoad* load = register_load(dst);
323328
switch (load->kind) {
329+
case RegisterLoad::kNop:
330+
break;
324331
case RegisterLoad::kConstant:
325332
asm_->LoadConstant(dst, load->type == kWasmI64
326333
? WasmValue(int64_t{load->value})
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2021 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --wasm-staging
6+
7+
// This is a fuzzer-generated test case that exposed a bug in Liftoff that only
8+
// affects ARM, where the fp register aliasing is different from other archs.
9+
// We were inncorrectly clearing the the high fp register in a LiftoffRegList
10+
// indicating registers to load, hitting a DCHECK.
11+
load('test/mjsunit/wasm/wasm-module-builder.js');
12+
13+
const builder = new WasmModuleBuilder();
14+
builder.addMemory(19, 32, false);
15+
builder.addGlobal(kWasmI32, 0);
16+
builder.addType(makeSig([], []));
17+
builder.addType(makeSig([kWasmI64, kWasmS128, kWasmF32], [kWasmI32]));
18+
// Generate function 1 (out of 5).
19+
builder.addFunction(undefined, 0 /* sig */)
20+
.addBodyWithEnd([
21+
// signature: v_v
22+
// body:
23+
kExprI32Const, 0x05, // i32.const
24+
kExprReturn, // return
25+
kExprUnreachable, // unreachable
26+
kExprEnd, // end @5
27+
]);
28+
// Generate function 4 (out of 5).
29+
builder.addFunction(undefined, 1 /* sig */)
30+
.addBodyWithEnd([
31+
// signature: i_lsf
32+
// body:
33+
kExprLocalGet, 0x01, // local.get
34+
kExprLocalGet, 0x01, // local.get
35+
kExprGlobalGet, 0x00, // global.get
36+
kExprDrop, // drop
37+
kExprLoop, kWasmStmt, // loop @8
38+
kExprLoop, 0x00, // loop @10
39+
kExprI32Const, 0x01, // i32.const
40+
kExprMemoryGrow, 0x00, // memory.grow
41+
kExprI64LoadMem8U, 0x00, 0x70, // i64.load8_u
42+
kExprLoop, 0x00, // loop @19
43+
kExprCallFunction, 0x00, // call function #0: v_v
44+
kExprEnd, // end @23
45+
kExprI64Const, 0xf1, 0x24, // i64.const
46+
kExprGlobalGet, 0x00, // global.get
47+
kExprDrop, // drop
48+
kExprBr, 0x00, // br depth=0
49+
kExprEnd, // end @32
50+
kExprEnd, // end @33
51+
kExprI32Const, 0x5b, // i32.const
52+
kExprReturn, // return
53+
kExprEnd, // end @37
54+
]);
55+
// Instantiation is enough to cause a crash.
56+
const instance = builder.instantiate();

0 commit comments

Comments
 (0)