blob: f2e89c41d09deba131f73ddc5db1deb11a46f3bc [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/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00006
sewardjde4a1d02002-03-22 01:27:54 +00007/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
41/*------------------------------------------------------------*/
42/*--- Instruction emission -- turning final uinstrs back ---*/
43/*--- into x86 code. ---*/
44/*------------------------------------------------------------*/
45
46/* [2001-07-08 This comment is now somewhat out of date.]
47
48 This is straightforward but for one thing: to facilitate generating
49 code in a single pass, we generate position-independent code. To
50 do this, calls and jmps to fixed addresses must specify the address
51 by first loading it into a register, and jump to/call that
52 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000053 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000054 call insns may only have a register as target anyway, so there's no
55 need to do anything fancy for them.
56
57 The emit_* routines constitute the lowest level of instruction
58 emission. They simply emit the sequence of bytes corresponding to
59 the relevant instruction, with no further ado. In particular there
60 is no checking about whether uses of byte registers makes sense,
61 nor whether shift insns have their first operand in %cl, etc.
62
63 These issues are taken care of by the level above, the synth_*
64 routines. These detect impossible operand combinations and turn
65 them into sequences of legal instructions. Finally, emitUInstr is
66 phrased in terms of the synth_* abstraction layer. */
67
sewardjfa492d42002-12-08 18:20:01 +000068/* Static state for the current basic block */
sewardjde4a1d02002-03-22 01:27:54 +000069static UChar* emitted_code;
70static Int emitted_code_used;
71static Int emitted_code_size;
72
sewardj22854b92002-11-30 14:00:47 +000073/* offset (in bytes into the basic block) */
74static UShort jumps[VG_MAX_JUMPS];
75static Int jumpidx;
76
sewardjfa492d42002-12-08 18:20:01 +000077static enum eflags_state {
78 UPD_Simd, /* baseblock copy is up to date */
79 UPD_Real, /* CPU copy is up to date */
80 UPD_Both, /* both are current */
81} eflags_state;
82
83/* single site for resetting state */
84static void reset_state(void)
85{
86 emitted_code_used = 0;
87 emitted_code_size = 500; /* reasonable initial size */
88 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
89 jumpidx = 0;
90 eflags_state = UPD_Simd;
91}
92
93
njn25e49d8e72002-09-23 09:36:25 +000094/* Statistics about C functions called from generated code. */
95static UInt ccalls = 0;
96static UInt ccall_reg_saves = 0;
97static UInt ccall_args = 0;
98static UInt ccall_arg_setup_instrs = 0;
99static UInt ccall_stack_clears = 0;
100static UInt ccall_retvals = 0;
101static UInt ccall_retval_movs = 0;
102
103/* Statistics about frequency of each UInstr */
104typedef
105 struct {
106 UInt counts;
107 UInt size;
108 } Histogram;
109
110/* Automatically zeroed because it's static. */
111static Histogram histogram[100];
112
113void VG_(print_ccall_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " ccalls: %u C calls, %u%% saves+restores avoided"
117 " (%d bytes)",
118 ccalls,
119 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
120 ((ccalls*3) - ccall_reg_saves)*2);
121 VG_(message)(Vg_DebugMsg,
122 " %u args, avg 0.%d setup instrs each (%d bytes)",
123 ccall_args,
124 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
125 (ccall_args - ccall_arg_setup_instrs)*2);
126 VG_(message)(Vg_DebugMsg,
127 " %d%% clear the stack (%d bytes)",
128 (UInt)(ccall_stack_clears/(double)ccalls*100),
129 (ccalls - ccall_stack_clears)*3);
130 VG_(message)(Vg_DebugMsg,
131 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
132 ccall_retvals,
133 ( ccall_retvals == 0
134 ? 100
135 : 100-(UInt)(ccall_retval_movs /
136 (double)ccall_retvals*100)),
137 (ccall_retvals-ccall_retval_movs)*2);
138}
139
140void VG_(print_UInstr_histogram)(void)
141{
142 Int i, j;
143 UInt total_counts = 0;
144 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000145
njn25e49d8e72002-09-23 09:36:25 +0000146 for (i = 0; i < 100; i++) {
147 total_counts += histogram[i].counts;
148 total_size += histogram[i].size;
149 }
150
151 VG_(printf)("-- UInstr frequencies -----------\n");
152 for (i = 0; i < 100; i++) {
153 if (0 != histogram[i].counts) {
154
155 UInt count_pc =
156 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
157 UInt size_pc =
158 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
159 UInt avg_size =
160 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
161
162 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000163 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000164 histogram[i].counts, count_pc,
165 avg_size, size_pc);
166
167 for (j = 0; j < size_pc; j++) VG_(printf)("O");
168 VG_(printf)("\n");
169
170 } else {
171 vg_assert(0 == histogram[i].size);
172 }
173 }
174
175 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
176}
177
sewardjde4a1d02002-03-22 01:27:54 +0000178static void expandEmittedCode ( void )
179{
180 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000181 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000182 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
183 for (i = 0; i < emitted_code_size; i++)
184 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000186 emitted_code = tmp;
187 emitted_code_size *= 2;
188}
189
njn25e49d8e72002-09-23 09:36:25 +0000190/* Local calls will be inlined, cross-module ones not */
191__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
193 if (dis) {
194 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
195 }
196 if (emitted_code_used == emitted_code_size)
197 expandEmittedCode();
198
199 emitted_code[emitted_code_used] = (UChar)b;
200 emitted_code_used++;
201}
202
njn25e49d8e72002-09-23 09:36:25 +0000203__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(emitB) ( (l) & 0x000000FF );
206 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000207}
208
njn25e49d8e72002-09-23 09:36:25 +0000209__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000210{
njn25e49d8e72002-09-23 09:36:25 +0000211 VG_(emitB) ( (l) & 0x000000FF );
212 VG_(emitB) ( (l >> 8) & 0x000000FF );
213 VG_(emitB) ( (l >> 16) & 0x000000FF );
214 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000215}
216
sewardjfa492d42002-12-08 18:20:01 +0000217static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000218{
sewardjfa492d42002-12-08 18:20:01 +0000219 Int off = 4 * VGOFF_(m_eflags);
220 vg_assert(off >= 0 && off < 128);
221
222 if (dis)
223 VG_(printf)("\t %4d: ", emitted_code_used );
224
225 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
226 VG_(emitB) ( 0x75 );
227 VG_(emitB) ( off );
228 VG_(emitB) ( 0x9D ); /* POPFL */
229 if (dis)
230 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
231}
232
233static void emit_put_eflags ( void )
234{
235 Int off = 4 * VGOFF_(m_eflags);
236 vg_assert(off >= 0 && off < 128);
237
238 if (dis)
239 VG_(printf)("\t %4d: ", emitted_code_used );
240
241 VG_(emitB) ( 0x9C ); /* PUSHFL */
242 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
243 VG_(emitB) ( 0x45 );
244 VG_(emitB) ( off );
245 if (dis)
246 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
247}
248
249static void maybe_emit_put_eflags( void )
250{
251 if (eflags_state == UPD_Real) {
252 eflags_state = UPD_Both;
253 emit_put_eflags();
254 }
255}
256
257static void maybe_emit_get_eflags( void )
258{
259 if (eflags_state == UPD_Simd) {
260 eflags_state = UPD_Both;
261 emit_get_eflags();
262 }
263}
264
265/* Call this before emitting each instruction.
266
267 Arguments are:
268 upds_simd_flags:
269 if true, this instruction updates the simulated %EFLAGS state,
270 otherwise it doesn't
271 use_flags: set of (real) flags the instruction uses
272 set_flags: set of (real) flags the instruction sets
273 */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool use, set;
279
280 use = use_flags != FlagsEmpty
281 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
282 set = set_flags != FlagsEmpty;
283
284 if (0)
285 VG_(printf)(
286 "new_emit: state=%d upds_simd_flags=%d use_flags=%x set_flags=%x\n",
287 eflags_state, upds_simd_flags, use_flags, set_flags);
288
289 if (upds_simd_flags) {
290 if (use && eflags_state == UPD_Simd) {
291 /* we need the CPU flags set, but they're not already */
292 eflags_state = UPD_Both;
293 emit_get_eflags();
294 }
295 if (set) {
296 /* if we're setting the flags, then the CPU will have the
297 only good copy */
298 eflags_state = UPD_Real;
299 }
300 } else {
301 /* presume that if non-simd code is using flags, it knows what
302 it's doing (ie, it just set up the flags). */
303 if (set) {
304 /* This instruction is going to trash the flags, so we'd
305 better save them away and say that they're only in the
306 simulated state. */
307 maybe_emit_put_eflags();
308 eflags_state = UPD_Simd;
309 }
310 }
311
sewardjde4a1d02002-03-22 01:27:54 +0000312 if (dis)
313 VG_(printf)("\t %4d: ", emitted_code_used );
314}
315
sewardjde4a1d02002-03-22 01:27:54 +0000316
317/*----------------------------------------------------*/
318/*--- Addressing modes ---*/
319/*----------------------------------------------------*/
320
321static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
322{
323 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
324}
325
326static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
327{
328 Int shift;
329 switch (scale) {
330 case 1: shift = 0; break;
331 case 2: shift = 1; break;
332 case 4: shift = 2; break;
333 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000334 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000335 }
336 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
337}
338
339static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
340{
341 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000342 VG_(emitB) ( mkModRegRM(0, reg, 5) );
343 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000344}
345
346static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
347{
348 /* (regmem), reg */
349 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000350 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000351 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000352 VG_(emitB) ( mkModRegRM(1, reg, 5) );
353 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000354 } else {
njn25e49d8e72002-09-23 09:36:25 +0000355 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000356 }
357}
358
njn25e49d8e72002-09-23 09:36:25 +0000359void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000360{
361 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000362 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000363 if (off < -128 || off > 127) {
364 /* Use a large offset */
365 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000366 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
367 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000368 } else {
369 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000370 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
371 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000372 }
373}
374
375static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
376 Int regindex, Int reg )
377{
378 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000379 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000380 if (off < -128 || off > 127) {
381 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000382 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
383 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
384 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000385 } else {
386 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000387 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
388 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
389 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000390 }
391}
392
njn25e49d8e72002-09-23 09:36:25 +0000393void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000394{
395 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000396 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000397}
398
399static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
400{
401 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000402 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000403}
404
405
406/*----------------------------------------------------*/
407/*--- Opcode translation ---*/
408/*----------------------------------------------------*/
409
410static __inline__ Int mkGrp1opcode ( Opcode opc )
411{
412 switch (opc) {
413 case ADD: return 0;
414 case OR: return 1;
415 case ADC: return 2;
416 case SBB: return 3;
417 case AND: return 4;
418 case SUB: return 5;
419 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000420 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000421 }
422}
423
sewardjfa492d42002-12-08 18:20:01 +0000424static __inline__ FlagSet nonshiftop_use(Opcode opc)
425{
426 switch(opc) {
427 case ADC:
428 case SBB:
429 return FlagC;
430
431 case ADD:
432 case OR:
433 case AND:
434 case SUB:
435 case XOR:
436 return FlagsEmpty;
437
438 default:
439 VG_(core_panic)("nonshiftop_use");
440 }
441}
442
443static __inline__ FlagSet nonshiftop_set(Opcode opc)
444{
445 switch(opc) {
446 case ADC:
447 case SBB:
448 case ADD:
449 case OR:
450 case AND:
451 case SUB:
452 case XOR:
453 return FlagsOSZACP;
454
455 default:
456 VG_(core_panic)("nonshiftop_set");
457 }
458}
459
sewardjde4a1d02002-03-22 01:27:54 +0000460static __inline__ Int mkGrp2opcode ( Opcode opc )
461{
462 switch (opc) {
463 case ROL: return 0;
464 case ROR: return 1;
465 case RCL: return 2;
466 case RCR: return 3;
467 case SHL: return 4;
468 case SHR: return 5;
469 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000470 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000471 }
472}
473
sewardjfa492d42002-12-08 18:20:01 +0000474static __inline__ FlagSet shiftop_use(Opcode opc)
475{
476 switch(opc) {
477 case ROR:
478 case ROL:
479 case SHL:
480 case SHR:
481 case SAR:
482 return FlagsEmpty;
483
484 case RCL:
485 case RCR:
486 return FlagC;
487
488 default:
489 VG_(core_panic)("shiftop_use");
490 }
491}
492
493static __inline__ FlagSet shiftop_set(Opcode opc)
494{
495 switch(opc) {
496 case ROR:
497 case ROL:
498 case RCL:
499 case RCR:
500 return FlagsOC;
501
502 case SHL:
503 case SHR:
504 case SAR:
505 return FlagsOSZACP;
506
507 default:
508 VG_(core_panic)("shiftop_set");
509 }
510}
511
sewardjde4a1d02002-03-22 01:27:54 +0000512static __inline__ Int mkGrp3opcode ( Opcode opc )
513{
514 switch (opc) {
515 case NOT: return 2;
516 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000517 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000518 }
519}
520
521static __inline__ Int mkGrp4opcode ( Opcode opc )
522{
523 switch (opc) {
524 case INC: return 0;
525 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000526 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000527 }
528}
529
530static __inline__ Int mkGrp5opcode ( Opcode opc )
531{
532 switch (opc) {
533 case CALLM: return 2;
534 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000535 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000536 }
537}
538
539static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
540{
541 switch (opc) {
542 case ADD: return 0x00;
543 case ADC: return 0x10;
544 case AND: return 0x20;
545 case XOR: return 0x30;
546 case OR: return 0x08;
547 case SBB: return 0x18;
548 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000549 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000550 }
551}
552
553/*----------------------------------------------------*/
554/*--- v-size (4, or 2 with OSO) insn emitters ---*/
555/*----------------------------------------------------*/
556
njn25e49d8e72002-09-23 09:36:25 +0000557void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000558{
sewardjfa492d42002-12-08 18:20:01 +0000559 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000560 if (sz == 2) VG_(emitB) ( 0x66 );
561 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
562 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000563 if (dis)
564 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
565 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
566}
567
njn25e49d8e72002-09-23 09:36:25 +0000568void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000569{
sewardjfa492d42002-12-08 18:20:01 +0000570 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000571 if (sz == 2) VG_(emitB) ( 0x66 );
572 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
573 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000574 if (dis)
575 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
576 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
577}
578
579static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
580{
sewardjfa492d42002-12-08 18:20:01 +0000581 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000582 if (sz == 2) VG_(emitB) ( 0x66 );
583 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000584 emit_amode_regmem_reg ( reg1, reg2 );
585 if (dis)
586 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
587 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
588}
589
590static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
591{
sewardjfa492d42002-12-08 18:20:01 +0000592 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000593 if (sz == 2) VG_(emitB) ( 0x66 );
594 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000595 emit_amode_regmem_reg ( reg2, reg1 );
596 if (dis)
597 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
598 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
599}
600
njn25e49d8e72002-09-23 09:36:25 +0000601void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000602{
sewardjfa492d42002-12-08 18:20:01 +0000603 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000604 if (sz == 2) VG_(emitB) ( 0x66 );
605 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
606 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000607 if (dis)
608 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
609 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
610}
611
sewardjfa492d42002-12-08 18:20:01 +0000612void VG_(emit_nonshiftopv_lit_reg) ( Bool upd_cc, Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000613{
sewardjfa492d42002-12-08 18:20:01 +0000614 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
615
njn25e49d8e72002-09-23 09:36:25 +0000616 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000617 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
618 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000619 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
620 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
621 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000622 } else {
njn25e49d8e72002-09-23 09:36:25 +0000623 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
624 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
625 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000626 }
627 if (dis)
628 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000629 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000630 lit, nameIReg(sz,reg));
631}
632
sewardjfa492d42002-12-08 18:20:01 +0000633void VG_(emit_nonshiftopv_lit_offregmem) ( Bool upd_cc, Int sz, Opcode opc, UInt lit,
634 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000635{
sewardjfa492d42002-12-08 18:20:01 +0000636 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
637 if (sz == 2) VG_(emitB) ( 0x66 );
638 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
639 /* short form OK */
640 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
641 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
642 VG_(emitB) ( lit & 0x000000FF );
643 } else {
644 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
645 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
646 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
647 }
648 if (dis)
649 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
650 VG_(name_UOpcode)(False,opc), nameISize(sz),
651 lit, off, nameIReg(sz,regmem));
652}
653
654void VG_(emit_shiftopv_lit_reg) ( Bool upd_cc, Int sz, Opcode opc, UInt lit, Int reg )
655{
656 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
657
njn25e49d8e72002-09-23 09:36:25 +0000658 if (sz == 2) VG_(emitB) ( 0x66 );
659 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
660 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
661 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000662 if (dis)
663 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000664 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000665 lit, nameIReg(sz,reg));
666}
667
sewardjfa492d42002-12-08 18:20:01 +0000668static void emit_shiftopv_cl_stack0 ( Bool upd_cc, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000669{
sewardjfa492d42002-12-08 18:20:01 +0000670 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000671 if (sz == 2) VG_(emitB) ( 0x66 );
672 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
673 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
674 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
675 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000676 if (dis)
677 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000678 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000679}
680
sewardjfa492d42002-12-08 18:20:01 +0000681static void emit_shiftopb_cl_stack0 ( Bool upd_cc, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000682{
sewardjfa492d42002-12-08 18:20:01 +0000683 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000684 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
685 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
686 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
687 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000688 if (dis)
689 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000690 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000691}
692
sewardjfa492d42002-12-08 18:20:01 +0000693static void emit_nonshiftopv_offregmem_reg ( Bool upd_cc, Int sz, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000694 Int off, Int areg, Int reg )
695{
sewardjfa492d42002-12-08 18:20:01 +0000696 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000697 if (sz == 2) VG_(emitB) ( 0x66 );
698 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
699 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000700 if (dis)
701 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000702 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000703 off, nameIReg(4,areg), nameIReg(sz,reg));
704}
705
sewardjfa492d42002-12-08 18:20:01 +0000706static void emit_nonshiftopv_reg_offregmem ( Bool upd_cc, Int sz, Opcode opc,
707 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000708{
sewardjfa492d42002-12-08 18:20:01 +0000709 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
710 if (sz == 2) VG_(emitB) ( 0x66 );
711 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
712 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
713 if (dis)
714 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
715 VG_(name_UOpcode)(False,opc), nameISize(sz),
716 nameIReg(sz,reg), off, nameIReg(4,areg));
717}
718
719void VG_(emit_nonshiftopv_reg_reg) ( Bool upd_cc, Int sz, Opcode opc,
720 Int reg1, Int reg2 )
721{
722 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000723 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000724# if 0
725 /* Perfectly correct, but the GNU assembler uses the other form.
726 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000727 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
728 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000729# else
njn25e49d8e72002-09-23 09:36:25 +0000730 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000731 emit_amode_greg_ereg ( reg1, reg2 );
732# endif
733 if (dis)
734 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000735 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000736 nameIReg(sz,reg1), nameIReg(sz,reg2));
737}
738
njn25e49d8e72002-09-23 09:36:25 +0000739void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000740{
sewardjfa492d42002-12-08 18:20:01 +0000741 if (lit == 0 && eflags_state != UPD_Real) {
742 /* Only emit this for zeroing if it won't stomp flags */
743 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000744 return;
745 }
sewardjfa492d42002-12-08 18:20:01 +0000746 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000747 if (sz == 2) VG_(emitB) ( 0x66 );
748 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
749 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000750 if (dis)
751 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
752 nameISize(sz), lit, nameIReg(sz,reg));
753}
754
sewardjfa492d42002-12-08 18:20:01 +0000755void VG_(emit_unaryopv_reg) ( Bool upd_cc, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000756{
sewardjde4a1d02002-03-22 01:27:54 +0000757 switch (opc) {
758 case NEG:
sewardjfa492d42002-12-08 18:20:01 +0000759 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
760 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000761 VG_(emitB) ( 0xF7 );
762 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000763 if (dis)
764 VG_(printf)( "\n\t\tneg%c\t%s\n",
765 nameISize(sz), nameIReg(sz,reg));
766 break;
767 case NOT:
sewardjfa492d42002-12-08 18:20:01 +0000768 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsEmpty);
769 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000770 VG_(emitB) ( 0xF7 );
771 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000772 if (dis)
773 VG_(printf)( "\n\t\tnot%c\t%s\n",
774 nameISize(sz), nameIReg(sz,reg));
775 break;
776 case DEC:
sewardjfa492d42002-12-08 18:20:01 +0000777 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
778 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000779 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000780 if (dis)
781 VG_(printf)( "\n\t\tdec%c\t%s\n",
782 nameISize(sz), nameIReg(sz,reg));
783 break;
784 case INC:
sewardjfa492d42002-12-08 18:20:01 +0000785 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
786 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000787 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000788 if (dis)
789 VG_(printf)( "\n\t\tinc%c\t%s\n",
790 nameISize(sz), nameIReg(sz,reg));
791 break;
792 default:
njne427a662002-10-02 11:08:25 +0000793 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000794 }
795}
796
njn25e49d8e72002-09-23 09:36:25 +0000797void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000798{
sewardjfa492d42002-12-08 18:20:01 +0000799 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000800 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000801 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000802 } else {
803 vg_assert(sz == 4);
804 }
njn25e49d8e72002-09-23 09:36:25 +0000805 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000806 if (dis)
807 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
808}
809
njn25e49d8e72002-09-23 09:36:25 +0000810void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000811{
sewardjfa492d42002-12-08 18:20:01 +0000812 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000813 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000814 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000815 } else {
816 vg_assert(sz == 4);
817 }
njn25e49d8e72002-09-23 09:36:25 +0000818 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000819 if (dis)
820 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
821}
822
njn25e49d8e72002-09-23 09:36:25 +0000823void VG_(emit_pushl_lit32) ( UInt int32 )
824{
sewardjfa492d42002-12-08 18:20:01 +0000825 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000826 VG_(emitB) ( 0x68 );
827 VG_(emitL) ( int32 );
828 if (dis)
829 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
830}
831
832void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +0000833{
834 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +0000835 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000836 VG_(emitB) ( 0x6A );
837 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +0000838 if (dis)
839 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
840}
841
sewardjfa492d42002-12-08 18:20:01 +0000842void VG_(emit_cmpl_zero_reg) ( Bool upd_cc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000843{
sewardjfa492d42002-12-08 18:20:01 +0000844 VG_(new_emit)(upd_cc, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +0000845 VG_(emitB) ( 0x83 );
846 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
847 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000848 if (dis)
849 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
850}
851
852static void emit_swapl_reg_ECX ( Int reg )
853{
sewardjfa492d42002-12-08 18:20:01 +0000854 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000855 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
856 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +0000857 if (dis)
858 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
859}
860
njn25e49d8e72002-09-23 09:36:25 +0000861void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000862{
sewardjfa492d42002-12-08 18:20:01 +0000863 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000864 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +0000865 if (dis)
866 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
867}
868
869static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
870{
sewardjfa492d42002-12-08 18:20:01 +0000871 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000872 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
873 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000874 if (dis)
875 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
876 nameIReg(4,reg2));
877}
878
879static void emit_bswapl_reg ( Int reg )
880{
sewardjfa492d42002-12-08 18:20:01 +0000881 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000882 VG_(emitB) ( 0x0F );
883 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
886}
887
888static void emit_movl_reg_reg ( Int regs, Int regd )
889{
sewardjfa492d42002-12-08 18:20:01 +0000890 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000891 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
892 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +0000893 if (dis)
894 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
895}
896
njn25e49d8e72002-09-23 09:36:25 +0000897void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +0000898{
sewardjfa492d42002-12-08 18:20:01 +0000899 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000900 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000901 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000902 } else {
903 vg_assert(sz == 4);
904 }
njn25e49d8e72002-09-23 09:36:25 +0000905 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
906 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
907 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000908 if (dis)
909 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
910 nameISize(sz), lit, off, nameIReg(4,memreg) );
911}
912
913
914/*----------------------------------------------------*/
915/*--- b-size (1 byte) instruction emitters ---*/
916/*----------------------------------------------------*/
917
918/* There is some doubt as to whether C6 (Grp 11) is in the
919 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +0000920void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
921{
sewardjfa492d42002-12-08 18:20:01 +0000922 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000923 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
924 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
925 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000926 if (dis)
927 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
928 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +0000929}
930
sewardjfa492d42002-12-08 18:20:01 +0000931static void emit_nonshiftopb_offregmem_reg ( Bool upd_cc, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000932 Int off, Int areg, Int reg )
933{
sewardj75f04932002-12-12 23:13:21 +0000934 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
936 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000937 if (dis)
938 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000939 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +0000940 nameIReg(1,reg));
941}
942
sewardjfa492d42002-12-08 18:20:01 +0000943static void emit_nonshiftopb_lit_offregmem ( Bool upd_cc, Opcode opc,
944 UInt lit, Int off, Int areg )
945{
946 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
947 VG_(emitB) ( 0x80 );
948 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
949 VG_(emitB) ( lit );
950 if (dis)
951 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
952 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
953}
954
955static void emit_nonshiftopb_reg_offregmem ( Bool upd_cc, Opcode opc,
956 Int off, Int areg, Int reg )
957{
958 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
959 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
960 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
961 if (dis)
962 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
963 VG_(name_UOpcode)(False,opc),
964 nameIReg(1,reg),
965 off, nameIReg(4,areg));
966}
967
njn25e49d8e72002-09-23 09:36:25 +0000968void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000969{
970 /* Could do better when reg == %al. */
sewardjfa492d42002-12-08 18:20:01 +0000971 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000972 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
973 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000974 if (dis)
975 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
976 nameIReg(1,reg), off, nameIReg(4,areg));
977}
978
sewardjfa492d42002-12-08 18:20:01 +0000979static void emit_nonshiftopb_reg_reg ( Bool upd_cc, Opcode opc, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000980{
sewardjfa492d42002-12-08 18:20:01 +0000981 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000982 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
983 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000984 if (dis)
985 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000986 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000987 nameIReg(1,reg1), nameIReg(1,reg2));
988}
989
990static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
991{
sewardjfa492d42002-12-08 18:20:01 +0000992 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +0000994 emit_amode_regmem_reg ( reg2, reg1 );
995 if (dis)
996 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
997 nameIReg(4,reg2));
998}
999
sewardjfa492d42002-12-08 18:20:01 +00001000static void emit_nonshiftopb_lit_reg ( Bool upd_cc, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001001{
sewardjfa492d42002-12-08 18:20:01 +00001002 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001003 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1004 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1005 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001006 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001007 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001008 lit, nameIReg(1,reg));
1009}
1010
sewardjfa492d42002-12-08 18:20:01 +00001011static void emit_shiftopb_lit_reg ( Bool upd_cc, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjfa492d42002-12-08 18:20:01 +00001013 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001014 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1015 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1016 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001017 if (dis)
1018 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001019 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001020 lit, nameIReg(1,reg));
1021}
1022
sewardjfa492d42002-12-08 18:20:01 +00001023void VG_(emit_unaryopb_reg) ( Bool upd_cc, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001024{
sewardjde4a1d02002-03-22 01:27:54 +00001025 switch (opc) {
1026 case INC:
sewardjfa492d42002-12-08 18:20:01 +00001027 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0xFE );
1029 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001030 if (dis)
1031 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1032 break;
1033 case DEC:
sewardjfa492d42002-12-08 18:20:01 +00001034 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001035 VG_(emitB) ( 0xFE );
1036 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001037 if (dis)
1038 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1039 break;
1040 case NOT:
sewardjfa492d42002-12-08 18:20:01 +00001041 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001042 VG_(emitB) ( 0xF6 );
1043 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001044 if (dis)
1045 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1046 break;
1047 case NEG:
sewardjfa492d42002-12-08 18:20:01 +00001048 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001049 VG_(emitB) ( 0xF6 );
1050 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001051 if (dis)
1052 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1053 break;
1054 default:
njne427a662002-10-02 11:08:25 +00001055 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001056 }
1057}
1058
sewardjfa492d42002-12-08 18:20:01 +00001059void VG_(emit_testb_lit_reg) ( Bool upd_cc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001060{
sewardjfa492d42002-12-08 18:20:01 +00001061 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001062 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1063 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1064 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001065 if (dis)
1066 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1067}
1068
sewardjde4a1d02002-03-22 01:27:54 +00001069/*----------------------------------------------------*/
1070/*--- zero-extended load emitters ---*/
1071/*----------------------------------------------------*/
1072
njn25e49d8e72002-09-23 09:36:25 +00001073void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001074{
sewardjfa492d42002-12-08 18:20:01 +00001075 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001076 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1077 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001078 if (dis)
1079 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1080 off, nameIReg(4,regmem), nameIReg(4,reg));
1081}
1082
1083static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1084{
sewardjfa492d42002-12-08 18:20:01 +00001085 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001087 emit_amode_regmem_reg ( reg1, reg2 );
1088 if (dis)
1089 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
njn25e49d8e72002-09-23 09:36:25 +00001093void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001094{
sewardjfa492d42002-12-08 18:20:01 +00001095 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1097 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1100 off, nameIReg(4,areg), nameIReg(4,reg));
1101}
1102
1103static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1104{
sewardjfa492d42002-12-08 18:20:01 +00001105 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001106 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001107 emit_amode_regmem_reg ( reg1, reg2 );
1108 if (dis)
1109 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1110 nameIReg(4,reg2));
1111}
1112
1113/*----------------------------------------------------*/
1114/*--- FPU instruction emitters ---*/
1115/*----------------------------------------------------*/
1116
1117static void emit_get_fpu_state ( void )
1118{
1119 Int off = 4 * VGOFF_(m_fpustate);
sewardjfa492d42002-12-08 18:20:01 +00001120 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001121 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1122 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001123 if (dis)
1124 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1125}
1126
1127static void emit_put_fpu_state ( void )
1128{
1129 Int off = 4 * VGOFF_(m_fpustate);
sewardjfa492d42002-12-08 18:20:01 +00001130 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001131 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1132 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001133 if (dis)
1134 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1135}
1136
sewardjfa492d42002-12-08 18:20:01 +00001137static void emit_fpu_no_mem ( FlagSet uses_flags, FlagSet sets_flags,
1138 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001139 UChar second_byte )
1140{
sewardjfa492d42002-12-08 18:20:01 +00001141 VG_(new_emit)(True, uses_flags, sets_flags);
njn25e49d8e72002-09-23 09:36:25 +00001142 VG_(emitB) ( first_byte );
1143 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001144 if (dis)
1145 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1146 (UInt)first_byte, (UInt)second_byte );
1147}
1148
sewardjfa492d42002-12-08 18:20:01 +00001149static void emit_fpu_regmem ( FlagSet uses_flags, FlagSet sets_flags,
1150 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001151 UChar second_byte_masked,
1152 Int reg )
1153{
sewardjfa492d42002-12-08 18:20:01 +00001154 VG_(new_emit)(True, uses_flags, sets_flags);
njn25e49d8e72002-09-23 09:36:25 +00001155 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001156 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1157 if (dis)
1158 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1159 (UInt)first_byte, (UInt)second_byte_masked,
1160 nameIReg(4,reg) );
1161}
1162
1163
1164/*----------------------------------------------------*/
1165/*--- misc instruction emitters ---*/
1166/*----------------------------------------------------*/
1167
njn25e49d8e72002-09-23 09:36:25 +00001168void VG_(emit_call_reg) ( Int reg )
1169{
sewardjfa492d42002-12-08 18:20:01 +00001170 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001171 VG_(emitB) ( 0xFF ); /* Grp5 */
1172 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1173 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001174 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001175}
1176
sewardjfa492d42002-12-08 18:20:01 +00001177static void emit_call_star_EBP_off ( Bool upd_cc, Int byte_off, FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001178{
sewardjfa492d42002-12-08 18:20:01 +00001179 /* Used for helpers which expect to see Simd flags in Real flags */
1180 VG_(new_emit)(upd_cc, use_flag, set_flag);
1181
1182 if (byte_off < -128 || byte_off > 127) {
1183 VG_(emitB) ( 0xFF );
1184 VG_(emitB) ( 0x95 );
1185 VG_(emitL) ( byte_off );
1186 } else {
1187 VG_(emitB) ( 0xFF );
1188 VG_(emitB) ( 0x55 );
1189 VG_(emitB) ( byte_off );
1190 }
1191 if (dis)
1192 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001193}
1194
1195
1196static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1197{
1198 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001199 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1201 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001202 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001203 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001204 if (dis)
1205 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1206 nameIReg(4,regmem));
1207}
1208
1209
njn25e49d8e72002-09-23 09:36:25 +00001210void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001211{
njne427a662002-10-02 11:08:25 +00001212 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001213 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1214 VG_(emitB) ( 0x8D );
1215 VG_(emitB) ( 0x64 );
1216 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001217 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001218 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001219 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001220}
1221
1222
1223static void emit_movb_AL_zeroESPmem ( void )
1224{
1225 /* movb %al, 0(%esp) */
1226 /* 88442400 movb %al, 0(%esp) */
sewardjfa492d42002-12-08 18:20:01 +00001227 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001228 VG_(emitB) ( 0x88 );
1229 VG_(emitB) ( 0x44 );
1230 VG_(emitB) ( 0x24 );
1231 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001232 if (dis)
1233 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1234}
1235
1236static void emit_movb_zeroESPmem_AL ( void )
1237{
1238 /* movb 0(%esp), %al */
1239 /* 8A442400 movb 0(%esp), %al */
sewardjfa492d42002-12-08 18:20:01 +00001240 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001241 VG_(emitB) ( 0x8A );
1242 VG_(emitB) ( 0x44 );
1243 VG_(emitB) ( 0x24 );
1244 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001245 if (dis)
1246 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1247}
1248
sewardja2113f92002-12-12 23:42:48 +00001249/* Jump target states */
1250#define TGT_UNDEF (1 << 16)
1251#define TGT_FORWARD (2 << 16)
1252#define TGT_BACKWARD (3 << 16)
1253
1254static inline Int tgt_state(Int tgt)
1255{
1256 return tgt & 0xffff0000;
1257}
1258
1259static inline Int tgt_addr(Int tgt)
1260{
1261 return tgt & 0x0000ffff;
1262}
1263
1264static inline Int mk_tgt(Int state, Int addr)
1265{
1266 vg_assert(state == TGT_UNDEF
1267 || state == TGT_FORWARD || state == TGT_BACKWARD);
1268 vg_assert((addr & 0xffff0000) == 0);
1269
1270 return state | addr;
1271}
1272
1273void VG_(init_target) ( Int *tgt )
1274{
1275 *tgt = TGT_UNDEF;
1276}
1277
1278void VG_(target_back) ( Int *tgt )
1279{
1280 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1281
1282 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1283}
1284
1285void VG_(target_forward) ( Int *tgt )
1286{
1287 Int delta;
1288
1289 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1290 tgt_state(*tgt) == TGT_UNDEF);
1291
1292 if (tgt_state(*tgt) == TGT_UNDEF)
1293 return; /* target not used */
1294
1295 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1296 vg_assert(delta >= -128 && delta <= 127);
1297 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001298 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001299 emitted_code[tgt_addr(*tgt)] = delta;
1300 if (dis)
1301 VG_(printf)("(target to jump site %d; delta: %d)\n",
1302 tgt_addr(*tgt), delta);
1303}
1304
1305void VG_(emit_target_delta) ( Int *tgt )
1306{
1307 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1308 tgt_state(*tgt) == TGT_BACKWARD);
1309
1310 if (tgt_state(*tgt) == TGT_UNDEF) {
1311 /* forward jump */
1312 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1313 VG_(emitB) (0x00);
1314 } else {
1315 /* backward jump */
1316 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1317 vg_assert(delta >= -128 && delta <= 127);
1318 VG_(emitB) (delta);
1319 }
1320}
1321
sewardjde4a1d02002-03-22 01:27:54 +00001322
1323/* Emit a jump short with an 8-bit signed offset. Note that the
1324 offset is that which should be added to %eip once %eip has been
1325 advanced over this insn. */
sewardjfa492d42002-12-08 18:20:01 +00001326void VG_(emit_jcondshort_delta) ( Bool simd, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001327{
1328 vg_assert(delta >= -128 && delta <= 127);
sewardjfa492d42002-12-08 18:20:01 +00001329 VG_(new_emit)(simd, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001330 VG_(emitB) ( 0x70 + (UInt)cond );
1331 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001332 if (dis)
1333 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
1334 VG_(nameCondcode)(cond), delta );
1335}
1336
sewardja2113f92002-12-12 23:42:48 +00001337/* Same as above, but defers emitting the delta */
1338void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1339{
1340 VG_(new_emit)(simd, FlagsOSZCP, False);
1341 VG_(emitB) ( 0x70 + (UInt)cond );
1342 VG_(emit_target_delta) (tgt);
1343 if (dis)
1344 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
1345 VG_(nameCondcode)(cond), tgt_addr(*tgt) );
1346}
1347
1348
1349
sewardjde4a1d02002-03-22 01:27:54 +00001350static void emit_setb_reg ( Int reg, Condcode cond )
1351{
sewardjfa492d42002-12-08 18:20:01 +00001352 VG_(new_emit)(True, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001353 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1354 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001355 if (dis)
1356 VG_(printf)("\n\t\tset%s %s\n",
1357 VG_(nameCondcode)(cond), nameIReg(1,reg));
1358}
1359
1360static void emit_ret ( void )
1361{
sewardjfa492d42002-12-08 18:20:01 +00001362 maybe_emit_put_eflags(); /* make sure flags are stored */
1363 VG_(new_emit)(False, False, False);
njn25e49d8e72002-09-23 09:36:25 +00001364 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001365 if (dis)
1366 VG_(printf)("\n\t\tret\n");
1367}
1368
sewardj22854b92002-11-30 14:00:47 +00001369/* Predicate used in sanity checks elsewhere - returns true if any
1370 jump-site is an actual chained jump */
1371Bool VG_(is_chained_jumpsite)(Addr a)
1372{
1373 UChar *cp = (UChar *)a;
1374
1375 return (*cp == 0xE9); /* 0xE9 -- jmp */
1376}
1377
sewardj83f11862002-12-01 02:07:08 +00001378static
1379Bool is_fresh_jumpsite(UChar *cp)
1380{
1381 return
1382 cp[0] == 0x0F && /* UD2 */
1383 cp[1] == 0x0B &&
1384 cp[2] == 0x0F && /* UD2 */
1385 cp[3] == 0x0B &&
1386 cp[4] == 0x90; /* NOP */
1387}
1388
sewardj22854b92002-11-30 14:00:47 +00001389/* Predicate used in sanity checks elsewhere - returns true if all
1390 jump-sites are calls to VG_(patch_me) */
1391Bool VG_(is_unchained_jumpsite)(Addr a)
1392{
1393 UChar *cp = (UChar *)a;
1394 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1395 Int idelta;
1396
1397 if (*cp++ != 0xE8) /* 0xE8 == call */
1398 return False;
1399
1400 idelta = (*cp++) << 0;
1401 idelta |= (*cp++) << 8;
1402 idelta |= (*cp++) << 16;
1403 idelta |= (*cp++) << 24;
1404
1405 return idelta == delta;
1406}
1407
1408/* Return target address for a direct jmp */
1409Addr VG_(get_jmp_dest)(Addr a)
1410{
1411 Int delta;
1412 UChar *cp = (UChar *)a;
1413
1414 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1415 return 0;
1416
1417 delta = (*cp++) << 0;
1418 delta |= (*cp++) << 8;
1419 delta |= (*cp++) << 16;
1420 delta |= (*cp++) << 24;
1421
1422 return a + VG_PATCHME_JMPSZ + delta;
1423}
1424
1425/* unchain a BB by generating a call to VG_(patch_me) */
1426void VG_(unchain_jumpsite)(Addr a)
1427{
1428 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1429 UChar *cp = (UChar *)a;
1430
1431 if (VG_(is_unchained_jumpsite)(a))
1432 return; /* don't write unnecessarily */
1433
sewardj83f11862002-12-01 02:07:08 +00001434 if (!is_fresh_jumpsite(cp))
1435 VG_(bb_dechain_count)++; /* update stats */
1436
sewardj22854b92002-11-30 14:00:47 +00001437 *cp++ = 0xE8; /* call */
1438 *cp++ = (delta >> 0) & 0xff;
1439 *cp++ = (delta >> 8) & 0xff;
1440 *cp++ = (delta >> 16) & 0xff;
1441 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001442}
1443
1444/* This doesn't actually generate a call to VG_(patch_me), but
1445 reserves enough space in the instruction stream for it to happen
1446 and records the offset into the jump table. This is because call
1447 is a relative jump, and so will be affected when this code gets
1448 moved about. The translation table will "unchain" this basic block
1449 on insertion (with VG_(unchain_BB)()), and thereby generate a
1450 proper call instruction. */
1451static void emit_call_patchme( void )
1452{
1453 vg_assert(VG_PATCHME_CALLSZ == 5);
1454
sewardjfa492d42002-12-08 18:20:01 +00001455 maybe_emit_put_eflags(); /* save flags before end of BB */
1456 VG_(new_emit)(False, False, False);
sewardj22854b92002-11-30 14:00:47 +00001457
1458 if (jumpidx >= VG_MAX_JUMPS) {
1459 /* If there too many jumps in this basic block, fall back to
1460 dispatch loop. We still need to keep it the same size as the
1461 call sequence. */
1462 VG_(emitB) ( 0xC3 ); /* ret */
1463 VG_(emitB) ( 0x90 ); /* nop */
1464 VG_(emitB) ( 0x90 ); /* nop */
1465 VG_(emitB) ( 0x90 ); /* nop */
1466 VG_(emitB) ( 0x90 ); /* nop */
1467
1468 if (dis)
1469 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1470
1471 if (0 && VG_(clo_verbosity))
1472 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1473 } else {
1474 jumps[jumpidx++] = emitted_code_used;
1475
1476 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1477 VG_(emitB) ( 0x0B );
1478 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1479 VG_(emitB) ( 0x0B );
1480 VG_(emitB) ( 0x90 ); /* NOP */
1481
1482 if (dis)
1483 VG_(printf)("\n\t\tud2; ud2; nop\n");
1484 }
1485}
1486
njn25e49d8e72002-09-23 09:36:25 +00001487void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001488{
sewardjfa492d42002-12-08 18:20:01 +00001489 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001490 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001491 if (dis)
1492 VG_(printf)("\n\t\tpushal\n");
1493}
1494
njn25e49d8e72002-09-23 09:36:25 +00001495void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001496{
sewardjfa492d42002-12-08 18:20:01 +00001497 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001498 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001499 if (dis)
1500 VG_(printf)("\n\t\tpopal\n");
1501}
1502
1503static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1504{
sewardjfa492d42002-12-08 18:20:01 +00001505 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001506 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1507 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001508 if (dis)
1509 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1510 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1511}
1512
1513static void emit_lea_sib_reg ( UInt lit, Int scale,
1514 Int regbase, Int regindex, Int reg )
1515{
sewardjfa492d42002-12-08 18:20:01 +00001516 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001517 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001518 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1519 if (dis)
1520 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1521 lit, nameIReg(4,regbase),
1522 nameIReg(4,regindex), scale,
1523 nameIReg(4,reg) );
1524}
1525
njn25e49d8e72002-09-23 09:36:25 +00001526void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001527{
sewardjfa492d42002-12-08 18:20:01 +00001528 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001529 VG_(emitB) ( 0x0F );
1530 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001531 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1532 if (dis)
1533 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1534}
1535
1536/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001537/*--- Helper offset -> addr translation ---*/
1538/*----------------------------------------------------*/
1539
1540/* Finds the baseBlock offset of a skin-specified helper.
1541 * Searches through compacts first, then non-compacts. */
1542Int VG_(helper_offset)(Addr a)
1543{
1544 Int i;
1545
1546 for (i = 0; i < VG_(n_compact_helpers); i++)
1547 if (VG_(compact_helper_addrs)[i] == a)
1548 return VG_(compact_helper_offsets)[i];
1549 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1550 if (VG_(noncompact_helper_addrs)[i] == a)
1551 return VG_(noncompact_helper_offsets)[i];
1552
1553 /* Shouldn't get here */
1554 VG_(printf)(
1555 "\nCouldn't find offset of helper from its address (%p).\n"
1556 "A helper function probably used hasn't been registered?\n\n", a);
1557
1558 VG_(printf)(" compact helpers: ");
1559 for (i = 0; i < VG_(n_compact_helpers); i++)
1560 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1561
1562 VG_(printf)("\n non-compact helpers: ");
1563 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1564 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1565
1566 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001567 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001568}
1569
1570/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001571/*--- Instruction synthesisers ---*/
1572/*----------------------------------------------------*/
1573
1574static Condcode invertCondition ( Condcode cond )
1575{
1576 return (Condcode)(1 ^ (UInt)cond);
1577}
1578
1579
1580/* Synthesise a call to *baseBlock[offset], ie,
1581 call * (4 x offset)(%ebp).
1582*/
sewardjfa492d42002-12-08 18:20:01 +00001583void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
1584 Bool upd_cc, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001585{
1586 vg_assert(word_offset >= 0);
1587 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001588 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001589 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001590 }
1591 emit_call_star_EBP_off ( upd_cc, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001592}
1593
njn25e49d8e72002-09-23 09:36:25 +00001594static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001595{
njn25e49d8e72002-09-23 09:36:25 +00001596 if (src != dst) {
1597 VG_(emit_movv_reg_reg) ( 4, src, dst );
1598 ccall_arg_setup_instrs++;
1599 }
njn6431be72002-07-28 09:53:34 +00001600}
njn25e49d8e72002-09-23 09:36:25 +00001601
1602/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1603static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1604{
1605 if (RealReg == tag) {
1606 maybe_emit_movl_reg_reg ( litOrReg, reg );
1607 } else if (Literal == tag) {
1608 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1609 ccall_arg_setup_instrs++;
1610 }
1611 else
njne427a662002-10-02 11:08:25 +00001612 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001613}
1614
1615static
1616void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1617{
1618 if (R_EAX == reg1) {
1619 VG_(emit_swapl_reg_EAX) ( reg2 );
1620 } else if (R_EAX == reg2) {
1621 VG_(emit_swapl_reg_EAX) ( reg1 );
1622 } else {
1623 emit_swapl_reg_reg ( reg1, reg2 );
1624 }
1625 ccall_arg_setup_instrs++;
1626}
1627
1628static
1629void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1630{
1631 if (dst1 != src2) {
1632 maybe_emit_movl_reg_reg ( src1, dst1 );
1633 maybe_emit_movl_reg_reg ( src2, dst2 );
1634
1635 } else if (dst2 != src1) {
1636 maybe_emit_movl_reg_reg ( src2, dst2 );
1637 maybe_emit_movl_reg_reg ( src1, dst1 );
1638
1639 } else {
1640 /* swap to break cycle */
1641 emit_swapl_arg_regs ( dst1, dst2 );
1642 }
1643}
1644
1645static
1646void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1647 UInt dst1, UInt dst2, UInt dst3)
1648{
1649 if (dst1 != src2 && dst1 != src3) {
1650 maybe_emit_movl_reg_reg ( src1, dst1 );
1651 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1652
1653 } else if (dst2 != src1 && dst2 != src3) {
1654 maybe_emit_movl_reg_reg ( src2, dst2 );
1655 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1656
1657 } else if (dst3 != src1 && dst3 != src2) {
1658 maybe_emit_movl_reg_reg ( src3, dst3 );
1659 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1660
1661 } else {
1662 /* break cycle */
1663 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1664 emit_swapl_arg_regs ( dst1, dst2 );
1665 emit_swapl_arg_regs ( dst1, dst3 );
1666
1667 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1668 emit_swapl_arg_regs ( dst1, dst3 );
1669 emit_swapl_arg_regs ( dst1, dst2 );
1670
1671 } else {
njne427a662002-10-02 11:08:25 +00001672 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001673 }
1674 }
1675}
1676
1677static
1678void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1679 UInt src1, UInt src2,
1680 UInt dst1, UInt dst2)
1681{
1682 /* If either are lits, order doesn't matter */
1683 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1684 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1685 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1686
1687 } else {
1688 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1689 }
1690}
1691
1692static
1693void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1694 UInt src1, UInt src2, UInt src3,
1695 UInt dst1, UInt dst2, UInt dst3)
1696{
1697 // SSS: fix this eventually -- make STOREV use two RealRegs?
1698 /* Not supporting literals for 3-arg C functions -- they're only used
1699 by STOREV which has 2 args */
1700 vg_assert(RealReg == tagv[src1] &&
1701 RealReg == tagv[src2] &&
1702 RealReg == tagv[src3]);
1703 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1704 dst1, dst2, dst3 );
1705}
1706
1707/* Synthesise a call to a C function `fn' (which must be registered in
1708 baseBlock) doing all the reg saving and arg handling work.
1709
1710 WARNING: a UInstr should *not* be translated with synth_ccall followed
1711 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1712 such behaviour and everything will fall over.
1713 */
1714void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1715 Tag tagv[], Int ret_reg,
1716 RRegSet regs_live_before, RRegSet regs_live_after )
1717{
1718 Int i;
1719 Int stack_used = 0;
1720 Bool preserve_eax, preserve_ecx, preserve_edx;
1721
1722 vg_assert(0 <= regparms_n && regparms_n <= 3);
1723
1724 ccalls++;
1725
1726 /* If %e[acd]x is live before and after the C call, save/restore it.
1727 Unless the return values clobbers the reg; in this case we must not
1728 save/restore the reg, because the restore would clobber the return
1729 value. (Before and after the UInstr really constitute separate live
1730 ranges, but you miss this if you don't consider what happens during
1731 the UInstr.) */
1732# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001733 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1734 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001735 ret_reg != realReg)
1736
1737 preserve_eax = PRESERVE_REG(R_EAX);
1738 preserve_ecx = PRESERVE_REG(R_ECX);
1739 preserve_edx = PRESERVE_REG(R_EDX);
1740
1741# undef PRESERVE_REG
1742
1743 /* Save caller-save regs as required */
1744 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1745 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1746 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1747
1748 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1749 is the number of args passed in regs (maximum 3 for GCC on x86). */
1750
1751 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001752
njn25e49d8e72002-09-23 09:36:25 +00001753 /* First push stack args (RealRegs or Literals) in reverse order. */
1754 for (i = argc-1; i >= regparms_n; i--) {
1755 switch (tagv[i]) {
1756 case RealReg:
1757 VG_(emit_pushv_reg) ( 4, argv[i] );
1758 break;
1759 case Literal:
1760 /* Use short form of pushl if possible. */
1761 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1762 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1763 else
1764 VG_(emit_pushl_lit32)( argv[i] );
1765 break;
1766 default:
1767 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001768 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001769 }
1770 stack_used += 4;
1771 ccall_arg_setup_instrs++;
1772 }
njn6431be72002-07-28 09:53:34 +00001773
njn25e49d8e72002-09-23 09:36:25 +00001774 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1775 If moving values between registers, be careful not to clobber any on
1776 the way. Happily we can use xchgl to swap registers.
1777 */
1778 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001779
njn25e49d8e72002-09-23 09:36:25 +00001780 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1781 case 3:
1782 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1783 R_EAX, R_EDX, R_ECX );
1784 break;
njn6431be72002-07-28 09:53:34 +00001785
njn25e49d8e72002-09-23 09:36:25 +00001786 /* Less-tricky. Args passed in %eax and %edx. */
1787 case 2:
1788 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1789 break;
1790
1791 /* Easy. Just move arg1 into %eax (if not already in there). */
1792 case 1:
1793 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1794 break;
1795
1796 case 0:
1797 break;
1798
1799 default:
njne427a662002-10-02 11:08:25 +00001800 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001801 }
1802
sewardjfa492d42002-12-08 18:20:01 +00001803 /* Call the function - may trash all flags */
1804 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00001805
1806 /* Clear any args from stack */
1807 if (0 != stack_used) {
1808 VG_(emit_add_lit_to_esp) ( stack_used );
1809 ccall_stack_clears++;
1810 }
1811
1812 /* Move return value into ret_reg if necessary and not already there */
1813 if (INVALID_REALREG != ret_reg) {
1814 ccall_retvals++;
1815 if (R_EAX != ret_reg) {
1816 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1817 ccall_retval_movs++;
1818 }
1819 }
1820
1821 /* Restore live caller-save regs as required */
1822 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1823 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1824 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001825}
sewardjde4a1d02002-03-22 01:27:54 +00001826
sewardj2e93c502002-04-12 11:12:52 +00001827static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001828{
sewardj2e93c502002-04-12 11:12:52 +00001829 switch (jmpkind) {
1830 case JmpBoring:
1831 break;
sewardj2e93c502002-04-12 11:12:52 +00001832 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001833 break;
1834 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001835 break;
1836 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001837 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001838 break;
1839 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001840 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001841 break;
1842 default:
njne427a662002-10-02 11:08:25 +00001843 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001844 }
1845}
1846
1847/* Jump to the next translation, by loading its original addr into
1848 %eax and returning to the scheduler. Signal special requirements
1849 by loading a special value into %ebp first.
1850*/
1851static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1852{
sewardjfa492d42002-12-08 18:20:01 +00001853 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00001854 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001855 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001856 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001857 emit_ret();
1858}
1859
sewardj22854b92002-11-30 14:00:47 +00001860static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00001861
1862/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001863static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001864{
sewardjfa492d42002-12-08 18:20:01 +00001865 maybe_emit_put_eflags(); /* save flags here */
1866
njn25e49d8e72002-09-23 09:36:25 +00001867 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00001868
1869 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
1870 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
1871 emit_call_patchme();
1872 } else {
1873 load_ebp_from_JmpKind ( jmpkind );
1874 emit_ret();
1875 }
sewardjde4a1d02002-03-22 01:27:54 +00001876}
1877
1878
sewardj2370f3b2002-11-30 15:01:01 +00001879static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
1880static void synth_nonshiftop_lit_reg ( Bool upd_cc,
1881 Opcode opcode, Int size,
1882 UInt lit, Int reg );
1883
sewardjfa492d42002-12-08 18:20:01 +00001884static void synth_jcond_lit ( Condcode cond,
1885 Addr addr,
1886 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00001887{
sewardj2370f3b2002-11-30 15:01:01 +00001888 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00001889 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00001890 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00001891
sewardja2113f92002-12-12 23:42:48 +00001892 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00001893 VG_(init_target)(&tgt2);
1894 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00001895
sewardjfa492d42002-12-08 18:20:01 +00001896 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
1897 if need be */
1898 maybe_emit_put_eflags();
1899 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
1900
1901 if (eflags_state == UPD_Both) {
1902 /* The flags are already set up, so we just use them as is. */
1903 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00001904 cond = invertCondition(cond);
1905 } else {
sewardj75f04932002-12-12 23:13:21 +00001906 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00001907
1908 /* The simd state contains the most recent version, so we emit a
1909 sequence to calculate the relevant condition directly out of
1910 the simd flags. This is much cheaper (on P3/P4/Athlon) than
1911 copying them back to the real flags via popf. Notice that
1912 some of these sequences trash %eax, but that should be free
1913 now since this is the end of a bb and therefore all regs are
1914 dead. */
1915 simd = False;
1916
1917 switch (cond) {
1918
sewardjbb6c1182002-12-12 23:54:47 +00001919 case CondLE: /* Z || S != O -> S || !P */
1920 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00001921 vg_assert(eax_trashable);
1922
1923 VG_(emit_movv_offregmem_reg)
1924 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1925 /* eax == %EFLAGS */
1926
sewardjbb6c1182002-12-12 23:54:47 +00001927 VG_(emit_nonshiftopv_lit_reg)
1928 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
1929 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00001930
sewardjbb6c1182002-12-12 23:54:47 +00001931 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
1932 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00001933
sewardjbb6c1182002-12-12 23:54:47 +00001934 if (cond == CondLE) {
1935 /* test Z */
1936 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
1937 /* test OF != SF */
1938 cond = CondP;
1939 } else {
1940 /* test Z */
1941 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
1942 /* test OF == SF */
1943 cond = CondNP;
1944 }
sewardj2370f3b2002-11-30 15:01:01 +00001945 break;
1946
sewardjfa492d42002-12-08 18:20:01 +00001947 case CondL:
1948 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00001949 vg_assert(eax_trashable);
1950
1951 VG_(emit_movv_offregmem_reg)
1952 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1953 /* eax == %EFLAGS */
1954
sewardj75f04932002-12-12 23:13:21 +00001955 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
1956 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00001957
sewardj75f04932002-12-12 23:13:21 +00001958 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
1959 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00001960
sewardj75f04932002-12-12 23:13:21 +00001961 if (cond == CondL) cond = CondP; else cond = CondNP;
1962 break;
sewardjfa492d42002-12-08 18:20:01 +00001963
1964 case CondB:
1965 case CondNB:
1966 mask = EFlagC; goto simple; /* C=1 */
1967
1968 case CondZ:
1969 case CondNZ:
1970 mask = EFlagZ; goto simple; /* Z=1 */
1971
1972 case CondBE:
1973 case CondNBE:
1974 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
1975
1976 case CondS:
1977 case CondNS:
1978 mask = EFlagS; goto simple; /* S=1 */
1979
1980 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00001981 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00001982 mask = EFlagP; goto simple; /* P=1 */
1983
sewardj39542072002-12-09 22:44:00 +00001984 case CondO:
1985 case CondNO:
1986 mask = EFlagO; goto simple; /* O=1 */
1987
sewardjfa492d42002-12-08 18:20:01 +00001988 default:
1989 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
1990 (Int)cond, VG_(nameCondcode)(cond) );
1991 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
1992
1993 simple:
1994 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00001995 if ((mask & 0xff) == mask) {
1996 VG_(emitB) ( 0xF6 ); /* Grp3 */
1997 VG_(emit_amode_offregmem_reg)(
1998 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1999 VG_(emitB) (mask);
2000 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002001 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002002 mask, VGOFF_(m_eflags) * 4);
2003 } else {
sewardjfa492d42002-12-08 18:20:01 +00002004 /* all cond codes are in lower 16 bits */
2005 vg_assert((mask & 0xffff) == mask);
2006
2007 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002008 VG_(emitB) ( 0xF7 );
2009 VG_(emit_amode_offregmem_reg)(
2010 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002011 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002012 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002013 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002014 mask, VGOFF_(m_eflags) * 4);
2015 }
2016
sewardj75f04932002-12-12 23:13:21 +00002017 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002018 break;
2019 }
2020 }
2021
sewardja2113f92002-12-12 23:42:48 +00002022 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002023
2024 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002025 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002026
2027 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002028 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002029}
2030
2031
sewardj2370f3b2002-11-30 15:01:01 +00002032
sewardjde4a1d02002-03-22 01:27:54 +00002033static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2034{
sewardja2113f92002-12-12 23:42:48 +00002035 Int tgt;
2036
2037 VG_(init_target)(&tgt);
2038
sewardjfa492d42002-12-08 18:20:01 +00002039 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002040
2041 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002042 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002043
2044 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002045}
2046
2047
2048static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2049{
2050 /* Load the zero-extended literal into reg, at size l,
2051 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002052 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002053}
2054
2055
2056static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2057{
2058 switch (size) {
2059 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2060 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2061 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002062 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002063 }
2064}
2065
2066
2067static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2068{
2069 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002070 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2071 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2072 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002073 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002074 }
2075}
2076
2077
2078static void synth_mov_reg_offregmem ( Int size, Int reg,
2079 Int off, Int areg )
2080{
2081 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002082 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2083 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002084 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002085 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002086 }
2087 else {
njn25e49d8e72002-09-23 09:36:25 +00002088 VG_(emit_swapl_reg_EAX) ( reg );
2089 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2090 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002091 }
2092 break;
njne427a662002-10-02 11:08:25 +00002093 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002094 }
2095}
2096
2097
2098static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2099{
2100 Int s1;
2101 switch (size) {
2102 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2103 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2104 case 1: if (reg1 < 4) {
2105 emit_movb_reg_regmem ( reg1, reg2 );
2106 }
2107 else {
2108 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2109 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2110 emit_swapl_reg_reg ( s1, reg1 );
2111 emit_movb_reg_regmem ( s1, reg2 );
2112 emit_swapl_reg_reg ( s1, reg1 );
2113 }
2114 break;
njne427a662002-10-02 11:08:25 +00002115 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002116 }
2117}
2118
2119
sewardj478335c2002-10-05 02:44:47 +00002120static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002121 Opcode opcode, Int size,
2122 Int reg )
2123{
2124 /* NB! opcode is a uinstr opcode, not an x86 one! */
2125 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002126 case 4: VG_(emit_unaryopv_reg) ( upd_cc, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002127 break;
sewardjfa492d42002-12-08 18:20:01 +00002128 case 2: VG_(emit_unaryopv_reg) ( upd_cc, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002129 break;
2130 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002131 VG_(emit_unaryopb_reg) ( upd_cc, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002132 } else {
njn25e49d8e72002-09-23 09:36:25 +00002133 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002134 VG_(emit_unaryopb_reg) ( upd_cc, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002135 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002136 }
2137 break;
njne427a662002-10-02 11:08:25 +00002138 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002139 }
2140}
2141
2142
2143
sewardj478335c2002-10-05 02:44:47 +00002144static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002145 Opcode opcode, Int size,
2146 Int reg1, Int reg2 )
2147{
2148 /* NB! opcode is a uinstr opcode, not an x86 one! */
2149 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002150 case 4: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002151 break;
sewardjfa492d42002-12-08 18:20:01 +00002152 case 2: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002153 break;
2154 case 1: { /* Horrible ... */
2155 Int s1, s2;
2156 /* Choose s1 and s2 to be x86 regs which we can talk about the
2157 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2158 sure s1 != s2 and that neither of them equal either reg1 or
2159 reg2. Then use them as temporaries to make things work. */
2160 if (reg1 < 4 && reg2 < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002161 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002162 break;
2163 }
2164 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2165 if (reg1 >= 4 && reg2 < 4) {
2166 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002167 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002168 emit_swapl_reg_reg ( reg1, s1 );
2169 break;
2170 }
2171 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2172 if (reg1 < 4 && reg2 >= 4) {
2173 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002174 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002175 emit_swapl_reg_reg ( reg2, s2 );
2176 break;
2177 }
2178 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2179 emit_swapl_reg_reg ( reg1, s1 );
2180 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002181 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002182 emit_swapl_reg_reg ( reg1, s1 );
2183 emit_swapl_reg_reg ( reg2, s2 );
2184 break;
2185 }
2186 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2187 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002188 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002189 emit_swapl_reg_reg ( reg1, s1 );
2190 break;
2191 }
njne427a662002-10-02 11:08:25 +00002192 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002193 }
njne427a662002-10-02 11:08:25 +00002194 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002195 }
2196}
2197
2198
sewardjfa492d42002-12-08 18:20:01 +00002199static void synth_nonshiftop_reg_offregmem (
2200 Bool upd_cc,
2201 Opcode opcode, Int size,
2202 Int off, Int areg, Int reg )
2203{
2204 switch (size) {
2205 case 4:
2206 emit_nonshiftopv_reg_offregmem ( upd_cc, 4, opcode, off, areg, reg );
2207 break;
2208 case 2:
2209 emit_nonshiftopv_reg_offregmem ( upd_cc, 2, opcode, off, areg, reg );
2210 break;
2211 case 1:
2212 if (reg < 4) {
2213 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, reg );
2214 } else {
2215 VG_(emit_swapl_reg_EAX) ( reg );
2216 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, R_AL );
2217 VG_(emit_swapl_reg_EAX) ( reg );
2218 }
2219 break;
2220 default:
2221 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2222 }
2223}
2224
sewardjde4a1d02002-03-22 01:27:54 +00002225static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002226 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002227 Opcode opcode, Int size,
2228 Int off, Int areg, Int reg )
2229{
2230 switch (size) {
2231 case 4:
sewardjfa492d42002-12-08 18:20:01 +00002232 emit_nonshiftopv_offregmem_reg ( upd_cc, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002233 break;
2234 case 2:
sewardjfa492d42002-12-08 18:20:01 +00002235 emit_nonshiftopv_offregmem_reg ( upd_cc, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002236 break;
2237 case 1:
2238 if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002239 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002240 } else {
njn25e49d8e72002-09-23 09:36:25 +00002241 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002242 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002243 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002244 }
2245 break;
2246 default:
njne427a662002-10-02 11:08:25 +00002247 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002248 }
2249}
2250
2251
sewardj478335c2002-10-05 02:44:47 +00002252static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002253 Opcode opcode, Int size,
2254 UInt lit, Int reg )
2255{
2256 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002257 case 4: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002258 break;
sewardjfa492d42002-12-08 18:20:01 +00002259 case 2: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002260 break;
2261 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002262 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002263 } else {
njn25e49d8e72002-09-23 09:36:25 +00002264 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002265 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002266 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002267 }
2268 break;
njne427a662002-10-02 11:08:25 +00002269 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002270 }
2271}
2272
sewardjfa492d42002-12-08 18:20:01 +00002273static void synth_nonshiftop_lit_offregmem ( Bool upd_cc,
2274 Opcode opcode, Int size,
2275 UInt lit, Int off, Int regmem )
2276{
2277 switch (size) {
2278 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 4, opcode, lit, off, regmem );
2279 break;
2280 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 2, opcode, lit, off, regmem );
2281 break;
2282 case 1: emit_nonshiftopb_lit_offregmem ( upd_cc, opcode, lit, off, regmem );
2283 break;
2284 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2285 }
2286}
2287
sewardjde4a1d02002-03-22 01:27:54 +00002288
2289static void synth_push_reg ( Int size, Int reg )
2290{
2291 switch (size) {
2292 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002293 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002294 break;
2295 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002296 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002297 break;
2298 /* Pray that we don't have to generate this really cruddy bit of
2299 code very often. Could do better, but can I be bothered? */
2300 case 1:
2301 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002302 VG_(emit_add_lit_to_esp)(-1);
2303 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002304 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002305 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002306 break;
2307 default:
njne427a662002-10-02 11:08:25 +00002308 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002309 }
2310}
2311
2312
2313static void synth_pop_reg ( Int size, Int reg )
2314{
2315 switch (size) {
2316 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002317 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002318 break;
2319 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002320 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002321 break;
2322 case 1:
2323 /* Same comment as above applies. */
2324 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002325 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002326 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002327 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2328 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002329 break;
njne427a662002-10-02 11:08:25 +00002330 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002331 }
2332}
2333
2334
sewardj478335c2002-10-05 02:44:47 +00002335static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002336 Opcode opcode, Int size,
2337 Int regs, Int regd )
2338{
2339 synth_push_reg ( size, regd );
2340 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002341 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002342 case 4: emit_shiftopv_cl_stack0 ( upd_cc, 4, opcode ); break;
2343 case 2: emit_shiftopv_cl_stack0 ( upd_cc, 2, opcode ); break;
2344 case 1: emit_shiftopb_cl_stack0 ( upd_cc, opcode ); break;
njne427a662002-10-02 11:08:25 +00002345 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002346 }
sewardjde4a1d02002-03-22 01:27:54 +00002347 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2348 synth_pop_reg ( size, regd );
2349}
2350
2351
sewardj478335c2002-10-05 02:44:47 +00002352static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002353 Opcode opcode, Int size,
2354 UInt lit, Int reg )
2355{
2356 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002357 case 4: VG_(emit_shiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002358 break;
sewardjfa492d42002-12-08 18:20:01 +00002359 case 2: VG_(emit_shiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002360 break;
2361 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002362 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002363 } else {
njn25e49d8e72002-09-23 09:36:25 +00002364 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002365 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002366 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002367 }
2368 break;
njne427a662002-10-02 11:08:25 +00002369 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002370 }
2371}
2372
2373
2374static void synth_setb_reg ( Int reg, Condcode cond )
2375{
sewardjde4a1d02002-03-22 01:27:54 +00002376 if (reg < 4) {
2377 emit_setb_reg ( reg, cond );
2378 } else {
njn25e49d8e72002-09-23 09:36:25 +00002379 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002380 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002381 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002382 }
2383}
2384
2385
sewardjfa492d42002-12-08 18:20:01 +00002386static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2387 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002388 UChar second_byte_masked,
2389 Int reg )
2390{
sewardjfa492d42002-12-08 18:20:01 +00002391 emit_fpu_regmem ( uses_flags, sets_flags, first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002392}
2393
2394
sewardjfa492d42002-12-08 18:20:01 +00002395static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2396 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002397 UChar second_byte )
2398{
sewardjfa492d42002-12-08 18:20:01 +00002399 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002400}
2401
2402
2403static void synth_movl_reg_reg ( Int src, Int dst )
2404{
2405 emit_movl_reg_reg ( src, dst );
2406}
2407
2408static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2409{
sewardja2113f92002-12-12 23:42:48 +00002410 Int tgt;
2411
2412 VG_(init_target)(&tgt);
2413
2414 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002415 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002416
2417 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002418}
2419
2420
sewardjde4a1d02002-03-22 01:27:54 +00002421/*----------------------------------------------------*/
2422/*--- Top level of the uinstr -> x86 translation. ---*/
2423/*----------------------------------------------------*/
2424
2425/* Return the byte offset from %ebp (ie, into baseBlock)
2426 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002427static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2428{
2429 if (tag == SpillNo) {
2430 vg_assert(size == 4);
2431 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2432 return 4 * (value + VGOFF_(spillslots));
2433 }
2434 if (tag == ArchReg) {
2435 switch (value) {
2436 case R_EAX: return 4 * VGOFF_(m_eax);
2437 case R_ECX: return 4 * VGOFF_(m_ecx);
2438 case R_EDX: return 4 * VGOFF_(m_edx);
2439 case R_EBX: return 4 * VGOFF_(m_ebx);
2440 case R_ESP:
2441 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2442 else return 4 * VGOFF_(m_esp);
2443 case R_EBP:
2444 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2445 else return 4 * VGOFF_(m_ebp);
2446 case R_ESI:
2447 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2448 else return 4 * VGOFF_(m_esi);
2449 case R_EDI:
2450 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2451 else return 4 * VGOFF_(m_edi);
2452 }
2453 }
njne427a662002-10-02 11:08:25 +00002454 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002455}
2456
sewardjde4a1d02002-03-22 01:27:54 +00002457static Int eflagsOffset ( void )
2458{
2459 return 4 * VGOFF_(m_eflags);
2460}
2461
sewardje1042472002-09-30 12:33:11 +00002462static Int segRegOffset ( UInt archregs )
2463{
2464 switch (archregs) {
2465 case R_CS: return 4 * VGOFF_(m_cs);
2466 case R_SS: return 4 * VGOFF_(m_ss);
2467 case R_DS: return 4 * VGOFF_(m_ds);
2468 case R_ES: return 4 * VGOFF_(m_es);
2469 case R_FS: return 4 * VGOFF_(m_fs);
2470 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002471 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002472 }
2473}
2474
sewardjde4a1d02002-03-22 01:27:54 +00002475
njn25e49d8e72002-09-23 09:36:25 +00002476/* Return the byte offset from %ebp (ie, into baseBlock)
2477 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002478Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002479{
2480 switch (arch) {
2481 case R_EAX: return 4 * VGOFF_(sh_eax);
2482 case R_ECX: return 4 * VGOFF_(sh_ecx);
2483 case R_EDX: return 4 * VGOFF_(sh_edx);
2484 case R_EBX: return 4 * VGOFF_(sh_ebx);
2485 case R_ESP: return 4 * VGOFF_(sh_esp);
2486 case R_EBP: return 4 * VGOFF_(sh_ebp);
2487 case R_ESI: return 4 * VGOFF_(sh_esi);
2488 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002489 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002490 }
2491}
2492
njn4ba5a792002-09-30 10:23:54 +00002493Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002494{
2495 return 4 * VGOFF_(sh_eflags);
2496}
2497
2498
sewardjde4a1d02002-03-22 01:27:54 +00002499
2500static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2501{
2502 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002503 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2504 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002505 }
2506 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002507 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2508 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002509 }
2510 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002511 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2512 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002513 }
2514 else
njne427a662002-10-02 11:08:25 +00002515 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002516}
2517
2518
njn25e49d8e72002-09-23 09:36:25 +00002519static void synth_handle_esp_assignment ( Int i, Int reg,
2520 RRegSet regs_live_before,
2521 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002522{
njn25e49d8e72002-09-23 09:36:25 +00002523 UInt argv[] = { reg };
2524 Tag tagv[] = { RealReg };
2525
2526 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2527 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002528}
2529
2530
sewardjde4a1d02002-03-22 01:27:54 +00002531/*----------------------------------------------------*/
2532/*--- Generate code for a single UInstr. ---*/
2533/*----------------------------------------------------*/
2534
sewardj478335c2002-10-05 02:44:47 +00002535static __inline__
2536Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002537{
2538 return (u->flags_w != FlagsEmpty);
2539}
2540
sewardjfa492d42002-12-08 18:20:01 +00002541static __inline__
2542Bool readFlagUse ( UInstr* u )
2543{
2544 /* If the UInstr writes some flags but not all, then we still need
2545 to consider it as reading flags so that the unchanged values are
2546 passed through properly. (D is special) */
2547 return
2548 (u->flags_r != FlagsEmpty) ||
2549 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2550}
2551
sewardj478335c2002-10-05 02:44:47 +00002552static __inline__
2553Bool anyFlagUse ( UInstr* u )
2554{
sewardjfa492d42002-12-08 18:20:01 +00002555 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002556}
2557
2558
sewardjb5ff83e2002-12-01 19:40:49 +00002559/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002560 the real FPU. If so we need to be very careful not to trash it.
2561 If FPU state is live and we deem it necessary to copy it back to
2562 the simulated machine's FPU state, we do so. The final state of
2563 fpliveness is returned. In short we _must_ do put_fpu_state if
2564 there is any chance at all that the code generated for a UInstr
2565 will change the real FPU state.
2566*/
sewardjb5ff83e2002-12-01 19:40:49 +00002567static void emitUInstr ( UCodeBlock* cb, Int i,
2568 RRegSet regs_live_before,
2569 /* Running state, which we update. */
2570 Bool* fplive, /* True<==>FPU state in real FPU */
2571 Addr* orig_eip, /* previous curr_eip, or zero */
2572 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002573{
njn25e49d8e72002-09-23 09:36:25 +00002574 Int old_emitted_code_used;
2575 UInstr* u = &cb->instrs[i];
2576
sewardjde4a1d02002-03-22 01:27:54 +00002577 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002578 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002579
njn25e49d8e72002-09-23 09:36:25 +00002580 old_emitted_code_used = emitted_code_used;
2581
sewardjde4a1d02002-03-22 01:27:54 +00002582 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002583 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002584
sewardjb5ff83e2002-12-01 19:40:49 +00002585 case INCEIP:
2586 /* Advance %EIP some small amount. */
2587 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002588
sewardjb5ff83e2002-12-01 19:40:49 +00002589 if (*orig_eip == 0 /* we don't know what the old value was */
2590 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2591 /* We have to update all 32 bits of the value. */
2592 VG_(emit_movv_lit_offregmem)(
2593 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2594 } else {
2595 /* Cool! we only need to update lowest 8 bits */
2596 VG_(emit_movb_lit_offregmem)(
2597 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002598 }
njn25e49d8e72002-09-23 09:36:25 +00002599
sewardjb5ff83e2002-12-01 19:40:49 +00002600 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002601 break;
sewardjde4a1d02002-03-22 01:27:54 +00002602
2603 case LEA1: {
2604 vg_assert(u->tag1 == RealReg);
2605 vg_assert(u->tag2 == RealReg);
2606 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2607 break;
2608 }
2609
2610 case LEA2: {
2611 vg_assert(u->tag1 == RealReg);
2612 vg_assert(u->tag2 == RealReg);
2613 vg_assert(u->tag3 == RealReg);
2614 emit_lea_sib_reg ( u->lit32, u->extra4b,
2615 u->val1, u->val2, u->val3 );
2616 break;
2617 }
2618
2619 case WIDEN: {
2620 vg_assert(u->tag1 == RealReg);
2621 if (u->signed_widen) {
2622 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2623 } else {
2624 /* no need to generate any code. */
2625 }
2626 break;
2627 }
2628
sewardjde4a1d02002-03-22 01:27:54 +00002629 case STORE: {
2630 vg_assert(u->tag1 == RealReg);
2631 vg_assert(u->tag2 == RealReg);
2632 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002633 break;
2634 }
2635
2636 case LOAD: {
2637 vg_assert(u->tag1 == RealReg);
2638 vg_assert(u->tag2 == RealReg);
2639 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2640 break;
2641 }
2642
sewardjde4a1d02002-03-22 01:27:54 +00002643 case GET: {
2644 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2645 vg_assert(u->tag2 == RealReg);
2646 synth_mov_offregmem_reg (
2647 u->size,
2648 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2649 R_EBP,
2650 u->val2
2651 );
2652 break;
2653 }
2654
2655 case PUT: {
2656 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2657 vg_assert(u->tag1 == RealReg);
2658 if (u->tag2 == ArchReg
2659 && u->val2 == R_ESP
2660 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002661 && (VG_(track_events).new_mem_stack ||
2662 VG_(track_events).new_mem_stack_aligned ||
2663 VG_(track_events).die_mem_stack ||
2664 VG_(track_events).die_mem_stack_aligned ||
2665 VG_(track_events).post_mem_write))
2666 {
2667 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2668 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002669 }
njn25e49d8e72002-09-23 09:36:25 +00002670 else {
2671 synth_mov_reg_offregmem (
2672 u->size,
2673 u->val1,
2674 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2675 R_EBP
2676 );
2677 }
sewardjde4a1d02002-03-22 01:27:54 +00002678 break;
2679 }
2680
sewardje1042472002-09-30 12:33:11 +00002681 case GETSEG: {
2682 vg_assert(u->tag1 == ArchRegS);
2683 vg_assert(u->tag2 == RealReg);
2684 vg_assert(u->size == 2);
2685 synth_mov_offregmem_reg (
2686 4,
2687 segRegOffset( u->val1 ),
2688 R_EBP,
2689 u->val2
2690 );
2691 break;
2692 }
2693
2694 case PUTSEG: {
2695 vg_assert(u->tag1 == RealReg);
2696 vg_assert(u->tag2 == ArchRegS);
2697 vg_assert(u->size == 2);
2698 synth_mov_reg_offregmem (
2699 4,
2700 u->val1,
2701 segRegOffset( u->val2 ),
2702 R_EBP
2703 );
2704 break;
2705 }
2706
sewardjde4a1d02002-03-22 01:27:54 +00002707 case GETF: {
2708 vg_assert(u->size == 2 || u->size == 4);
2709 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002710
2711 /* This complexity is because the D(irection) flag is stored
2712 separately from the rest of EFLAGS. */
2713
2714 /* We're only fetching from the Simd state, so make sure it's
2715 up to date. */
2716 maybe_emit_put_eflags();
2717
2718 /* get D in u->val1 (== 1 or -1) */
2719 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
2720
2721 /* u->val1 &= EFlagD (== 0 or EFlagD) */
2722 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2723
2724 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2725 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2726 eflagsOffset(), R_EBP);
2727
2728 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2729 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2730 eflagsOffset(), R_EBP);
2731
2732 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
2733 synth_nonshiftop_offregmem_reg(False, OR, u->size,
2734 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00002735 break;
2736 }
2737
2738 case PUTF: {
2739 vg_assert(u->size == 2 || u->size == 4);
2740 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002741
2742 /* When putting a value into EFLAGS, this generates the
2743 correct value for m_dflag (-1 or 1), and clears the D bit
2744 in EFLAGS. */
2745
2746 /* We're updating the whole flag state, so the old state
2747 doesn't matter; make sure that the new simulated state
2748 will be fetched when needed. */
2749 eflags_state = UPD_Simd;
2750
2751 /* store EFLAGS (with D) */
2752 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
2753
2754 /* u->val1 &= EFlagD */
2755 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2756
2757 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
2758 synth_unaryop_reg(False, NEG, u->size, u->val1);
2759 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
2760 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
2761
2762 /* save D */
2763 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
2764
2765 /* EFLAGS &= ~EFlagD */
2766 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2767 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00002768 break;
2769 }
2770
2771 case MOV: {
2772 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2773 vg_assert(u->tag2 == RealReg);
2774 switch (u->tag1) {
2775 case RealReg: vg_assert(u->size == 4);
2776 if (u->val1 != u->val2)
2777 synth_movl_reg_reg ( u->val1, u->val2 );
2778 break;
2779 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2780 break;
njne427a662002-10-02 11:08:25 +00002781 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002782 }
2783 break;
2784 }
2785
sewardje1042472002-09-30 12:33:11 +00002786 case USESEG: {
2787 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2788 ones. */
sewardjd077f532002-09-30 21:52:50 +00002789 UInt argv[] = { u->val1, u->val2 };
2790 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002791 UInt ret_reg = u->val2;
2792
2793 vg_assert(u->tag1 == RealReg);
2794 vg_assert(u->tag2 == RealReg);
2795 vg_assert(u->size == 0);
2796
sewardjb5ff83e2002-12-01 19:40:49 +00002797 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002798 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002799 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002800 }
2801
sewardje1042472002-09-30 12:33:11 +00002802 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2803 2, /* args */
2804 0, /* regparms_n */
2805 argv, tagv,
2806 ret_reg, regs_live_before, u->regs_live_after );
2807 break;
2808 }
2809
sewardj478335c2002-10-05 02:44:47 +00002810 case SBB:
2811 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002812 case XOR:
2813 case OR:
2814 case AND:
2815 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002816 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002817 vg_assert(u->tag2 == RealReg);
2818 switch (u->tag1) {
2819 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002820 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002821 u->opcode, u->size, u->lit32, u->val2 );
2822 break;
2823 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002824 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002825 u->opcode, u->size, u->val1, u->val2 );
2826 break;
2827 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002828 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002829 u->opcode, u->size,
2830 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2831 R_EBP,
2832 u->val2 );
2833 break;
njne427a662002-10-02 11:08:25 +00002834 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002835 }
2836 break;
2837 }
2838
sewardj478335c2002-10-05 02:44:47 +00002839 case RCR:
2840 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002841 case ROR:
2842 case ROL:
2843 case SAR:
2844 case SHR:
2845 case SHL: {
2846 vg_assert(u->tag2 == RealReg);
2847 switch (u->tag1) {
2848 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002849 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002850 u->opcode, u->size, u->lit32, u->val2 );
2851 break;
2852 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002853 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002854 u->opcode, u->size, u->val1, u->val2 );
2855 break;
njne427a662002-10-02 11:08:25 +00002856 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002857 }
2858 break;
2859 }
2860
2861 case INC:
2862 case DEC:
2863 case NEG:
2864 case NOT:
2865 vg_assert(u->tag1 == RealReg);
2866 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002867 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002868 break;
2869
2870 case BSWAP:
2871 vg_assert(u->tag1 == RealReg);
2872 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002873 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002874 emit_bswapl_reg ( u->val1 );
2875 break;
2876
2877 case CMOV:
2878 vg_assert(u->tag1 == RealReg);
2879 vg_assert(u->tag2 == RealReg);
2880 vg_assert(u->cond != CondAlways);
2881 vg_assert(u->size == 4);
2882 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2883 break;
2884
2885 case JMP: {
2886 vg_assert(u->tag2 == NoValue);
2887 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00002888 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002889 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002890 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002891 }
sewardjde4a1d02002-03-22 01:27:54 +00002892 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002893 switch (u->tag1) {
2894 case RealReg:
2895 synth_jmp_reg ( u->val1, u->jmpkind );
2896 break;
2897 case Literal:
2898 synth_jmp_lit ( u->lit32, u->jmpkind );
2899 break;
2900 default:
njne427a662002-10-02 11:08:25 +00002901 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002902 break;
sewardjde4a1d02002-03-22 01:27:54 +00002903 }
2904 } else {
sewardj2e93c502002-04-12 11:12:52 +00002905 switch (u->tag1) {
2906 case RealReg:
njne427a662002-10-02 11:08:25 +00002907 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002908 break;
2909 case Literal:
2910 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00002911 /* %eax had better not be live since synth_jcond_lit
2912 trashes it in some circumstances. If that turns
2913 out to be a problem we can get synth_jcond_lit to
2914 push/pop it when it is live. */
2915 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
2916 u->regs_live_after));
2917 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00002918 break;
2919 default:
njne427a662002-10-02 11:08:25 +00002920 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002921 break;
sewardjde4a1d02002-03-22 01:27:54 +00002922 }
2923 }
2924 break;
2925 }
2926
2927 case JIFZ:
2928 vg_assert(u->tag1 == RealReg);
2929 vg_assert(u->tag2 == Literal);
2930 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00002931 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002932 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002933 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002934 }
sewardjde4a1d02002-03-22 01:27:54 +00002935 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2936 break;
2937
sewardjde4a1d02002-03-22 01:27:54 +00002938 case PUSH:
2939 vg_assert(u->tag1 == RealReg);
2940 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002941 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002942 break;
2943
2944 case POP:
2945 vg_assert(u->tag1 == RealReg);
2946 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002947 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002948 break;
2949
2950 case CALLM:
2951 vg_assert(u->tag1 == Lit16);
2952 vg_assert(u->tag2 == NoValue);
2953 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00002954 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002955 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002956 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002957 }
sewardjfa492d42002-12-08 18:20:01 +00002958 /* Call to a helper which is pretending to be a real CPU
2959 instruction (and therefore operates on Real flags and
2960 registers) */
2961 VG_(synth_call) ( False, u->val1,
2962 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00002963 break;
2964
njn25e49d8e72002-09-23 09:36:25 +00002965 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002966 /* If you change this, remember to change USESEG above, since
2967 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002968 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2969 ones. */
2970 UInt argv[] = { u->val1, u->val2, u->val3 };
2971 UInt tagv[] = { RealReg, RealReg, RealReg };
2972 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2973
2974 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2975 else vg_assert(u->tag1 == NoValue);
2976 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2977 else vg_assert(u->tag2 == NoValue);
2978 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2979 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002980 vg_assert(u->size == 0);
2981
sewardjb5ff83e2002-12-01 19:40:49 +00002982 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002983 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002984 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002985 }
njn25e49d8e72002-09-23 09:36:25 +00002986 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2987 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002988 break;
njn25e49d8e72002-09-23 09:36:25 +00002989 }
sewardje1042472002-09-30 12:33:11 +00002990
sewardjde4a1d02002-03-22 01:27:54 +00002991 case CLEAR:
2992 vg_assert(u->tag1 == Lit16);
2993 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002994 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002995 break;
2996
2997 case CC2VAL:
2998 vg_assert(u->tag1 == RealReg);
2999 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003000 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003001 synth_setb_reg ( u->val1, u->cond );
3002 break;
3003
sewardjde4a1d02002-03-22 01:27:54 +00003004 case FPU_R:
3005 case FPU_W:
3006 vg_assert(u->tag1 == Lit16);
3007 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003008 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003009 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003010 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003011 }
sewardjfa492d42002-12-08 18:20:01 +00003012 synth_fpu_regmem ( u->flags_r, u->flags_w,
3013 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003014 u->val1 & 0xFF,
3015 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003016 break;
3017
3018 case FPU:
3019 vg_assert(u->tag1 == Lit16);
3020 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00003021 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00003022 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00003023 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003024 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003025 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003026 }
sewardjfa492d42002-12-08 18:20:01 +00003027 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3028 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003029 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003030 break;
3031
3032 default:
sewardj1b7d8022002-11-30 12:35:42 +00003033 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003034 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003035 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003036 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003037 }
njn4ba5a792002-09-30 10:23:54 +00003038 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003039 } else {
njn25e49d8e72002-09-23 09:36:25 +00003040 VG_(printf)("\nError:\n"
3041 " unhandled opcode: %u. Perhaps "
3042 " VG_(needs).extended_UCode should be set?\n",
3043 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003044 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003045 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003046 }
sewardjde4a1d02002-03-22 01:27:54 +00003047 }
3048
sewardjb5ff83e2002-12-01 19:40:49 +00003049 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003050 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003051 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003052 }
3053
njn25e49d8e72002-09-23 09:36:25 +00003054 /* Update UInstr histogram */
3055 vg_assert(u->opcode < 100);
3056 histogram[u->opcode].counts++;
3057 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003058}
3059
3060
3061/* Emit x86 for the ucode in cb, returning the address of the
3062 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003063UChar* VG_(emit_code) ( UCodeBlock* cb,
3064 Int* nbytes,
3065 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003066{
3067 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003068 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003069 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003070 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003071 Int tgt;
3072
sewardjfa492d42002-12-08 18:20:01 +00003073 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003074
njn25e49d8e72002-09-23 09:36:25 +00003075 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003076
sewardj22854b92002-11-30 14:00:47 +00003077 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3078 zero. We have to do this regardless of whether we're t-chaining
3079 or not. */
sewardja2113f92002-12-12 23:42:48 +00003080 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003081 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003082 VG_(emitB) (0xFF); /* decl */
3083 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3084 if (dis)
3085 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003086 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003087 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3088 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003089 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003090
sewardjb5ff83e2002-12-01 19:40:49 +00003091 /* Set up running state. */
3092 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003093 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003094 curr_eip = cb->orig_eip;
3095 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3096 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003097 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003098 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003099 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003100 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003101
sewardjde4a1d02002-03-22 01:27:54 +00003102 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003103 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003104 if (!sane) {
3105 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003106 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003107 }
3108 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003109 emitUInstr( cb, i, regs_live_before,
3110 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003111 }
njn25e49d8e72002-09-23 09:36:25 +00003112 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003113 }
njn25e49d8e72002-09-23 09:36:25 +00003114 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003115 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3116 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003117
sewardj22854b92002-11-30 14:00:47 +00003118 if (j != NULL) {
3119 vg_assert(jumpidx <= VG_MAX_JUMPS);
3120 for(i = 0; i < jumpidx; i++)
3121 j[i] = jumps[i];
3122 }
3123
sewardjde4a1d02002-03-22 01:27:54 +00003124 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003125 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003126 *nbytes = emitted_code_used;
3127 return emitted_code;
3128}
3129
njn25e49d8e72002-09-23 09:36:25 +00003130#undef dis
3131
sewardjde4a1d02002-03-22 01:27:54 +00003132/*--------------------------------------------------------------------*/
3133/*--- end vg_from_ucode.c ---*/
3134/*--------------------------------------------------------------------*/