blob: e99bfaa897c2012a85a9e20ad0247e4acbd104a8 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2000-2002 Julian Seward
11 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000029*/
30
31#include "vg_include.h"
32
33
34/*------------------------------------------------------------*/
35/*--- Renamings of frequently-used global functions. ---*/
36/*------------------------------------------------------------*/
37
sewardjde4a1d02002-03-22 01:27:54 +000038#define nameIReg VG_(nameOfIntReg)
39#define nameISize VG_(nameOfIntSize)
40
njn25e49d8e72002-09-23 09:36:25 +000041#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000042
43/*------------------------------------------------------------*/
44/*--- Instruction emission -- turning final uinstrs back ---*/
45/*--- into x86 code. ---*/
46/*------------------------------------------------------------*/
47
48/* [2001-07-08 This comment is now somewhat out of date.]
49
50 This is straightforward but for one thing: to facilitate generating
51 code in a single pass, we generate position-independent code. To
52 do this, calls and jmps to fixed addresses must specify the address
53 by first loading it into a register, and jump to/call that
54 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000055 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000056 call insns may only have a register as target anyway, so there's no
57 need to do anything fancy for them.
58
59 The emit_* routines constitute the lowest level of instruction
60 emission. They simply emit the sequence of bytes corresponding to
61 the relevant instruction, with no further ado. In particular there
62 is no checking about whether uses of byte registers makes sense,
63 nor whether shift insns have their first operand in %cl, etc.
64
65 These issues are taken care of by the level above, the synth_*
66 routines. These detect impossible operand combinations and turn
67 them into sequences of legal instructions. Finally, emitUInstr is
68 phrased in terms of the synth_* abstraction layer. */
69
70static UChar* emitted_code;
71static Int emitted_code_used;
72static Int emitted_code_size;
73
njn25e49d8e72002-09-23 09:36:25 +000074/* Statistics about C functions called from generated code. */
75static UInt ccalls = 0;
76static UInt ccall_reg_saves = 0;
77static UInt ccall_args = 0;
78static UInt ccall_arg_setup_instrs = 0;
79static UInt ccall_stack_clears = 0;
80static UInt ccall_retvals = 0;
81static UInt ccall_retval_movs = 0;
82
83/* Statistics about frequency of each UInstr */
84typedef
85 struct {
86 UInt counts;
87 UInt size;
88 } Histogram;
89
90/* Automatically zeroed because it's static. */
91static Histogram histogram[100];
92
93void VG_(print_ccall_stats)(void)
94{
95 VG_(message)(Vg_DebugMsg,
96 " ccalls: %u C calls, %u%% saves+restores avoided"
97 " (%d bytes)",
98 ccalls,
99 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
100 ((ccalls*3) - ccall_reg_saves)*2);
101 VG_(message)(Vg_DebugMsg,
102 " %u args, avg 0.%d setup instrs each (%d bytes)",
103 ccall_args,
104 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
105 (ccall_args - ccall_arg_setup_instrs)*2);
106 VG_(message)(Vg_DebugMsg,
107 " %d%% clear the stack (%d bytes)",
108 (UInt)(ccall_stack_clears/(double)ccalls*100),
109 (ccalls - ccall_stack_clears)*3);
110 VG_(message)(Vg_DebugMsg,
111 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
112 ccall_retvals,
113 ( ccall_retvals == 0
114 ? 100
115 : 100-(UInt)(ccall_retval_movs /
116 (double)ccall_retvals*100)),
117 (ccall_retvals-ccall_retval_movs)*2);
118}
119
120void VG_(print_UInstr_histogram)(void)
121{
122 Int i, j;
123 UInt total_counts = 0;
124 UInt total_size = 0;
125
126 for (i = 0; i < 100; i++) {
127 total_counts += histogram[i].counts;
128 total_size += histogram[i].size;
129 }
130
131 VG_(printf)("-- UInstr frequencies -----------\n");
132 for (i = 0; i < 100; i++) {
133 if (0 != histogram[i].counts) {
134
135 UInt count_pc =
136 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
137 UInt size_pc =
138 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
139 UInt avg_size =
140 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
141
142 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
143 VG_(nameUOpcode)(True, i),
144 histogram[i].counts, count_pc,
145 avg_size, size_pc);
146
147 for (j = 0; j < size_pc; j++) VG_(printf)("O");
148 VG_(printf)("\n");
149
150 } else {
151 vg_assert(0 == histogram[i].size);
152 }
153 }
154
155 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
156}
157
sewardjde4a1d02002-03-22 01:27:54 +0000158static void expandEmittedCode ( void )
159{
160 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000161 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000162 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
163 for (i = 0; i < emitted_code_size; i++)
164 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000165 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000166 emitted_code = tmp;
167 emitted_code_size *= 2;
168}
169
njn25e49d8e72002-09-23 09:36:25 +0000170/* Local calls will be inlined, cross-module ones not */
171__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000172{
173 if (dis) {
174 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
175 }
176 if (emitted_code_used == emitted_code_size)
177 expandEmittedCode();
178
179 emitted_code[emitted_code_used] = (UChar)b;
180 emitted_code_used++;
181}
182
njn25e49d8e72002-09-23 09:36:25 +0000183__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000184{
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(emitB) ( (l) & 0x000000FF );
186 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000187}
188
njn25e49d8e72002-09-23 09:36:25 +0000189__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000190{
njn25e49d8e72002-09-23 09:36:25 +0000191 VG_(emitB) ( (l) & 0x000000FF );
192 VG_(emitB) ( (l >> 8) & 0x000000FF );
193 VG_(emitB) ( (l >> 16) & 0x000000FF );
194 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000195}
196
njn25e49d8e72002-09-23 09:36:25 +0000197__inline__ void VG_(newEmit) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000198{
199 if (dis)
200 VG_(printf)("\t %4d: ", emitted_code_used );
201}
202
sewardjde4a1d02002-03-22 01:27:54 +0000203
204/*----------------------------------------------------*/
205/*--- Addressing modes ---*/
206/*----------------------------------------------------*/
207
208static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
209{
210 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
211}
212
213static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
214{
215 Int shift;
216 switch (scale) {
217 case 1: shift = 0; break;
218 case 2: shift = 1; break;
219 case 4: shift = 2; break;
220 case 8: shift = 3; break;
221 default: VG_(panic)( "mkSIB" );
222 }
223 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
224}
225
226static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
227{
228 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000229 VG_(emitB) ( mkModRegRM(0, reg, 5) );
230 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000231}
232
233static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
234{
235 /* (regmem), reg */
236 if (regmem == R_ESP)
237 VG_(panic)("emit_amode_regmem_reg");
238 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000239 VG_(emitB) ( mkModRegRM(1, reg, 5) );
240 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000241 } else {
njn25e49d8e72002-09-23 09:36:25 +0000242 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000243 }
244}
245
njn25e49d8e72002-09-23 09:36:25 +0000246void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000247{
248 if (regmem == R_ESP)
249 VG_(panic)("emit_amode_offregmem_reg(ESP)");
250 if (off < -128 || off > 127) {
251 /* Use a large offset */
252 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000253 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
254 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000255 } else {
256 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000257 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
258 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000259 }
260}
261
262static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
263 Int regindex, Int reg )
264{
265 if (regindex == R_ESP)
266 VG_(panic)("emit_amode_sib_reg(ESP)");
267 if (off < -128 || off > 127) {
268 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000269 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
270 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
271 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000272 } else {
273 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000274 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
275 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
276 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000277 }
278}
279
njn25e49d8e72002-09-23 09:36:25 +0000280void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000281{
282 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000283 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000284}
285
286static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
287{
288 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000289 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000290}
291
292
293/*----------------------------------------------------*/
294/*--- Opcode translation ---*/
295/*----------------------------------------------------*/
296
297static __inline__ Int mkGrp1opcode ( Opcode opc )
298{
299 switch (opc) {
300 case ADD: return 0;
301 case OR: return 1;
302 case ADC: return 2;
303 case SBB: return 3;
304 case AND: return 4;
305 case SUB: return 5;
306 case XOR: return 6;
307 default: VG_(panic)("mkGrp1opcode");
308 }
309}
310
311static __inline__ Int mkGrp2opcode ( Opcode opc )
312{
313 switch (opc) {
314 case ROL: return 0;
315 case ROR: return 1;
316 case RCL: return 2;
317 case RCR: return 3;
318 case SHL: return 4;
319 case SHR: return 5;
320 case SAR: return 7;
321 default: VG_(panic)("mkGrp2opcode");
322 }
323}
324
325static __inline__ Int mkGrp3opcode ( Opcode opc )
326{
327 switch (opc) {
328 case NOT: return 2;
329 case NEG: return 3;
330 default: VG_(panic)("mkGrp3opcode");
331 }
332}
333
334static __inline__ Int mkGrp4opcode ( Opcode opc )
335{
336 switch (opc) {
337 case INC: return 0;
338 case DEC: return 1;
339 default: VG_(panic)("mkGrp4opcode");
340 }
341}
342
343static __inline__ Int mkGrp5opcode ( Opcode opc )
344{
345 switch (opc) {
346 case CALLM: return 2;
347 case JMP: return 4;
348 default: VG_(panic)("mkGrp5opcode");
349 }
350}
351
352static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
353{
354 switch (opc) {
355 case ADD: return 0x00;
356 case ADC: return 0x10;
357 case AND: return 0x20;
358 case XOR: return 0x30;
359 case OR: return 0x08;
360 case SBB: return 0x18;
361 case SUB: return 0x28;
362 default: VG_(panic)("mkPrimaryOpcode");
363 }
364}
365
366/*----------------------------------------------------*/
367/*--- v-size (4, or 2 with OSO) insn emitters ---*/
368/*----------------------------------------------------*/
369
njn25e49d8e72002-09-23 09:36:25 +0000370void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000371{
njn25e49d8e72002-09-23 09:36:25 +0000372 VG_(newEmit)();
373 if (sz == 2) VG_(emitB) ( 0x66 );
374 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
375 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000376 if (dis)
377 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
378 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
379}
380
njn25e49d8e72002-09-23 09:36:25 +0000381void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000382{
njn25e49d8e72002-09-23 09:36:25 +0000383 VG_(newEmit)();
384 if (sz == 2) VG_(emitB) ( 0x66 );
385 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
386 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000387 if (dis)
388 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
389 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
390}
391
392static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
393{
njn25e49d8e72002-09-23 09:36:25 +0000394 VG_(newEmit)();
395 if (sz == 2) VG_(emitB) ( 0x66 );
396 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000397 emit_amode_regmem_reg ( reg1, reg2 );
398 if (dis)
399 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
400 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
401}
402
403static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
404{
njn25e49d8e72002-09-23 09:36:25 +0000405 VG_(newEmit)();
406 if (sz == 2) VG_(emitB) ( 0x66 );
407 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000408 emit_amode_regmem_reg ( reg2, reg1 );
409 if (dis)
410 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
411 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
412}
413
njn25e49d8e72002-09-23 09:36:25 +0000414void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000415{
njn25e49d8e72002-09-23 09:36:25 +0000416 VG_(newEmit)();
417 if (sz == 2) VG_(emitB) ( 0x66 );
418 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
419 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000420 if (dis)
421 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
422 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
423}
424
njn25e49d8e72002-09-23 09:36:25 +0000425void VG_(emit_nonshiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000426{
njn25e49d8e72002-09-23 09:36:25 +0000427 VG_(newEmit)();
428 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000429 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
430 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000431 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
432 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
433 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000434 } else {
njn25e49d8e72002-09-23 09:36:25 +0000435 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
436 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
437 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000438 }
439 if (dis)
440 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
441 VG_(nameUOpcode)(False,opc), nameISize(sz),
442 lit, nameIReg(sz,reg));
443}
444
njn25e49d8e72002-09-23 09:36:25 +0000445void VG_(emit_shiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000446{
njn25e49d8e72002-09-23 09:36:25 +0000447 VG_(newEmit)();
448 if (sz == 2) VG_(emitB) ( 0x66 );
449 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
450 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
451 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000452 if (dis)
453 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
454 VG_(nameUOpcode)(False,opc), nameISize(sz),
455 lit, nameIReg(sz,reg));
456}
457
458static void emit_shiftopv_cl_stack0 ( Int sz, Opcode opc )
459{
njn25e49d8e72002-09-23 09:36:25 +0000460 VG_(newEmit)();
461 if (sz == 2) VG_(emitB) ( 0x66 );
462 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
463 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
464 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
465 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000466 if (dis)
467 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
468 VG_(nameUOpcode)(False,opc), nameISize(sz) );
469}
470
471static void emit_shiftopb_cl_stack0 ( Opcode opc )
472{
njn25e49d8e72002-09-23 09:36:25 +0000473 VG_(newEmit)();
474 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
475 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
476 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
477 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000478 if (dis)
479 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
480 VG_(nameUOpcode)(False,opc), nameISize(1) );
481}
482
483static void emit_nonshiftopv_offregmem_reg ( Int sz, Opcode opc,
484 Int off, Int areg, Int reg )
485{
njn25e49d8e72002-09-23 09:36:25 +0000486 VG_(newEmit)();
487 if (sz == 2) VG_(emitB) ( 0x66 );
488 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
489 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000490 if (dis)
491 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
492 VG_(nameUOpcode)(False,opc), nameISize(sz),
493 off, nameIReg(4,areg), nameIReg(sz,reg));
494}
495
njn25e49d8e72002-09-23 09:36:25 +0000496void VG_(emit_nonshiftopv_reg_reg) ( Int sz, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000497 Int reg1, Int reg2 )
498{
njn25e49d8e72002-09-23 09:36:25 +0000499 VG_(newEmit)();
500 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000501# if 0
502 /* Perfectly correct, but the GNU assembler uses the other form.
503 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000504 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
505 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000506# else
njn25e49d8e72002-09-23 09:36:25 +0000507 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000508 emit_amode_greg_ereg ( reg1, reg2 );
509# endif
510 if (dis)
511 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
512 VG_(nameUOpcode)(False,opc), nameISize(sz),
513 nameIReg(sz,reg1), nameIReg(sz,reg2));
514}
515
njn25e49d8e72002-09-23 09:36:25 +0000516void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000517{
518 if (lit == 0) {
njn25e49d8e72002-09-23 09:36:25 +0000519 VG_(emit_nonshiftopv_reg_reg) ( sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000520 return;
521 }
njn25e49d8e72002-09-23 09:36:25 +0000522 VG_(newEmit)();
523 if (sz == 2) VG_(emitB) ( 0x66 );
524 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
525 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000526 if (dis)
527 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
528 nameISize(sz), lit, nameIReg(sz,reg));
529}
530
njn25e49d8e72002-09-23 09:36:25 +0000531void VG_(emit_unaryopv_reg) ( Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000532{
njn25e49d8e72002-09-23 09:36:25 +0000533 VG_(newEmit)();
534 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000535 switch (opc) {
536 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000537 VG_(emitB) ( 0xF7 );
538 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000539 if (dis)
540 VG_(printf)( "\n\t\tneg%c\t%s\n",
541 nameISize(sz), nameIReg(sz,reg));
542 break;
543 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000544 VG_(emitB) ( 0xF7 );
545 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000546 if (dis)
547 VG_(printf)( "\n\t\tnot%c\t%s\n",
548 nameISize(sz), nameIReg(sz,reg));
549 break;
550 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000551 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000552 if (dis)
553 VG_(printf)( "\n\t\tdec%c\t%s\n",
554 nameISize(sz), nameIReg(sz,reg));
555 break;
556 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000557 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000558 if (dis)
559 VG_(printf)( "\n\t\tinc%c\t%s\n",
560 nameISize(sz), nameIReg(sz,reg));
561 break;
562 default:
njn25e49d8e72002-09-23 09:36:25 +0000563 VG_(panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000564 }
565}
566
njn25e49d8e72002-09-23 09:36:25 +0000567void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000568{
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(newEmit)();
sewardjde4a1d02002-03-22 01:27:54 +0000570 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000571 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000572 } else {
573 vg_assert(sz == 4);
574 }
njn25e49d8e72002-09-23 09:36:25 +0000575 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000576 if (dis)
577 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
578}
579
njn25e49d8e72002-09-23 09:36:25 +0000580void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000581{
njn25e49d8e72002-09-23 09:36:25 +0000582 VG_(newEmit)();
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000584 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000585 } else {
586 vg_assert(sz == 4);
587 }
njn25e49d8e72002-09-23 09:36:25 +0000588 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000589 if (dis)
590 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
591}
592
njn25e49d8e72002-09-23 09:36:25 +0000593void VG_(emit_pushl_lit32) ( UInt int32 )
594{
595 VG_(newEmit)();
596 VG_(emitB) ( 0x68 );
597 VG_(emitL) ( int32 );
598 if (dis)
599 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
600}
601
602void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +0000603{
604 vg_assert(lit8 >= -128 && lit8 < 128);
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(newEmit)();
606 VG_(emitB) ( 0x6A );
607 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +0000608 if (dis)
609 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
610}
611
njn25e49d8e72002-09-23 09:36:25 +0000612void VG_(emit_cmpl_zero_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000613{
njn25e49d8e72002-09-23 09:36:25 +0000614 VG_(newEmit)();
615 VG_(emitB) ( 0x83 );
616 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
617 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000618 if (dis)
619 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
620}
621
622static void emit_swapl_reg_ECX ( Int reg )
623{
njn25e49d8e72002-09-23 09:36:25 +0000624 VG_(newEmit)();
625 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
626 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +0000627 if (dis)
628 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
629}
630
njn25e49d8e72002-09-23 09:36:25 +0000631void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000632{
njn25e49d8e72002-09-23 09:36:25 +0000633 VG_(newEmit)();
634 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +0000635 if (dis)
636 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
637}
638
639static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
640{
njn25e49d8e72002-09-23 09:36:25 +0000641 VG_(newEmit)();
642 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
643 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000644 if (dis)
645 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
646 nameIReg(4,reg2));
647}
648
649static void emit_bswapl_reg ( Int reg )
650{
njn25e49d8e72002-09-23 09:36:25 +0000651 VG_(newEmit)();
652 VG_(emitB) ( 0x0F );
653 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +0000654 if (dis)
655 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
656}
657
658static void emit_movl_reg_reg ( Int regs, Int regd )
659{
njn25e49d8e72002-09-23 09:36:25 +0000660 VG_(newEmit)();
661 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
662 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +0000663 if (dis)
664 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
665}
666
njn25e49d8e72002-09-23 09:36:25 +0000667void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +0000668{
njn25e49d8e72002-09-23 09:36:25 +0000669 VG_(newEmit)();
sewardjde4a1d02002-03-22 01:27:54 +0000670 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000671 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000672 } else {
673 vg_assert(sz == 4);
674 }
njn25e49d8e72002-09-23 09:36:25 +0000675 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
676 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
677 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000678 if (dis)
679 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
680 nameISize(sz), lit, off, nameIReg(4,memreg) );
681}
682
683
684/*----------------------------------------------------*/
685/*--- b-size (1 byte) instruction emitters ---*/
686/*----------------------------------------------------*/
687
688/* There is some doubt as to whether C6 (Grp 11) is in the
689 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +0000690void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
691{
692 VG_(newEmit)();
693 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
694 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
695 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000696 if (dis)
697 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
698 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +0000699}
700
sewardjde4a1d02002-03-22 01:27:54 +0000701static void emit_nonshiftopb_offregmem_reg ( Opcode opc,
702 Int off, Int areg, Int reg )
703{
njn25e49d8e72002-09-23 09:36:25 +0000704 VG_(newEmit)();
705 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
706 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000707 if (dis)
708 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
709 VG_(nameUOpcode)(False,opc), off, nameIReg(4,areg),
710 nameIReg(1,reg));
711}
712
njn25e49d8e72002-09-23 09:36:25 +0000713void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000714{
715 /* Could do better when reg == %al. */
njn25e49d8e72002-09-23 09:36:25 +0000716 VG_(newEmit)();
717 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
718 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000719 if (dis)
720 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
721 nameIReg(1,reg), off, nameIReg(4,areg));
722}
723
724static void emit_nonshiftopb_reg_reg ( Opcode opc, Int reg1, Int reg2 )
725{
njn25e49d8e72002-09-23 09:36:25 +0000726 VG_(newEmit)();
727 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
728 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000729 if (dis)
730 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
731 VG_(nameUOpcode)(False,opc),
732 nameIReg(1,reg1), nameIReg(1,reg2));
733}
734
735static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
736{
njn25e49d8e72002-09-23 09:36:25 +0000737 VG_(newEmit)();
738 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +0000739 emit_amode_regmem_reg ( reg2, reg1 );
740 if (dis)
741 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
742 nameIReg(4,reg2));
743}
744
745static void emit_nonshiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
746{
njn25e49d8e72002-09-23 09:36:25 +0000747 VG_(newEmit)();
748 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
749 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
750 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000751 if (dis)
752 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(nameUOpcode)(False,opc),
753 lit, nameIReg(1,reg));
754}
755
756static void emit_shiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
757{
njn25e49d8e72002-09-23 09:36:25 +0000758 VG_(newEmit)();
759 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
760 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
761 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000762 if (dis)
763 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
764 VG_(nameUOpcode)(False,opc),
765 lit, nameIReg(1,reg));
766}
767
njn25e49d8e72002-09-23 09:36:25 +0000768void VG_(emit_unaryopb_reg) ( Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000769{
njn25e49d8e72002-09-23 09:36:25 +0000770 VG_(newEmit)();
sewardjde4a1d02002-03-22 01:27:54 +0000771 switch (opc) {
772 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000773 VG_(emitB) ( 0xFE );
774 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +0000775 if (dis)
776 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
777 break;
778 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000779 VG_(emitB) ( 0xFE );
780 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +0000781 if (dis)
782 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
783 break;
784 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000785 VG_(emitB) ( 0xF6 );
786 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000787 if (dis)
788 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
789 break;
790 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000791 VG_(emitB) ( 0xF6 );
792 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000793 if (dis)
794 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
795 break;
796 default:
njn25e49d8e72002-09-23 09:36:25 +0000797 VG_(panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000798 }
799}
800
njn25e49d8e72002-09-23 09:36:25 +0000801void VG_(emit_testb_lit_reg) ( UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000802{
njn25e49d8e72002-09-23 09:36:25 +0000803 VG_(newEmit)();
804 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
805 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
806 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000807 if (dis)
808 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
809}
810
sewardjde4a1d02002-03-22 01:27:54 +0000811/*----------------------------------------------------*/
812/*--- zero-extended load emitters ---*/
813/*----------------------------------------------------*/
814
njn25e49d8e72002-09-23 09:36:25 +0000815void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000816{
njn25e49d8e72002-09-23 09:36:25 +0000817 VG_(newEmit)();
818 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
819 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000820 if (dis)
821 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
822 off, nameIReg(4,regmem), nameIReg(4,reg));
823}
824
825static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
826{
njn25e49d8e72002-09-23 09:36:25 +0000827 VG_(newEmit)();
828 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +0000829 emit_amode_regmem_reg ( reg1, reg2 );
830 if (dis)
831 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
832 nameIReg(4,reg2));
833}
834
njn25e49d8e72002-09-23 09:36:25 +0000835void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000836{
njn25e49d8e72002-09-23 09:36:25 +0000837 VG_(newEmit)();
838 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
839 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000840 if (dis)
841 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
842 off, nameIReg(4,areg), nameIReg(4,reg));
843}
844
845static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
846{
njn25e49d8e72002-09-23 09:36:25 +0000847 VG_(newEmit)();
848 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +0000849 emit_amode_regmem_reg ( reg1, reg2 );
850 if (dis)
851 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
852 nameIReg(4,reg2));
853}
854
855/*----------------------------------------------------*/
856/*--- FPU instruction emitters ---*/
857/*----------------------------------------------------*/
858
859static void emit_get_fpu_state ( void )
860{
861 Int off = 4 * VGOFF_(m_fpustate);
njn25e49d8e72002-09-23 09:36:25 +0000862 VG_(newEmit)();
863 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
864 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000865 if (dis)
866 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
867}
868
869static void emit_put_fpu_state ( void )
870{
871 Int off = 4 * VGOFF_(m_fpustate);
njn25e49d8e72002-09-23 09:36:25 +0000872 VG_(newEmit)();
873 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
874 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000875 if (dis)
876 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
877}
878
879static void emit_fpu_no_mem ( UChar first_byte,
880 UChar second_byte )
881{
njn25e49d8e72002-09-23 09:36:25 +0000882 VG_(newEmit)();
883 VG_(emitB) ( first_byte );
884 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000885 if (dis)
886 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
887 (UInt)first_byte, (UInt)second_byte );
888}
889
890static void emit_fpu_regmem ( UChar first_byte,
891 UChar second_byte_masked,
892 Int reg )
893{
njn25e49d8e72002-09-23 09:36:25 +0000894 VG_(newEmit)();
895 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000896 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
897 if (dis)
898 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
899 (UInt)first_byte, (UInt)second_byte_masked,
900 nameIReg(4,reg) );
901}
902
903
904/*----------------------------------------------------*/
905/*--- misc instruction emitters ---*/
906/*----------------------------------------------------*/
907
njn25e49d8e72002-09-23 09:36:25 +0000908void VG_(emit_call_reg) ( Int reg )
909{
910 VG_(newEmit)();
911 VG_(emitB) ( 0xFF ); /* Grp5 */
912 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
913 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +0000914 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +0000915}
916
sewardjde4a1d02002-03-22 01:27:54 +0000917static void emit_call_star_EBP_off ( Int byte_off )
918{
njn25e49d8e72002-09-23 09:36:25 +0000919 VG_(newEmit)();
sewardjde4a1d02002-03-22 01:27:54 +0000920 if (byte_off < -128 || byte_off > 127) {
njn25e49d8e72002-09-23 09:36:25 +0000921 VG_(emitB) ( 0xFF );
922 VG_(emitB) ( 0x95 );
923 VG_(emitL) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000924 } else {
njn25e49d8e72002-09-23 09:36:25 +0000925 VG_(emitB) ( 0xFF );
926 VG_(emitB) ( 0x55 );
927 VG_(emitB) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000928 }
929 if (dis)
930 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
931}
932
933
934static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
935{
936 vg_assert(lit8 >= -128 && lit8 < 128);
njn25e49d8e72002-09-23 09:36:25 +0000937 VG_(newEmit)();
938 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
939 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +0000940 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +0000941 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000942 if (dis)
943 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
944 nameIReg(4,regmem));
945}
946
947
njn25e49d8e72002-09-23 09:36:25 +0000948void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +0000949{
njn25e49d8e72002-09-23 09:36:25 +0000950 if (lit < -128 || lit > 127) VG_(panic)("VG_(emit_add_lit_to_esp)");
951 VG_(newEmit)();
952 VG_(emitB) ( 0x83 );
953 VG_(emitB) ( 0xC4 );
954 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000955 if (dis)
956 VG_(printf)( "\n\t\taddl $%d, %%esp\n", lit );
957}
958
959
960static void emit_movb_AL_zeroESPmem ( void )
961{
962 /* movb %al, 0(%esp) */
963 /* 88442400 movb %al, 0(%esp) */
njn25e49d8e72002-09-23 09:36:25 +0000964 VG_(newEmit)();
965 VG_(emitB) ( 0x88 );
966 VG_(emitB) ( 0x44 );
967 VG_(emitB) ( 0x24 );
968 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000969 if (dis)
970 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
971}
972
973static void emit_movb_zeroESPmem_AL ( void )
974{
975 /* movb 0(%esp), %al */
976 /* 8A442400 movb 0(%esp), %al */
njn25e49d8e72002-09-23 09:36:25 +0000977 VG_(newEmit)();
978 VG_(emitB) ( 0x8A );
979 VG_(emitB) ( 0x44 );
980 VG_(emitB) ( 0x24 );
981 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000982 if (dis)
983 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
984}
985
986
987/* Emit a jump short with an 8-bit signed offset. Note that the
988 offset is that which should be added to %eip once %eip has been
989 advanced over this insn. */
njn25e49d8e72002-09-23 09:36:25 +0000990void VG_(emit_jcondshort_delta) ( Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +0000991{
992 vg_assert(delta >= -128 && delta <= 127);
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(newEmit)();
994 VG_(emitB) ( 0x70 + (UInt)cond );
995 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +0000996 if (dis)
997 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
998 VG_(nameCondcode)(cond), delta );
999}
1000
1001static void emit_get_eflags ( void )
1002{
1003 Int off = 4 * VGOFF_(m_eflags);
1004 vg_assert(off >= 0 && off < 128);
njn25e49d8e72002-09-23 09:36:25 +00001005 VG_(newEmit)();
1006 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
1007 VG_(emitB) ( 0x75 );
1008 VG_(emitB) ( off );
1009 VG_(emitB) ( 0x9D ); /* POPFL */
sewardjde4a1d02002-03-22 01:27:54 +00001010 if (dis)
1011 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
1012}
1013
1014static void emit_put_eflags ( void )
1015{
1016 Int off = 4 * VGOFF_(m_eflags);
1017 vg_assert(off >= 0 && off < 128);
njn25e49d8e72002-09-23 09:36:25 +00001018 VG_(newEmit)();
1019 VG_(emitB) ( 0x9C ); /* PUSHFL */
1020 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
1021 VG_(emitB) ( 0x45 );
1022 VG_(emitB) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001023 if (dis)
1024 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
1025}
1026
1027static void emit_setb_reg ( Int reg, Condcode cond )
1028{
njn25e49d8e72002-09-23 09:36:25 +00001029 VG_(newEmit)();
1030 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1031 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001032 if (dis)
1033 VG_(printf)("\n\t\tset%s %s\n",
1034 VG_(nameCondcode)(cond), nameIReg(1,reg));
1035}
1036
1037static void emit_ret ( void )
1038{
njn25e49d8e72002-09-23 09:36:25 +00001039 VG_(newEmit)();
1040 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001041 if (dis)
1042 VG_(printf)("\n\t\tret\n");
1043}
1044
njn25e49d8e72002-09-23 09:36:25 +00001045void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001046{
njn25e49d8e72002-09-23 09:36:25 +00001047 VG_(newEmit)();
1048 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001049 if (dis)
1050 VG_(printf)("\n\t\tpushal\n");
1051}
1052
njn25e49d8e72002-09-23 09:36:25 +00001053void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001054{
njn25e49d8e72002-09-23 09:36:25 +00001055 VG_(newEmit)();
1056 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001057 if (dis)
1058 VG_(printf)("\n\t\tpopal\n");
1059}
1060
1061static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1062{
njn25e49d8e72002-09-23 09:36:25 +00001063 VG_(newEmit)();
1064 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1065 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001066 if (dis)
1067 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1068 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1069}
1070
1071static void emit_lea_sib_reg ( UInt lit, Int scale,
1072 Int regbase, Int regindex, Int reg )
1073{
njn25e49d8e72002-09-23 09:36:25 +00001074 VG_(newEmit)();
1075 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001076 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1077 if (dis)
1078 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1079 lit, nameIReg(4,regbase),
1080 nameIReg(4,regindex), scale,
1081 nameIReg(4,reg) );
1082}
1083
njn25e49d8e72002-09-23 09:36:25 +00001084void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001085{
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(newEmit)();
1087 VG_(emitB) ( 0x0F );
1088 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001089 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1090 if (dis)
1091 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1092}
1093
1094/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001095/*--- Helper offset -> addr translation ---*/
1096/*----------------------------------------------------*/
1097
1098/* Finds the baseBlock offset of a skin-specified helper.
1099 * Searches through compacts first, then non-compacts. */
1100Int VG_(helper_offset)(Addr a)
1101{
1102 Int i;
1103
1104 for (i = 0; i < VG_(n_compact_helpers); i++)
1105 if (VG_(compact_helper_addrs)[i] == a)
1106 return VG_(compact_helper_offsets)[i];
1107 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1108 if (VG_(noncompact_helper_addrs)[i] == a)
1109 return VG_(noncompact_helper_offsets)[i];
1110
1111 /* Shouldn't get here */
1112 VG_(printf)(
1113 "\nCouldn't find offset of helper from its address (%p).\n"
1114 "A helper function probably used hasn't been registered?\n\n", a);
1115
1116 VG_(printf)(" compact helpers: ");
1117 for (i = 0; i < VG_(n_compact_helpers); i++)
1118 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1119
1120 VG_(printf)("\n non-compact helpers: ");
1121 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1122 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1123
1124 VG_(printf)("\n");
1125 VG_(skin_error)("Unfound helper");
1126}
1127
1128/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001129/*--- Instruction synthesisers ---*/
1130/*----------------------------------------------------*/
1131
1132static Condcode invertCondition ( Condcode cond )
1133{
1134 return (Condcode)(1 ^ (UInt)cond);
1135}
1136
1137
1138/* Synthesise a call to *baseBlock[offset], ie,
1139 call * (4 x offset)(%ebp).
1140*/
njn25e49d8e72002-09-23 09:36:25 +00001141void VG_(synth_call) ( Bool ensure_shortform, Int word_offset )
sewardjde4a1d02002-03-22 01:27:54 +00001142{
1143 vg_assert(word_offset >= 0);
1144 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1145 if (ensure_shortform)
1146 vg_assert(word_offset < 32);
1147 emit_call_star_EBP_off ( 4 * word_offset );
1148}
1149
njn25e49d8e72002-09-23 09:36:25 +00001150static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001151{
njn25e49d8e72002-09-23 09:36:25 +00001152 if (src != dst) {
1153 VG_(emit_movv_reg_reg) ( 4, src, dst );
1154 ccall_arg_setup_instrs++;
1155 }
njn6431be72002-07-28 09:53:34 +00001156}
njn25e49d8e72002-09-23 09:36:25 +00001157
1158/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1159static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1160{
1161 if (RealReg == tag) {
1162 maybe_emit_movl_reg_reg ( litOrReg, reg );
1163 } else if (Literal == tag) {
1164 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1165 ccall_arg_setup_instrs++;
1166 }
1167 else
1168 VG_(panic)("emit_movl_litOrReg_reg: unexpected tag");
1169}
1170
1171static
1172void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1173{
1174 if (R_EAX == reg1) {
1175 VG_(emit_swapl_reg_EAX) ( reg2 );
1176 } else if (R_EAX == reg2) {
1177 VG_(emit_swapl_reg_EAX) ( reg1 );
1178 } else {
1179 emit_swapl_reg_reg ( reg1, reg2 );
1180 }
1181 ccall_arg_setup_instrs++;
1182}
1183
1184static
1185void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1186{
1187 if (dst1 != src2) {
1188 maybe_emit_movl_reg_reg ( src1, dst1 );
1189 maybe_emit_movl_reg_reg ( src2, dst2 );
1190
1191 } else if (dst2 != src1) {
1192 maybe_emit_movl_reg_reg ( src2, dst2 );
1193 maybe_emit_movl_reg_reg ( src1, dst1 );
1194
1195 } else {
1196 /* swap to break cycle */
1197 emit_swapl_arg_regs ( dst1, dst2 );
1198 }
1199}
1200
1201static
1202void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1203 UInt dst1, UInt dst2, UInt dst3)
1204{
1205 if (dst1 != src2 && dst1 != src3) {
1206 maybe_emit_movl_reg_reg ( src1, dst1 );
1207 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1208
1209 } else if (dst2 != src1 && dst2 != src3) {
1210 maybe_emit_movl_reg_reg ( src2, dst2 );
1211 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1212
1213 } else if (dst3 != src1 && dst3 != src2) {
1214 maybe_emit_movl_reg_reg ( src3, dst3 );
1215 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1216
1217 } else {
1218 /* break cycle */
1219 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1220 emit_swapl_arg_regs ( dst1, dst2 );
1221 emit_swapl_arg_regs ( dst1, dst3 );
1222
1223 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1224 emit_swapl_arg_regs ( dst1, dst3 );
1225 emit_swapl_arg_regs ( dst1, dst2 );
1226
1227 } else {
1228 VG_(panic)("impossible 3-cycle");
1229 }
1230 }
1231}
1232
1233static
1234void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1235 UInt src1, UInt src2,
1236 UInt dst1, UInt dst2)
1237{
1238 /* If either are lits, order doesn't matter */
1239 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1240 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1241 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1242
1243 } else {
1244 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1245 }
1246}
1247
1248static
1249void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1250 UInt src1, UInt src2, UInt src3,
1251 UInt dst1, UInt dst2, UInt dst3)
1252{
1253 // SSS: fix this eventually -- make STOREV use two RealRegs?
1254 /* Not supporting literals for 3-arg C functions -- they're only used
1255 by STOREV which has 2 args */
1256 vg_assert(RealReg == tagv[src1] &&
1257 RealReg == tagv[src2] &&
1258 RealReg == tagv[src3]);
1259 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1260 dst1, dst2, dst3 );
1261}
1262
1263/* Synthesise a call to a C function `fn' (which must be registered in
1264 baseBlock) doing all the reg saving and arg handling work.
1265
1266 WARNING: a UInstr should *not* be translated with synth_ccall followed
1267 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1268 such behaviour and everything will fall over.
1269 */
1270void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1271 Tag tagv[], Int ret_reg,
1272 RRegSet regs_live_before, RRegSet regs_live_after )
1273{
1274 Int i;
1275 Int stack_used = 0;
1276 Bool preserve_eax, preserve_ecx, preserve_edx;
1277
1278 vg_assert(0 <= regparms_n && regparms_n <= 3);
1279
1280 ccalls++;
1281
1282 /* If %e[acd]x is live before and after the C call, save/restore it.
1283 Unless the return values clobbers the reg; in this case we must not
1284 save/restore the reg, because the restore would clobber the return
1285 value. (Before and after the UInstr really constitute separate live
1286 ranges, but you miss this if you don't consider what happens during
1287 the UInstr.) */
1288# define PRESERVE_REG(realReg) \
1289 (IS_RREG_LIVE(VG_(realRegNumToRank)(realReg), regs_live_before) && \
1290 IS_RREG_LIVE(VG_(realRegNumToRank)(realReg), regs_live_after) && \
1291 ret_reg != realReg)
1292
1293 preserve_eax = PRESERVE_REG(R_EAX);
1294 preserve_ecx = PRESERVE_REG(R_ECX);
1295 preserve_edx = PRESERVE_REG(R_EDX);
1296
1297# undef PRESERVE_REG
1298
1299 /* Save caller-save regs as required */
1300 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1301 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1302 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1303
1304 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1305 is the number of args passed in regs (maximum 3 for GCC on x86). */
1306
1307 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001308
njn25e49d8e72002-09-23 09:36:25 +00001309 /* First push stack args (RealRegs or Literals) in reverse order. */
1310 for (i = argc-1; i >= regparms_n; i--) {
1311 switch (tagv[i]) {
1312 case RealReg:
1313 VG_(emit_pushv_reg) ( 4, argv[i] );
1314 break;
1315 case Literal:
1316 /* Use short form of pushl if possible. */
1317 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1318 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1319 else
1320 VG_(emit_pushl_lit32)( argv[i] );
1321 break;
1322 default:
1323 VG_(printf)("tag=%d\n", tagv[i]);
1324 VG_(panic)("VG_(synth_ccall): bad tag");
1325 }
1326 stack_used += 4;
1327 ccall_arg_setup_instrs++;
1328 }
njn6431be72002-07-28 09:53:34 +00001329
njn25e49d8e72002-09-23 09:36:25 +00001330 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1331 If moving values between registers, be careful not to clobber any on
1332 the way. Happily we can use xchgl to swap registers.
1333 */
1334 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001335
njn25e49d8e72002-09-23 09:36:25 +00001336 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1337 case 3:
1338 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1339 R_EAX, R_EDX, R_ECX );
1340 break;
njn6431be72002-07-28 09:53:34 +00001341
njn25e49d8e72002-09-23 09:36:25 +00001342 /* Less-tricky. Args passed in %eax and %edx. */
1343 case 2:
1344 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1345 break;
1346
1347 /* Easy. Just move arg1 into %eax (if not already in there). */
1348 case 1:
1349 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1350 break;
1351
1352 case 0:
1353 break;
1354
1355 default:
1356 VG_(panic)("VG_(synth_call): regparms_n value not in range 0..3");
1357 }
1358
1359 /* Call the function */
1360 VG_(synth_call) ( False, VG_(helper_offset) ( fn ) );
1361
1362 /* Clear any args from stack */
1363 if (0 != stack_used) {
1364 VG_(emit_add_lit_to_esp) ( stack_used );
1365 ccall_stack_clears++;
1366 }
1367
1368 /* Move return value into ret_reg if necessary and not already there */
1369 if (INVALID_REALREG != ret_reg) {
1370 ccall_retvals++;
1371 if (R_EAX != ret_reg) {
1372 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1373 ccall_retval_movs++;
1374 }
1375 }
1376
1377 /* Restore live caller-save regs as required */
1378 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1379 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1380 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001381}
sewardjde4a1d02002-03-22 01:27:54 +00001382
sewardj2e93c502002-04-12 11:12:52 +00001383static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001384{
sewardj2e93c502002-04-12 11:12:52 +00001385 switch (jmpkind) {
1386 case JmpBoring:
1387 break;
sewardj2e93c502002-04-12 11:12:52 +00001388 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001389 break;
1390 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001391 break;
1392 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001393 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001394 break;
1395 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001396 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001397 break;
1398 default:
1399 VG_(panic)("load_ebp_from_JmpKind");
1400 }
1401}
1402
1403/* Jump to the next translation, by loading its original addr into
1404 %eax and returning to the scheduler. Signal special requirements
1405 by loading a special value into %ebp first.
1406*/
1407static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1408{
1409 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001410 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001411 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001412 emit_ret();
1413}
1414
1415
1416/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001417static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001418{
sewardj2e93c502002-04-12 11:12:52 +00001419 load_ebp_from_JmpKind ( jmpkind );
njn25e49d8e72002-09-23 09:36:25 +00001420 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001421 emit_ret();
1422}
1423
1424
sewardjde4a1d02002-03-22 01:27:54 +00001425static void synth_jcond_lit ( Condcode cond, Addr addr )
1426{
1427 /* Do the following:
1428 get eflags
1429 jmp short if not cond to xyxyxy
1430 addr -> eax
1431 ret
1432 xyxyxy
1433
1434 2 0000 750C jnz xyxyxy
1435 3 0002 B877665544 movl $0x44556677, %eax
1436 4 0007 C3 ret
1437 5 0008 FFE3 jmp *%ebx
1438 6 xyxyxy:
1439 */
1440 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001441 VG_(emit_jcondshort_delta) ( invertCondition(cond), 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001442 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001443}
1444
1445
1446static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1447{
1448 /* 0000 83FF00 cmpl $0, %edi
1449 0003 750A jnz next
1450 0005 B844332211 movl $0x11223344, %eax
1451 000a C3 ret
1452 next:
1453 */
njn25e49d8e72002-09-23 09:36:25 +00001454 VG_(emit_cmpl_zero_reg) ( reg );
1455 VG_(emit_jcondshort_delta) ( CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001456 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001457}
1458
1459
1460static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1461{
1462 /* Load the zero-extended literal into reg, at size l,
1463 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00001464 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001465}
1466
1467
1468static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
1469{
1470 switch (size) {
1471 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
1472 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
1473 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
1474 default: VG_(panic)("synth_mov_regmem_reg");
1475 }
1476}
1477
1478
1479static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
1480{
1481 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001482 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
1483 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
1484 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00001485 default: VG_(panic)("synth_mov_offregmem_reg");
1486 }
1487}
1488
1489
1490static void synth_mov_reg_offregmem ( Int size, Int reg,
1491 Int off, Int areg )
1492{
1493 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001494 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
1495 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00001496 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00001497 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00001498 }
1499 else {
njn25e49d8e72002-09-23 09:36:25 +00001500 VG_(emit_swapl_reg_EAX) ( reg );
1501 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
1502 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001503 }
1504 break;
1505 default: VG_(panic)("synth_mov_reg_offregmem");
1506 }
1507}
1508
1509
1510static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
1511{
1512 Int s1;
1513 switch (size) {
1514 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
1515 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
1516 case 1: if (reg1 < 4) {
1517 emit_movb_reg_regmem ( reg1, reg2 );
1518 }
1519 else {
1520 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
1521 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1522 emit_swapl_reg_reg ( s1, reg1 );
1523 emit_movb_reg_regmem ( s1, reg2 );
1524 emit_swapl_reg_reg ( s1, reg1 );
1525 }
1526 break;
1527 default: VG_(panic)("synth_mov_reg_litmem");
1528 }
1529}
1530
1531
njn5a74eb82002-08-06 20:56:40 +00001532static void synth_unaryop_reg ( Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001533 Opcode opcode, Int size,
1534 Int reg )
1535{
1536 /* NB! opcode is a uinstr opcode, not an x86 one! */
1537 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001538 case 4: //if (rd_cc) emit_get_eflags(); (never needed --njn)
njn25e49d8e72002-09-23 09:36:25 +00001539 VG_(emit_unaryopv_reg) ( 4, opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001540 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001541 break;
njn5a74eb82002-08-06 20:56:40 +00001542 case 2: //if (rd_cc) emit_get_eflags(); (never needed --njn)
njn25e49d8e72002-09-23 09:36:25 +00001543 VG_(emit_unaryopv_reg) ( 2, opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001544 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001545 break;
1546 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001547 //if (rd_cc) emit_get_eflags(); (never needed --njn)
njn25e49d8e72002-09-23 09:36:25 +00001548 VG_(emit_unaryopb_reg) ( opcode, reg );
njn5a74eb82002-08-06 20:56:40 +00001549 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001550 } else {
njn25e49d8e72002-09-23 09:36:25 +00001551 VG_(emit_swapl_reg_EAX) ( reg );
njn5a74eb82002-08-06 20:56:40 +00001552 //if (rd_cc) emit_get_eflags(); (never needed --njn)
njn25e49d8e72002-09-23 09:36:25 +00001553 VG_(emit_unaryopb_reg) ( opcode, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001554 if (wr_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001555 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001556 }
1557 break;
1558 default: VG_(panic)("synth_unaryop_reg");
1559 }
1560}
1561
1562
1563
njn5a74eb82002-08-06 20:56:40 +00001564static void synth_nonshiftop_reg_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001565 Opcode opcode, Int size,
1566 Int reg1, Int reg2 )
1567{
1568 /* NB! opcode is a uinstr opcode, not an x86 one! */
1569 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001570 case 4: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001571 VG_(emit_nonshiftopv_reg_reg) ( 4, opcode, reg1, reg2 );
njn5a74eb82002-08-06 20:56:40 +00001572 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001573 break;
njn5a74eb82002-08-06 20:56:40 +00001574 case 2: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001575 VG_(emit_nonshiftopv_reg_reg) ( 2, opcode, reg1, reg2 );
njn5a74eb82002-08-06 20:56:40 +00001576 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001577 break;
1578 case 1: { /* Horrible ... */
1579 Int s1, s2;
1580 /* Choose s1 and s2 to be x86 regs which we can talk about the
1581 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
1582 sure s1 != s2 and that neither of them equal either reg1 or
1583 reg2. Then use them as temporaries to make things work. */
1584 if (reg1 < 4 && reg2 < 4) {
njn5a74eb82002-08-06 20:56:40 +00001585 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001586 emit_nonshiftopb_reg_reg(opcode, reg1, reg2);
njn5a74eb82002-08-06 20:56:40 +00001587 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001588 break;
1589 }
1590 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1591 if (reg1 >= 4 && reg2 < 4) {
1592 emit_swapl_reg_reg ( reg1, s1 );
njn5a74eb82002-08-06 20:56:40 +00001593 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001594 emit_nonshiftopb_reg_reg(opcode, s1, reg2);
njn5a74eb82002-08-06 20:56:40 +00001595 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001596 emit_swapl_reg_reg ( reg1, s1 );
1597 break;
1598 }
1599 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
1600 if (reg1 < 4 && reg2 >= 4) {
1601 emit_swapl_reg_reg ( reg2, s2 );
njn5a74eb82002-08-06 20:56:40 +00001602 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001603 emit_nonshiftopb_reg_reg(opcode, reg1, s2);
njn5a74eb82002-08-06 20:56:40 +00001604 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001605 emit_swapl_reg_reg ( reg2, s2 );
1606 break;
1607 }
1608 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
1609 emit_swapl_reg_reg ( reg1, s1 );
1610 emit_swapl_reg_reg ( reg2, s2 );
njn5a74eb82002-08-06 20:56:40 +00001611 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001612 emit_nonshiftopb_reg_reg(opcode, s1, s2);
njn5a74eb82002-08-06 20:56:40 +00001613 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001614 emit_swapl_reg_reg ( reg1, s1 );
1615 emit_swapl_reg_reg ( reg2, s2 );
1616 break;
1617 }
1618 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
1619 emit_swapl_reg_reg ( reg1, s1 );
njn5a74eb82002-08-06 20:56:40 +00001620 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001621 emit_nonshiftopb_reg_reg(opcode, s1, s1);
njn5a74eb82002-08-06 20:56:40 +00001622 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001623 emit_swapl_reg_reg ( reg1, s1 );
1624 break;
1625 }
1626 VG_(panic)("synth_nonshiftopb_reg_reg");
1627 }
1628 default: VG_(panic)("synth_nonshiftop_reg_reg");
1629 }
1630}
1631
1632
1633static void synth_nonshiftop_offregmem_reg (
njn5a74eb82002-08-06 20:56:40 +00001634 Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001635 Opcode opcode, Int size,
1636 Int off, Int areg, Int reg )
1637{
1638 switch (size) {
1639 case 4:
njn5a74eb82002-08-06 20:56:40 +00001640 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001641 emit_nonshiftopv_offregmem_reg ( 4, opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001642 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001643 break;
1644 case 2:
njn5a74eb82002-08-06 20:56:40 +00001645 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001646 emit_nonshiftopv_offregmem_reg ( 2, opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001647 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001648 break;
1649 case 1:
1650 if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001651 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001652 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, reg );
njn5a74eb82002-08-06 20:56:40 +00001653 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001654 } else {
njn25e49d8e72002-09-23 09:36:25 +00001655 VG_(emit_swapl_reg_EAX) ( reg );
njn5a74eb82002-08-06 20:56:40 +00001656 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001657 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001658 if (wr_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001659 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001660 }
1661 break;
1662 default:
njn5a74eb82002-08-06 20:56:40 +00001663 VG_(panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001664 }
1665}
1666
1667
njn5a74eb82002-08-06 20:56:40 +00001668static void synth_nonshiftop_lit_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001669 Opcode opcode, Int size,
1670 UInt lit, Int reg )
1671{
1672 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001673 case 4: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001674 VG_(emit_nonshiftopv_lit_reg) ( 4, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001675 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001676 break;
njn5a74eb82002-08-06 20:56:40 +00001677 case 2: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001678 VG_(emit_nonshiftopv_lit_reg) ( 2, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001679 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001680 break;
1681 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001682 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001683 emit_nonshiftopb_lit_reg ( opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001684 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001685 } else {
njn25e49d8e72002-09-23 09:36:25 +00001686 VG_(emit_swapl_reg_EAX) ( reg );
njn5a74eb82002-08-06 20:56:40 +00001687 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001688 emit_nonshiftopb_lit_reg ( opcode, lit, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001689 if (wr_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001690 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001691 }
1692 break;
1693 default: VG_(panic)("synth_nonshiftop_lit_reg");
1694 }
1695}
1696
1697
1698static void synth_push_reg ( Int size, Int reg )
1699{
1700 switch (size) {
1701 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001702 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001703 break;
1704 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001705 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001706 break;
1707 /* Pray that we don't have to generate this really cruddy bit of
1708 code very often. Could do better, but can I be bothered? */
1709 case 1:
1710 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001711 VG_(emit_add_lit_to_esp)(-1);
1712 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001713 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00001714 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001715 break;
1716 default:
1717 VG_(panic)("synth_push_reg");
1718 }
1719}
1720
1721
1722static void synth_pop_reg ( Int size, Int reg )
1723{
1724 switch (size) {
1725 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001726 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001727 break;
1728 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001729 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001730 break;
1731 case 1:
1732 /* Same comment as above applies. */
1733 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001734 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001735 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00001736 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
1737 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001738 break;
1739 default: VG_(panic)("synth_pop_reg");
1740 }
1741}
1742
1743
njn5a74eb82002-08-06 20:56:40 +00001744static void synth_shiftop_reg_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001745 Opcode opcode, Int size,
1746 Int regs, Int regd )
1747{
1748 synth_push_reg ( size, regd );
1749 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
njn5a74eb82002-08-06 20:56:40 +00001750 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001751 switch (size) {
1752 case 4: emit_shiftopv_cl_stack0 ( 4, opcode ); break;
1753 case 2: emit_shiftopv_cl_stack0 ( 2, opcode ); break;
1754 case 1: emit_shiftopb_cl_stack0 ( opcode ); break;
1755 default: VG_(panic)("synth_shiftop_reg_reg");
1756 }
njn5a74eb82002-08-06 20:56:40 +00001757 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001758 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
1759 synth_pop_reg ( size, regd );
1760}
1761
1762
njn5a74eb82002-08-06 20:56:40 +00001763static void synth_shiftop_lit_reg ( Bool rd_cc, Bool wr_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001764 Opcode opcode, Int size,
1765 UInt lit, Int reg )
1766{
1767 switch (size) {
njn5a74eb82002-08-06 20:56:40 +00001768 case 4: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001769 VG_(emit_shiftopv_lit_reg) ( 4, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001770 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001771 break;
njn5a74eb82002-08-06 20:56:40 +00001772 case 2: if (rd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001773 VG_(emit_shiftopv_lit_reg) ( 2, opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001774 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001775 break;
1776 case 1: if (reg < 4) {
njn5a74eb82002-08-06 20:56:40 +00001777 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001778 emit_shiftopb_lit_reg ( opcode, lit, reg );
njn5a74eb82002-08-06 20:56:40 +00001779 if (wr_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001780 } else {
njn25e49d8e72002-09-23 09:36:25 +00001781 VG_(emit_swapl_reg_EAX) ( reg );
njn5a74eb82002-08-06 20:56:40 +00001782 if (rd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001783 emit_shiftopb_lit_reg ( opcode, lit, R_AL );
njn5a74eb82002-08-06 20:56:40 +00001784 if (wr_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001785 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001786 }
1787 break;
njn5a74eb82002-08-06 20:56:40 +00001788 default: VG_(panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001789 }
1790}
1791
1792
1793static void synth_setb_reg ( Int reg, Condcode cond )
1794{
1795 emit_get_eflags();
1796 if (reg < 4) {
1797 emit_setb_reg ( reg, cond );
1798 } else {
njn25e49d8e72002-09-23 09:36:25 +00001799 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001800 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00001801 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001802 }
1803}
1804
1805
1806static void synth_fpu_regmem ( UChar first_byte,
1807 UChar second_byte_masked,
1808 Int reg )
1809{
1810 emit_get_fpu_state();
1811 emit_fpu_regmem ( first_byte, second_byte_masked, reg );
1812 emit_put_fpu_state();
1813}
1814
1815
1816static void synth_fpu_no_mem ( UChar first_byte,
1817 UChar second_byte )
1818{
1819 emit_get_fpu_state();
1820 emit_fpu_no_mem ( first_byte, second_byte );
1821 emit_put_fpu_state();
1822}
1823
1824
1825static void synth_movl_reg_reg ( Int src, Int dst )
1826{
1827 emit_movl_reg_reg ( src, dst );
1828}
1829
1830static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
1831{
1832 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001833 VG_(emit_jcondshort_delta) ( invertCondition(cond),
sewardjde4a1d02002-03-22 01:27:54 +00001834 2 /* length of the next insn */ );
1835 emit_movl_reg_reg ( src, dst );
1836}
1837
1838
sewardjde4a1d02002-03-22 01:27:54 +00001839/*----------------------------------------------------*/
1840/*--- Top level of the uinstr -> x86 translation. ---*/
1841/*----------------------------------------------------*/
1842
1843/* Return the byte offset from %ebp (ie, into baseBlock)
1844 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00001845static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
1846{
1847 if (tag == SpillNo) {
1848 vg_assert(size == 4);
1849 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
1850 return 4 * (value + VGOFF_(spillslots));
1851 }
1852 if (tag == ArchReg) {
1853 switch (value) {
1854 case R_EAX: return 4 * VGOFF_(m_eax);
1855 case R_ECX: return 4 * VGOFF_(m_ecx);
1856 case R_EDX: return 4 * VGOFF_(m_edx);
1857 case R_EBX: return 4 * VGOFF_(m_ebx);
1858 case R_ESP:
1859 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
1860 else return 4 * VGOFF_(m_esp);
1861 case R_EBP:
1862 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
1863 else return 4 * VGOFF_(m_ebp);
1864 case R_ESI:
1865 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
1866 else return 4 * VGOFF_(m_esi);
1867 case R_EDI:
1868 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
1869 else return 4 * VGOFF_(m_edi);
1870 }
1871 }
1872 VG_(panic)("spillOrArchOffset");
1873}
1874
sewardjde4a1d02002-03-22 01:27:54 +00001875static Int eflagsOffset ( void )
1876{
1877 return 4 * VGOFF_(m_eflags);
1878}
1879
1880
njn25e49d8e72002-09-23 09:36:25 +00001881/* Return the byte offset from %ebp (ie, into baseBlock)
1882 for the specified shadow register */
1883Int VG_(shadowRegOffset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00001884{
1885 switch (arch) {
1886 case R_EAX: return 4 * VGOFF_(sh_eax);
1887 case R_ECX: return 4 * VGOFF_(sh_ecx);
1888 case R_EDX: return 4 * VGOFF_(sh_edx);
1889 case R_EBX: return 4 * VGOFF_(sh_ebx);
1890 case R_ESP: return 4 * VGOFF_(sh_esp);
1891 case R_EBP: return 4 * VGOFF_(sh_ebp);
1892 case R_ESI: return 4 * VGOFF_(sh_esi);
1893 case R_EDI: return 4 * VGOFF_(sh_edi);
1894 default: VG_(panic)( "shadowOffset");
1895 }
1896}
1897
njn25e49d8e72002-09-23 09:36:25 +00001898Int VG_(shadowFlagsOffset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001899{
1900 return 4 * VGOFF_(sh_eflags);
1901}
1902
1903
sewardjde4a1d02002-03-22 01:27:54 +00001904
1905static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
1906{
1907 if (sz_src == 1 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00001908 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 24, reg );
1909 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001910 }
1911 else if (sz_src == 2 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00001912 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 16, reg );
1913 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001914 }
1915 else if (sz_src == 1 && sz_dst == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001916 VG_(emit_shiftopv_lit_reg) ( 2, SHL, 8, reg );
1917 VG_(emit_shiftopv_lit_reg) ( 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001918 }
1919 else
1920 VG_(panic)("synth_WIDEN");
1921}
1922
1923
njn25e49d8e72002-09-23 09:36:25 +00001924static void synth_handle_esp_assignment ( Int i, Int reg,
1925 RRegSet regs_live_before,
1926 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00001927{
njn25e49d8e72002-09-23 09:36:25 +00001928 UInt argv[] = { reg };
1929 Tag tagv[] = { RealReg };
1930
1931 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
1932 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00001933}
1934
1935
sewardjde4a1d02002-03-22 01:27:54 +00001936/*----------------------------------------------------*/
1937/*--- Generate code for a single UInstr. ---*/
1938/*----------------------------------------------------*/
1939
njn5a74eb82002-08-06 20:56:40 +00001940static Bool readFlagUse ( UInstr* u )
1941{
1942 return (u->flags_r != FlagsEmpty);
1943}
1944
1945static Bool writeFlagUse ( UInstr* u )
1946{
1947 return (u->flags_w != FlagsEmpty);
1948}
1949
njn25e49d8e72002-09-23 09:36:25 +00001950static void emitUInstr ( UCodeBlock* cb, Int i, RRegSet regs_live_before )
sewardjde4a1d02002-03-22 01:27:54 +00001951{
njn25e49d8e72002-09-23 09:36:25 +00001952 Int old_emitted_code_used;
1953 UInstr* u = &cb->instrs[i];
1954
sewardjde4a1d02002-03-22 01:27:54 +00001955 if (dis)
njn25e49d8e72002-09-23 09:36:25 +00001956 VG_(ppUInstrWithRegs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00001957
1958# if 0
1959 if (0&& VG_(translations_done) >= 600) {
1960 Bool old_dis = dis;
1961 dis = False;
1962 synth_OINK(i);
1963 dis = old_dis;
1964 }
1965# endif
1966
njn25e49d8e72002-09-23 09:36:25 +00001967 old_emitted_code_used = emitted_code_used;
1968
sewardjde4a1d02002-03-22 01:27:54 +00001969 switch (u->opcode) {
sewardjde4a1d02002-03-22 01:27:54 +00001970 case NOP: case CALLM_S: case CALLM_E: break;
1971
1972 case INCEIP: {
njn25e49d8e72002-09-23 09:36:25 +00001973 /* Note: Redundant INCEIP merging. A potentially useful
1974 performance enhancementa, but currently disabled. Reason
1975 is that it needs a surefire way to know if a UInstr might
1976 give rise to a stack snapshot being taken. The logic below
1977 is correct (hopefully ...) for the core UInstrs, but is
1978 incorrect if a skin has its own UInstrs, since the logic
1979 currently assumes that none of them can cause a stack
1980 trace, and that's just wrong. Note this isn't
1981 mission-critical -- the system still functions -- but will
1982 cause incorrect source locations in some situations,
1983 specifically for the memcheck skin. This is known to
1984 confuse programmers, understandable. */
1985# if 0
1986 Bool can_skip;
1987 Int j;
1988
1989 /* Scan forwards to see if this INCEIP dominates (in the
1990 technical sense) a later one, AND there are no CCALLs in
1991 between. If so, skip this one and instead add its count
1992 with the later one. */
1993 can_skip = True;
1994 j = i+1;
1995 while (True) {
1996 if (cb->instrs[j].opcode == CCALL
1997 || cb->instrs[j].opcode == CALLM) {
1998 /* CCALL -- we can't skip this INCEIP. */
1999 can_skip = False;
2000 break;
2001 }
2002 if (cb->instrs[j].opcode == INCEIP) {
2003 /* Another INCEIP. Check that the sum will fit. */
2004 if (cb->instrs[i].val1 + cb->instrs[j].val1 > 127)
2005 can_skip = False;
2006 break;
2007 }
2008 if (cb->instrs[j].opcode == JMP || cb->instrs[j].opcode == JIFZ) {
2009 /* Execution is not guaranteed to get beyond this
2010 point. Give up. */
2011 can_skip = False;
2012 break;
2013 }
2014 j++;
2015 /* Assertion should hold because all blocks should end in an
2016 unconditional JMP, so the above test should get us out of
2017 the loop at the end of a block. */
2018 vg_assert(j < cb->used);
2019 }
2020 if (can_skip) {
2021 /* yay! Accumulate the delta into the next INCEIP. */
2022 // VG_(printf)("skip INCEIP %d\n", cb->instrs[i].val1);
2023 vg_assert(j > i);
2024 vg_assert(j < cb->used);
2025 vg_assert(cb->instrs[j].opcode == INCEIP);
2026 vg_assert(cb->instrs[i].opcode == INCEIP);
2027 vg_assert(cb->instrs[j].tag1 == Lit16);
2028 vg_assert(cb->instrs[i].tag1 == Lit16);
2029 cb->instrs[j].val1 += cb->instrs[i].val1;
2030 /* do nothing now */
2031 } else
2032# endif
2033
2034 {
2035 /* no, we really have to do this, alas */
2036 // VG_(printf)(" do INCEIP %d\n", cb->instrs[i].val1);
2037 vg_assert(u->tag1 == Lit16);
2038 emit_addlit8_offregmem ( u->val1, R_EBP, 4 * VGOFF_(m_eip) );
2039 }
sewardjde4a1d02002-03-22 01:27:54 +00002040 break;
2041 }
2042
2043 case LEA1: {
2044 vg_assert(u->tag1 == RealReg);
2045 vg_assert(u->tag2 == RealReg);
2046 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2047 break;
2048 }
2049
2050 case LEA2: {
2051 vg_assert(u->tag1 == RealReg);
2052 vg_assert(u->tag2 == RealReg);
2053 vg_assert(u->tag3 == RealReg);
2054 emit_lea_sib_reg ( u->lit32, u->extra4b,
2055 u->val1, u->val2, u->val3 );
2056 break;
2057 }
2058
2059 case WIDEN: {
2060 vg_assert(u->tag1 == RealReg);
2061 if (u->signed_widen) {
2062 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2063 } else {
2064 /* no need to generate any code. */
2065 }
2066 break;
2067 }
2068
sewardjde4a1d02002-03-22 01:27:54 +00002069 case STORE: {
2070 vg_assert(u->tag1 == RealReg);
2071 vg_assert(u->tag2 == RealReg);
2072 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002073 break;
2074 }
2075
2076 case LOAD: {
2077 vg_assert(u->tag1 == RealReg);
2078 vg_assert(u->tag2 == RealReg);
2079 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2080 break;
2081 }
2082
sewardjde4a1d02002-03-22 01:27:54 +00002083 case GET: {
2084 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2085 vg_assert(u->tag2 == RealReg);
2086 synth_mov_offregmem_reg (
2087 u->size,
2088 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2089 R_EBP,
2090 u->val2
2091 );
2092 break;
2093 }
2094
2095 case PUT: {
2096 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2097 vg_assert(u->tag1 == RealReg);
2098 if (u->tag2 == ArchReg
2099 && u->val2 == R_ESP
2100 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002101 && (VG_(track_events).new_mem_stack ||
2102 VG_(track_events).new_mem_stack_aligned ||
2103 VG_(track_events).die_mem_stack ||
2104 VG_(track_events).die_mem_stack_aligned ||
2105 VG_(track_events).post_mem_write))
2106 {
2107 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2108 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002109 }
njn25e49d8e72002-09-23 09:36:25 +00002110 else {
2111 synth_mov_reg_offregmem (
2112 u->size,
2113 u->val1,
2114 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2115 R_EBP
2116 );
2117 }
sewardjde4a1d02002-03-22 01:27:54 +00002118 break;
2119 }
2120
2121 case GETF: {
2122 vg_assert(u->size == 2 || u->size == 4);
2123 vg_assert(u->tag1 == RealReg);
2124 synth_mov_offregmem_reg (
2125 u->size,
2126 eflagsOffset(),
2127 R_EBP,
2128 u->val1
2129 );
2130 break;
2131 }
2132
2133 case PUTF: {
2134 vg_assert(u->size == 2 || u->size == 4);
2135 vg_assert(u->tag1 == RealReg);
2136 synth_mov_reg_offregmem (
2137 u->size,
2138 u->val1,
2139 eflagsOffset(),
2140 R_EBP
2141 );
2142 break;
2143 }
2144
2145 case MOV: {
2146 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2147 vg_assert(u->tag2 == RealReg);
2148 switch (u->tag1) {
2149 case RealReg: vg_assert(u->size == 4);
2150 if (u->val1 != u->val2)
2151 synth_movl_reg_reg ( u->val1, u->val2 );
2152 break;
2153 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2154 break;
2155 default: VG_(panic)("emitUInstr:mov");
2156 }
2157 break;
2158 }
2159
sewardjde4a1d02002-03-22 01:27:54 +00002160 case XOR:
2161 case OR:
2162 case AND:
2163 case SUB:
njn5a74eb82002-08-06 20:56:40 +00002164 case ADD:
2165 vg_assert(! readFlagUse ( u ));
2166 /* fall thru */
2167 case SBB:
2168 case ADC: {
sewardjde4a1d02002-03-22 01:27:54 +00002169 vg_assert(u->tag2 == RealReg);
2170 switch (u->tag1) {
2171 case Literal: synth_nonshiftop_lit_reg (
njn5a74eb82002-08-06 20:56:40 +00002172 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002173 u->opcode, u->size, u->lit32, u->val2 );
2174 break;
2175 case RealReg: synth_nonshiftop_reg_reg (
njn5a74eb82002-08-06 20:56:40 +00002176 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002177 u->opcode, u->size, u->val1, u->val2 );
2178 break;
2179 case ArchReg: synth_nonshiftop_offregmem_reg (
njn5a74eb82002-08-06 20:56:40 +00002180 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002181 u->opcode, u->size,
2182 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2183 R_EBP,
2184 u->val2 );
2185 break;
2186 default: VG_(panic)("emitUInstr:non-shift-op");
2187 }
2188 break;
2189 }
2190
sewardjde4a1d02002-03-22 01:27:54 +00002191 case ROR:
2192 case ROL:
2193 case SAR:
2194 case SHR:
2195 case SHL: {
njn5a74eb82002-08-06 20:56:40 +00002196 vg_assert(! readFlagUse ( u ));
2197 /* fall thru */
2198 case RCR:
2199 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002200 vg_assert(u->tag2 == RealReg);
2201 switch (u->tag1) {
2202 case Literal: synth_shiftop_lit_reg (
njn5a74eb82002-08-06 20:56:40 +00002203 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002204 u->opcode, u->size, u->lit32, u->val2 );
2205 break;
2206 case RealReg: synth_shiftop_reg_reg (
njn5a74eb82002-08-06 20:56:40 +00002207 readFlagUse(u), writeFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002208 u->opcode, u->size, u->val1, u->val2 );
2209 break;
2210 default: VG_(panic)("emitUInstr:non-shift-op");
2211 }
2212 break;
2213 }
2214
2215 case INC:
2216 case DEC:
2217 case NEG:
2218 case NOT:
2219 vg_assert(u->tag1 == RealReg);
njn5a74eb82002-08-06 20:56:40 +00002220 vg_assert(! readFlagUse ( u ));
sewardjde4a1d02002-03-22 01:27:54 +00002221 synth_unaryop_reg (
njn5a74eb82002-08-06 20:56:40 +00002222 writeFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002223 break;
2224
2225 case BSWAP:
2226 vg_assert(u->tag1 == RealReg);
2227 vg_assert(u->size == 4);
2228 vg_assert(!VG_(anyFlagUse)(u));
2229 emit_bswapl_reg ( u->val1 );
2230 break;
2231
2232 case CMOV:
2233 vg_assert(u->tag1 == RealReg);
2234 vg_assert(u->tag2 == RealReg);
2235 vg_assert(u->cond != CondAlways);
2236 vg_assert(u->size == 4);
2237 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2238 break;
2239
2240 case JMP: {
2241 vg_assert(u->tag2 == NoValue);
2242 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2243 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002244 switch (u->tag1) {
2245 case RealReg:
2246 synth_jmp_reg ( u->val1, u->jmpkind );
2247 break;
2248 case Literal:
2249 synth_jmp_lit ( u->lit32, u->jmpkind );
2250 break;
2251 default:
2252 VG_(panic)("emitUInstr(JMP, unconditional, default)");
2253 break;
sewardjde4a1d02002-03-22 01:27:54 +00002254 }
2255 } else {
sewardj2e93c502002-04-12 11:12:52 +00002256 switch (u->tag1) {
2257 case RealReg:
2258 VG_(panic)("emitUInstr(JMP, conditional, RealReg)");
2259 break;
2260 case Literal:
2261 vg_assert(u->jmpkind == JmpBoring);
2262 synth_jcond_lit ( u->cond, u->lit32 );
2263 break;
2264 default:
2265 VG_(panic)("emitUInstr(JMP, conditional, default)");
2266 break;
sewardjde4a1d02002-03-22 01:27:54 +00002267 }
2268 }
2269 break;
2270 }
2271
2272 case JIFZ:
2273 vg_assert(u->tag1 == RealReg);
2274 vg_assert(u->tag2 == Literal);
2275 vg_assert(u->size == 4);
2276 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2277 break;
2278
sewardjde4a1d02002-03-22 01:27:54 +00002279 case PUSH:
2280 vg_assert(u->tag1 == RealReg);
2281 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002282 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002283 break;
2284
2285 case POP:
2286 vg_assert(u->tag1 == RealReg);
2287 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002288 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002289 break;
2290
2291 case CALLM:
2292 vg_assert(u->tag1 == Lit16);
2293 vg_assert(u->tag2 == NoValue);
2294 vg_assert(u->size == 0);
njn5a74eb82002-08-06 20:56:40 +00002295 if (readFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002296 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002297 VG_(synth_call) ( False, u->val1 );
njn5a74eb82002-08-06 20:56:40 +00002298 if (writeFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002299 emit_put_eflags();
2300 break;
2301
njn25e49d8e72002-09-23 09:36:25 +00002302 case CCALL: {
2303 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2304 ones. */
2305 UInt argv[] = { u->val1, u->val2, u->val3 };
2306 UInt tagv[] = { RealReg, RealReg, RealReg };
2307 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2308
2309 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2310 else vg_assert(u->tag1 == NoValue);
2311 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2312 else vg_assert(u->tag2 == NoValue);
2313 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2314 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002315 vg_assert(u->size == 0);
2316
njn25e49d8e72002-09-23 09:36:25 +00002317 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2318 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002319 break;
njn25e49d8e72002-09-23 09:36:25 +00002320 }
sewardjde4a1d02002-03-22 01:27:54 +00002321 case CLEAR:
2322 vg_assert(u->tag1 == Lit16);
2323 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002324 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002325 break;
2326
2327 case CC2VAL:
2328 vg_assert(u->tag1 == RealReg);
2329 vg_assert(u->tag2 == NoValue);
2330 vg_assert(VG_(anyFlagUse)(u));
2331 synth_setb_reg ( u->val1, u->cond );
2332 break;
2333
sewardjde4a1d02002-03-22 01:27:54 +00002334 case FPU_R:
2335 case FPU_W:
2336 vg_assert(u->tag1 == Lit16);
2337 vg_assert(u->tag2 == RealReg);
sewardjde4a1d02002-03-22 01:27:54 +00002338 synth_fpu_regmem ( (u->val1 >> 8) & 0xFF,
2339 u->val1 & 0xFF,
2340 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002341 break;
2342
2343 case FPU:
2344 vg_assert(u->tag1 == Lit16);
2345 vg_assert(u->tag2 == NoValue);
njn5a74eb82002-08-06 20:56:40 +00002346 if (readFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002347 emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002348 synth_fpu_no_mem ( (u->val1 >> 8) & 0xFF,
2349 u->val1 & 0xFF );
njn5a74eb82002-08-06 20:56:40 +00002350 if (writeFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002351 emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002352 break;
2353
2354 default:
njn25e49d8e72002-09-23 09:36:25 +00002355 if (VG_(needs).extended_UCode)
2356 SK_(emitExtUInstr)(u, regs_live_before);
2357 else {
2358 VG_(printf)("\nError:\n"
2359 " unhandled opcode: %u. Perhaps "
2360 " VG_(needs).extended_UCode should be set?\n",
2361 u->opcode);
2362 VG_(ppUInstr)(0,u);
2363 VG_(panic)("emitUInstr: unimplemented opcode");
2364 }
sewardjde4a1d02002-03-22 01:27:54 +00002365 }
2366
njn25e49d8e72002-09-23 09:36:25 +00002367 /* Update UInstr histogram */
2368 vg_assert(u->opcode < 100);
2369 histogram[u->opcode].counts++;
2370 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00002371}
2372
2373
2374/* Emit x86 for the ucode in cb, returning the address of the
2375 generated code and setting *nbytes to its size. */
2376UChar* VG_(emit_code) ( UCodeBlock* cb, Int* nbytes )
2377{
2378 Int i;
njn25e49d8e72002-09-23 09:36:25 +00002379 UChar regs_live_before = 0; /* No regs live at BB start */
2380
sewardjde4a1d02002-03-22 01:27:54 +00002381 emitted_code_used = 0;
2382 emitted_code_size = 500; /* reasonable initial size */
njn25e49d8e72002-09-23 09:36:25 +00002383 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +00002384
njn25e49d8e72002-09-23 09:36:25 +00002385 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00002386
2387 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00002388 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00002389 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00002390
sewardjde4a1d02002-03-22 01:27:54 +00002391 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00002392 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00002393 if (!sane) {
2394 VG_(printf)("\ninsane instruction\n");
njn25e49d8e72002-09-23 09:36:25 +00002395 VG_(upUInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00002396 }
2397 vg_assert(sane);
njn25e49d8e72002-09-23 09:36:25 +00002398 emitUInstr( cb, i, regs_live_before );
sewardjde4a1d02002-03-22 01:27:54 +00002399 }
njn25e49d8e72002-09-23 09:36:25 +00002400 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00002401 }
njn25e49d8e72002-09-23 09:36:25 +00002402 if (dis) VG_(printf)("\n");
sewardjde4a1d02002-03-22 01:27:54 +00002403
2404 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00002405 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00002406 *nbytes = emitted_code_used;
2407 return emitted_code;
2408}
2409
njn25e49d8e72002-09-23 09:36:25 +00002410#undef dis
2411
sewardjde4a1d02002-03-22 01:27:54 +00002412/*--------------------------------------------------------------------*/
2413/*--- end vg_from_ucode.c ---*/
2414/*--------------------------------------------------------------------*/