2 * amd64-codegen.h: Macros for generating x86 code
5 * Paolo Molaro (lupus@ximian.com)
6 * Intel Corporation (ORP Project)
7 * Sergey Chaban (serge@wildwestsoftware.com)
8 * Dietmar Maurer (dietmar@ximian.com)
12 * Not all routines are done for AMD64. Much could also be removed from here if supporting tramp.c is the only goal.
14 * Copyright (C) 2000 Intel Corporation. All rights reserved.
15 * Copyright (C) 2001, 2002 Ximian, Inc.
62 AMD64_REX_B = 1, /* The register in r/m field, base register in SIB byte, or reg in opcode is 8-15 rather than 0-7 */
63 AMD64_REX_X = 2, /* The index register in SIB byte is 8-15 rather than 0-7 */
64 AMD64_REX_R = 4, /* The reg field of ModRM byte is 8-15 rather than 0-7 */
65 AMD64_REX_W = 8 /* Opeartion is 64-bits instead of 32 (default) or 16 (with 0x66 prefix) */
68 #define AMD64_REX(bits) ((unsigned char)(0x40 | (bits)))
69 #define amd64_emit_rex(inst, width, reg_modrm, reg_index, reg_rm_base_opcode) \
71 unsigned char _amd64_rex_bits = \
72 (((width) > 4) ? AMD64_REX_W : 0) | \
73 (((reg_modrm) > 7) ? AMD64_REX_R : 0) | \
74 (((reg_index) > 7) ? AMD64_REX_X : 0) | \
75 (((reg_rm_base_opcode) > 7) ? AMD64_REX_B : 0); \
76 if (_amd64_rex_bits != 0) *(inst)++ = AMD64_REX(_amd64_rex_bits); \
84 #include "../x86/x86-codegen.h"
87 /* Need to fill this info in for amd64. */
91 // bitvector mask for callee-saved registers
93 #define X86_ESI_MASK (1<<X86_ESI)
94 #define X86_EDI_MASK (1<<X86_EDI)
95 #define X86_EBX_MASK (1<<X86_EBX)
96 #define X86_EBP_MASK (1<<X86_EBP)
98 #define X86_CALLEE_REGS ((1<<X86_EAX) | (1<<X86_ECX) | (1<<X86_EDX))
99 #define X86_CALLER_REGS ((1<<X86_EBX) | (1<<X86_EBP) | (1<<X86_ESI) | (1<<X86_EDI))
100 #define X86_BYTE_REGS ((1<<X86_EAX) | (1<<X86_ECX) | (1<<X86_EDX) | (1<<X86_EBX))
102 #define X86_IS_SCRATCH(reg) (X86_CALLER_REGS & (1 << (reg))) /* X86_EAX, X86_ECX, or X86_EDX */
103 #define X86_IS_CALLEE(reg) (X86_CALLEE_REGS & (1 << (reg))) /* X86_ESI, X86_EDI, X86_EBX, or X86_EBP */
105 #define X86_IS_BYTE_REG(reg) ((reg) < 4)
110 // +--------------------------------+
111 // | in_arg[0] = var[0] |
112 // | in_arg[1] = var[1] |
114 // | in_arg[n_arg-1] = var[n_arg-1] |
115 // +--------------------------------+
117 // +--------------------------------+
118 // | saved EBP | <-- frame pointer (EBP)
119 // +--------------------------------+
121 // +--------------------------------+
123 // | var[n_arg+1] | local variables area
126 // +--------------------------------+
129 // | spill area | area for spilling mimic stack
131 // +--------------------------------|
133 // | ebp [ESP_Frame only] |
134 // | esi | 0..3 callee-saved regs
135 // | edi | <-- stack pointer (ESP)
136 // +--------------------------------+
138 // | stk1 | operand stack area/
139 // | . . . | out args
141 // +--------------------------------|
147 #define x86_imm_emit64(inst,imm) \
149 amd64_imm_buf imb; imb.val = (long) (imm); \
150 *(inst)++ = imb.b [0]; \
151 *(inst)++ = imb.b [1]; \
152 *(inst)++ = imb.b [2]; \
153 *(inst)++ = imb.b [3]; \
154 *(inst)++ = imb.b [4]; \
155 *(inst)++ = imb.b [5]; \
156 *(inst)++ = imb.b [6]; \
157 *(inst)++ = imb.b [7]; \
160 #define amd64_alu_reg_imm(inst,opc,reg,imm) \
162 if ((reg) == X86_EAX) { \
163 amd64_emit_rex(inst, 8, 0, 0, 0); \
164 *(inst)++ = (((unsigned char)(opc)) << 3) + 5; \
165 x86_imm_emit64 ((inst), (imm)); \
168 if (x86_is_imm8((imm))) { \
169 amd64_emit_rex(inst, 8, 0, 0, (reg)); \
170 *(inst)++ = (unsigned char)0x83; \
171 x86_reg_emit ((inst), (opc), (reg)); \
172 x86_imm_emit8 ((inst), (imm)); \
174 amd64_emit_rex(inst, 8, 0, 0, (reg)); \
175 *(inst)++ = (unsigned char)0x81; \
176 x86_reg_emit ((inst), (opc), (reg)); \
177 x86_imm_emit32 ((inst), (imm)); \
181 #define amd64_alu_reg_reg(inst,opc,dreg,reg) \
183 amd64_emit_rex(inst, 8, (dreg), 0, (reg)); \
184 *(inst)++ = (((unsigned char)(opc)) << 3) + 3; \
185 x86_reg_emit ((inst), (dreg), (reg)); \
188 #define amd64_mov_regp_reg(inst,regp,reg,size) \
191 *(inst)++ = (unsigned char)0x66; \
192 amd64_emit_rex(inst, (size), (reg), 0, (regp)); \
194 case 1: *(inst)++ = (unsigned char)0x88; break; \
195 case 2: case 4: case 8: *(inst)++ = (unsigned char)0x89; break; \
196 default: assert (0); \
198 x86_regp_emit ((inst), (reg), (regp)); \
201 #define amd64_mov_membase_reg(inst,basereg,disp,reg,size) \
204 *(inst)++ = (unsigned char)0x66; \
205 amd64_emit_rex(inst, (size), (reg), 0, (basereg)); \
207 case 1: *(inst)++ = (unsigned char)0x88; break; \
208 case 2: case 4: case 8: *(inst)++ = (unsigned char)0x89; break; \
209 default: assert (0); \
211 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
215 #define amd64_mov_reg_reg(inst,dreg,reg,size) \
218 *(inst)++ = (unsigned char)0x66; \
219 amd64_emit_rex(inst, (size), (dreg), 0, (reg)); \
221 case 1: *(inst)++ = (unsigned char)0x8a; break; \
222 case 2: case 4: case 8: *(inst)++ = (unsigned char)0x8b; break; \
223 default: assert (0); \
225 x86_reg_emit ((inst), (dreg), (reg)); \
228 #define amd64_mov_reg_mem(inst,reg,mem,size) \
231 *(inst)++ = (unsigned char)0x66; \
232 amd64_emit_rex(inst, (size), (reg), 0, 0); \
234 case 1: *(inst)++ = (unsigned char)0x8a; break; \
235 case 2: case 4: case 8: *(inst)++ = (unsigned char)0x8b; break; \
236 default: assert (0); \
238 x86_mem_emit ((inst), (reg), (mem)); \
241 #define amd64_mov_reg_membase(inst,reg,basereg,disp,size) \
244 *(inst)++ = (unsigned char)0x66; \
245 amd64_emit_rex(inst, (size), (reg), 0, (basereg)); \
247 case 1: *(inst)++ = (unsigned char)0x8a; break; \
248 case 2: case 4: case 8: *(inst)++ = (unsigned char)0x8b; break; \
249 default: assert (0); \
251 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
254 #define amd64_movzx_reg_membase(inst,reg,basereg,disp,size) \
256 amd64_emit_rex(inst, (size), (reg), 0, (basereg)); \
258 case 1: *(inst)++ = (unsigned char)0x0f; *(inst)++ = (unsigned char)0xb6; break; \
259 case 2: *(inst)++ = (unsigned char)0x0f; *(inst)++ = (unsigned char)0xb7; break; \
260 case 4: case 8: *(inst)++ = (unsigned char)0x8b; break; \
261 default: assert (0); \
263 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
266 /* Pretty much the only instruction that supports a 64-bit immediate. Optimize for common case of
267 * 32-bit immediate. Pepper with casts to avoid warnings.
269 #define amd64_mov_reg_imm(inst,reg,imm) \
271 int _amd64_width_temp = ((long)(imm) == (long)(int)(long)(imm)); \
272 amd64_emit_rex(inst, _amd64_width_temp ? 8 : 4, 0, 0, (reg)); \
273 *(inst)++ = (unsigned char)0xb8 + ((reg) & 0x7); \
274 if (_amd64_width_temp) \
275 x86_imm_emit64 ((inst), (long)(imm)); \
277 x86_imm_emit32 ((inst), (int)(long)(imm)); \
280 #define amd64_mov_membase_imm(inst,basereg,disp,imm,size) \
283 *(inst)++ = (unsigned char)0x66; \
284 amd64_emit_rex(inst, (size), 0, 0, (basereg)); \
286 *(inst)++ = (unsigned char)0xc6; \
287 x86_membase_emit ((inst), 0, (basereg), (disp)); \
288 x86_imm_emit8 ((inst), (imm)); \
289 } else if ((size) == 2) { \
290 *(inst)++ = (unsigned char)0xc7; \
291 x86_membase_emit ((inst), 0, (basereg), (disp)); \
292 x86_imm_emit16 ((inst), (imm)); \
294 *(inst)++ = (unsigned char)0xc7; \
295 x86_membase_emit ((inst), 0, (basereg), (disp)); \
296 x86_imm_emit32 ((inst), (imm)); \
300 #define amd64_lea_membase(inst,reg,basereg,disp) \
302 amd64_emit_rex(inst, 8, (reg), 0, (basereg)); \
303 *(inst)++ = (unsigned char)0x8d; \
304 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
307 /* Instruction are implicitly 64-bits so don't generate REX for just the size. */
308 #define amd64_push_reg(inst,reg) \
310 amd64_emit_rex(inst, 0, 0, 0, (reg)); \
311 *(inst)++ = (unsigned char)0x50 + ((reg) & 0x7); \
314 /* Instruction is implicitly 64-bits so don't generate REX for just the size. */
315 #define amd64_push_membase(inst,basereg,disp) \
317 amd64_emit_rex(inst, 0, 0, 0, (basereg)); \
318 *(inst)++ = (unsigned char)0xff; \
319 x86_membase_emit ((inst), 6, (basereg), (disp)); \
322 #define amd64_pop_reg(inst,reg) \
324 amd64_emit_rex(inst, 0, 0, 0, (reg)); \
325 *(inst)++ = (unsigned char)0x58 + (reg); \
328 #define amd64_call_reg(inst,reg) \
330 amd64_emit_rex(inst, 0, 0, 0, (reg)); \
331 *(inst)++ = (unsigned char)0xff; \
332 x86_reg_emit ((inst), 2, (reg)); \
335 #define amd64_ret(inst) do { *(inst)++ = (unsigned char)0xc3; } while (0)
336 #define amd64_leave(inst) do { *(inst)++ = (unsigned char)0xc9; } while (0)
337 #define amd64_movsd_reg_regp(inst,reg,regp) \
339 *(inst)++ = (unsigned char)0xf2; \
340 amd64_emit_rex(inst, 0, (reg), 0, (regp)); \
341 *(inst)++ = (unsigned char)0x0f; \
342 *(inst)++ = (unsigned char)0x10; \
343 x86_regp_emit ((inst), (reg), (regp)); \
346 #define amd64_movsd_regp_reg(inst,regp,reg) \
348 *(inst)++ = (unsigned char)0xf2; \
349 amd64_emit_rex(inst, 0, (reg), 0, (regp)); \
350 *(inst)++ = (unsigned char)0x0f; \
351 *(inst)++ = (unsigned char)0x11; \
352 x86_regp_emit ((inst), (reg), (regp)); \
355 #define amd64_movss_reg_regp(inst,reg,regp) \
357 *(inst)++ = (unsigned char)0xf3; \
358 amd64_emit_rex(inst, 0, (reg), 0, (regp)); \
359 *(inst)++ = (unsigned char)0x0f; \
360 *(inst)++ = (unsigned char)0x10; \
361 x86_regp_emit ((inst), (reg), (regp)); \
364 #define amd64_movss_regp_reg(inst,regp,reg) \
366 *(inst)++ = (unsigned char)0xf3; \
367 amd64_emit_rex(inst, 0, (reg), 0, (regp)); \
368 *(inst)++ = (unsigned char)0x0f; \
369 *(inst)++ = (unsigned char)0x11; \
370 x86_regp_emit ((inst), (reg), (regp)); \
373 #define amd64_movsd_reg_membase(inst,reg,basereg,disp) \
375 *(inst)++ = (unsigned char)0xf2; \
376 amd64_emit_rex(inst, 0, (reg), 0, (basereg)); \
377 *(inst)++ = (unsigned char)0x0f; \
378 *(inst)++ = (unsigned char)0x10; \
379 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
382 #define amd64_movss_reg_membase(inst,reg,basereg,disp) \
384 *(inst)++ = (unsigned char)0xf3; \
385 amd64_emit_rex(inst, 0, (reg), 0, (basereg)); \
386 *(inst)++ = (unsigned char)0x0f; \
387 *(inst)++ = (unsigned char)0x10; \
388 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
391 #define amd64_movsd_membase_reg(inst,reg,basereg,disp) \
393 *(inst)++ = (unsigned char)0xf2; \
394 amd64_emit_rex(inst, 0, (reg), 0, (basereg)); \
395 *(inst)++ = (unsigned char)0x0f; \
396 *(inst)++ = (unsigned char)0x11; \
397 x86_membase_emit ((inst), (reg), (basereg), (disp)); \
400 #define amd64_movss_membase_reg(inst,reg,basereg,disp) \
402 *(inst)++ = (unsigned char)0xf3; \
403 amd64_emit_rex(inst, 0, (reg), 0, (basereg)); \
404 *(inst)++ = (unsigned char)0x0f; \
405 *(inst)++ = (unsigned char)0x11; \
406 x86_membase_emit ((inst), (reg), (basereg), (disp)); \