/
assembler.go
276 lines (256 loc) · 10.1 KB
/
assembler.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
package x86_64
/*
Instructions
The below instructions implement a simple Instruction interface that allows
them to be combined, optimised and encoded into machine code.
x86_64 is a bit interesting in that instructions with different sets of
operands might require subtly different machine code opcodes, even though
they do the same thing functionally speaking, so the below instructions
make use of a thing called OpcodeMaps that will match the given arguments
to an appropriate opcode. For more on OpcodeMaps see asm/opcodes/
*/
import (
"github.com/bspaans/jit-compiler/asm/x86_64/encoding"
"github.com/bspaans/jit-compiler/asm/x86_64/opcodes"
"github.com/bspaans/jit-compiler/lib"
)
func ADD(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("add", opcodes.ADD, 2, dest, src)
}
func AND(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("and", opcodes.AND, 2, dest, src)
}
func CALL(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("call", opcodes.CALL, 1, dest)
}
func CMP(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("cmp", opcodes.CMP, 2, dest, src)
}
func CMP_immediate(v uint64, dest lib.Operand) lib.Instruction {
if reg, ok := dest.(*encoding.Register); ok && reg.Width() == lib.BYTE {
return CMP(encoding.Uint8(v), dest)
}
return opcodes.OpcodesToInstruction("cmp", opcodes.CMP, 2, dest, encoding.Uint32(v))
}
// Convert signed integer to scalar double-precision floating point (float64)
func CVTSI2SD(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("cvtsi2sd", opcodes.CVTSI2SD, 2, dest, src)
}
// Convert double precision float to signed integer
func CVTTSD2SI(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("cvttsd2si", opcodes.CVTTSD2SI, 2, dest, src)
}
// Convert Byte to Word; al:ah = sign extend(ah)
func CBW() lib.Instruction {
return opcodes.OpcodesToInstruction("cbw", []*encoding.Opcode{opcodes.CBW}, 0)
}
// Convert Word to Doubleword; dx:ax = sign extend(ax)
func CWD() lib.Instruction {
return opcodes.OpcodesToInstruction("cwd", []*encoding.Opcode{opcodes.CWD}, 0)
}
// Convert Double word to Quadword; edx:eax = sign extend(eax)
func CDQ() lib.Instruction {
return opcodes.OpcodesToInstruction("cdq", []*encoding.Opcode{opcodes.CDQ}, 0)
}
// Convert Quad word to double quad word; rdx:rax = sign extend(rax)
func CQO() lib.Instruction {
return opcodes.OpcodesToInstruction("cqo", []*encoding.Opcode{opcodes.CQO}, 0)
}
func DEC(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("dec", opcodes.DEC, 1, dest)
}
func DIV(src lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("div", opcodes.DIV, 1, src)
}
func IDIV1(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("div", opcodes.IDIV1, 1, dest)
}
func IDIV2(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("div", opcodes.IDIV2, 2, dest, src)
}
func INC(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("inc", opcodes.INC, 1, dest)
}
func JA(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("ja", opcodes.JA, 1, dest)
}
func JAE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jae", opcodes.JAE, 1, dest)
}
func JB(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jb", opcodes.JB, 1, dest)
}
func JBE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jbe", opcodes.JBE, 1, dest)
}
func JE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("je", opcodes.JE, 1, dest)
}
func JG(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jg", opcodes.JG, 1, dest)
}
func JGE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jge", opcodes.JGE, 1, dest)
}
func JL(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jl", opcodes.JL, 1, dest)
}
func JLE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jle", opcodes.JLE, 1, dest)
}
func JNA(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jna", opcodes.JNA, 1, dest)
}
func JNAE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnae", opcodes.JNAE, 1, dest)
}
func JNB(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnb", opcodes.JNB, 1, dest)
}
func JNBE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnbe", opcodes.JNBE, 1, dest)
}
func JNE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jne", opcodes.JNE, 1, dest)
}
func JNG(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jng", opcodes.JNG, 1, dest)
}
func JNGE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnge", opcodes.JNGE, 1, dest)
}
func JNL(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnl", opcodes.JNL, 1, dest)
}
func JNLE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jnle", opcodes.JNLE, 1, dest)
}
func JMP(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("jmp", opcodes.JMP, 1, dest)
}
func LEA(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("lea", opcodes.LEA, 2, dest, src)
}
func MOV(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("mov", opcodes.MOV, 2, dest, src)
}
func MOV_immediate(v uint64, dest lib.Operand) lib.Instruction {
if reg, ok := dest.(*encoding.Register); ok && reg.Width() == lib.BYTE {
return MOV(encoding.Uint8(v), dest)
}
if reg, ok := dest.(*encoding.Register); ok && reg.Width() == lib.WORD {
return MOV(encoding.Uint16(v), dest)
}
if v < (1 << 32) {
return MOV(encoding.Uint32(v), dest)
}
return MOV(encoding.Uint64(v), dest)
}
// Move with sign-extend
func MOVSX(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("movsx", opcodes.MOVSX, 2, dest, src)
}
// Move with zero-extend
func MOVZX(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("movzx", opcodes.MOVZX, 2, dest, src)
}
func IMUL1(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("imul", opcodes.IMUL1, 1, dest)
}
func IMUL2(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("imul", opcodes.IMUL2, 2, dest, src)
}
func MUL(src lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("mul", opcodes.MUL, 1, src)
}
func OR(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("or", opcodes.OR, 2, dest, src)
}
func POP(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("pop", opcodes.POP, 1, dest)
}
func PUSH(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("push", opcodes.PUSH, 1, dest)
}
func PUSHFQ() lib.Instruction {
return opcodes.OpcodeToInstruction("pushfq", opcodes.PUSHFQ, 0)
}
func RETURN() lib.Instruction {
return opcodes.OpcodeToInstruction("return", opcodes.RETURN, 0)
}
func SETA(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("seta", opcodes.SETA, 1, dest)
}
func SETAE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setae", opcodes.SETAE, 1, dest)
}
func SETB(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setb", opcodes.SETB, 1, dest)
}
func SETBE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setbe", opcodes.SETBE, 1, dest)
}
func SETC(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setc", opcodes.SETC, 1, dest)
}
func SETE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("sete", opcodes.SETE, 1, dest)
}
func SETL(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setl", opcodes.SETL, 1, dest)
}
func SETLE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setle", opcodes.SETLE, 1, dest)
}
func SETG(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setg", opcodes.SETG, 1, dest)
}
func SETGE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setge", opcodes.SETGE, 1, dest)
}
func SETNE(dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("setne", opcodes.SETNE, 1, dest)
}
func SUB(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("sub", opcodes.SUB, 2, dest, src)
}
func SHL(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("shl", opcodes.SHL, 2, dest, src)
}
func SHR(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("shr", opcodes.SHR, 2, dest, src)
}
func SYSCALL() lib.Instruction {
return opcodes.OpcodeToInstruction("syscall", opcodes.SYSCALL, 0)
}
// Add packed byte integers from op1 (register), and op2 (register or address)
// and store in dest.
func VPADDB(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpaddb", opcodes.VPADDB, 3, dest, op2, op1)
}
// Add packed word integers from op1 (register), and op2 (register or address)
// and store in dest.
func VPADDW(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpaddw", opcodes.VPADDW, 3, dest, op2, op1)
}
// Add packed double integers from op1 (register), and op2 (register or address)
// and store in dest.
func VPADDD(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpaddd", opcodes.VPADDD, 3, dest, op2, op1)
}
// Add packed quadword integers from op1 (register), and op2 (register or address)
// and store in dest.
func VPADDQ(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpaddq", opcodes.VPADDD, 3, dest, op2, op1)
}
// Bitwise AND of op1 and op2, store result in dest.
func VPAND(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpand", opcodes.VPAND, 3, dest, op2, op1)
}
// Bitwise OR of op1 and op2, store result in dest.
func VPOR(op1, op2, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("vpor", opcodes.VPOR, 3, dest, op2, op1)
}
func XOR(src, dest lib.Operand) lib.Instruction {
return opcodes.OpcodesToInstruction("xor", opcodes.XOR, 2, dest, src)
}