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:
Takeshi Yoneda
2024-02-09 14:20:59 -08:00
committed by GitHub
parent 939f404470
commit b0b99d0712
4 changed files with 132 additions and 55 deletions

View File

@@ -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)
}
}

View File

@@ -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)
})
}

Binary file not shown.

View 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))
)