/
memory.go
109 lines (86 loc) · 2.87 KB
/
memory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright (c) 2018 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm
import (
"github.com/tsavola/wag/internal/gen"
"github.com/tsavola/wag/internal/gen/operand"
"github.com/tsavola/wag/internal/gen/reg"
"github.com/tsavola/wag/internal/gen/storage"
"github.com/tsavola/wag/internal/isa/arm/in"
"github.com/tsavola/wag/trap"
"github.com/tsavola/wag/wa"
)
func (MacroAssembler) Load(f *gen.Func, props uint16, index operand.O, resultType wa.Type, align, offset uint32) operand.O {
var o outbuf
r := f.Regs.AllocResult(resultType)
o.access(f, in.Memory(props), r, index, offset)
o.copy(f.Text.Extend(o.size))
return operand.Reg(resultType, r)
}
func (MacroAssembler) Store(f *gen.Func, props uint16, index, x operand.O, align, offset uint32) {
var o outbuf
r := RegZero
if !(x.Storage == storage.Imm && x.ImmValue() == 0) {
r = RegResult
o.move(f, r, x)
}
o.access(f, in.Memory(props), r, index, offset)
o.copy(f.Text.Extend(o.size))
}
func (o *outbuf) access(f *gen.Func, op in.Memory, dataReg reg.R, index operand.O, offset uint32) {
if offset >= 0x80000000 {
f.ValueBecameUnreachable(index)
asm.Trap(f, trap.MemoryAccessOutOfBounds)
return
}
switch index.Storage {
case storage.Imm:
value := uint64(index.ImmValue())
addr := value + uint64(offset)
if value >= 0x80000000 || addr >= 0x80000000 {
asm.Trap(f, trap.MemoryAccessOutOfBounds)
return
}
switch {
case addr <= 255:
o.insn(op.OpcodeUnscaled().RtRnI9(dataReg, RegMemoryBase, uint32(addr)))
default:
o.moveUintImm32(RegScratch, uint32(addr))
o.insn(op.OpcodeReg().RtRnSOptionRm(dataReg, RegMemoryBase, in.Unscaled, in.UXTW, RegScratch))
}
default:
r := o.getScratchReg(f, index)
if offset < 1<<24 {
imm := uint64(offset)
if imm != 0 {
o.insn(in.ADDi.RdRnI12S2(r, r, in.Uint12(imm), 0, wa.Size32))
}
imm >>= 12
if imm != 0 {
o.insn(in.ADDi.RdRnI12S2(r, r, in.Uint12(imm), 1, wa.Size32))
}
} else {
o.moveUintImm32(RegScratch2, offset)
o.insn(in.ADDs.RdRnI6RmS2(r, r, 0, RegScratch2, 0, wa.Size32))
}
// UXTW masks index register unconditionally.
o.insn(op.OpcodeReg().RtRnSOptionRm(dataReg, RegMemoryBase, in.Unscaled, in.UXTW, r))
f.Regs.Free(wa.I32, r)
}
f.MapTrapAddr(o.addr(&f.Text)) // Address of instruction pointer during SIGSEGV handling.
}
func (MacroAssembler) CurrentMemory(f *gen.Func) int32 {
var o outbuf
o.insn(in.LDUR.RtRnI9(RegScratch, RegTextBase, in.Int9(gen.VectorOffsetCurrentMemory), wa.I64))
o.insn(in.BLR.Rn(RegScratch))
o.copy(f.Text.Extend(o.size))
return f.Text.Addr
}
func (MacroAssembler) GrowMemory(f *gen.Func) int32 {
var o outbuf
o.insn(in.LDUR.RtRnI9(RegScratch, RegTextBase, in.Int9(gen.VectorOffsetGrowMemory), wa.I64))
o.insn(in.BLR.Rn(RegScratch))
o.copy(f.Text.Extend(o.size))
return f.Text.Addr
}