blob: 001cd78e5b0d4bd2696f7c68f8bb07983448a04b [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
414void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
415{
416 initHRegUsage(u);
417 switch (i->tag) {
418 case Xin_Alu32R:
419 addRegUsage_X86RMI(u, i->Xin.Alu32R.src);
420 if (i->Xin.Alu32R.op == Xalu_MOV)
421 addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
422 else
423 addHRegUse(u, HRmModify, i->Xin.Alu32R.dst);
424 return;
425 case Xin_Alu32M:
426 addRegUsage_X86RI(u, i->Xin.Alu32M.src);
427 addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
428 return;
429 case Xin_Sh32:
430 addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify);
431 if (i->Xin.Sh32.src == 0)
432 addHRegUse(u, HRmRead, hregX86_ECX());
433 return;
sewardj0ec33252004-07-03 13:30:00 +0000434 case Xin_RET:
sewardja9a0cd22004-07-03 14:49:41 +0000435 /* Using our calling conventions, %eax is live into a ret,
436 because we know the dispatcher -- to which we're returning
437 -- uses that value as the next guest address. */
438 addHRegUse(u, HRmRead, hregX86_EAX());
sewardj0ec33252004-07-03 13:30:00 +0000439 return;
sewardj53f85a92004-07-02 13:45:17 +0000440 default:
sewardj0ec33252004-07-03 13:30:00 +0000441 ppX86Instr(stderr, i);
sewardj53f85a92004-07-02 13:45:17 +0000442 panic("getRegUsage_X86Instr");
443 }
444}
445
446void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
447{
448 switch (i->tag) {
449 case Xin_Alu32R:
450 mapRegs_X86RMI(m, i->Xin.Alu32R.src);
451 i->Xin.Alu32R.dst = lookupHRegRemap(m, i->Xin.Alu32R.dst);
452 return;
453 case Xin_Alu32M:
454 mapRegs_X86RI(m, i->Xin.Alu32M.src);
455 mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
456 return;
457 case Xin_Sh32:
458 mapRegs_X86RM(m, i->Xin.Sh32.dst);
459 return;
sewardj0ec33252004-07-03 13:30:00 +0000460 case Xin_RET:
461 return;
sewardj53f85a92004-07-02 13:45:17 +0000462 default:
sewardj0ec33252004-07-03 13:30:00 +0000463 ppX86Instr(stderr, i);
sewardj53f85a92004-07-02 13:45:17 +0000464 panic("mapRegs_X86Instr");
465 }
466}
467
sewardja9a0cd22004-07-03 14:49:41 +0000468Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
469{
470 if (i->tag != Xin_Alu32R)
471 return False;
472 if (i->Xin.Alu32R.op != Xalu_MOV)
473 return False;
474 if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
475 return False;
476 *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
477 *dst = i->Xin.Alu32R.dst;
478 return True;
479}