blob: d7262d2385dedd45e099f3970575bec330b6333d [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);
1298 vg_assert(tgt_addr(*tgt) < emitted_code_size);
1299 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;
sewardja2113f92002-12-12 23:42:48 +00001890 Int tgt;
sewardj2370f3b2002-11-30 15:01:01 +00001891
sewardja2113f92002-12-12 23:42:48 +00001892 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00001893
sewardjfa492d42002-12-08 18:20:01 +00001894 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
1895 if need be */
1896 maybe_emit_put_eflags();
1897 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
1898
1899 if (eflags_state == UPD_Both) {
1900 /* The flags are already set up, so we just use them as is. */
1901 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00001902 cond = invertCondition(cond);
1903 } else {
sewardj75f04932002-12-12 23:13:21 +00001904 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00001905
1906 /* The simd state contains the most recent version, so we emit a
1907 sequence to calculate the relevant condition directly out of
1908 the simd flags. This is much cheaper (on P3/P4/Athlon) than
1909 copying them back to the real flags via popf. Notice that
1910 some of these sequences trash %eax, but that should be free
1911 now since this is the end of a bb and therefore all regs are
1912 dead. */
1913 simd = False;
1914
1915 switch (cond) {
1916
1917 case CondLE:
1918 case CondNLE:
1919 vg_assert(eax_trashable);
1920
1921 VG_(emit_movv_offregmem_reg)
1922 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1923 /* eax == %EFLAGS */
1924
1925 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 11-7, R_EAX );
1926 /* eax has OF in SF's place */
1927
1928 emit_nonshiftopv_offregmem_reg
1929 ( False, 4, XOR, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1930 /* eax has (OF xor SF) in SF's place */
1931
1932 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7-6, R_EAX );
1933 /* eax has (OF xor SF) in ZF's place */
1934
1935 emit_nonshiftopv_offregmem_reg
1936 ( False, 4, OR, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1937 /* eax has ((OF xor SF) or ZF) in SF's place */
1938
1939 VG_(emit_nonshiftopv_lit_reg)( False, 4, AND, 1 << 6, R_EAX );
1940 /* Z is now set iff ((OF xor SF) or ZF) == 1 */
1941
1942 if (cond == CondLE) cond = CondZ; else cond = CondNZ;
sewardj2370f3b2002-11-30 15:01:01 +00001943 break;
1944
sewardjfa492d42002-12-08 18:20:01 +00001945 case CondL:
1946 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00001947 vg_assert(eax_trashable);
1948
1949 VG_(emit_movv_offregmem_reg)
1950 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1951 /* eax == %EFLAGS */
1952
sewardj75f04932002-12-12 23:13:21 +00001953 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
1954 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00001955
sewardj75f04932002-12-12 23:13:21 +00001956 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
1957 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00001958
sewardj75f04932002-12-12 23:13:21 +00001959 if (cond == CondL) cond = CondP; else cond = CondNP;
1960 break;
sewardjfa492d42002-12-08 18:20:01 +00001961
1962 case CondB:
1963 case CondNB:
1964 mask = EFlagC; goto simple; /* C=1 */
1965
1966 case CondZ:
1967 case CondNZ:
1968 mask = EFlagZ; goto simple; /* Z=1 */
1969
1970 case CondBE:
1971 case CondNBE:
1972 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
1973
1974 case CondS:
1975 case CondNS:
1976 mask = EFlagS; goto simple; /* S=1 */
1977
1978 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00001979 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00001980 mask = EFlagP; goto simple; /* P=1 */
1981
sewardj39542072002-12-09 22:44:00 +00001982 case CondO:
1983 case CondNO:
1984 mask = EFlagO; goto simple; /* O=1 */
1985
sewardjfa492d42002-12-08 18:20:01 +00001986 default:
1987 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
1988 (Int)cond, VG_(nameCondcode)(cond) );
1989 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
1990
1991 simple:
1992 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00001993 if ((mask & 0xff) == mask) {
1994 VG_(emitB) ( 0xF6 ); /* Grp3 */
1995 VG_(emit_amode_offregmem_reg)(
1996 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1997 VG_(emitB) (mask);
1998 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001999 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002000 mask, VGOFF_(m_eflags) * 4);
2001 } else {
sewardjfa492d42002-12-08 18:20:01 +00002002 /* all cond codes are in lower 16 bits */
2003 vg_assert((mask & 0xffff) == mask);
2004
2005 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002006 VG_(emitB) ( 0xF7 );
2007 VG_(emit_amode_offregmem_reg)(
2008 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002009 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002010 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002011 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002012 mask, VGOFF_(m_eflags) * 4);
2013 }
2014
sewardj75f04932002-12-12 23:13:21 +00002015 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002016 break;
2017 }
2018 }
2019
sewardja2113f92002-12-12 23:42:48 +00002020 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002021 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002022
2023 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002024}
2025
2026
sewardj2370f3b2002-11-30 15:01:01 +00002027
sewardjde4a1d02002-03-22 01:27:54 +00002028static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2029{
sewardja2113f92002-12-12 23:42:48 +00002030 Int tgt;
2031
2032 VG_(init_target)(&tgt);
2033
sewardjfa492d42002-12-08 18:20:01 +00002034 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002035
2036 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002037 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002038
2039 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002040}
2041
2042
2043static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2044{
2045 /* Load the zero-extended literal into reg, at size l,
2046 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002047 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002048}
2049
2050
2051static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2052{
2053 switch (size) {
2054 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2055 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2056 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002057 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002058 }
2059}
2060
2061
2062static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2063{
2064 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002065 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2066 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2067 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002068 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002069 }
2070}
2071
2072
2073static void synth_mov_reg_offregmem ( Int size, Int reg,
2074 Int off, Int areg )
2075{
2076 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002077 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2078 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002079 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002080 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002081 }
2082 else {
njn25e49d8e72002-09-23 09:36:25 +00002083 VG_(emit_swapl_reg_EAX) ( reg );
2084 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2085 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002086 }
2087 break;
njne427a662002-10-02 11:08:25 +00002088 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002089 }
2090}
2091
2092
2093static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2094{
2095 Int s1;
2096 switch (size) {
2097 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2098 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2099 case 1: if (reg1 < 4) {
2100 emit_movb_reg_regmem ( reg1, reg2 );
2101 }
2102 else {
2103 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2104 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2105 emit_swapl_reg_reg ( s1, reg1 );
2106 emit_movb_reg_regmem ( s1, reg2 );
2107 emit_swapl_reg_reg ( s1, reg1 );
2108 }
2109 break;
njne427a662002-10-02 11:08:25 +00002110 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002111 }
2112}
2113
2114
sewardj478335c2002-10-05 02:44:47 +00002115static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002116 Opcode opcode, Int size,
2117 Int reg )
2118{
2119 /* NB! opcode is a uinstr opcode, not an x86 one! */
2120 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002121 case 4: VG_(emit_unaryopv_reg) ( upd_cc, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002122 break;
sewardjfa492d42002-12-08 18:20:01 +00002123 case 2: VG_(emit_unaryopv_reg) ( upd_cc, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002124 break;
2125 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002126 VG_(emit_unaryopb_reg) ( upd_cc, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002127 } else {
njn25e49d8e72002-09-23 09:36:25 +00002128 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002129 VG_(emit_unaryopb_reg) ( upd_cc, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002130 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002131 }
2132 break;
njne427a662002-10-02 11:08:25 +00002133 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002134 }
2135}
2136
2137
2138
sewardj478335c2002-10-05 02:44:47 +00002139static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002140 Opcode opcode, Int size,
2141 Int reg1, Int reg2 )
2142{
2143 /* NB! opcode is a uinstr opcode, not an x86 one! */
2144 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002145 case 4: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002146 break;
sewardjfa492d42002-12-08 18:20:01 +00002147 case 2: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002148 break;
2149 case 1: { /* Horrible ... */
2150 Int s1, s2;
2151 /* Choose s1 and s2 to be x86 regs which we can talk about the
2152 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2153 sure s1 != s2 and that neither of them equal either reg1 or
2154 reg2. Then use them as temporaries to make things work. */
2155 if (reg1 < 4 && reg2 < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002156 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002157 break;
2158 }
2159 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2160 if (reg1 >= 4 && reg2 < 4) {
2161 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002162 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002163 emit_swapl_reg_reg ( reg1, s1 );
2164 break;
2165 }
2166 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2167 if (reg1 < 4 && reg2 >= 4) {
2168 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002169 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002170 emit_swapl_reg_reg ( reg2, s2 );
2171 break;
2172 }
2173 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2174 emit_swapl_reg_reg ( reg1, s1 );
2175 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002176 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002177 emit_swapl_reg_reg ( reg1, s1 );
2178 emit_swapl_reg_reg ( reg2, s2 );
2179 break;
2180 }
2181 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2182 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002183 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002184 emit_swapl_reg_reg ( reg1, s1 );
2185 break;
2186 }
njne427a662002-10-02 11:08:25 +00002187 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002188 }
njne427a662002-10-02 11:08:25 +00002189 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002190 }
2191}
2192
2193
sewardjfa492d42002-12-08 18:20:01 +00002194static void synth_nonshiftop_reg_offregmem (
2195 Bool upd_cc,
2196 Opcode opcode, Int size,
2197 Int off, Int areg, Int reg )
2198{
2199 switch (size) {
2200 case 4:
2201 emit_nonshiftopv_reg_offregmem ( upd_cc, 4, opcode, off, areg, reg );
2202 break;
2203 case 2:
2204 emit_nonshiftopv_reg_offregmem ( upd_cc, 2, opcode, off, areg, reg );
2205 break;
2206 case 1:
2207 if (reg < 4) {
2208 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, reg );
2209 } else {
2210 VG_(emit_swapl_reg_EAX) ( reg );
2211 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, R_AL );
2212 VG_(emit_swapl_reg_EAX) ( reg );
2213 }
2214 break;
2215 default:
2216 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2217 }
2218}
2219
sewardjde4a1d02002-03-22 01:27:54 +00002220static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002221 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002222 Opcode opcode, Int size,
2223 Int off, Int areg, Int reg )
2224{
2225 switch (size) {
2226 case 4:
sewardjfa492d42002-12-08 18:20:01 +00002227 emit_nonshiftopv_offregmem_reg ( upd_cc, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002228 break;
2229 case 2:
sewardjfa492d42002-12-08 18:20:01 +00002230 emit_nonshiftopv_offregmem_reg ( upd_cc, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002231 break;
2232 case 1:
2233 if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002234 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002235 } else {
njn25e49d8e72002-09-23 09:36:25 +00002236 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002237 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002238 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002239 }
2240 break;
2241 default:
njne427a662002-10-02 11:08:25 +00002242 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002243 }
2244}
2245
2246
sewardj478335c2002-10-05 02:44:47 +00002247static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002248 Opcode opcode, Int size,
2249 UInt lit, Int reg )
2250{
2251 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002252 case 4: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002253 break;
sewardjfa492d42002-12-08 18:20:01 +00002254 case 2: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002255 break;
2256 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002257 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002258 } else {
njn25e49d8e72002-09-23 09:36:25 +00002259 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002260 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002261 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002262 }
2263 break;
njne427a662002-10-02 11:08:25 +00002264 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002265 }
2266}
2267
sewardjfa492d42002-12-08 18:20:01 +00002268static void synth_nonshiftop_lit_offregmem ( Bool upd_cc,
2269 Opcode opcode, Int size,
2270 UInt lit, Int off, Int regmem )
2271{
2272 switch (size) {
2273 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 4, opcode, lit, off, regmem );
2274 break;
2275 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 2, opcode, lit, off, regmem );
2276 break;
2277 case 1: emit_nonshiftopb_lit_offregmem ( upd_cc, opcode, lit, off, regmem );
2278 break;
2279 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2280 }
2281}
2282
sewardjde4a1d02002-03-22 01:27:54 +00002283
2284static void synth_push_reg ( Int size, Int reg )
2285{
2286 switch (size) {
2287 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002288 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002289 break;
2290 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002291 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002292 break;
2293 /* Pray that we don't have to generate this really cruddy bit of
2294 code very often. Could do better, but can I be bothered? */
2295 case 1:
2296 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002297 VG_(emit_add_lit_to_esp)(-1);
2298 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002299 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002300 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002301 break;
2302 default:
njne427a662002-10-02 11:08:25 +00002303 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002304 }
2305}
2306
2307
2308static void synth_pop_reg ( Int size, Int reg )
2309{
2310 switch (size) {
2311 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002312 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002313 break;
2314 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002315 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002316 break;
2317 case 1:
2318 /* Same comment as above applies. */
2319 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002320 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002321 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002322 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2323 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002324 break;
njne427a662002-10-02 11:08:25 +00002325 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002326 }
2327}
2328
2329
sewardj478335c2002-10-05 02:44:47 +00002330static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002331 Opcode opcode, Int size,
2332 Int regs, Int regd )
2333{
2334 synth_push_reg ( size, regd );
2335 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002336 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002337 case 4: emit_shiftopv_cl_stack0 ( upd_cc, 4, opcode ); break;
2338 case 2: emit_shiftopv_cl_stack0 ( upd_cc, 2, opcode ); break;
2339 case 1: emit_shiftopb_cl_stack0 ( upd_cc, opcode ); break;
njne427a662002-10-02 11:08:25 +00002340 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002341 }
sewardjde4a1d02002-03-22 01:27:54 +00002342 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2343 synth_pop_reg ( size, regd );
2344}
2345
2346
sewardj478335c2002-10-05 02:44:47 +00002347static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002348 Opcode opcode, Int size,
2349 UInt lit, Int reg )
2350{
2351 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002352 case 4: VG_(emit_shiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002353 break;
sewardjfa492d42002-12-08 18:20:01 +00002354 case 2: VG_(emit_shiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002355 break;
2356 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002357 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002358 } else {
njn25e49d8e72002-09-23 09:36:25 +00002359 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002360 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002361 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002362 }
2363 break;
njne427a662002-10-02 11:08:25 +00002364 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002365 }
2366}
2367
2368
2369static void synth_setb_reg ( Int reg, Condcode cond )
2370{
sewardjde4a1d02002-03-22 01:27:54 +00002371 if (reg < 4) {
2372 emit_setb_reg ( reg, cond );
2373 } else {
njn25e49d8e72002-09-23 09:36:25 +00002374 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002375 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002376 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002377 }
2378}
2379
2380
sewardjfa492d42002-12-08 18:20:01 +00002381static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2382 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002383 UChar second_byte_masked,
2384 Int reg )
2385{
sewardjfa492d42002-12-08 18:20:01 +00002386 emit_fpu_regmem ( uses_flags, sets_flags, first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002387}
2388
2389
sewardjfa492d42002-12-08 18:20:01 +00002390static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2391 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002392 UChar second_byte )
2393{
sewardjfa492d42002-12-08 18:20:01 +00002394 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002395}
2396
2397
2398static void synth_movl_reg_reg ( Int src, Int dst )
2399{
2400 emit_movl_reg_reg ( src, dst );
2401}
2402
2403static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2404{
sewardja2113f92002-12-12 23:42:48 +00002405 Int tgt;
2406
2407 VG_(init_target)(&tgt);
2408
2409 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002410 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002411
2412 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002413}
2414
2415
sewardjde4a1d02002-03-22 01:27:54 +00002416/*----------------------------------------------------*/
2417/*--- Top level of the uinstr -> x86 translation. ---*/
2418/*----------------------------------------------------*/
2419
2420/* Return the byte offset from %ebp (ie, into baseBlock)
2421 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002422static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2423{
2424 if (tag == SpillNo) {
2425 vg_assert(size == 4);
2426 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2427 return 4 * (value + VGOFF_(spillslots));
2428 }
2429 if (tag == ArchReg) {
2430 switch (value) {
2431 case R_EAX: return 4 * VGOFF_(m_eax);
2432 case R_ECX: return 4 * VGOFF_(m_ecx);
2433 case R_EDX: return 4 * VGOFF_(m_edx);
2434 case R_EBX: return 4 * VGOFF_(m_ebx);
2435 case R_ESP:
2436 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2437 else return 4 * VGOFF_(m_esp);
2438 case R_EBP:
2439 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2440 else return 4 * VGOFF_(m_ebp);
2441 case R_ESI:
2442 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2443 else return 4 * VGOFF_(m_esi);
2444 case R_EDI:
2445 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2446 else return 4 * VGOFF_(m_edi);
2447 }
2448 }
njne427a662002-10-02 11:08:25 +00002449 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002450}
2451
sewardjde4a1d02002-03-22 01:27:54 +00002452static Int eflagsOffset ( void )
2453{
2454 return 4 * VGOFF_(m_eflags);
2455}
2456
sewardje1042472002-09-30 12:33:11 +00002457static Int segRegOffset ( UInt archregs )
2458{
2459 switch (archregs) {
2460 case R_CS: return 4 * VGOFF_(m_cs);
2461 case R_SS: return 4 * VGOFF_(m_ss);
2462 case R_DS: return 4 * VGOFF_(m_ds);
2463 case R_ES: return 4 * VGOFF_(m_es);
2464 case R_FS: return 4 * VGOFF_(m_fs);
2465 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002466 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002467 }
2468}
2469
sewardjde4a1d02002-03-22 01:27:54 +00002470
njn25e49d8e72002-09-23 09:36:25 +00002471/* Return the byte offset from %ebp (ie, into baseBlock)
2472 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002473Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002474{
2475 switch (arch) {
2476 case R_EAX: return 4 * VGOFF_(sh_eax);
2477 case R_ECX: return 4 * VGOFF_(sh_ecx);
2478 case R_EDX: return 4 * VGOFF_(sh_edx);
2479 case R_EBX: return 4 * VGOFF_(sh_ebx);
2480 case R_ESP: return 4 * VGOFF_(sh_esp);
2481 case R_EBP: return 4 * VGOFF_(sh_ebp);
2482 case R_ESI: return 4 * VGOFF_(sh_esi);
2483 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002484 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002485 }
2486}
2487
njn4ba5a792002-09-30 10:23:54 +00002488Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002489{
2490 return 4 * VGOFF_(sh_eflags);
2491}
2492
2493
sewardjde4a1d02002-03-22 01:27:54 +00002494
2495static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2496{
2497 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002498 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2499 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002500 }
2501 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002502 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2503 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002504 }
2505 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002506 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2507 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002508 }
2509 else
njne427a662002-10-02 11:08:25 +00002510 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002511}
2512
2513
njn25e49d8e72002-09-23 09:36:25 +00002514static void synth_handle_esp_assignment ( Int i, Int reg,
2515 RRegSet regs_live_before,
2516 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002517{
njn25e49d8e72002-09-23 09:36:25 +00002518 UInt argv[] = { reg };
2519 Tag tagv[] = { RealReg };
2520
2521 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2522 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002523}
2524
2525
sewardjde4a1d02002-03-22 01:27:54 +00002526/*----------------------------------------------------*/
2527/*--- Generate code for a single UInstr. ---*/
2528/*----------------------------------------------------*/
2529
sewardj478335c2002-10-05 02:44:47 +00002530static __inline__
2531Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002532{
2533 return (u->flags_w != FlagsEmpty);
2534}
2535
sewardjfa492d42002-12-08 18:20:01 +00002536static __inline__
2537Bool readFlagUse ( UInstr* u )
2538{
2539 /* If the UInstr writes some flags but not all, then we still need
2540 to consider it as reading flags so that the unchanged values are
2541 passed through properly. (D is special) */
2542 return
2543 (u->flags_r != FlagsEmpty) ||
2544 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2545}
2546
sewardj478335c2002-10-05 02:44:47 +00002547static __inline__
2548Bool anyFlagUse ( UInstr* u )
2549{
sewardjfa492d42002-12-08 18:20:01 +00002550 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002551}
2552
2553
sewardjb5ff83e2002-12-01 19:40:49 +00002554/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002555 the real FPU. If so we need to be very careful not to trash it.
2556 If FPU state is live and we deem it necessary to copy it back to
2557 the simulated machine's FPU state, we do so. The final state of
2558 fpliveness is returned. In short we _must_ do put_fpu_state if
2559 there is any chance at all that the code generated for a UInstr
2560 will change the real FPU state.
2561*/
sewardjb5ff83e2002-12-01 19:40:49 +00002562static void emitUInstr ( UCodeBlock* cb, Int i,
2563 RRegSet regs_live_before,
2564 /* Running state, which we update. */
2565 Bool* fplive, /* True<==>FPU state in real FPU */
2566 Addr* orig_eip, /* previous curr_eip, or zero */
2567 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002568{
njn25e49d8e72002-09-23 09:36:25 +00002569 Int old_emitted_code_used;
2570 UInstr* u = &cb->instrs[i];
2571
sewardjde4a1d02002-03-22 01:27:54 +00002572 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002573 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002574
njn25e49d8e72002-09-23 09:36:25 +00002575 old_emitted_code_used = emitted_code_used;
2576
sewardjde4a1d02002-03-22 01:27:54 +00002577 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002578 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002579
sewardjb5ff83e2002-12-01 19:40:49 +00002580 case INCEIP:
2581 /* Advance %EIP some small amount. */
2582 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002583
sewardjb5ff83e2002-12-01 19:40:49 +00002584 if (*orig_eip == 0 /* we don't know what the old value was */
2585 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2586 /* We have to update all 32 bits of the value. */
2587 VG_(emit_movv_lit_offregmem)(
2588 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2589 } else {
2590 /* Cool! we only need to update lowest 8 bits */
2591 VG_(emit_movb_lit_offregmem)(
2592 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002593 }
njn25e49d8e72002-09-23 09:36:25 +00002594
sewardjb5ff83e2002-12-01 19:40:49 +00002595 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002596 break;
sewardjde4a1d02002-03-22 01:27:54 +00002597
2598 case LEA1: {
2599 vg_assert(u->tag1 == RealReg);
2600 vg_assert(u->tag2 == RealReg);
2601 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2602 break;
2603 }
2604
2605 case LEA2: {
2606 vg_assert(u->tag1 == RealReg);
2607 vg_assert(u->tag2 == RealReg);
2608 vg_assert(u->tag3 == RealReg);
2609 emit_lea_sib_reg ( u->lit32, u->extra4b,
2610 u->val1, u->val2, u->val3 );
2611 break;
2612 }
2613
2614 case WIDEN: {
2615 vg_assert(u->tag1 == RealReg);
2616 if (u->signed_widen) {
2617 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2618 } else {
2619 /* no need to generate any code. */
2620 }
2621 break;
2622 }
2623
sewardjde4a1d02002-03-22 01:27:54 +00002624 case STORE: {
2625 vg_assert(u->tag1 == RealReg);
2626 vg_assert(u->tag2 == RealReg);
2627 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002628 break;
2629 }
2630
2631 case LOAD: {
2632 vg_assert(u->tag1 == RealReg);
2633 vg_assert(u->tag2 == RealReg);
2634 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2635 break;
2636 }
2637
sewardjde4a1d02002-03-22 01:27:54 +00002638 case GET: {
2639 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2640 vg_assert(u->tag2 == RealReg);
2641 synth_mov_offregmem_reg (
2642 u->size,
2643 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2644 R_EBP,
2645 u->val2
2646 );
2647 break;
2648 }
2649
2650 case PUT: {
2651 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2652 vg_assert(u->tag1 == RealReg);
2653 if (u->tag2 == ArchReg
2654 && u->val2 == R_ESP
2655 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002656 && (VG_(track_events).new_mem_stack ||
2657 VG_(track_events).new_mem_stack_aligned ||
2658 VG_(track_events).die_mem_stack ||
2659 VG_(track_events).die_mem_stack_aligned ||
2660 VG_(track_events).post_mem_write))
2661 {
2662 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2663 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002664 }
njn25e49d8e72002-09-23 09:36:25 +00002665 else {
2666 synth_mov_reg_offregmem (
2667 u->size,
2668 u->val1,
2669 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2670 R_EBP
2671 );
2672 }
sewardjde4a1d02002-03-22 01:27:54 +00002673 break;
2674 }
2675
sewardje1042472002-09-30 12:33:11 +00002676 case GETSEG: {
2677 vg_assert(u->tag1 == ArchRegS);
2678 vg_assert(u->tag2 == RealReg);
2679 vg_assert(u->size == 2);
2680 synth_mov_offregmem_reg (
2681 4,
2682 segRegOffset( u->val1 ),
2683 R_EBP,
2684 u->val2
2685 );
2686 break;
2687 }
2688
2689 case PUTSEG: {
2690 vg_assert(u->tag1 == RealReg);
2691 vg_assert(u->tag2 == ArchRegS);
2692 vg_assert(u->size == 2);
2693 synth_mov_reg_offregmem (
2694 4,
2695 u->val1,
2696 segRegOffset( u->val2 ),
2697 R_EBP
2698 );
2699 break;
2700 }
2701
sewardjde4a1d02002-03-22 01:27:54 +00002702 case GETF: {
2703 vg_assert(u->size == 2 || u->size == 4);
2704 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002705
2706 /* This complexity is because the D(irection) flag is stored
2707 separately from the rest of EFLAGS. */
2708
2709 /* We're only fetching from the Simd state, so make sure it's
2710 up to date. */
2711 maybe_emit_put_eflags();
2712
2713 /* get D in u->val1 (== 1 or -1) */
2714 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
2715
2716 /* u->val1 &= EFlagD (== 0 or EFlagD) */
2717 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2718
2719 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2720 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2721 eflagsOffset(), R_EBP);
2722
2723 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2724 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2725 eflagsOffset(), R_EBP);
2726
2727 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
2728 synth_nonshiftop_offregmem_reg(False, OR, u->size,
2729 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00002730 break;
2731 }
2732
2733 case PUTF: {
2734 vg_assert(u->size == 2 || u->size == 4);
2735 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002736
2737 /* When putting a value into EFLAGS, this generates the
2738 correct value for m_dflag (-1 or 1), and clears the D bit
2739 in EFLAGS. */
2740
2741 /* We're updating the whole flag state, so the old state
2742 doesn't matter; make sure that the new simulated state
2743 will be fetched when needed. */
2744 eflags_state = UPD_Simd;
2745
2746 /* store EFLAGS (with D) */
2747 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
2748
2749 /* u->val1 &= EFlagD */
2750 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2751
2752 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
2753 synth_unaryop_reg(False, NEG, u->size, u->val1);
2754 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
2755 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
2756
2757 /* save D */
2758 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
2759
2760 /* EFLAGS &= ~EFlagD */
2761 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2762 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00002763 break;
2764 }
2765
2766 case MOV: {
2767 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2768 vg_assert(u->tag2 == RealReg);
2769 switch (u->tag1) {
2770 case RealReg: vg_assert(u->size == 4);
2771 if (u->val1 != u->val2)
2772 synth_movl_reg_reg ( u->val1, u->val2 );
2773 break;
2774 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2775 break;
njne427a662002-10-02 11:08:25 +00002776 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002777 }
2778 break;
2779 }
2780
sewardje1042472002-09-30 12:33:11 +00002781 case USESEG: {
2782 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2783 ones. */
sewardjd077f532002-09-30 21:52:50 +00002784 UInt argv[] = { u->val1, u->val2 };
2785 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002786 UInt ret_reg = u->val2;
2787
2788 vg_assert(u->tag1 == RealReg);
2789 vg_assert(u->tag2 == RealReg);
2790 vg_assert(u->size == 0);
2791
sewardjb5ff83e2002-12-01 19:40:49 +00002792 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002793 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002794 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002795 }
2796
sewardje1042472002-09-30 12:33:11 +00002797 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2798 2, /* args */
2799 0, /* regparms_n */
2800 argv, tagv,
2801 ret_reg, regs_live_before, u->regs_live_after );
2802 break;
2803 }
2804
sewardj478335c2002-10-05 02:44:47 +00002805 case SBB:
2806 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002807 case XOR:
2808 case OR:
2809 case AND:
2810 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002811 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002812 vg_assert(u->tag2 == RealReg);
2813 switch (u->tag1) {
2814 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002815 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002816 u->opcode, u->size, u->lit32, u->val2 );
2817 break;
2818 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002819 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002820 u->opcode, u->size, u->val1, u->val2 );
2821 break;
2822 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002823 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002824 u->opcode, u->size,
2825 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2826 R_EBP,
2827 u->val2 );
2828 break;
njne427a662002-10-02 11:08:25 +00002829 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002830 }
2831 break;
2832 }
2833
sewardj478335c2002-10-05 02:44:47 +00002834 case RCR:
2835 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002836 case ROR:
2837 case ROL:
2838 case SAR:
2839 case SHR:
2840 case SHL: {
2841 vg_assert(u->tag2 == RealReg);
2842 switch (u->tag1) {
2843 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002844 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002845 u->opcode, u->size, u->lit32, u->val2 );
2846 break;
2847 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002848 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002849 u->opcode, u->size, u->val1, u->val2 );
2850 break;
njne427a662002-10-02 11:08:25 +00002851 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002852 }
2853 break;
2854 }
2855
2856 case INC:
2857 case DEC:
2858 case NEG:
2859 case NOT:
2860 vg_assert(u->tag1 == RealReg);
2861 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002862 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002863 break;
2864
2865 case BSWAP:
2866 vg_assert(u->tag1 == RealReg);
2867 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002868 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002869 emit_bswapl_reg ( u->val1 );
2870 break;
2871
2872 case CMOV:
2873 vg_assert(u->tag1 == RealReg);
2874 vg_assert(u->tag2 == RealReg);
2875 vg_assert(u->cond != CondAlways);
2876 vg_assert(u->size == 4);
2877 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2878 break;
2879
2880 case JMP: {
2881 vg_assert(u->tag2 == NoValue);
2882 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00002883 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002884 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002885 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002886 }
sewardjde4a1d02002-03-22 01:27:54 +00002887 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002888 switch (u->tag1) {
2889 case RealReg:
2890 synth_jmp_reg ( u->val1, u->jmpkind );
2891 break;
2892 case Literal:
2893 synth_jmp_lit ( u->lit32, u->jmpkind );
2894 break;
2895 default:
njne427a662002-10-02 11:08:25 +00002896 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002897 break;
sewardjde4a1d02002-03-22 01:27:54 +00002898 }
2899 } else {
sewardj2e93c502002-04-12 11:12:52 +00002900 switch (u->tag1) {
2901 case RealReg:
njne427a662002-10-02 11:08:25 +00002902 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002903 break;
2904 case Literal:
2905 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00002906 /* %eax had better not be live since synth_jcond_lit
2907 trashes it in some circumstances. If that turns
2908 out to be a problem we can get synth_jcond_lit to
2909 push/pop it when it is live. */
2910 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
2911 u->regs_live_after));
2912 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00002913 break;
2914 default:
njne427a662002-10-02 11:08:25 +00002915 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002916 break;
sewardjde4a1d02002-03-22 01:27:54 +00002917 }
2918 }
2919 break;
2920 }
2921
2922 case JIFZ:
2923 vg_assert(u->tag1 == RealReg);
2924 vg_assert(u->tag2 == Literal);
2925 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00002926 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002927 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002928 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002929 }
sewardjde4a1d02002-03-22 01:27:54 +00002930 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2931 break;
2932
sewardjde4a1d02002-03-22 01:27:54 +00002933 case PUSH:
2934 vg_assert(u->tag1 == RealReg);
2935 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002936 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002937 break;
2938
2939 case POP:
2940 vg_assert(u->tag1 == RealReg);
2941 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002942 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002943 break;
2944
2945 case CALLM:
2946 vg_assert(u->tag1 == Lit16);
2947 vg_assert(u->tag2 == NoValue);
2948 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00002949 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002950 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002951 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002952 }
sewardjfa492d42002-12-08 18:20:01 +00002953 /* Call to a helper which is pretending to be a real CPU
2954 instruction (and therefore operates on Real flags and
2955 registers) */
2956 VG_(synth_call) ( False, u->val1,
2957 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00002958 break;
2959
njn25e49d8e72002-09-23 09:36:25 +00002960 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002961 /* If you change this, remember to change USESEG above, since
2962 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002963 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2964 ones. */
2965 UInt argv[] = { u->val1, u->val2, u->val3 };
2966 UInt tagv[] = { RealReg, RealReg, RealReg };
2967 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2968
2969 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2970 else vg_assert(u->tag1 == NoValue);
2971 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2972 else vg_assert(u->tag2 == NoValue);
2973 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2974 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002975 vg_assert(u->size == 0);
2976
sewardjb5ff83e2002-12-01 19:40:49 +00002977 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002978 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002979 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002980 }
njn25e49d8e72002-09-23 09:36:25 +00002981 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2982 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002983 break;
njn25e49d8e72002-09-23 09:36:25 +00002984 }
sewardje1042472002-09-30 12:33:11 +00002985
sewardjde4a1d02002-03-22 01:27:54 +00002986 case CLEAR:
2987 vg_assert(u->tag1 == Lit16);
2988 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002989 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002990 break;
2991
2992 case CC2VAL:
2993 vg_assert(u->tag1 == RealReg);
2994 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00002995 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002996 synth_setb_reg ( u->val1, u->cond );
2997 break;
2998
sewardjde4a1d02002-03-22 01:27:54 +00002999 case FPU_R:
3000 case FPU_W:
3001 vg_assert(u->tag1 == Lit16);
3002 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003003 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003004 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003005 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003006 }
sewardjfa492d42002-12-08 18:20:01 +00003007 synth_fpu_regmem ( u->flags_r, u->flags_w,
3008 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003009 u->val1 & 0xFF,
3010 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003011 break;
3012
3013 case FPU:
3014 vg_assert(u->tag1 == Lit16);
3015 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00003016 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00003017 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00003018 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003019 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003020 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003021 }
sewardjfa492d42002-12-08 18:20:01 +00003022 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3023 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003024 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003025 break;
3026
3027 default:
sewardj1b7d8022002-11-30 12:35:42 +00003028 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003029 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003030 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003031 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003032 }
njn4ba5a792002-09-30 10:23:54 +00003033 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003034 } else {
njn25e49d8e72002-09-23 09:36:25 +00003035 VG_(printf)("\nError:\n"
3036 " unhandled opcode: %u. Perhaps "
3037 " VG_(needs).extended_UCode should be set?\n",
3038 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003039 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003040 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003041 }
sewardjde4a1d02002-03-22 01:27:54 +00003042 }
3043
sewardjb5ff83e2002-12-01 19:40:49 +00003044 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003045 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003046 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003047 }
3048
njn25e49d8e72002-09-23 09:36:25 +00003049 /* Update UInstr histogram */
3050 vg_assert(u->opcode < 100);
3051 histogram[u->opcode].counts++;
3052 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003053}
3054
3055
3056/* Emit x86 for the ucode in cb, returning the address of the
3057 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003058UChar* VG_(emit_code) ( UCodeBlock* cb,
3059 Int* nbytes,
3060 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003061{
3062 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003063 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003064 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003065 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003066 Int tgt;
3067
sewardjfa492d42002-12-08 18:20:01 +00003068 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003069
njn25e49d8e72002-09-23 09:36:25 +00003070 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003071
sewardj22854b92002-11-30 14:00:47 +00003072 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3073 zero. We have to do this regardless of whether we're t-chaining
3074 or not. */
sewardja2113f92002-12-12 23:42:48 +00003075 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003076 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003077 VG_(emitB) (0xFF); /* decl */
3078 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3079 if (dis)
3080 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003081 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003082 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3083 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003084 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003085
sewardjb5ff83e2002-12-01 19:40:49 +00003086 /* Set up running state. */
3087 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003088 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003089 curr_eip = cb->orig_eip;
3090 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3091 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003092 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003093 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003094 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003095 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003096
sewardjde4a1d02002-03-22 01:27:54 +00003097 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003098 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003099 if (!sane) {
3100 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003101 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003102 }
3103 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003104 emitUInstr( cb, i, regs_live_before,
3105 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003106 }
njn25e49d8e72002-09-23 09:36:25 +00003107 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003108 }
njn25e49d8e72002-09-23 09:36:25 +00003109 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003110 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3111 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003112
sewardj22854b92002-11-30 14:00:47 +00003113 if (j != NULL) {
3114 vg_assert(jumpidx <= VG_MAX_JUMPS);
3115 for(i = 0; i < jumpidx; i++)
3116 j[i] = jumps[i];
3117 }
3118
sewardjde4a1d02002-03-22 01:27:54 +00003119 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003120 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003121 *nbytes = emitted_code_used;
3122 return emitted_code;
3123}
3124
njn25e49d8e72002-09-23 09:36:25 +00003125#undef dis
3126
sewardjde4a1d02002-03-22 01:27:54 +00003127/*--------------------------------------------------------------------*/
3128/*--- end vg_from_ucode.c ---*/
3129/*--------------------------------------------------------------------*/