From 9264104c0b64da54cbc4727b3bc87fb8147148df Mon Sep 17 00:00:00 2001 From: Edoardo Vacchi Date: Thu, 19 Oct 2023 00:10:45 +0200 Subject: [PATCH] wazevo: fuzz, fix simd shl, shr, shuffle, vbitselect (#1797) --- .../wazevo/backend/isa/arm64/lower_instr.go | 24 +- .../backend/isa/arm64/lower_instr_test.go | 28 +- internal/engine/wazevo/frontend/lower.go | 5 +- .../fuzzcases/fuzzcases_test.go | 64 ++ .../fuzzcases/testdata/1797a.wasm | Bin 0 -> 192 bytes .../fuzzcases/testdata/1797a.wat | 67 ++ .../fuzzcases/testdata/1797b.wasm | Bin 0 -> 123 bytes .../fuzzcases/testdata/1797b.wat | 17 + .../fuzzcases/testdata/1797c.wasm | Bin 0 -> 389 bytes .../fuzzcases/testdata/1797c.wat | 93 ++ .../fuzzcases/testdata/1797d.wasm | Bin 0 -> 2968 bytes .../fuzzcases/testdata/1797d.wat | 886 ++++++++++++++++++ 12 files changed, 1160 insertions(+), 24 deletions(-) create mode 100644 internal/integration_test/fuzzcases/testdata/1797a.wasm create mode 100644 internal/integration_test/fuzzcases/testdata/1797a.wat create mode 100644 internal/integration_test/fuzzcases/testdata/1797b.wasm create mode 100644 internal/integration_test/fuzzcases/testdata/1797b.wat create mode 100644 internal/integration_test/fuzzcases/testdata/1797c.wasm create mode 100644 internal/integration_test/fuzzcases/testdata/1797c.wat create mode 100644 internal/integration_test/fuzzcases/testdata/1797d.wasm create mode 100644 internal/integration_test/fuzzcases/testdata/1797d.wat diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go index 319df83d..864ffac8 100644 --- a/internal/engine/wazevo/backend/isa/arm64/lower_instr.go +++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr.go @@ -358,15 +358,22 @@ func (m *machine) LowerInstr(instr *ssa.Instruction) { rn := m.getOperand_NR(m.compiler.ValueDefinition(x), extModeNone) rm := m.getOperand_NR(m.compiler.ValueDefinition(y), extModeNone) creg := m.getOperand_NR(m.compiler.ValueDefinition(c), extModeNone) + tmp := operandNR(m.compiler.AllocateVReg(ssa.TypeV128)) + // creg is overwritten by BSL, so we need to move it to the result register before the instruction // in case when it is used somewhere else. rd := m.compiler.VRegOf(instr.Return()) mov := m.allocateInstr() - mov.asFpuMov128(rd, creg.nr()) + mov.asFpuMov128(tmp.nr(), creg.nr()) m.insert(mov) + ins := m.allocateInstr() - ins.asVecRRR(vecOpBsl, operandNR(rd), rn, rm, vecArrangement16B) + ins.asVecRRR(vecOpBsl, tmp, rn, rm, vecArrangement16B) m.insert(ins) + + mov2 := m.allocateInstr() + mov2.asFpuMov128(rd, tmp.nr()) + m.insert(mov2) case ssa.OpcodeVanyTrue, ssa.OpcodeVallTrue: x, lane := instr.ArgWithLane() var arr vecArrangement @@ -751,31 +758,32 @@ func (m *machine) lowerVShift(op ssa.Opcode, rd, rn, rm operand, arr vecArrangem panic("unsupported arrangment " + arr.String()) } - tmp := operandNR(m.compiler.AllocateVReg(ssa.TypeV128)) + rtmp := operandNR(m.compiler.AllocateVReg(ssa.TypeI64)) + vtmp := operandNR(m.compiler.AllocateVReg(ssa.TypeV128)) and := m.allocateInstr() - and.asALUBitmaskImm(aluOpAnd, tmp.nr(), rm.nr(), uint64(modulo), false) + and.asALUBitmaskImm(aluOpAnd, rtmp.nr(), rm.nr(), uint64(modulo), true) m.insert(and) if op != ssa.OpcodeVIshl { // Negate the amount to make this as right shift. neg := m.allocateInstr() - neg.asALU(aluOpSub, tmp, operandNR(xzrVReg), tmp, false) + neg.asALU(aluOpSub, rtmp, operandNR(xzrVReg), rtmp, true) m.insert(neg) } // Copy the shift amount into a vector register as sshl/ushl requires it to be there. dup := m.allocateInstr() - dup.asVecDup(tmp, tmp, arr) + dup.asVecDup(vtmp, rtmp, arr) m.insert(dup) if op == ssa.OpcodeVIshl || op == ssa.OpcodeVSshr { sshl := m.allocateInstr() - sshl.asVecRRR(vecOpSshl, rd, rn, tmp, arr) + sshl.asVecRRR(vecOpSshl, rd, rn, vtmp, arr) m.insert(sshl) } else { ushl := m.allocateInstr() - ushl.asVecRRR(vecOpUshl, rd, rn, tmp, arr) + ushl.asVecRRR(vecOpUshl, rd, rn, vtmp, arr) m.insert(ushl) } } diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go index 278bc429..dec0ba74 100644 --- a/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go +++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go @@ -784,35 +784,35 @@ func TestMachine_lowerVShift(t *testing.T) { op: ssa.OpcodeVIshl, arrangement: vecArrangement16B, expectedAsm: ` -and s1?, w15, #0x7 -dup v1?.16b, d1? -sshl x1.16b, x2.16b, v1?.16b +and x1?, x15, #0x7 +dup v2?.16b, x1? +sshl x1.16b, x2.16b, v2?.16b `, - expectedBytes: "e0090012000c014e4144204e", + expectedBytes: "e0094092000c014e4144204e", }, { name: "VSshr", op: ssa.OpcodeVSshr, arrangement: vecArrangement16B, expectedAsm: ` -and s1?, w15, #0x7 -sub s1?, wzr, s1? -dup v1?.16b, d1? -sshl x1.16b, x2.16b, v1?.16b +and x1?, x15, #0x7 +sub x1?, xzr, x1? +dup v2?.16b, x1? +sshl x1.16b, x2.16b, v2?.16b `, - expectedBytes: "e0090012e003004b000c014e4144204e", + expectedBytes: "e0094092e00300cb000c014e4144204e", }, { name: "VUshr", op: ssa.OpcodeVUshr, arrangement: vecArrangement16B, expectedAsm: ` -and s1?, w15, #0x7 -sub s1?, wzr, s1? -dup v1?.16b, d1? -ushl x1.16b, x2.16b, v1?.16b +and x1?, x15, #0x7 +sub x1?, xzr, x1? +dup v2?.16b, x1? +ushl x1.16b, x2.16b, v2?.16b `, - expectedBytes: "e0090012e003004b000c014e4144206e", + expectedBytes: "e0094092e00300cb000c014e4144206e", }, } { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/engine/wazevo/frontend/lower.go b/internal/engine/wazevo/frontend/lower.go index a2506150..0816910e 100644 --- a/internal/engine/wazevo/frontend/lower.go +++ b/internal/engine/wazevo/frontend/lower.go @@ -3097,13 +3097,14 @@ func (c *Compiler) lowerCurrentOpcode() { state.push(ret) case wasm.OpcodeVecV128i8x16Shuffle: state.pc++ + laneIndexes := c.wasmFunctionBody[state.pc : state.pc+16] + state.pc += 15 if state.unreachable { break } v2 := state.pop() v1 := state.pop() - ret := builder.AllocateInstruction().AsShuffle(v1, v2, c.wasmFunctionBody[state.pc:state.pc+16]).Insert(builder).Return() - state.pc += 15 + ret := builder.AllocateInstruction().AsShuffle(v1, v2, laneIndexes).Insert(builder).Return() state.push(ret) case wasm.OpcodeVecI8x16Swizzle: diff --git a/internal/integration_test/fuzzcases/fuzzcases_test.go b/internal/integration_test/fuzzcases/fuzzcases_test.go index e9714385..4c41fa57 100644 --- a/internal/integration_test/fuzzcases/fuzzcases_test.go +++ b/internal/integration_test/fuzzcases/fuzzcases_test.go @@ -545,3 +545,67 @@ func Test1793d(t *testing.T) { require.Equal(t, uint64(0), m.Globals[1].Val) }) } + +// Test1797a tests that i8x16.shl uses the right register types when lowered. +func Test1797a(t *testing.T) { + if !platform.CompilerSupported() { + return + } + run(t, func(t *testing.T, r wazero.Runtime) { + mod, err := r.Instantiate(ctx, getWasmBinary(t, "1797a")) + require.NoError(t, err) + m := mod.(*wasm.ModuleInstance) + res, err := m.ExportedFunction("").Call(ctx) + require.NoError(t, err) + require.Equal(t, uint64(0), res[0]) + }) +} + +// Test1797a tests that i16x8.shr_u uses the right register types when lowered. +func Test1797b(t *testing.T) { + if !platform.CompilerSupported() { + return + } + run(t, func(t *testing.T, r wazero.Runtime) { + mod, err := r.Instantiate(ctx, getWasmBinary(t, "1797b")) + require.NoError(t, err) + m := mod.(*wasm.ModuleInstance) + _, err = m.ExportedFunction("\x00\x00\x00\x00\x00").Call(ctx, 0, 0, 0, 0, 0, 0) + require.NoError(t, err) + require.Equal(t, uint64(2666130977255796624), m.Globals[0].Val) + require.Equal(t, uint64(9223142857682330634), m.Globals[0].ValHi) + }) +} + +// Test1797c tests that the program counter for V128*Shuffle is advanced correctly +// even when an unreachable instruction is present. +func Test1797c(t *testing.T) { + if !platform.CompilerSupported() { + return + } + run(t, func(t *testing.T, r wazero.Runtime) { + mod, err := r.Instantiate(ctx, getWasmBinary(t, "1797c")) + require.NoError(t, err, "wasm binary should build successfully") + m := mod.(*wasm.ModuleInstance) + params := make([]uint64, 20) + _, err = m.ExportedFunction("~zz\x00E1E\x00EE\x00$").Call(ctx, params...) + require.Error(t, err, "wasm error: unreachable") + }) +} + +// Test1797d tests that the registers are allocated correctly in Vbitselect. +func Test1797d(t *testing.T) { + if !platform.CompilerSupported() { + return + } + run(t, func(t *testing.T, r wazero.Runtime) { + mod, err := r.Instantiate(ctx, getWasmBinary(t, "1797d")) + require.NoError(t, err, "wasm binary should build successfully") + m := mod.(*wasm.ModuleInstance) + params := make([]uint64, 20) + _, err = m.ExportedFunction("p").Call(ctx, params...) + require.NoError(t, err) + require.Equal(t, uint64(15092115255309870764), m.Globals[2].Val) + require.Equal(t, uint64(9241386435284803069), m.Globals[2].ValHi) + }) +} diff --git a/internal/integration_test/fuzzcases/testdata/1797a.wasm b/internal/integration_test/fuzzcases/testdata/1797a.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ca3c414dcad06f0233af9477e37ebb091e25b459 GIT binary patch literal 192 zcmZQbEY4+QU|?VrVM$=DXRfcWPhhIAXGmaRtWRKIU}j=uVv}L2X8g+oRD%Mz>lqzi zuyeC>Fad=b4Vf9ZN*Ie68LJ&%U0r>>?l1q}3?&ATt^@VRSb;%-;jiQ0pufi%{~l!g ntH`iw2Lb4G>;M1jtFFG9RJQytKh*H-zi%0p8U6;UFmM9^qs~ZR literal 0 HcmV?d00001 diff --git a/internal/integration_test/fuzzcases/testdata/1797a.wat b/internal/integration_test/fuzzcases/testdata/1797a.wat new file mode 100644 index 00000000..fe2b92dd --- /dev/null +++ b/internal/integration_test/fuzzcases/testdata/1797a.wat @@ -0,0 +1,67 @@ +(module + (type (;0;) (func (param i32) (result i32 i32 i32))) + (type (;1;) (func (param i32 i32))) + (type (;2;) (func (result i32))) + (type (;3;) (func)) + (func (;0;) (type 2) (result i32) + (local v128) + i32.const -353703190 + i8x16.splat + f32x4.floor + local.tee 0 + v128.const i32x4 0x7fc00000 0x7fc00000 0x7fc00000 0x7fc00000 + local.get 0 + local.get 0 + f32x4.eq + v128.bitselect + i64x2.extend_low_i32x4_s + i64x2.neg + f64x2.extract_lane 0 + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + f64.convert_i32_u + i32.trunc_f64_s + i64.const -709973716250918950 + i32.wrap_i64 + i8x16.splat + i32.const -353703190 + i8x16.shl + f64x2.neg + global.get 0 + v128.xor + global.set 0 + ) + (global (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (global (;1;) (mut i32) i32.const 1000) + (export "" (func 0)) + (export "1" (global 0)) +) diff --git a/internal/integration_test/fuzzcases/testdata/1797b.wasm b/internal/integration_test/fuzzcases/testdata/1797b.wasm new file mode 100644 index 0000000000000000000000000000000000000000..20f586e585378f677ef4354bea91791625cfc2c1 GIT binary patch literal 123 zcmZQbEY4+QU|?Y6VoYGG2LlFXCPoG}8K!E+zdS%06u@22==g%2o1KS=6(-Kiz-7v4 y%%IHZ%HqJlt<31in5_cTIYIwF2&izWT$=!5|9!xy!1}kB5lAaD{0&rL;06E~JshS0 literal 0 HcmV?d00001 diff --git a/internal/integration_test/fuzzcases/testdata/1797b.wat b/internal/integration_test/fuzzcases/testdata/1797b.wat new file mode 100644 index 00000000..cafdfa9c --- /dev/null +++ b/internal/integration_test/fuzzcases/testdata/1797b.wat @@ -0,0 +1,17 @@ +(module + (type (;0;) (func (param i32 i32 i32 i32 i32 i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32 i32 i32) + v128.const i32x4 0xffff2f90 0x24ffffff 0x90d6240a 0xffff2f90 + f32x4.abs + local.get 5 + i16x8.shr_u + f32x4.abs + global.get 0 + v128.xor + global.set 0 + ) + (global (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (global (;1;) (mut i32) i32.const 1000) + (export "\00\00\00\00\00" (func 0)) + (export "" (global 0)) +) diff --git a/internal/integration_test/fuzzcases/testdata/1797c.wasm b/internal/integration_test/fuzzcases/testdata/1797c.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4e6782653fc360f2d62db5f03803b5b57453fd16 GIT binary patch literal 389 zcma)%F-rqM6ohAXj~vOao`qncMdbDmsGU_dxR!!HK+sY|8@n^)u1RlUp{12SAhv;P z@+U+@EW|>v45G_=CyFQ{ehiP{F+ApB=Ww3@xWMh%{1>8nCkQD8&{&j5^t#G_L-pB( z%4r{B70*YypJi}M4$i^UL2_AwE0UUQ4TKmHsc=yTDixM{MtB`igiuApH~~Wl?W8Qr zcCzlu5`He~9-m)bJ|Da`QOQ2tj9wak#y|33s{6Xtx=6*=1jbJ_KlyNf-MOW|Ak@Z> x&Z4unTVt}I;q|-!8ZL$3G#I5E7%Dq1PVRd4`fPaLv&Cs{p;U{EC#YVX#v2;pgPZ^W literal 0 HcmV?d00001 diff --git a/internal/integration_test/fuzzcases/testdata/1797c.wat b/internal/integration_test/fuzzcases/testdata/1797c.wat new file mode 100644 index 00000000..335d7458 --- /dev/null +++ b/internal/integration_test/fuzzcases/testdata/1797c.wat @@ -0,0 +1,93 @@ +(module + (type (;0;) (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32 i32 i32 i32))) + (func (;0;) (type 0) (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32 i32 i32 i32) + global.get 2 + i32.eqz + if ;; label = @1 + unreachable + end + global.get 2 + i32.const 1 + i32.sub + global.set 2 + v128.const i32x4 0xff8000ff 0x000000ff 0x000fc5ff 0xffffff01 + local.get 15 + i32.extend8_s + i32.extend8_s + i32.extend8_s + local.get 15 + i32.eq + i32.eqz + i32.extend8_s + i32.extend8_s + unreachable + i8x16.replace_lane 4 + i64.const -585884069744 + data.drop 0 + data.drop 0 + i32.const 1869573999 + i16x8.splat + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + v128.const i32x4 0x45000000 0x0000003a 0x00000000 0x2400f75d + i8x16.shuffle 9 9 9 9 9 9 9 9 9 13 9 9 9 9 9 9 + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f64x2.abs + f32x4.abs + i32x4.extend_low_i16x8_s + unreachable + ) + (func (;1;) (type 0) (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32 i32 i32 i32) + global.get 2 + i32.eqz + if ;; label = @1 + unreachable + end + global.get 2 + i32.const 1 + i32.sub + global.set 2 + block ;; label = @1 + f64.const -0x1.a246969696969p+1016 (;=-1147356289394718200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;) + br 0 (;@1;) + v128.const i32x4 0x69696969 0x69696969 0x69696969 0x45696969 + global.get 0 + v128.xor + global.set 0 + i64.reinterpret_f64 + global.get 1 + i64.xor + global.set 1 + end + i32.const -867893179 + i32.const -858993444 + i32.const -13312 + i32.const 0 + ) + (global (;0;) (mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) + (global (;1;) (mut i64) i64.const 0) + (global (;2;) (mut i32) i32.const 1000) + (export "~zz\00E1E\00EE\00$" (func 0)) + (export "" (func 1)) + (export "2" (global 0)) + (export "3" (global 1)) + (data (;0;) "\f7\00\ff\ff\ff\0e\00") +) \ No newline at end of file diff --git a/internal/integration_test/fuzzcases/testdata/1797d.wasm b/internal/integration_test/fuzzcases/testdata/1797d.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a22947593cd2676b09aee0512282e263c1c5a217 GIT binary patch literal 2968 zcmeI!zfTik7zgmX79?q#=uir@{P@zA@}vB03$*3uwFOFnL01-xolJ}-EJlzvRYT&` z!C>OV#AbA0G!eq!;2+@RWK5i09Q1PDm&evNDG3UwgKyLK?(^Pz&pr3Ny|&8r^;@c< zC~DlY=FHV-H3!#h<(Zpm&T3JWOTqe_swwv4ZbQ`_X3VN)-%=CDhd(vg8=Up(9rLJF zQA1W$4VwWXR;%r?OWk%^qW3Ku$sOaXQS>^KigJ*H6V6pn(c36$L?h)Ax!|IjL``U- znnlfMrdmWTXrbI9H{6s*O?2y6?x&M zd?FuwlwahBpXw5Ip^FNL0tisuqHc6kJ)$1;P`#pF^iqAIKJ-yRQ4m3@U(}C&YCtrA z0cub*h(T&dG=w2)STu}bYD6@G5h^4KAw-2mVT7rOD1rzzDjLNoH6|Lv7&R^$$2b)g zMG>W9q8MUSTogx~nh;H3f|?XfVv?E?O<{_f7ENQCni0)lhME=4VwTcG8Z;^)N+3Zc zMM)&7lqiK1H7Aj`l%U+7sTL>aU5?Kkt-5CA2knnsyJn7uHQOIs)#~b0 zWLSE}{$6EHu0bg`Ca>Q}%f#|pa+xb`q;!YBIQHYYm9tNMt~vdkf-BFDj*j+U`IL3P z;`UketA5M>&Bc_!eZGY~O*HM<{*xD5+Q+v~x9@4YhdbOqEIi_V;r(4Lzx%LY_S=O` M%`pEl*M8Z*1FO