wazevo(arm64): fixes return lowering for float->int order (#2034)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -113,63 +113,74 @@ func (m *machine) LowerParams(args []ssa.Value) {
|
||||
|
||||
// LowerReturns implements backend.Machine.
|
||||
func (m *machine) LowerReturns(rets []ssa.Value) {
|
||||
// Load the XMM registers first as it might need a temporary register to inline
|
||||
// constant return.
|
||||
a := m.currentABI
|
||||
|
||||
l := len(rets) - 1
|
||||
for i := range rets {
|
||||
// Reverse order in order to avoid overwriting the stack returns existing in the return registers.
|
||||
ret := rets[l-i]
|
||||
r := &a.Rets[l-i]
|
||||
reg := m.c.VRegOf(ret)
|
||||
if def := m.c.ValueDefinition(ret); def.IsFromInstr() {
|
||||
// Constant instructions are inlined.
|
||||
if inst := def.Instr; inst.Constant() {
|
||||
m.InsertLoadConstant(inst, reg)
|
||||
}
|
||||
for i, ret := range rets {
|
||||
r := &a.Rets[i]
|
||||
if !r.Type.IsInt() {
|
||||
m.LowerReturn(ret, r)
|
||||
}
|
||||
if r.Kind == backend.ABIArgKindReg {
|
||||
m.InsertMove(r.Reg, reg, ret.Type())
|
||||
} else {
|
||||
//
|
||||
// (high address)
|
||||
// +-----------------+
|
||||
// | ....... |
|
||||
// | ret Y |
|
||||
// | ....... |
|
||||
// | ret 0 |
|
||||
// | arg X |
|
||||
// | ....... |
|
||||
// | arg 1 |
|
||||
// | arg 0 |
|
||||
// | ReturnAddress |
|
||||
// | Caller_RBP |
|
||||
// +-----------------+ <-- RBP
|
||||
// | ........... |
|
||||
// | clobbered M |
|
||||
// | ............ |
|
||||
// | clobbered 0 |
|
||||
// | spill slot N |
|
||||
// | ........... |
|
||||
// | spill slot 0 |
|
||||
// RSP--> +-----------------+
|
||||
// (low address)
|
||||
|
||||
// Store the value to the return stack slot above the current RBP.
|
||||
store := m.allocateInstr()
|
||||
mem := newOperandMem(m.newAmodeImmRBPReg(uint32(a.ArgStackSize + 16 + r.Offset)))
|
||||
switch r.Type {
|
||||
case ssa.TypeI32:
|
||||
store.asMovRM(reg, mem, 4)
|
||||
case ssa.TypeI64:
|
||||
store.asMovRM(reg, mem, 8)
|
||||
case ssa.TypeF32:
|
||||
store.asXmmMovRM(sseOpcodeMovss, reg, mem)
|
||||
case ssa.TypeF64:
|
||||
store.asXmmMovRM(sseOpcodeMovsd, reg, mem)
|
||||
case ssa.TypeV128:
|
||||
store.asXmmMovRM(sseOpcodeMovdqu, reg, mem)
|
||||
}
|
||||
m.insert(store)
|
||||
}
|
||||
// Then load the GPR registers.
|
||||
for i, ret := range rets {
|
||||
r := &a.Rets[i]
|
||||
if r.Type.IsInt() {
|
||||
m.LowerReturn(ret, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *machine) LowerReturn(ret ssa.Value, r *backend.ABIArg) {
|
||||
reg := m.c.VRegOf(ret)
|
||||
if def := m.c.ValueDefinition(ret); def.IsFromInstr() {
|
||||
// Constant instructions are inlined.
|
||||
if inst := def.Instr; inst.Constant() {
|
||||
m.InsertLoadConstant(inst, reg)
|
||||
}
|
||||
}
|
||||
if r.Kind == backend.ABIArgKindReg {
|
||||
m.InsertMove(r.Reg, reg, ret.Type())
|
||||
} else {
|
||||
//
|
||||
// (high address)
|
||||
// +-----------------+
|
||||
// | ....... |
|
||||
// | ret Y |
|
||||
// | ....... |
|
||||
// | ret 0 |
|
||||
// | arg X |
|
||||
// | ....... |
|
||||
// | arg 1 |
|
||||
// | arg 0 |
|
||||
// | ReturnAddress |
|
||||
// | Caller_RBP |
|
||||
// +-----------------+ <-- RBP
|
||||
// | ........... |
|
||||
// | clobbered M |
|
||||
// | ............ |
|
||||
// | clobbered 0 |
|
||||
// | spill slot N |
|
||||
// | ........... |
|
||||
// | spill slot 0 |
|
||||
// RSP--> +-----------------+
|
||||
// (low address)
|
||||
|
||||
// Store the value to the return stack slot above the current RBP.
|
||||
store := m.allocateInstr()
|
||||
mem := newOperandMem(m.newAmodeImmRBPReg(uint32(m.currentABI.ArgStackSize + 16 + r.Offset)))
|
||||
switch r.Type {
|
||||
case ssa.TypeI32:
|
||||
store.asMovRM(reg, mem, 4)
|
||||
case ssa.TypeI64:
|
||||
store.asMovRM(reg, mem, 8)
|
||||
case ssa.TypeF32:
|
||||
store.asXmmMovRM(sseOpcodeMovss, reg, mem)
|
||||
case ssa.TypeF64:
|
||||
store.asXmmMovRM(sseOpcodeMovsd, reg, mem)
|
||||
case ssa.TypeV128:
|
||||
store.asXmmMovRM(sseOpcodeMovdqu, reg, mem)
|
||||
}
|
||||
m.insert(store)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,3 +960,16 @@ func Test2031(t *testing.T) {
|
||||
require.Equal(t, []uint64{2139095040, 9218868437227405312}, res)
|
||||
})
|
||||
}
|
||||
|
||||
func Test2034(t *testing.T) {
|
||||
if !platform.CompilerSupported() {
|
||||
return
|
||||
}
|
||||
run(t, func(t *testing.T, r wazero.Runtime) {
|
||||
mod, err := r.Instantiate(ctx, getWasmBinary(t, "2034"))
|
||||
require.NoError(t, err)
|
||||
res, err := mod.ExportedFunction("").Call(ctx, make([]uint64, 20)...)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []uint64{0xf0f0f280f0f280f, 0x0, 0x0, 0x0, 0x0}, res)
|
||||
})
|
||||
}
|
||||
|
||||
BIN
internal/integration_test/fuzzcases/testdata/2034.wasm
vendored
Normal file
BIN
internal/integration_test/fuzzcases/testdata/2034.wasm
vendored
Normal file
Binary file not shown.
53
internal/integration_test/fuzzcases/testdata/2034.wat
vendored
Normal file
53
internal/integration_test/fuzzcases/testdata/2034.wat
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
(module
|
||||
(func (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i32 i64 i64) (result f64 f32 i64 i64 i64)
|
||||
(local f64 f64 f64)
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 0
|
||||
local.get 6
|
||||
local.set 12
|
||||
f32.const 0x1.f93f78p+8 (;=505.24792;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 15
|
||||
i32.const 1
|
||||
f32.reinterpret_i32
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const 0x1.0b4948p-118 (;=0.000000000000000000000000000000000003141935;)
|
||||
i64.trunc_f32_s
|
||||
local.set 12
|
||||
f32.const 0x0p+0 (;=0;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const -0x1.494948p-54 (;=-0.000000000000000071402575;)
|
||||
i64.trunc_f32_u
|
||||
local.set 12
|
||||
f32.const 0x0p+0 (;=0;)
|
||||
i64.trunc_f32_u
|
||||
local.set 15
|
||||
global.get 0
|
||||
global.set 0
|
||||
f64.const 0x1.f0f280f0f280fp-783 (;=0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038157836926462445;)
|
||||
f32.const 0
|
||||
i64.const 0
|
||||
i64.const 0
|
||||
i64.const 0
|
||||
)
|
||||
(global (;0;) (mut i64) i64.const 0)
|
||||
(export "" (func 0))
|
||||
)
|
||||
Reference in New Issue
Block a user