1 |
/* |
2 |
* md_amd64.h - Machine-dependent definitions for x86_64 (AMD64/EM64T). |
3 |
* |
4 |
* Copyright (C) 2003,2005 Southern Storm Software, Pty Ltd. |
5 |
* |
6 |
* This program is free software; you can redistribute it and/or modify |
7 |
* it under the terms of the GNU General Public License as published by |
8 |
* the Free Software Foundation; either version 2 of the License, or |
9 |
* (at your option) any later version. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
*/ |
20 |
|
21 |
#ifndef _ENGINE_MD_AMD64_H |
22 |
#define _ENGINE_MD_AMD64_H |
23 |
|
24 |
#include "amd64_codegen.h" |
25 |
|
26 |
#ifdef __cplusplus |
27 |
extern "C" { |
28 |
#endif |
29 |
|
30 |
/* |
31 |
* Register numbers in the standard register allocation order. |
32 |
* -1 is the list terminator. |
33 |
*/ |
34 |
#define MD_REG_0 AMD64_RAX |
35 |
#define MD_REG_1 AMD64_RCX |
36 |
#define MD_REG_2 AMD64_RBP |
37 |
#define MD_REG_3 AMD64_RBX |
38 |
#define MD_REG_4 AMD64_RDX |
39 |
#define MD_REG_5 AMD64_RSI |
40 |
#define MD_REG_6 AMD64_RDI |
41 |
#define MD_REG_7 -1 |
42 |
#define MD_REG_8 -1 |
43 |
#define MD_REG_9 -1 |
44 |
#define MD_REG_10 -1 |
45 |
#define MD_REG_11 -1 |
46 |
#define MD_REG_12 -1 |
47 |
#define MD_REG_13 -1 |
48 |
#define MD_REG_14 -1 |
49 |
#define MD_REG_15 -1 |
50 |
|
51 |
/* |
52 |
* Mask that indicates a floating-point register. |
53 |
*/ |
54 |
#define MD_FREG_MASK 0x0010 |
55 |
|
56 |
/* |
57 |
* Floating point register numbers in the standard allocation order. |
58 |
* -1 is the list terminator. The floating point register numbers |
59 |
* must include the MD_FREG_MASK value. |
60 |
*/ |
61 |
//#define MD_FREG_0 (MD_FREG_MASK | 0) |
62 |
#define MD_FREG_0 -1 /* TODO: implement FPU support */ |
63 |
#define MD_FREG_1 (MD_FREG_MASK | 1) |
64 |
#define MD_FREG_2 (MD_FREG_MASK | 2) |
65 |
#define MD_FREG_3 (MD_FREG_MASK | 3) |
66 |
#define MD_FREG_4 (MD_FREG_MASK | 4) |
67 |
#define MD_FREG_5 (MD_FREG_MASK | 5) |
68 |
#define MD_FREG_6 (MD_FREG_MASK | 6) |
69 |
#define MD_FREG_7 (MD_FREG_MASK | 7) |
70 |
#define MD_FREG_8 -1 |
71 |
#define MD_FREG_9 -1 |
72 |
#define MD_FREG_10 -1 |
73 |
#define MD_FREG_11 -1 |
74 |
#define MD_FREG_12 -1 |
75 |
#define MD_FREG_13 -1 |
76 |
#define MD_FREG_14 -1 |
77 |
#define MD_FREG_15 -1 |
78 |
|
79 |
/* |
80 |
* Set this to a non-zero value if floating-point registers are organised |
81 |
* in a stack (e.g. the x87 FPU). |
82 |
*/ |
83 |
#define MD_FP_STACK_SIZE 0 |
84 |
|
85 |
/* |
86 |
* The register that contains the CVM program counter. This may be |
87 |
* present in the standard register allocation order. This can be |
88 |
* set to -1 if MD_STATE_ALREADY_IN_REGS is 0. |
89 |
*/ |
90 |
#define MD_REG_PC AMD64_R12 |
91 |
|
92 |
/* |
93 |
* The register that contains the CVM stacktop pointer. This must not |
94 |
* be present in the standard register allocation order. |
95 |
*/ |
96 |
#define MD_REG_STACK AMD64_R14 |
97 |
|
98 |
/* |
99 |
* The register that contains the CVM frame pointer. This must not |
100 |
* be present in the standard register allocation order. |
101 |
*/ |
102 |
#define MD_REG_FRAME AMD64_R15 |
103 |
|
104 |
/* |
105 |
* Set this to 1 if "pc", "stacktop", and "frame" are already in |
106 |
* the above registers when unrolled code is entered. i.e. the |
107 |
* CVM interpreter has manual assignments of registers to variables |
108 |
* in the file "cvm.c". If the state is not already in registers, |
109 |
* then set this value to zero. |
110 |
*/ |
111 |
#define MD_STATE_ALREADY_IN_REGS 1 |
112 |
|
113 |
/* |
114 |
* Registers that must be saved on the system stack prior to their use |
115 |
* in unrolled code for temporary stack values. |
116 |
*/ |
117 |
#define MD_REGS_TO_BE_SAVED (1 << AMD64_RBP) |
118 |
|
119 |
/* |
120 |
* Registers with special meanings (pc, stacktop, frame) that must |
121 |
* be saved if MD_STATE_ALREADY_IN_REGS is 0. |
122 |
*/ |
123 |
#define MD_SPECIAL_REGS_TO_BE_SAVED 0 |
124 |
|
125 |
/* |
126 |
* Floating-point register numbers that must be saved. |
127 |
*/ |
128 |
#define MD_FREGS_TO_BE_SAVED 0 |
129 |
|
130 |
/* |
131 |
* Set this to 1 if the CPU has integer division operations. |
132 |
* Set it to zero if integer division is too hard to be performed |
133 |
* inline using a simple opcode. |
134 |
*/ |
135 |
#define MD_HAS_INT_DIVISION 0 |
136 |
|
137 |
/* |
138 |
* Set to 1 if 64-bit register pairs are stored in little-endian order. |
139 |
*/ |
140 |
#define MD_LITTLE_ENDIAN_LONGS 0 |
141 |
|
142 |
/* |
143 |
* Type of the instruction pointer for outputting code. |
144 |
*/ |
145 |
typedef unsigned char *md_inst_ptr; |
146 |
|
147 |
/* |
148 |
* Trap TODO code while executing |
149 |
*/ |
150 |
|
151 |
#define TODO_trap(inst) \ |
152 |
do { \ |
153 |
amd64_breakpoint_size((inst), 8); \ |
154 |
}while(0) |
155 |
|
156 |
/* |
157 |
* Push a word register onto the system stack. |
158 |
*/ |
159 |
#define md_push_reg(inst,reg) amd64_push_reg((inst), (reg)) |
160 |
|
161 |
/* |
162 |
* Pop a word register from the system stack. |
163 |
*/ |
164 |
#define md_pop_reg(inst,reg) amd64_pop_reg((inst), (reg)) |
165 |
|
166 |
/* |
167 |
* Discard the contents of a floating-point register. |
168 |
*/ |
169 |
#define md_discard_freg(inst,reg) do { ; } while (0) |
170 |
|
171 |
/* |
172 |
* Load a 32-bit integer constant into a register. This will sign-extend |
173 |
* if the native word size is larger. |
174 |
*/ |
175 |
#define md_load_const_32(inst,reg,value) \ |
176 |
amd64_mov_reg_imm_size((inst), (reg), (value), 4) |
177 |
|
178 |
/* |
179 |
* Load a native integer constant into a register. |
180 |
*/ |
181 |
#define md_load_const_native(inst,reg,value) \ |
182 |
amd64_mov_reg_imm_size((inst), (reg), (value), 8) |
183 |
|
184 |
/* |
185 |
* Load a 32-bit floating-point constant into a register. The constant |
186 |
* is at a particular memory location. If the system does not use |
187 |
* floating-point registers, then load onto the top of the stack. |
188 |
*/ |
189 |
#define md_load_const_float_32(inst,reg,mem) \ |
190 |
x86_fld((inst), (int)(mem), 0) |
191 |
|
192 |
/* |
193 |
* Load a 64-bit floating-point constant into a register. The constant |
194 |
* is at a particular memory location. If the system does not use |
195 |
* floating-point registers, then load onto the top of the stack. |
196 |
*/ |
197 |
#define md_load_const_float_64(inst,reg,mem) \ |
198 |
x86_fld((inst), (int)(mem), 1) |
199 |
|
200 |
/* |
201 |
* Load the 32-bit constant zero into a register. This will zero-extend |
202 |
* if the native word size is larger. |
203 |
*/ |
204 |
#define md_load_zero_32(inst,reg) \ |
205 |
amd64_clear_reg_size((inst), (reg), 4) |
206 |
|
207 |
/* |
208 |
* Load the native constant zero into a register. |
209 |
*/ |
210 |
#define md_load_zero_native(inst,reg) \ |
211 |
amd64_clear_reg((inst), (reg)) |
212 |
|
213 |
/* |
214 |
* Load a 32-bit word register from an offset from a pointer register. |
215 |
* This will sign-extend if the native word size is larger. |
216 |
*/ |
217 |
#define md_load_membase_word_32(inst,reg,basereg,offset) \ |
218 |
amd64_mov_reg_membase((inst), (reg), (basereg), (offset), 4) |
219 |
|
220 |
/* |
221 |
* Load a native-sized word register from an offset from a pointer register. |
222 |
*/ |
223 |
#define md_load_membase_word_native(inst,reg,basereg,offset) \ |
224 |
amd64_mov_reg_membase((inst), (reg), (basereg), (offset), 8) |
225 |
|
226 |
/* |
227 |
* Load a 64-bit word register from an offset from a pointer register |
228 |
* into a pair of 32-bit registers. Only used on 32-bit systems. |
229 |
*/ |
230 |
#define md_load_membase_word_64(inst,lreg,hreg,basereg,offset) \ |
231 |
do { \ |
232 |
TODO_trap(inst);\ |
233 |
} while (0) |
234 |
|
235 |
/* |
236 |
* Load a byte value from an offset from a pointer register. |
237 |
*/ |
238 |
#define md_load_membase_byte(inst,reg,basereg,offset) \ |
239 |
amd64_widen_membase((inst), (reg), (basereg), (offset), 0, 0) |
240 |
|
241 |
/* |
242 |
* Load a signed byte value from an offset from a pointer register. |
243 |
*/ |
244 |
#define md_load_membase_sbyte(inst,reg,basereg,offset) \ |
245 |
amd64_widen_membase((inst), (reg), (basereg), (offset), 1, 0) |
246 |
|
247 |
/* |
248 |
* Load a short value from an offset from a pointer register. |
249 |
*/ |
250 |
#define md_load_membase_short(inst,reg,basereg,offset) \ |
251 |
amd64_widen_membase((inst), (reg), (basereg), (offset), 1, 1) |
252 |
|
253 |
/* |
254 |
* Load an unsigned short value from an offset from a pointer register. |
255 |
*/ |
256 |
#define md_load_membase_ushort(inst,reg,basereg,offset) \ |
257 |
amd64_widen_membase((inst), (reg), (basereg), (offset), 0, 1) |
258 |
|
259 |
/* |
260 |
* Load a floating-point value from an offset from a pointer register. |
261 |
* If the system uses floating-point registers, then the value is |
262 |
* loaded into "reg". Otherwise it is loaded onto the top of the |
263 |
* floating-point stack. |
264 |
*/ |
265 |
#define md_load_membase_float_32(inst,reg,basereg,offset) \ |
266 |
x86_fld_membase((inst), (basereg), (offset), 0) |
267 |
#define md_load_membase_float_64(inst,reg,basereg,offset) \ |
268 |
x86_fld_membase((inst), (basereg), (offset), 1) |
269 |
#define md_load_membase_float_native(inst,reg,basereg,offset) \ |
270 |
x86_fld80_membase((inst), (basereg), (offset)) |
271 |
|
272 |
/* |
273 |
* Store a 32-bit word register to an offset from a pointer register. |
274 |
*/ |
275 |
#define md_store_membase_word_32(inst,reg,basereg,offset) \ |
276 |
amd64_mov_membase_reg((inst), (basereg), (offset), (reg), 4) |
277 |
|
278 |
/* |
279 |
* Store a native-sized word register to an offset from a pointer register. |
280 |
*/ |
281 |
#define md_store_membase_word_native(inst,reg,basereg,offset) \ |
282 |
amd64_mov_membase_reg((inst), (basereg), (offset), (reg), 8) |
283 |
|
284 |
/* |
285 |
* Store a pair of 32-bit word registers to an offset from a pointer |
286 |
* register as a 64-bit value. Only used on 32-bit systems. |
287 |
*/ |
288 |
#define md_store_membase_word_64(inst,lreg,hreg,basereg,offset) \ |
289 |
do { \ |
290 |
TODO_trap(inst);\ |
291 |
} while (0) |
292 |
|
293 |
/* |
294 |
* Store a byte value to an offset from a pointer register. |
295 |
*/ |
296 |
md_inst_ptr _md_x86_mov_membase_reg_byte |
297 |
(md_inst_ptr inst, int basereg, int offset, int srcreg); |
298 |
#define md_store_membase_byte(inst,reg,basereg,offset) \ |
299 |
do { \ |
300 |
(inst) = _md_x86_mov_membase_reg_byte \ |
301 |
((inst), (basereg), (int)(offset), (reg)); \ |
302 |
} while (0) |
303 |
|
304 |
/* |
305 |
* Store a signed byte value to an offset from a pointer register. |
306 |
*/ |
307 |
#define md_store_membase_sbyte(inst,reg,basereg,offset) \ |
308 |
md_store_membase_byte((inst), (reg), (basereg), (offset)) |
309 |
|
310 |
/* |
311 |
* Store a short value to an offset from a pointer register. |
312 |
*/ |
313 |
#define md_store_membase_short(inst,reg,basereg,offset) \ |
314 |
x86_mov_membase_reg((inst), (basereg), (offset), (reg), 2) |
315 |
|
316 |
/* |
317 |
* Store an unsigned short value to an offset from a pointer register. |
318 |
*/ |
319 |
#define md_store_membase_ushort(inst,reg,basereg,offset) \ |
320 |
x86_mov_membase_reg((inst), (basereg), (offset), (reg), 2) |
321 |
|
322 |
/* |
323 |
* Store a floating-point value to an offset from a pointer register. |
324 |
* If the system uses floating-point registers, then the value is |
325 |
* stored from "reg". Otherwise it is stored from the top of the |
326 |
* floating-point stack. |
327 |
*/ |
328 |
#define md_store_membase_float_32(inst,reg,basereg,offset) \ |
329 |
x86_fst_membase((inst), (basereg), (offset), 0, 1) |
330 |
#define md_store_membase_float_64(inst,reg,basereg,offset) \ |
331 |
x86_fst_membase((inst), (basereg), (offset), 1, 1) |
332 |
#define md_store_membase_float_native(inst,reg,basereg,offset) \ |
333 |
x86_fst80_membase((inst), (basereg), (offset)) |
334 |
|
335 |
/* |
336 |
* Add an immediate value to a register. |
337 |
*/ |
338 |
#define md_add_reg_imm(inst,reg,imm) \ |
339 |
amd64_alu_reg_imm_size((inst), X86_ADD, (reg), (imm), 8) |
340 |
|
341 |
/* |
342 |
* Subtract an immediate value from a register. |
343 |
*/ |
344 |
#define md_sub_reg_imm(inst,reg,imm) \ |
345 |
amd64_alu_reg_imm_size((inst), X86_SUB, (reg), (imm), 8) |
346 |
|
347 |
/* |
348 |
* Perform arithmetic and logical operations on 32-bit word registers. |
349 |
* |
350 |
* Division is tricky, so it is handled elsewhere for x86. |
351 |
*/ |
352 |
#define md_add_reg_reg_word_32(inst,reg1,reg2) \ |
353 |
amd64_alu_reg_reg_size((inst), X86_ADD, (reg1), (reg2), 4) |
354 |
#define md_sub_reg_reg_word_32(inst,reg1,reg2) \ |
355 |
amd64_alu_reg_reg_size((inst), X86_SUB, (reg1), (reg2), 4) |
356 |
#define md_mul_reg_reg_word_32(inst,reg1,reg2) \ |
357 |
amd64_imul_reg_reg_size((inst), (reg1), (reg2), 4) |
358 |
extern md_inst_ptr _md_x86_divide(md_inst_ptr inst, int reg1, int reg2, |
359 |
int isSigned, int wantRemainder); |
360 |
#define md_div_reg_reg_word_32(inst,reg1,reg2) \ |
361 |
do { ; } while (0) |
362 |
#define md_udiv_reg_reg_word_32(inst,reg1,reg2) \ |
363 |
do { ; } while (0) |
364 |
#define md_rem_reg_reg_word_32(inst,reg1,reg2) \ |
365 |
do { ; } while (0) |
366 |
#define md_urem_reg_reg_word_32(inst,reg1,reg2) \ |
367 |
do { ; } while (0) |
368 |
#define md_neg_reg_word_32(inst,reg) \ |
369 |
amd64_neg_reg_size((inst), (reg), 4) |
370 |
#define md_and_reg_reg_word_32(inst,reg1,reg2) \ |
371 |
amd64_alu_reg_reg_size((inst), X86_AND, (reg1), (reg2), 4) |
372 |
#define md_xor_reg_reg_word_32(inst,reg1,reg2) \ |
373 |
amd64_alu_reg_reg_size((inst), X86_XOR, (reg1), (reg2), 4) |
374 |
#define md_or_reg_reg_word_32(inst,reg1,reg2) \ |
375 |
amd64_alu_reg_reg_size((inst), X86_OR, (reg1), (reg2), 4) |
376 |
#define md_not_reg_word_32(inst,reg) \ |
377 |
amd64_not_reg_size((inst), (reg), 4) |
378 |
extern md_inst_ptr _md_x86_shift(md_inst_ptr inst, int opc, int reg1, int reg2); |
379 |
#define md_shl_reg_reg_word_32(inst,reg1,reg2) \ |
380 |
do { (inst) = _md_x86_shift \ |
381 |
((inst), X86_SHL, (reg1), (reg2)); } while (0) |
382 |
#define md_shr_reg_reg_word_32(inst,reg1,reg2) \ |
383 |
do { (inst) = _md_x86_shift \ |
384 |
((inst), X86_SAR, (reg1), (reg2)); } while (0) |
385 |
#define md_ushr_reg_reg_word_32(inst,reg1,reg2) \ |
386 |
do { (inst) = _md_x86_shift \ |
387 |
((inst), X86_SHR, (reg1), (reg2)); } while (0) |
388 |
/* |
389 |
* Perform arithmetic on native word values |
390 |
*/ |
391 |
|
392 |
#define md_add_reg_reg_word_native(inst,reg1,reg2) \ |
393 |
amd64_alu_reg_reg_size((inst), X86_ADD, (reg1), (reg2), 8) |
394 |
#define md_sub_reg_reg_word_native(inst,reg1,reg2) \ |
395 |
amd64_alu_reg_reg_size((inst), X86_SUB, (reg1), (reg2), 8) |
396 |
#define md_neg_reg_word_native(inst,reg) \ |
397 |
amd64_neg_reg((inst), (reg)) |
398 |
#define md_and_reg_reg_word_native(inst,reg1,reg2) \ |
399 |
amd64_alu_reg_reg_size((inst), X86_AND, (reg1), (reg2), 8) |
400 |
#define md_xor_reg_reg_word_native(inst,reg1,reg2) \ |
401 |
amd64_alu_reg_reg_size((inst), X86_XOR, (reg1), (reg2), 8) |
402 |
#define md_or_reg_reg_word_native(inst,reg1,reg2) \ |
403 |
amd64_alu_reg_reg_size((inst), X86_OR, (reg1), (reg2), 8) |
404 |
#define md_not_reg_word_native(inst,reg) \ |
405 |
amd64_not_reg((inst), (reg)) |
406 |
|
407 |
/* |
408 |
* Perform arithmetic on 64-bit values represented as 32-bit word pairs. |
409 |
*/ |
410 |
#define md_add_reg_reg_word_64(inst,lreg1,hreg1,lreg2,hreg2) \ |
411 |
do { \ |
412 |
TODO_trap(inst); \ |
413 |
} while (0) |
414 |
#define md_sub_reg_reg_word_64(inst,lreg1,hreg1,lreg2,hreg2) \ |
415 |
do { \ |
416 |
TODO_trap(inst); \ |
417 |
} while (0) |
418 |
#define md_neg_reg_word_64(inst,lreg,hreg) \ |
419 |
do { \ |
420 |
TODO_trap(inst); \ |
421 |
} while (0) |
422 |
|
423 |
/* |
424 |
* Perform arithmetic operations on native float values. If the system |
425 |
* uses a floating-point stack, then the register arguments are ignored. |
426 |
* |
427 |
* Note: x86 remainder is handled elsewhere because it is complicated. |
428 |
*/ |
429 |
#define md_add_reg_reg_float(inst,reg1,reg2) \ |
430 |
x86_fp_op_reg((inst), X86_FADD, 1, 1) |
431 |
#define md_sub_reg_reg_float(inst,reg1,reg2) \ |
432 |
x86_fp_op_reg((inst), X86_FSUB, 1, 1) |
433 |
#define md_mul_reg_reg_float(inst,reg1,reg2) \ |
434 |
x86_fp_op_reg((inst), X86_FMUL, 1, 1) |
435 |
#define md_div_reg_reg_float(inst,reg1,reg2) \ |
436 |
x86_fp_op_reg((inst), X86_FDIV, 1, 1) |
437 |
extern md_inst_ptr _md_x86_rem_float |
438 |
(md_inst_ptr inst, int reg1, int reg2, int used); |
439 |
#define md_rem_reg_reg_float(inst,reg1,reg2,used) \ |
440 |
do { (inst) = _md_x86_rem_float \ |
441 |
((inst), (reg1), (reg2), (used)); } while (0) |
442 |
#define md_neg_reg_float(inst,reg) \ |
443 |
x86_fchs((inst)) |
444 |
|
445 |
/* |
446 |
* Compare two floating point values and produce a -1, 0, or 1 result. |
447 |
*/ |
448 |
extern md_inst_ptr _md_x86_cmp_float(md_inst_ptr inst, int dreg, int lessop); |
449 |
#define md_cmp_reg_reg_float(inst, dreg, sreg1, sreg2, lessop) \ |
450 |
do { \ |
451 |
(inst) = _md_x86_cmp_float((inst), (dreg), (lessop)); \ |
452 |
} while (0) |
453 |
|
454 |
/* |
455 |
* Convert word registers between various types. |
456 |
*/ |
457 |
extern md_inst_ptr _md_x86_widen_byte(md_inst_ptr inst, int reg, int isSigned); |
458 |
#define md_reg_to_byte(inst,reg) \ |
459 |
do { \ |
460 |
(inst) = _md_x86_widen_byte((inst), (reg), 0); \ |
461 |
} while (0) |
462 |
#define md_reg_to_sbyte(inst,reg) \ |
463 |
do { \ |
464 |
(inst) = _md_x86_widen_byte((inst), (reg), 1); \ |
465 |
} while (0) |
466 |
#define md_reg_to_short(inst,reg) \ |
467 |
amd64_widen_reg((inst), (reg), (reg), 1, 1) |
468 |
#define md_reg_to_ushort(inst,reg) \ |
469 |
amd64_widen_reg((inst), (reg), (reg), 0, 1) |
470 |
#define md_reg_to_word_32(inst,reg) \ |
471 |
amd64_mov_reg_reg((inst), (reg), (reg), 4) |
472 |
#define md_reg_to_word_native(inst,reg) \ |
473 |
amd64_movxsd_reg_reg((inst), (reg), (reg)) |
474 |
#define md_reg_to_word_native_un(inst,reg) \ |
475 |
amd64_mov_reg_reg_size((inst), (reg), (reg), 4) |
476 |
|
477 |
/* |
478 |
* Truncate floating point values to 32-bit or 64-bit. |
479 |
*/ |
480 |
#define md_reg_to_float_32(inst,reg) \ |
481 |
do { \ |
482 |
x86_alu_reg_imm((inst), X86_SUB, X86_ESP, 4); \ |
483 |
x86_fst_membase((inst), X86_ESP, 0, 0, 1); \ |
484 |
x86_fld_membase((inst), X86_ESP, 0, 0); \ |
485 |
x86_alu_reg_imm((inst), X86_ADD, X86_ESP, 4); \ |
486 |
} while (0) |
487 |
#define md_reg_to_float_64(inst,reg) \ |
488 |
do { \ |
489 |
x86_alu_reg_imm((inst), X86_SUB, X86_ESP, 8); \ |
490 |
x86_fst_membase((inst), X86_ESP, 0, 1, 1); \ |
491 |
x86_fld_membase((inst), X86_ESP, 0, 1); \ |
492 |
x86_alu_reg_imm((inst), X86_ADD, X86_ESP, 8); \ |
493 |
} while (0) |
494 |
|
495 |
/* |
496 |
* Swap the top two items on the floating-point stack. |
497 |
*/ |
498 |
#define md_freg_swap(inst) x86_fxch((inst), 1) |
499 |
|
500 |
/* |
501 |
* Jump back into the CVM interpreter to execute the instruction |
502 |
* at "pc". If "label" is non-NULL, then it indicates the address |
503 |
* of the CVM instruction handler to jump directly to. |
504 |
*/ |
505 |
#define md_jump_to_cvm(inst,pc,label) \ |
506 |
do { \ |
507 |
amd64_mov_reg_imm_size((inst), MD_REG_PC, (void*)pc, 8); \ |
508 |
if((label)) \ |
509 |
{ \ |
510 |
amd64_jump_code((inst), label); \ |
511 |
} \ |
512 |
else \ |
513 |
{ \ |
514 |
amd64_jump_membase((inst), MD_REG_PC, 0); \ |
515 |
} \ |
516 |
} while (0) |
517 |
|
518 |
/* |
519 |
* Jump to a program counter that is defined by a switch table. |
520 |
*/ |
521 |
#define md_switch(inst,reg,table) \ |
522 |
do { \ |
523 |
/* amd64_mov_reg_memindex((inst), MD_REG_PC, X86_NOBASEREG, \ |
524 |
(long long)(table), (reg), 2, 4); \ |
525 |
amd64_jump_membase((inst), MD_REG_PC, 0); */\ |
526 |
TODO_trap(inst);\ |
527 |
} while (0) |
528 |
|
529 |
/* |
530 |
* Perform a clear operation at a memory base. |
531 |
*/ |
532 |
#define md_clear_membase_start(inst) do { ; } while (0) |
533 |
#define md_clear_membase(inst,reg,offset) \ |
534 |
do { \ |
535 |
amd64_mov_membase_imm((inst), (reg), (offset), 0, 8); \ |
536 |
} while (0) |
537 |
|
538 |
/* |
539 |
* Load the effective address of a memory base into a register. |
540 |
*/ |
541 |
#define md_lea_membase(inst,reg,basereg,offset) \ |
542 |
do { \ |
543 |
int __value = (int)(offset); \ |
544 |
if(!__value) \ |
545 |
{ \ |
546 |
amd64_mov_reg_reg((inst), (reg), (basereg), 8); \ |
547 |
} \ |
548 |
else \ |
549 |
{ \ |
550 |
amd64_lea_membase((inst), (reg), (basereg), __value); \ |
551 |
} \ |
552 |
} while (0) |
553 |
|
554 |
/* |
555 |
* Move values between registers. |
556 |
*/ |
557 |
#define md_mov_reg_reg(inst,dreg,sreg) \ |
558 |
amd64_mov_reg_reg((inst), (dreg), (sreg), 4) |
559 |
|
560 |
/* |
561 |
* Set a register to a 0 or 1 value based on a condition. |
562 |
*/ |
563 |
extern md_inst_ptr _md_x86_setcc(md_inst_ptr inst, int reg, int cond); |
564 |
#define md_seteq_reg(inst,reg) \ |
565 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_EQ); } while (0) |
566 |
#define md_setne_reg(inst,reg) \ |
567 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_NE); } while (0) |
568 |
#define md_setlt_reg(inst,reg) \ |
569 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_LT); } while (0) |
570 |
#define md_setle_reg(inst,reg) \ |
571 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_LE); } while (0) |
572 |
#define md_setgt_reg(inst,reg) \ |
573 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_GT); } while (0) |
574 |
#define md_setge_reg(inst,reg) \ |
575 |
do { (inst) = _md_x86_setcc((inst), (reg), X86_CC_GE); } while (0) |
576 |
|
577 |
/* |
578 |
* Set a register to -1, 0, or 1 based on comparing two values. |
579 |
*/ |
580 |
extern md_inst_ptr _md_x86_compare |
581 |
(md_inst_ptr inst, int reg1, int reg2, int isSigned); |
582 |
#define md_cmp_reg_reg_word_32(inst,reg1,reg2) \ |
583 |
do { (inst) = _md_x86_compare \ |
584 |
((inst), (reg1), (reg2), 1); } while (0) |
585 |
#define md_ucmp_reg_reg_word_32(inst,reg1,reg2) \ |
586 |
do { (inst) = _md_x86_compare \ |
587 |
((inst), (reg1), (reg2), 0); } while (0) |
588 |
|
589 |
/* |
590 |
* Set the condition codes based on comparing two values. |
591 |
* The "cond" value indicates the type of condition that we |
592 |
* want to check for. |
593 |
*/ |
594 |
#define md_cmp_cc_reg_reg_word_32(inst,cond,reg1,reg2) \ |
595 |
amd64_alu_reg_reg_size((inst), X86_CMP, (reg1), (reg2), 4) |
596 |
#define md_cmp_cc_reg_reg_word_native(inst,cond,reg1,reg2) \ |
597 |
amd64_alu_reg_reg((inst), X86_CMP, (reg1), (reg2)) |
598 |
|
599 |
/* |
600 |
* Test the contents of a register against NULL and set the |
601 |
* condition codes based on the result. |
602 |
*/ |
603 |
#define md_reg_is_null(inst,reg) \ |
604 |
amd64_alu_reg_reg((inst), X86_OR, (reg), (reg)) |
605 |
|
606 |
/* |
607 |
* Test the contents of a register against 32-bit zero and set the |
608 |
* condition codes based on the result. |
609 |
*/ |
610 |
#define md_reg_is_zero(inst,reg) \ |
611 |
amd64_alu_reg_reg((inst), X86_OR, (reg), (reg)) |
612 |
|
613 |
/* |
614 |
* Compare a 32-bit register against an immediate value and set |
615 |
* the condition codes based on the result. |
616 |
*/ |
617 |
#define md_cmp_reg_imm_word_32(inst,cond,reg,imm) \ |
618 |
x86_alu_reg_imm((inst), X86_CMP, (reg), (int)(imm)) |
619 |
|
620 |
/* |
621 |
* Output a branch to a location based on a condition. The actual |
622 |
* jump offset will be filled in by a later "md_patch" call. |
623 |
*/ |
624 |
#define md_branch_eq(inst) \ |
625 |
amd64_branch32((inst), X86_CC_EQ, 0, 0) |
626 |
#define md_branch_ne(inst) \ |
627 |
amd64_branch32((inst), X86_CC_NE, 0, 0) |
628 |
#define md_branch_lt(inst) \ |
629 |
amd64_branch32((inst), X86_CC_LT, 0, 1) |
630 |
#define md_branch_le(inst) \ |
631 |
amd64_branch32((inst), X86_CC_LE, 0, 1) |
632 |
#define md_branch_gt(inst) \ |
633 |
amd64_branch32((inst), X86_CC_GT, 0, 1) |
634 |
#define md_branch_ge(inst) \ |
635 |
amd64_branch32((inst), X86_CC_GE, 0, 1) |
636 |
#define md_branch_lt_un(inst) \ |
637 |
amd64_branch32((inst), X86_CC_LT, 0, 0) |
638 |
#define md_branch_le_un(inst) \ |
639 |
amd64_branch32((inst), X86_CC_LE, 0, 0) |
640 |
#define md_branch_gt_un(inst) \ |
641 |
amd64_branch32((inst), X86_CC_GT, 0, 0) |
642 |
#define md_branch_ge_un(inst) \ |
643 |
amd64_branch32((inst), X86_CC_GE, 0, 0) |
644 |
#define md_branch_cc(inst,cond) \ |
645 |
amd64_branch32((inst), (cond) & 15, 0, ((cond) & 16) != 0) |
646 |
|
647 |
/* |
648 |
* Specific condition codes for "md_branch_cc". |
649 |
*/ |
650 |
#define MD_CC_EQ X86_CC_EQ |
651 |
#define MD_CC_NE X86_CC_NE |
652 |
#define MD_CC_LT (X86_CC_LT | 16) |
653 |
#define MD_CC_LE (X86_CC_LE | 16) |
654 |
#define MD_CC_GT (X86_CC_GT | 16) |
655 |
#define MD_CC_GE (X86_CC_GE | 16) |
656 |
#define MD_CC_LT_UN X86_CC_LT |
657 |
#define MD_CC_LE_UN X86_CC_LE |
658 |
#define MD_CC_GT_UN X86_CC_GT |
659 |
#define MD_CC_GE_UN X86_CC_GE |
660 |
|
661 |
/* |
662 |
* Back-patch a branch instruction at "patch" to branch to "inst". |
663 |
*/ |
664 |
#define md_patch(patch,inst) \ |
665 |
amd64_patch((patch), (inst)) |
666 |
|
667 |
/* |
668 |
* Check an array bounds value. "reg1" points to the array, |
669 |
* and "reg2" is the array index to check. |
670 |
*/ |
671 |
#define md_bounds_check(inst,reg1,reg2) \ |
672 |
x86_alu_reg_membase((inst), X86_CMP, (reg2), (reg1), 0) |
673 |
|
674 |
/* |
675 |
* Load a 32-bit word value from an indexed array. "disp" is the offset |
676 |
* to use to skip over the array bounds value. Some platforms may ignore |
677 |
* "disp" if they advance the base pointer in "md_bounds_check". |
678 |
*/ |
679 |
#define md_load_memindex_word_32(inst,reg,basereg,indexreg,disp) \ |
680 |
do { \ |
681 |
x86_mov_reg_memindex((inst), (reg), (basereg), \ |
682 |
(disp), (indexreg), 2, 4); \ |
683 |
} while (0) |
684 |
|
685 |
/* |
686 |
* Load a native word value from an indexed array. |
687 |
*/ |
688 |
#define md_load_memindex_word_native(inst,reg,basereg,indexreg,disp) \ |
689 |
do { \ |
690 |
x86_mov_reg_memindex((inst), (reg), (basereg), \ |
691 |
(disp), (indexreg), 2, 4); \ |
692 |
} while (0) |
693 |
|
694 |
/* |
695 |
* Load a byte value from an indexed array. |
696 |
*/ |
697 |
#define md_load_memindex_byte(inst,reg,basereg,indexreg,disp) \ |
698 |
do { \ |
699 |
x86_widen_memindex((inst), (reg), (basereg), \ |
700 |
(disp), (indexreg), 0, 0, 0); \ |
701 |
} while (0) |
702 |
|
703 |
/* |
704 |
* Load a signed byte value from an indexed array. |
705 |
*/ |
706 |
#define md_load_memindex_sbyte(inst,reg,basereg,indexreg,disp) \ |
707 |
do { \ |
708 |
x86_widen_memindex((inst), (reg), (basereg), \ |
709 |
(disp), (indexreg), 0, 1, 0); \ |
710 |
} while (0) |
711 |
|
712 |
/* |
713 |
* Load a short value from an indexed array. |
714 |
*/ |
715 |
#define md_load_memindex_short(inst,reg,basereg,indexreg,disp) \ |
716 |
do { \ |
717 |
x86_widen_memindex((inst), (reg), (basereg), \ |
718 |
(disp), (indexreg), 1, 1, 1); \ |
719 |
} while (0) |
720 |
|
721 |
/* |
722 |
* Load an unsigned short value from an indexed array. |
723 |
*/ |
724 |
#define md_load_memindex_ushort(inst,reg,basereg,indexreg,disp) \ |
725 |
do { \ |
726 |
x86_widen_memindex((inst), (reg), (basereg), \ |
727 |
(disp), (indexreg), 1, 0, 1); \ |
728 |
} while (0) |
729 |
|
730 |
/* |
731 |
* Store a 32-bit word value into an indexed array. |
732 |
*/ |
733 |
#define md_store_memindex_word_32(inst,reg,basereg,indexreg,disp) \ |
734 |
do { \ |
735 |
x86_mov_memindex_reg((inst), (basereg), (disp), (indexreg), \ |
736 |
2, (reg), 4); \ |
737 |
} while (0) |
738 |
|
739 |
/* |
740 |
* Store a native word value into an indexed array. |
741 |
*/ |
742 |
#define md_store_memindex_word_native(inst,reg,basereg,indexreg,disp) \ |
743 |
do { \ |
744 |
x86_mov_memindex_reg((inst), (basereg), (disp), (indexreg), \ |
745 |
2, (reg), 4); \ |
746 |
} while (0) |
747 |
|
748 |
/* |
749 |
* Store a byte value into an indexed array. |
750 |
*/ |
751 |
extern md_inst_ptr _md_x86_mov_memindex_reg_byte |
752 |
(md_inst_ptr inst, int basereg, |
753 |
unsigned offset, int indexreg, int srcreg); |
754 |
#define md_store_memindex_byte(inst,reg,basereg,indexreg,disp) \ |
755 |
do { \ |
756 |
(inst) = _md_x86_mov_memindex_reg_byte \ |
757 |
((inst), (basereg), (disp), (indexreg), (reg)); \ |
758 |
} while (0) |
759 |
|
760 |
/* |
761 |
* Store a signed byte value into an indexed array. |
762 |
*/ |
763 |
#define md_store_memindex_sbyte(inst,reg,basereg,indexreg,disp) \ |
764 |
do { \ |
765 |
(inst) = _md_x86_mov_memindex_reg_byte \ |
766 |
((inst), (basereg), (disp), (indexreg), (reg)); \ |
767 |
} while (0) |
768 |
|
769 |
/* |
770 |
* Store a short value into an indexed array. |
771 |
*/ |
772 |
#define md_store_memindex_short(inst,reg,basereg,indexreg,disp) \ |
773 |
do { \ |
774 |
x86_mov_memindex_reg((inst), (basereg), (disp), (indexreg), \ |
775 |
1, (reg), 2); \ |
776 |
} while (0) |
777 |
|
778 |
/* |
779 |
* Store an unsigned short value into an indexed array. |
780 |
*/ |
781 |
#define md_store_memindex_ushort(inst,reg,basereg,indexreg,disp) \ |
782 |
do { \ |
783 |
x86_mov_memindex_reg((inst), (basereg), (disp), (indexreg), \ |
784 |
1, (reg), 2); \ |
785 |
} while (0) |
786 |
|
787 |
#ifdef __cplusplus |
788 |
}; |
789 |
#endif |
790 |
|
791 |
#endif /* _ENGINE_MD_X86_H */ |