1 package amd64
2
3 import (
4 "fmt"
5 "math"
6
7 "github.com/tetratelabs/wazero/internal/asm"
8 )
9
10
11
12
13 const defaultMaxDisplacementForConstantPool = 1 << 30
14
15 func (a *AssemblerImpl) maybeFlushConstants(buf asm.Buffer, isEndOfFunction bool) {
16 if a.pool.Empty() {
17 return
18 }
19
20 if isEndOfFunction ||
21
22
23
24 ((a.pool.PoolSizeInBytes+buf.Len())-int(a.pool.FirstUseOffsetInBinary)) >= a.MaxDisplacementForConstantPool {
25
26 if !isEndOfFunction {
27
28
29
30
31 if a.pool.PoolSizeInBytes >= math.MaxInt8-2 {
32
33 buf.AppendByte(0xe9)
34 buf.AppendUint32(uint32(a.pool.PoolSizeInBytes))
35 } else {
36
37 buf.AppendByte(0xeb)
38 buf.AppendByte(byte(a.pool.PoolSizeInBytes))
39 }
40 }
41
42 for _, c := range a.pool.Consts {
43 c.SetOffsetInBinary(uint64(buf.Len()))
44 buf.AppendBytes(c.Raw)
45 }
46
47 a.pool.Reset()
48 }
49 }
50
51 func (a *AssemblerImpl) encodeRegisterToStaticConst(buf asm.Buffer, n *nodeImpl) (err error) {
52 var opc []byte
53 var rex byte
54 switch n.instruction {
55 case CMPL:
56 opc, rex = []byte{0x3b}, rexPrefixNone
57 case CMPQ:
58 opc, rex = []byte{0x3b}, rexPrefixW
59 default:
60 return errorEncodingUnsupported(n)
61 }
62 return a.encodeStaticConstImpl(buf, n, opc, rex, 0)
63 }
64
65 var staticConstToRegisterOpcodes = [...]struct {
66 opcode, vopcode []byte
67 mandatoryPrefix, vmandatoryPrefix byte
68 rex rexPrefix
69 }{
70
71 MOVDQU: {mandatoryPrefix: 0xf3, opcode: []byte{0x0f, 0x6f}},
72
73 LEAQ: {opcode: []byte{0x8d}, rex: rexPrefixW},
74
75 MOVUPD: {mandatoryPrefix: 0x66, opcode: []byte{0x0f, 0x10}},
76
77 MOVL: {opcode: []byte{0x8b}, vopcode: []byte{0x0f, 0x6e}, vmandatoryPrefix: 0x66},
78 MOVQ: {opcode: []byte{0x8b}, rex: rexPrefixW, vopcode: []byte{0x0f, 0x7e}, vmandatoryPrefix: 0xf3},
79
80 UCOMISD: {opcode: []byte{0x0f, 0x2e}, mandatoryPrefix: 0x66},
81
82 UCOMISS: {opcode: []byte{0x0f, 0x2e}},
83
84 SUBSS: {opcode: []byte{0x0f, 0x5c}, mandatoryPrefix: 0xf3},
85
86 SUBSD: {opcode: []byte{0x0f, 0x5c}, mandatoryPrefix: 0xf2},
87
88 CMPL: {opcode: []byte{0x39}},
89 CMPQ: {opcode: []byte{0x39}, rex: rexPrefixW},
90
91 ADDL: {opcode: []byte{0x03}},
92 ADDQ: {opcode: []byte{0x03}, rex: rexPrefixW},
93 }
94
95 func (a *AssemblerImpl) encodeStaticConstToRegister(buf asm.Buffer, n *nodeImpl) (err error) {
96 var opc []byte
97 var rex, mandatoryPrefix byte
98 info := staticConstToRegisterOpcodes[n.instruction]
99 switch n.instruction {
100 case MOVL, MOVQ:
101 if isVectorRegister(n.dstReg) {
102 opc, mandatoryPrefix = info.vopcode, info.vmandatoryPrefix
103 break
104 }
105 fallthrough
106 default:
107 opc, rex, mandatoryPrefix = info.opcode, info.rex, info.mandatoryPrefix
108 }
109 return a.encodeStaticConstImpl(buf, n, opc, rex, mandatoryPrefix)
110 }
111
112
113
114 func (a *AssemblerImpl) encodeStaticConstImpl(buf asm.Buffer, n *nodeImpl, opcode []byte, rex rexPrefix, mandatoryPrefix byte) error {
115 a.pool.AddConst(n.staticConst, uint64(buf.Len()))
116
117 var reg asm.Register
118 if n.dstReg != asm.NilRegister {
119 reg = n.dstReg
120 } else {
121 reg = n.srcReg
122 }
123
124 reg3Bits, rexPrefix := register3bits(reg, registerSpecifierPositionModRMFieldReg)
125 rexPrefix |= rex
126
127 base := buf.Len()
128 code := buf.Append(len(opcode) + 7)[:0]
129
130 if mandatoryPrefix != 0 {
131 code = append(code, mandatoryPrefix)
132 }
133
134 if rexPrefix != rexPrefixNone {
135 code = append(code, rexPrefix)
136 }
137
138 code = append(code, opcode...)
139
140
141 modRM := 0b00_000_101 |
142 (reg3Bits << 3)
143 code = append(code, modRM)
144
145
146 code = append(code, 0, 0, 0, 0)
147
148 if !n.staticConstReferrersAdded {
149 a.staticConstReferrers = append(a.staticConstReferrers, staticConstReferrer{n: n, instLen: len(code)})
150 n.staticConstReferrersAdded = true
151 }
152
153 buf.Truncate(base + len(code))
154 return nil
155 }
156
157
158 func (a *AssemblerImpl) CompileStaticConstToRegister(instruction asm.Instruction, c *asm.StaticConst, dstReg asm.Register) (err error) {
159 if len(c.Raw)%2 != 0 {
160 err = fmt.Errorf("the length of a static constant must be even but was %d", len(c.Raw))
161 return
162 }
163
164 n := a.newNode(instruction, operandTypesStaticConstToRegister)
165 n.dstReg = dstReg
166 n.staticConst = c
167 return
168 }
169
170
171 func (a *AssemblerImpl) CompileRegisterToStaticConst(instruction asm.Instruction, srcReg asm.Register, c *asm.StaticConst) (err error) {
172 if len(c.Raw)%2 != 0 {
173 err = fmt.Errorf("the length of a static constant must be even but was %d", len(c.Raw))
174 return
175 }
176
177 n := a.newNode(instruction, operandTypesRegisterToStaticConst)
178 n.srcReg = srcReg
179 n.staticConst = c
180 return
181 }
182
View as plain text