blob: 170964309fed4e1e277e94e663725a041f6a3350 [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (x86h_defs.c) is ---*/
5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
9#include <stdio.h>
10#include <malloc.h>
11
12#include "basictypes.h"
13#include "host_regs.h"
14#include "x86h_defs.h"
15
16
17/* --------- Registers. --------- */
18
19void ppHRegX86 ( FILE* f, HReg reg )
20{
21 Int r;
22 static Char* ireg32_names[8]
23 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" };
24 /* Be generic for all virtual regs. */
25 if (hregIsVirtual(reg)) {
26 ppHReg(f, reg);
27 return;
28 }
29 /* But specific for real regs. */
30 switch (hregClass(reg)) {
31 case HRcInt:
32 r = hregNumber(reg);
33 assert(r >= 0 && r < 8);
34 fprintf(f, "%s", ireg32_names[r]);
35 return;
36 case HRcFloat:
37 r = hregNumber(reg);
38 assert(r >= 0 && r < 6);
39 fprintf(f, "%%fake%d", r);
40 return;
41 case HRcVector:
42 panic("ppHRegX86: real vector reg");
43 default:
44 panic("ppHRegX86");
45 }
46}
47
sewardj53f85a92004-07-02 13:45:17 +000048HReg hregX86_EAX ( void ) { return mkHReg(0, HRcInt, False); }
sewardj2cd80dc2004-07-02 15:20:40 +000049HReg hregX86_EBX ( void ) { return mkHReg(3, HRcInt, False); }
sewardj53f85a92004-07-02 13:45:17 +000050HReg hregX86_ECX ( void ) { return mkHReg(1, HRcInt, False); }
sewardj2cd80dc2004-07-02 15:20:40 +000051HReg hregX86_EDX ( void ) { return mkHReg(2, HRcInt, False); }
sewardj53f85a92004-07-02 13:45:17 +000052HReg hregX86_EBP ( void ) { return mkHReg(5, HRcInt, False); }
53
sewardjc97096c2004-06-30 09:28:04 +000054
55/* --------- X86AMode: memory address expressions. --------- */
56
57X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) {
58 X86AMode* am = malloc(sizeof(X86AMode));
59 am->tag = Xam_IR;
60 am->Xam.IR.imm = imm32;
61 am->Xam.IR.reg = reg;
62 return am;
63}
64
65X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg index, Int shift ) {
66 X86AMode* am = malloc(sizeof(X86AMode));
67 am->tag = Xam_IRRS;
68 am->Xam.IRRS.imm = imm32;
69 am->Xam.IRRS.base = base;
70 am->Xam.IRRS.index = index;
71 am->Xam.IRRS.shift = shift;
72 assert(shift >= 0 && shift <= 3);
73 return am;
74}
75
76void ppX86AMode ( FILE* f, X86AMode* am ) {
77 switch (am->tag) {
78 case Xam_IR:
79 fprintf(f, "0x%x(", am->Xam.IR.imm);
80 ppHRegX86(f, am->Xam.IR.reg);
81 fprintf(f, ")");
82 return;
83 case Xam_IRRS:
84 fprintf(f, "0x%x(", am->Xam.IRRS.imm);
85 ppHRegX86(f, am->Xam.IRRS.base);
86 fprintf(f, ",");
87 ppHRegX86(f, am->Xam.IRRS.index);
88 fprintf(f, ",%d)", am->Xam.IRRS.shift);
89 return;
90 default:
91 panic("ppX86AMode");
92 }
93}
94
sewardj53f85a92004-07-02 13:45:17 +000095static void addRegUsage_X86AMode ( HRegUsage* u, X86AMode* am ) {
96 switch (am->tag) {
97 case Xam_IR:
98 addHRegUse(u, HRmRead, am->Xam.IR.reg);
99 return;
100 case Xam_IRRS:
101 addHRegUse(u, HRmRead, am->Xam.IRRS.base);
102 addHRegUse(u, HRmRead, am->Xam.IRRS.index);
103 return;
104 default:
105 panic("addRegUsage_X86AMode");
106 }
107}
108
109static void mapRegs_X86AMode ( HRegRemap* m, X86AMode* am ) {
110 switch (am->tag) {
111 case Xam_IR:
112 am->Xam.IR.reg = lookupHRegRemap(m, am->Xam.IR.reg);
113 return;
114 case Xam_IRRS:
115 am->Xam.IRRS.base = lookupHRegRemap(m, am->Xam.IRRS.base);
116 am->Xam.IRRS.index = lookupHRegRemap(m, am->Xam.IRRS.index);
117 return;
118 default:
119 panic("mapRegs_X86AMode");
120 }
121}
sewardjc97096c2004-06-30 09:28:04 +0000122
sewardj66f2f792004-06-30 16:37:16 +0000123/* --------- Operand, which can be reg, immediate or memory. --------- */
sewardjc97096c2004-06-30 09:28:04 +0000124
sewardj66f2f792004-06-30 16:37:16 +0000125X86RMI* X86RMI_Imm ( UInt imm32 ) {
126 X86RMI* op = malloc(sizeof(X86RMI));
127 op->tag = Xrmi_Imm;
128 op->Xrmi.Imm.imm32 = imm32;
sewardjc97096c2004-06-30 09:28:04 +0000129 return op;
130}
131
sewardj66f2f792004-06-30 16:37:16 +0000132X86RMI* X86RMI_Reg ( HReg reg ) {
133 X86RMI* op = malloc(sizeof(X86RMI));
134 op->tag = Xrmi_Reg;
135 op->Xrmi.Reg.reg = reg;
sewardjc97096c2004-06-30 09:28:04 +0000136 return op;
137}
138
sewardj66f2f792004-06-30 16:37:16 +0000139X86RMI* X86RMI_Mem ( X86AMode* am ) {
140 X86RMI* op = malloc(sizeof(X86RMI));
141 op->tag = Xrmi_Mem;
142 op->Xrmi.Mem.am = am;
sewardjc97096c2004-06-30 09:28:04 +0000143 return op;
144}
145
sewardj66f2f792004-06-30 16:37:16 +0000146void ppX86RMI ( FILE* f, X86RMI* op ) {
sewardjc97096c2004-06-30 09:28:04 +0000147 switch (op->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000148 case Xrmi_Imm:
149 fprintf(f, "$0x%x", op->Xrmi.Imm.imm32);
sewardjc97096c2004-06-30 09:28:04 +0000150 return;
sewardj66f2f792004-06-30 16:37:16 +0000151 case Xrmi_Reg:
152 ppHRegX86(f, op->Xrmi.Reg.reg);
sewardjc97096c2004-06-30 09:28:04 +0000153 return;
sewardj66f2f792004-06-30 16:37:16 +0000154 case Xrmi_Mem:
155 ppX86AMode(f, op->Xrmi.Mem.am);
sewardjc97096c2004-06-30 09:28:04 +0000156 return;
157 default:
sewardj66f2f792004-06-30 16:37:16 +0000158 panic("ppX86RMI");
159 }
160}
161
sewardj53f85a92004-07-02 13:45:17 +0000162/* An X86RMI can only be used in a "read" context (what would it mean
163 to write or modify a literal?) and so we enumerate its registers
164 accordingly. */
165static void addRegUsage_X86RMI ( HRegUsage* u, X86RMI* op ) {
166 switch (op->tag) {
167 case Xrmi_Imm:
168 return;
169 case Xrmi_Reg:
170 addHRegUse(u, HRmRead, op->Xrmi.Reg.reg);
171 return;
172 case Xrmi_Mem:
173 addRegUsage_X86AMode(u, op->Xrmi.Mem.am);
174 return;
175 default:
176 panic("addRegUsage_X86RMI");
177 }
178}
179
180static void mapRegs_X86RMI ( HRegRemap* m, X86RMI* op ) {
181 switch (op->tag) {
182 case Xrmi_Imm:
183 return;
184 case Xrmi_Reg:
185 op->Xrmi.Reg.reg = lookupHRegRemap(m, op->Xrmi.Reg.reg);
186 return;
187 case Xrmi_Mem:
188 mapRegs_X86AMode(m, op->Xrmi.Mem.am);
189 return;
190 default:
191 panic("mapRegs_X86RMI");
192 }
193}
194
sewardj66f2f792004-06-30 16:37:16 +0000195
196/* --------- Operand, which can be reg or immediate only. --------- */
197
198X86RI* X86RI_Imm ( UInt imm32 ) {
199 X86RI* op = malloc(sizeof(X86RI));
200 op->tag = Xri_Imm;
201 op->Xri.Imm.imm32 = imm32;
202 return op;
203}
204
205X86RI* X86RI_Reg ( HReg reg ) {
206 X86RI* op = malloc(sizeof(X86RI));
207 op->tag = Xri_Reg;
208 op->Xri.Reg.reg = reg;
209 return op;
210}
211
212void ppX86RI ( FILE* f, X86RI* op ) {
213 switch (op->tag) {
214 case Xri_Imm:
215 fprintf(f, "$0x%x", op->Xri.Imm.imm32);
216 return;
217 case Xri_Reg:
218 ppHRegX86(f, op->Xri.Reg.reg);
219 return;
220 default:
221 panic("ppX86RI");
222 }
223}
224
sewardj53f85a92004-07-02 13:45:17 +0000225/* An X86RI can only be used in a "read" context (what would it mean
226 to write or modify a literal?) and so we enumerate its registers
227 accordingly. */
228static void addRegUsage_X86RI ( HRegUsage* u, X86RI* op ) {
229 switch (op->tag) {
230 case Xri_Imm:
231 return;
232 case Xri_Reg:
233 addHRegUse(u, HRmRead, op->Xri.Reg.reg);
234 return;
235 default:
236 panic("addRegUsage_X86RI");
237 }
238}
239
240static void mapRegs_X86RI ( HRegRemap* m, X86RI* op ) {
241 switch (op->tag) {
242 case Xri_Imm:
243 return;
244 case Xri_Reg:
245 op->Xri.Reg.reg = lookupHRegRemap(m, op->Xri.Reg.reg);
246 return;
247 default:
248 panic("mapRegs_X86RI");
249 }
250}
251
sewardj66f2f792004-06-30 16:37:16 +0000252
253/* --------- Operand, which can be reg or memory only. --------- */
254
255X86RM* X86RM_Reg ( HReg reg ) {
256 X86RM* op = malloc(sizeof(X86RM));
257 op->tag = Xrm_Reg;
258 op->Xrm.Reg.reg = reg;
259 return op;
260}
261
262X86RM* X86RM_Mem ( X86AMode* am ) {
263 X86RM* op = malloc(sizeof(X86RM));
264 op->tag = Xrm_Mem;
265 op->Xrm.Mem.am = am;
266 return op;
267}
268
269void ppX86RM ( FILE* f, X86RM* op ) {
270 switch (op->tag) {
271 case Xrm_Mem:
272 ppX86AMode(f, op->Xrm.Mem.am);
273 return;
274 case Xrm_Reg:
275 ppHRegX86(f, op->Xrm.Reg.reg);
276 return;
277 default:
278 panic("ppX86RM");
sewardjc97096c2004-06-30 09:28:04 +0000279 }
280}
281
sewardj53f85a92004-07-02 13:45:17 +0000282/* Because an X86RM can be both a source or destination operand, we
283 have to supply a mode -- pertaining to the operand as a whole --
284 indicating how it's being used. */
285static void addRegUsage_X86RM ( HRegUsage* u, X86RM* op, HRegMode mode ) {
286 switch (op->tag) {
287 case Xrm_Mem:
288 /* Memory is read, written or modified. So we just want to
289 know the regs read by the amode. */
290 addRegUsage_X86AMode(u, op->Xrm.Mem.am);
291 return;
292 case Xrm_Reg:
293 /* reg is read, written or modified. Add it in the
294 appropriate way. */
295 addHRegUse(u, mode, op->Xrm.Reg.reg);
296 return;
297 default:
298 panic("addRegUsage_X86RM");
299 }
300}
301
302static void mapRegs_X86RM ( HRegRemap* m, X86RM* op )
303{
304 switch (op->tag) {
305 case Xrm_Mem:
306 mapRegs_X86AMode(m, op->Xrm.Mem.am);
307 return;
308 case Xrm_Reg:
309 op->Xrm.Reg.reg = lookupHRegRemap(m, op->Xrm.Reg.reg);
310 return;
311 default:
312 panic("mapRegs_X86RM");
313 }
314}
315
sewardjc97096c2004-06-30 09:28:04 +0000316
317/* --------- Instructions. --------- */
318
319void ppX86AluOp ( FILE* f, X86AluOp op ) {
320 Char* name;
321 switch (op) {
sewardj66f2f792004-06-30 16:37:16 +0000322 case Xalu_MOV: name = "mov"; break;
sewardjc97096c2004-06-30 09:28:04 +0000323 case Xalu_ADD: name = "add"; break;
324 case Xalu_SUB: name = "sub"; break;
325 case Xalu_ADC: name = "adc"; break;
326 case Xalu_SBB: name = "sbb"; break;
327 case Xalu_AND: name = "and"; break;
328 case Xalu_OR: name = "or"; break;
329 case Xalu_XOR: name = "xor"; break;
330 default: panic("ppX86AluOp");
331 }
332 fprintf(f, "%s", name);
333}
334
sewardj66f2f792004-06-30 16:37:16 +0000335void ppX86ShiftOp ( FILE* f, X86ShiftOp op ) {
336 Char* name;
337 switch (op) {
338 case Xsh_SHL: name = "shl"; break;
339 case Xsh_SHR: name = "shr"; break;
340 case Xsh_SAR: name = "sar"; break;
341 case Xsh_ROL: name = "rol"; break;
342 case Xsh_ROR: name = "ror"; break;
343 default: panic("ppX86ShiftOp");
344 }
345 fprintf(f, "%s", name);
346}
347
348X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
349 X86Instr* i = malloc(sizeof(X86Instr));
350 i->tag = Xin_Alu32R;
351 i->Xin.Alu32R.op = op;
352 i->Xin.Alu32R.src = src;
353 i->Xin.Alu32R.dst = dst;
354 return i;
355}
356
357X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
358 X86Instr* i = malloc(sizeof(X86Instr));
359 i->tag = Xin_Alu32M;
360 i->Xin.Alu32M.op = op;
361 i->Xin.Alu32M.src = src;
362 i->Xin.Alu32M.dst = dst;
363 return i;
364}
365
366X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
sewardjc97096c2004-06-30 09:28:04 +0000367 X86Instr* i = malloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000368 i->tag = Xin_Sh32;
369 i->Xin.Sh32.op = op;
370 i->Xin.Sh32.src = src;
371 i->Xin.Sh32.dst = dst;
sewardjc97096c2004-06-30 09:28:04 +0000372 return i;
373}
374
sewardj66f2f792004-06-30 16:37:16 +0000375X86Instr* X86Instr_RET ( void ) {
sewardjc97096c2004-06-30 09:28:04 +0000376 X86Instr* i = malloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000377 i->tag = Xin_RET;
sewardjc97096c2004-06-30 09:28:04 +0000378 return i;
379}
380
sewardjc97096c2004-06-30 09:28:04 +0000381void ppX86Instr ( FILE* f, X86Instr* i ) {
382 switch (i->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000383 case Xin_Alu32R:
384 ppX86AluOp(f, i->Xin.Alu32R.op);
sewardjc97096c2004-06-30 09:28:04 +0000385 fprintf(f, "l ");
sewardj66f2f792004-06-30 16:37:16 +0000386 ppX86RMI(f, i->Xin.Alu32R.src);
sewardjc97096c2004-06-30 09:28:04 +0000387 fprintf(f, ",");
sewardj66f2f792004-06-30 16:37:16 +0000388 ppHRegX86(f, i->Xin.Alu32R.dst);
sewardjc97096c2004-06-30 09:28:04 +0000389 return;
sewardj66f2f792004-06-30 16:37:16 +0000390 case Xin_Alu32M:
391 ppX86AluOp(f, i->Xin.Alu32M.op);
392 fprintf(f, "l ");
393 ppX86RI(f, i->Xin.Alu32M.src);
sewardjc97096c2004-06-30 09:28:04 +0000394 fprintf(f, ",");
sewardj66f2f792004-06-30 16:37:16 +0000395 ppX86AMode(f, i->Xin.Alu32M.dst);
sewardjc97096c2004-06-30 09:28:04 +0000396 return;
sewardj66f2f792004-06-30 16:37:16 +0000397 case Xin_Sh32:
398 ppX86ShiftOp(f, i->Xin.Sh32.op);
399 fprintf(f, "l ");
400 if (i->Xin.Sh32.src == 0)
401 fprintf(f, " %%cl,");
402 else
403 fprintf(f, " $%d,", i->Xin.Sh32.src);
404 ppX86RM(f, i->Xin.Sh32.dst);
405 return;
406 case Xin_RET:
407 fprintf(f, "ret");
sewardjc97096c2004-06-30 09:28:04 +0000408 return;
409 default:
410 panic("ppX86Instr");
411 }
412}
sewardj53f85a92004-07-02 13:45:17 +0000413
sewardj194d54a2004-07-03 19:08:18 +0000414/* --------- Helpers for register allocation. --------- */
415
sewardj53f85a92004-07-02 13:45:17 +0000416void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
417{
418 initHRegUsage(u);
419 switch (i->tag) {
420 case Xin_Alu32R:
421 addRegUsage_X86RMI(u, i->Xin.Alu32R.src);
422 if (i->Xin.Alu32R.op == Xalu_MOV)
423 addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
424 else
425 addHRegUse(u, HRmModify, i->Xin.Alu32R.dst);
426 return;
427 case Xin_Alu32M:
428 addRegUsage_X86RI(u, i->Xin.Alu32M.src);
429 addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
430 return;
431 case Xin_Sh32:
432 addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify);
433 if (i->Xin.Sh32.src == 0)
434 addHRegUse(u, HRmRead, hregX86_ECX());
435 return;
sewardj0ec33252004-07-03 13:30:00 +0000436 case Xin_RET:
sewardja9a0cd22004-07-03 14:49:41 +0000437 /* Using our calling conventions, %eax is live into a ret,
438 because we know the dispatcher -- to which we're returning
sewardj194d54a2004-07-03 19:08:18 +0000439 -- uses that value as the next guest address. Hmm. What
440 if we're simulating a 64-bit guest on an x86 host? */
sewardja9a0cd22004-07-03 14:49:41 +0000441 addHRegUse(u, HRmRead, hregX86_EAX());
sewardj0ec33252004-07-03 13:30:00 +0000442 return;
sewardj53f85a92004-07-02 13:45:17 +0000443 default:
sewardj0ec33252004-07-03 13:30:00 +0000444 ppX86Instr(stderr, i);
sewardj53f85a92004-07-02 13:45:17 +0000445 panic("getRegUsage_X86Instr");
446 }
447}
448
449void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
450{
451 switch (i->tag) {
452 case Xin_Alu32R:
453 mapRegs_X86RMI(m, i->Xin.Alu32R.src);
454 i->Xin.Alu32R.dst = lookupHRegRemap(m, i->Xin.Alu32R.dst);
455 return;
456 case Xin_Alu32M:
457 mapRegs_X86RI(m, i->Xin.Alu32M.src);
458 mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
459 return;
460 case Xin_Sh32:
461 mapRegs_X86RM(m, i->Xin.Sh32.dst);
462 return;
sewardj0ec33252004-07-03 13:30:00 +0000463 case Xin_RET:
464 return;
sewardj53f85a92004-07-02 13:45:17 +0000465 default:
sewardj0ec33252004-07-03 13:30:00 +0000466 ppX86Instr(stderr, i);
sewardj53f85a92004-07-02 13:45:17 +0000467 panic("mapRegs_X86Instr");
468 }
469}
470
sewardja9a0cd22004-07-03 14:49:41 +0000471Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
472{
473 if (i->tag != Xin_Alu32R)
474 return False;
475 if (i->Xin.Alu32R.op != Xalu_MOV)
476 return False;
477 if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
478 return False;
479 *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
480 *dst = i->Xin.Alu32R.dst;
481 return True;
482}
sewardj194d54a2004-07-03 19:08:18 +0000483
484X86Instr* genSpill_X86 ( HReg rreg, Int offset )
485{
486 assert(!hregIsVirtual(rreg));
487 switch (hregClass(rreg)) {
488 case HRcInt:
489 return
490 X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg),
491 X86AMode_IR(offset + 0x1000,
492 hregX86_EBP()));
493 default:
494 ppHRegClass(stderr, hregClass(rreg));
495 panic("genSpill_X86: unimplemented regclass");
496 }
497}
498
499X86Instr* genReload_X86 ( HReg rreg, Int offset )
500{
501 assert(!hregIsVirtual(rreg));
502 switch (hregClass(rreg)) {
503 case HRcInt:
504 return
505 X86Instr_Alu32R ( Xalu_MOV,
506 X86RMI_Mem(X86AMode_IR(offset + 0x1000,
507 hregX86_EBP())),
508 rreg );
509 default:
510 ppHRegClass(stderr, hregClass(rreg));
511 panic("genReload_X86: unimplemented regclass");
512 }
513}