blob: 1c03aa586f6585e26aebd34f362bda1af0fe8004 [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{
sewardjfa492d42002-12-08 18:20:01 +0000934 VG_(new_emit)(upd_cc, (opc == ADC || opc == SBB) ? FlagC : FlagsEmpty, True);
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
1249
1250/* Emit a jump short with an 8-bit signed offset. Note that the
1251 offset is that which should be added to %eip once %eip has been
1252 advanced over this insn. */
sewardjfa492d42002-12-08 18:20:01 +00001253void VG_(emit_jcondshort_delta) ( Bool simd, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001254{
1255 vg_assert(delta >= -128 && delta <= 127);
sewardjfa492d42002-12-08 18:20:01 +00001256 VG_(new_emit)(simd, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001257 VG_(emitB) ( 0x70 + (UInt)cond );
1258 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001259 if (dis)
1260 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
1261 VG_(nameCondcode)(cond), delta );
1262}
1263
sewardjde4a1d02002-03-22 01:27:54 +00001264static void emit_setb_reg ( Int reg, Condcode cond )
1265{
sewardjfa492d42002-12-08 18:20:01 +00001266 VG_(new_emit)(True, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001267 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1268 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001269 if (dis)
1270 VG_(printf)("\n\t\tset%s %s\n",
1271 VG_(nameCondcode)(cond), nameIReg(1,reg));
1272}
1273
1274static void emit_ret ( void )
1275{
sewardjfa492d42002-12-08 18:20:01 +00001276 maybe_emit_put_eflags(); /* make sure flags are stored */
1277 VG_(new_emit)(False, False, False);
njn25e49d8e72002-09-23 09:36:25 +00001278 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001279 if (dis)
1280 VG_(printf)("\n\t\tret\n");
1281}
1282
sewardj22854b92002-11-30 14:00:47 +00001283/* Predicate used in sanity checks elsewhere - returns true if any
1284 jump-site is an actual chained jump */
1285Bool VG_(is_chained_jumpsite)(Addr a)
1286{
1287 UChar *cp = (UChar *)a;
1288
1289 return (*cp == 0xE9); /* 0xE9 -- jmp */
1290}
1291
sewardj83f11862002-12-01 02:07:08 +00001292static
1293Bool is_fresh_jumpsite(UChar *cp)
1294{
1295 return
1296 cp[0] == 0x0F && /* UD2 */
1297 cp[1] == 0x0B &&
1298 cp[2] == 0x0F && /* UD2 */
1299 cp[3] == 0x0B &&
1300 cp[4] == 0x90; /* NOP */
1301}
1302
sewardj22854b92002-11-30 14:00:47 +00001303/* Predicate used in sanity checks elsewhere - returns true if all
1304 jump-sites are calls to VG_(patch_me) */
1305Bool VG_(is_unchained_jumpsite)(Addr a)
1306{
1307 UChar *cp = (UChar *)a;
1308 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1309 Int idelta;
1310
1311 if (*cp++ != 0xE8) /* 0xE8 == call */
1312 return False;
1313
1314 idelta = (*cp++) << 0;
1315 idelta |= (*cp++) << 8;
1316 idelta |= (*cp++) << 16;
1317 idelta |= (*cp++) << 24;
1318
1319 return idelta == delta;
1320}
1321
1322/* Return target address for a direct jmp */
1323Addr VG_(get_jmp_dest)(Addr a)
1324{
1325 Int delta;
1326 UChar *cp = (UChar *)a;
1327
1328 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1329 return 0;
1330
1331 delta = (*cp++) << 0;
1332 delta |= (*cp++) << 8;
1333 delta |= (*cp++) << 16;
1334 delta |= (*cp++) << 24;
1335
1336 return a + VG_PATCHME_JMPSZ + delta;
1337}
1338
1339/* unchain a BB by generating a call to VG_(patch_me) */
1340void VG_(unchain_jumpsite)(Addr a)
1341{
1342 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1343 UChar *cp = (UChar *)a;
1344
1345 if (VG_(is_unchained_jumpsite)(a))
1346 return; /* don't write unnecessarily */
1347
sewardj83f11862002-12-01 02:07:08 +00001348 if (!is_fresh_jumpsite(cp))
1349 VG_(bb_dechain_count)++; /* update stats */
1350
sewardj22854b92002-11-30 14:00:47 +00001351 *cp++ = 0xE8; /* call */
1352 *cp++ = (delta >> 0) & 0xff;
1353 *cp++ = (delta >> 8) & 0xff;
1354 *cp++ = (delta >> 16) & 0xff;
1355 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001356}
1357
1358/* This doesn't actually generate a call to VG_(patch_me), but
1359 reserves enough space in the instruction stream for it to happen
1360 and records the offset into the jump table. This is because call
1361 is a relative jump, and so will be affected when this code gets
1362 moved about. The translation table will "unchain" this basic block
1363 on insertion (with VG_(unchain_BB)()), and thereby generate a
1364 proper call instruction. */
1365static void emit_call_patchme( void )
1366{
1367 vg_assert(VG_PATCHME_CALLSZ == 5);
1368
sewardjfa492d42002-12-08 18:20:01 +00001369 maybe_emit_put_eflags(); /* save flags before end of BB */
1370 VG_(new_emit)(False, False, False);
sewardj22854b92002-11-30 14:00:47 +00001371
1372 if (jumpidx >= VG_MAX_JUMPS) {
1373 /* If there too many jumps in this basic block, fall back to
1374 dispatch loop. We still need to keep it the same size as the
1375 call sequence. */
1376 VG_(emitB) ( 0xC3 ); /* ret */
1377 VG_(emitB) ( 0x90 ); /* nop */
1378 VG_(emitB) ( 0x90 ); /* nop */
1379 VG_(emitB) ( 0x90 ); /* nop */
1380 VG_(emitB) ( 0x90 ); /* nop */
1381
1382 if (dis)
1383 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1384
1385 if (0 && VG_(clo_verbosity))
1386 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1387 } else {
1388 jumps[jumpidx++] = emitted_code_used;
1389
1390 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1391 VG_(emitB) ( 0x0B );
1392 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1393 VG_(emitB) ( 0x0B );
1394 VG_(emitB) ( 0x90 ); /* NOP */
1395
1396 if (dis)
1397 VG_(printf)("\n\t\tud2; ud2; nop\n");
1398 }
1399}
1400
njn25e49d8e72002-09-23 09:36:25 +00001401void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001402{
sewardjfa492d42002-12-08 18:20:01 +00001403 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001404 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001405 if (dis)
1406 VG_(printf)("\n\t\tpushal\n");
1407}
1408
njn25e49d8e72002-09-23 09:36:25 +00001409void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001410{
sewardjfa492d42002-12-08 18:20:01 +00001411 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001412 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001413 if (dis)
1414 VG_(printf)("\n\t\tpopal\n");
1415}
1416
1417static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1418{
sewardjfa492d42002-12-08 18:20:01 +00001419 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001420 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1421 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001422 if (dis)
1423 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1424 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1425}
1426
1427static void emit_lea_sib_reg ( UInt lit, Int scale,
1428 Int regbase, Int regindex, Int reg )
1429{
sewardjfa492d42002-12-08 18:20:01 +00001430 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001431 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001432 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1433 if (dis)
1434 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1435 lit, nameIReg(4,regbase),
1436 nameIReg(4,regindex), scale,
1437 nameIReg(4,reg) );
1438}
1439
njn25e49d8e72002-09-23 09:36:25 +00001440void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001441{
sewardjfa492d42002-12-08 18:20:01 +00001442 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001443 VG_(emitB) ( 0x0F );
1444 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001445 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1446 if (dis)
1447 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1448}
1449
1450/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001451/*--- Helper offset -> addr translation ---*/
1452/*----------------------------------------------------*/
1453
1454/* Finds the baseBlock offset of a skin-specified helper.
1455 * Searches through compacts first, then non-compacts. */
1456Int VG_(helper_offset)(Addr a)
1457{
1458 Int i;
1459
1460 for (i = 0; i < VG_(n_compact_helpers); i++)
1461 if (VG_(compact_helper_addrs)[i] == a)
1462 return VG_(compact_helper_offsets)[i];
1463 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1464 if (VG_(noncompact_helper_addrs)[i] == a)
1465 return VG_(noncompact_helper_offsets)[i];
1466
1467 /* Shouldn't get here */
1468 VG_(printf)(
1469 "\nCouldn't find offset of helper from its address (%p).\n"
1470 "A helper function probably used hasn't been registered?\n\n", a);
1471
1472 VG_(printf)(" compact helpers: ");
1473 for (i = 0; i < VG_(n_compact_helpers); i++)
1474 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1475
1476 VG_(printf)("\n non-compact helpers: ");
1477 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1478 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1479
1480 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001481 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001482}
1483
1484/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001485/*--- Instruction synthesisers ---*/
1486/*----------------------------------------------------*/
1487
1488static Condcode invertCondition ( Condcode cond )
1489{
1490 return (Condcode)(1 ^ (UInt)cond);
1491}
1492
1493
1494/* Synthesise a call to *baseBlock[offset], ie,
1495 call * (4 x offset)(%ebp).
1496*/
sewardjfa492d42002-12-08 18:20:01 +00001497void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
1498 Bool upd_cc, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001499{
1500 vg_assert(word_offset >= 0);
1501 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001502 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001503 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001504 }
1505 emit_call_star_EBP_off ( upd_cc, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001506}
1507
njn25e49d8e72002-09-23 09:36:25 +00001508static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001509{
njn25e49d8e72002-09-23 09:36:25 +00001510 if (src != dst) {
1511 VG_(emit_movv_reg_reg) ( 4, src, dst );
1512 ccall_arg_setup_instrs++;
1513 }
njn6431be72002-07-28 09:53:34 +00001514}
njn25e49d8e72002-09-23 09:36:25 +00001515
1516/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1517static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1518{
1519 if (RealReg == tag) {
1520 maybe_emit_movl_reg_reg ( litOrReg, reg );
1521 } else if (Literal == tag) {
1522 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1523 ccall_arg_setup_instrs++;
1524 }
1525 else
njne427a662002-10-02 11:08:25 +00001526 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001527}
1528
1529static
1530void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1531{
1532 if (R_EAX == reg1) {
1533 VG_(emit_swapl_reg_EAX) ( reg2 );
1534 } else if (R_EAX == reg2) {
1535 VG_(emit_swapl_reg_EAX) ( reg1 );
1536 } else {
1537 emit_swapl_reg_reg ( reg1, reg2 );
1538 }
1539 ccall_arg_setup_instrs++;
1540}
1541
1542static
1543void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1544{
1545 if (dst1 != src2) {
1546 maybe_emit_movl_reg_reg ( src1, dst1 );
1547 maybe_emit_movl_reg_reg ( src2, dst2 );
1548
1549 } else if (dst2 != src1) {
1550 maybe_emit_movl_reg_reg ( src2, dst2 );
1551 maybe_emit_movl_reg_reg ( src1, dst1 );
1552
1553 } else {
1554 /* swap to break cycle */
1555 emit_swapl_arg_regs ( dst1, dst2 );
1556 }
1557}
1558
1559static
1560void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1561 UInt dst1, UInt dst2, UInt dst3)
1562{
1563 if (dst1 != src2 && dst1 != src3) {
1564 maybe_emit_movl_reg_reg ( src1, dst1 );
1565 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1566
1567 } else if (dst2 != src1 && dst2 != src3) {
1568 maybe_emit_movl_reg_reg ( src2, dst2 );
1569 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1570
1571 } else if (dst3 != src1 && dst3 != src2) {
1572 maybe_emit_movl_reg_reg ( src3, dst3 );
1573 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1574
1575 } else {
1576 /* break cycle */
1577 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1578 emit_swapl_arg_regs ( dst1, dst2 );
1579 emit_swapl_arg_regs ( dst1, dst3 );
1580
1581 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1582 emit_swapl_arg_regs ( dst1, dst3 );
1583 emit_swapl_arg_regs ( dst1, dst2 );
1584
1585 } else {
njne427a662002-10-02 11:08:25 +00001586 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001587 }
1588 }
1589}
1590
1591static
1592void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1593 UInt src1, UInt src2,
1594 UInt dst1, UInt dst2)
1595{
1596 /* If either are lits, order doesn't matter */
1597 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1598 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1599 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1600
1601 } else {
1602 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1603 }
1604}
1605
1606static
1607void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1608 UInt src1, UInt src2, UInt src3,
1609 UInt dst1, UInt dst2, UInt dst3)
1610{
1611 // SSS: fix this eventually -- make STOREV use two RealRegs?
1612 /* Not supporting literals for 3-arg C functions -- they're only used
1613 by STOREV which has 2 args */
1614 vg_assert(RealReg == tagv[src1] &&
1615 RealReg == tagv[src2] &&
1616 RealReg == tagv[src3]);
1617 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1618 dst1, dst2, dst3 );
1619}
1620
1621/* Synthesise a call to a C function `fn' (which must be registered in
1622 baseBlock) doing all the reg saving and arg handling work.
1623
1624 WARNING: a UInstr should *not* be translated with synth_ccall followed
1625 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1626 such behaviour and everything will fall over.
1627 */
1628void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1629 Tag tagv[], Int ret_reg,
1630 RRegSet regs_live_before, RRegSet regs_live_after )
1631{
1632 Int i;
1633 Int stack_used = 0;
1634 Bool preserve_eax, preserve_ecx, preserve_edx;
1635
1636 vg_assert(0 <= regparms_n && regparms_n <= 3);
1637
1638 ccalls++;
1639
1640 /* If %e[acd]x is live before and after the C call, save/restore it.
1641 Unless the return values clobbers the reg; in this case we must not
1642 save/restore the reg, because the restore would clobber the return
1643 value. (Before and after the UInstr really constitute separate live
1644 ranges, but you miss this if you don't consider what happens during
1645 the UInstr.) */
1646# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001647 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1648 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001649 ret_reg != realReg)
1650
1651 preserve_eax = PRESERVE_REG(R_EAX);
1652 preserve_ecx = PRESERVE_REG(R_ECX);
1653 preserve_edx = PRESERVE_REG(R_EDX);
1654
1655# undef PRESERVE_REG
1656
1657 /* Save caller-save regs as required */
1658 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1659 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1660 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1661
1662 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1663 is the number of args passed in regs (maximum 3 for GCC on x86). */
1664
1665 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001666
njn25e49d8e72002-09-23 09:36:25 +00001667 /* First push stack args (RealRegs or Literals) in reverse order. */
1668 for (i = argc-1; i >= regparms_n; i--) {
1669 switch (tagv[i]) {
1670 case RealReg:
1671 VG_(emit_pushv_reg) ( 4, argv[i] );
1672 break;
1673 case Literal:
1674 /* Use short form of pushl if possible. */
1675 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1676 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1677 else
1678 VG_(emit_pushl_lit32)( argv[i] );
1679 break;
1680 default:
1681 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001682 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001683 }
1684 stack_used += 4;
1685 ccall_arg_setup_instrs++;
1686 }
njn6431be72002-07-28 09:53:34 +00001687
njn25e49d8e72002-09-23 09:36:25 +00001688 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1689 If moving values between registers, be careful not to clobber any on
1690 the way. Happily we can use xchgl to swap registers.
1691 */
1692 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001693
njn25e49d8e72002-09-23 09:36:25 +00001694 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1695 case 3:
1696 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1697 R_EAX, R_EDX, R_ECX );
1698 break;
njn6431be72002-07-28 09:53:34 +00001699
njn25e49d8e72002-09-23 09:36:25 +00001700 /* Less-tricky. Args passed in %eax and %edx. */
1701 case 2:
1702 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1703 break;
1704
1705 /* Easy. Just move arg1 into %eax (if not already in there). */
1706 case 1:
1707 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1708 break;
1709
1710 case 0:
1711 break;
1712
1713 default:
njne427a662002-10-02 11:08:25 +00001714 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001715 }
1716
sewardjfa492d42002-12-08 18:20:01 +00001717 /* Call the function - may trash all flags */
1718 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00001719
1720 /* Clear any args from stack */
1721 if (0 != stack_used) {
1722 VG_(emit_add_lit_to_esp) ( stack_used );
1723 ccall_stack_clears++;
1724 }
1725
1726 /* Move return value into ret_reg if necessary and not already there */
1727 if (INVALID_REALREG != ret_reg) {
1728 ccall_retvals++;
1729 if (R_EAX != ret_reg) {
1730 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1731 ccall_retval_movs++;
1732 }
1733 }
1734
1735 /* Restore live caller-save regs as required */
1736 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1737 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1738 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001739}
sewardjde4a1d02002-03-22 01:27:54 +00001740
sewardj2e93c502002-04-12 11:12:52 +00001741static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001742{
sewardj2e93c502002-04-12 11:12:52 +00001743 switch (jmpkind) {
1744 case JmpBoring:
1745 break;
sewardj2e93c502002-04-12 11:12:52 +00001746 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001747 break;
1748 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001749 break;
1750 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001751 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001752 break;
1753 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001754 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001755 break;
1756 default:
njne427a662002-10-02 11:08:25 +00001757 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001758 }
1759}
1760
1761/* Jump to the next translation, by loading its original addr into
1762 %eax and returning to the scheduler. Signal special requirements
1763 by loading a special value into %ebp first.
1764*/
1765static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1766{
sewardjfa492d42002-12-08 18:20:01 +00001767 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00001768 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001769 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001770 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001771 emit_ret();
1772}
1773
sewardj22854b92002-11-30 14:00:47 +00001774static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00001775
1776/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001777static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001778{
sewardjfa492d42002-12-08 18:20:01 +00001779 maybe_emit_put_eflags(); /* save flags here */
1780
njn25e49d8e72002-09-23 09:36:25 +00001781 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00001782
1783 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
1784 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
1785 emit_call_patchme();
1786 } else {
1787 load_ebp_from_JmpKind ( jmpkind );
1788 emit_ret();
1789 }
sewardjde4a1d02002-03-22 01:27:54 +00001790}
1791
1792
sewardj2370f3b2002-11-30 15:01:01 +00001793static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
1794static void synth_nonshiftop_lit_reg ( Bool upd_cc,
1795 Opcode opcode, Int size,
1796 UInt lit, Int reg );
1797
sewardjfa492d42002-12-08 18:20:01 +00001798static void synth_jcond_lit ( Condcode cond,
1799 Addr addr,
1800 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00001801{
sewardj2370f3b2002-11-30 15:01:01 +00001802 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00001803 Int delta;
1804 Bool simd;
sewardj2370f3b2002-11-30 15:01:01 +00001805
sewardj22854b92002-11-30 14:00:47 +00001806 if (VG_(clo_chain_bb)) {
1807 /* When using BB chaining, the jump sequence is:
sewardjfa492d42002-12-08 18:20:01 +00001808 ensure that simulated eflags are up-to-date
1809 jmp short if not cond to xyxyxy, using the real
1810 machine eflags if we can, synthesising a suitable sequence
1811 to examine the simulated ones otherwise
1812 addr -> eax
1813 call VG_(patch_me)/jmp target
1814 xyxyxy
1815
1816 <possibly sequence to compute some condition>
1817 j<cond> xyxyxy
1818 mov $0x4000d190,%eax // 5
1819 mov %eax, VGOFF_(m_eip)(%ebp) // 3
1820 call 0x40050f9a <vgPlain_patch_me> // 5
1821 xyxyxy: mov $0x4000d042,%eax
1822 call 0x40050f9a <vgPlain_patch_me>
sewardj22854b92002-11-30 14:00:47 +00001823 */
sewardj83f11862002-12-01 02:07:08 +00001824 delta = 5+3+5;
sewardjfa492d42002-12-08 18:20:01 +00001825 } else {
1826 /* When not using BB chaining:
1827 ensure that simulated eflags are up-to-date
1828 jmp short if not cond to xyxyxy, using the real
1829 machine eflags if we can, synthesising a suitable sequence
1830 to examine the simulated ones otherwise
1831 addr -> eax
1832 ret
1833 xyxyxy
1834
1835 <possibly sequence to compute some condition>
1836 j<cond> xyxyxy
1837 movl $0x44556677, %eax // 5
1838 ret // 1
1839 xyxyxy:
1840 */
sewardj2370f3b2002-11-30 15:01:01 +00001841 delta = 5+1;
sewardjfa492d42002-12-08 18:20:01 +00001842 }
sewardj2370f3b2002-11-30 15:01:01 +00001843
sewardjfa492d42002-12-08 18:20:01 +00001844 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
1845 if need be */
1846 maybe_emit_put_eflags();
1847 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
1848
1849 if (eflags_state == UPD_Both) {
1850 /* The flags are already set up, so we just use them as is. */
1851 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00001852 cond = invertCondition(cond);
1853 } else {
sewardjfa492d42002-12-08 18:20:01 +00001854
1855 /* The simd state contains the most recent version, so we emit a
1856 sequence to calculate the relevant condition directly out of
1857 the simd flags. This is much cheaper (on P3/P4/Athlon) than
1858 copying them back to the real flags via popf. Notice that
1859 some of these sequences trash %eax, but that should be free
1860 now since this is the end of a bb and therefore all regs are
1861 dead. */
1862 simd = False;
1863
1864 switch (cond) {
1865
1866 case CondLE:
1867 case CondNLE:
1868 vg_assert(eax_trashable);
1869
1870 VG_(emit_movv_offregmem_reg)
1871 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1872 /* eax == %EFLAGS */
1873
1874 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 11-7, R_EAX );
1875 /* eax has OF in SF's place */
1876
1877 emit_nonshiftopv_offregmem_reg
1878 ( False, 4, XOR, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1879 /* eax has (OF xor SF) in SF's place */
1880
1881 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7-6, R_EAX );
1882 /* eax has (OF xor SF) in ZF's place */
1883
1884 emit_nonshiftopv_offregmem_reg
1885 ( False, 4, OR, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1886 /* eax has ((OF xor SF) or ZF) in SF's place */
1887
1888 VG_(emit_nonshiftopv_lit_reg)( False, 4, AND, 1 << 6, R_EAX );
1889 /* Z is now set iff ((OF xor SF) or ZF) == 1 */
1890
1891 if (cond == CondLE) cond = CondZ; else cond = CondNZ;
sewardj2370f3b2002-11-30 15:01:01 +00001892 break;
1893
sewardjfa492d42002-12-08 18:20:01 +00001894 case CondL:
1895 case CondNL:
1896 vg_assert(eax_trashable);
1897
1898 VG_(emit_movv_offregmem_reg)
1899 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1900 /* eax == %EFLAGS */
1901
1902 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 11-7, R_EAX );
1903 /* eax has OF in SF's place */
1904
1905 emit_nonshiftopv_offregmem_reg
1906 ( False, 4, XOR, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1907 /* eax has (OF xor SF) in SF's place */
1908
1909 VG_(emit_nonshiftopv_lit_reg)( False, 4, AND, 1 << 7, R_EAX );
1910 /* Z is now set iff (OF xor SF) == 1 */
1911
1912 if (cond == CondL) cond = CondZ; else cond = CondNZ;
1913 break;
1914
1915 case CondB:
1916 case CondNB:
1917 mask = EFlagC; goto simple; /* C=1 */
1918
1919 case CondZ:
1920 case CondNZ:
1921 mask = EFlagZ; goto simple; /* Z=1 */
1922
1923 case CondBE:
1924 case CondNBE:
1925 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
1926
1927 case CondS:
1928 case CondNS:
1929 mask = EFlagS; goto simple; /* S=1 */
1930
1931 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00001932 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00001933 mask = EFlagP; goto simple; /* P=1 */
1934
1935 default:
1936 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
1937 (Int)cond, VG_(nameCondcode)(cond) );
1938 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
1939
1940 simple:
1941 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00001942 if ((mask & 0xff) == mask) {
1943 VG_(emitB) ( 0xF6 ); /* Grp3 */
1944 VG_(emit_amode_offregmem_reg)(
1945 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1946 VG_(emitB) (mask);
1947 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001948 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00001949 mask, VGOFF_(m_eflags) * 4);
1950 } else {
sewardjfa492d42002-12-08 18:20:01 +00001951 /* all cond codes are in lower 16 bits */
1952 vg_assert((mask & 0xffff) == mask);
1953
1954 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00001955 VG_(emitB) ( 0xF7 );
1956 VG_(emit_amode_offregmem_reg)(
1957 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00001958 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00001959 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001960 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00001961 mask, VGOFF_(m_eflags) * 4);
1962 }
1963
1964 if (cond & 1)
1965 cond = CondNZ;
1966 else
1967 cond = CondZ;
1968 break;
1969 }
1970 }
1971
sewardjfa492d42002-12-08 18:20:01 +00001972 VG_(emit_jcondshort_delta) ( simd, cond, delta );
sewardj2e93c502002-04-12 11:12:52 +00001973 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001974}
1975
1976
sewardj2370f3b2002-11-30 15:01:01 +00001977
sewardjde4a1d02002-03-22 01:27:54 +00001978static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1979{
1980 /* 0000 83FF00 cmpl $0, %edi
1981 0003 750A jnz next
1982 0005 B844332211 movl $0x11223344, %eax
1983 000a C3 ret
1984 next:
1985 */
sewardjfa492d42002-12-08 18:20:01 +00001986 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardj22854b92002-11-30 14:00:47 +00001987 if (VG_(clo_chain_bb))
sewardjfa492d42002-12-08 18:20:01 +00001988 VG_(emit_jcondshort_delta) ( False, CondNZ, 5+3+5 );
sewardj22854b92002-11-30 14:00:47 +00001989 else
sewardjfa492d42002-12-08 18:20:01 +00001990 VG_(emit_jcondshort_delta) ( False, CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001991 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001992}
1993
1994
1995static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1996{
1997 /* Load the zero-extended literal into reg, at size l,
1998 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00001999 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002000}
2001
2002
2003static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2004{
2005 switch (size) {
2006 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2007 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2008 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002009 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002010 }
2011}
2012
2013
2014static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2015{
2016 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002017 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2018 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2019 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002020 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002021 }
2022}
2023
2024
2025static void synth_mov_reg_offregmem ( Int size, Int reg,
2026 Int off, Int areg )
2027{
2028 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002029 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2030 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002031 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002032 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002033 }
2034 else {
njn25e49d8e72002-09-23 09:36:25 +00002035 VG_(emit_swapl_reg_EAX) ( reg );
2036 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2037 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002038 }
2039 break;
njne427a662002-10-02 11:08:25 +00002040 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002041 }
2042}
2043
2044
2045static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2046{
2047 Int s1;
2048 switch (size) {
2049 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2050 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2051 case 1: if (reg1 < 4) {
2052 emit_movb_reg_regmem ( reg1, reg2 );
2053 }
2054 else {
2055 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2056 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2057 emit_swapl_reg_reg ( s1, reg1 );
2058 emit_movb_reg_regmem ( s1, reg2 );
2059 emit_swapl_reg_reg ( s1, reg1 );
2060 }
2061 break;
njne427a662002-10-02 11:08:25 +00002062 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002063 }
2064}
2065
2066
sewardj478335c2002-10-05 02:44:47 +00002067static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002068 Opcode opcode, Int size,
2069 Int reg )
2070{
2071 /* NB! opcode is a uinstr opcode, not an x86 one! */
2072 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002073 case 4: VG_(emit_unaryopv_reg) ( upd_cc, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002074 break;
sewardjfa492d42002-12-08 18:20:01 +00002075 case 2: VG_(emit_unaryopv_reg) ( upd_cc, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002076 break;
2077 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002078 VG_(emit_unaryopb_reg) ( upd_cc, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002079 } else {
njn25e49d8e72002-09-23 09:36:25 +00002080 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002081 VG_(emit_unaryopb_reg) ( upd_cc, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002082 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002083 }
2084 break;
njne427a662002-10-02 11:08:25 +00002085 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002086 }
2087}
2088
2089
2090
sewardj478335c2002-10-05 02:44:47 +00002091static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002092 Opcode opcode, Int size,
2093 Int reg1, Int reg2 )
2094{
2095 /* NB! opcode is a uinstr opcode, not an x86 one! */
2096 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002097 case 4: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002098 break;
sewardjfa492d42002-12-08 18:20:01 +00002099 case 2: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002100 break;
2101 case 1: { /* Horrible ... */
2102 Int s1, s2;
2103 /* Choose s1 and s2 to be x86 regs which we can talk about the
2104 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2105 sure s1 != s2 and that neither of them equal either reg1 or
2106 reg2. Then use them as temporaries to make things work. */
2107 if (reg1 < 4 && reg2 < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002108 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002109 break;
2110 }
2111 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2112 if (reg1 >= 4 && reg2 < 4) {
2113 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002114 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002115 emit_swapl_reg_reg ( reg1, s1 );
2116 break;
2117 }
2118 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2119 if (reg1 < 4 && reg2 >= 4) {
2120 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002121 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002122 emit_swapl_reg_reg ( reg2, s2 );
2123 break;
2124 }
2125 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2126 emit_swapl_reg_reg ( reg1, s1 );
2127 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002128 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002129 emit_swapl_reg_reg ( reg1, s1 );
2130 emit_swapl_reg_reg ( reg2, s2 );
2131 break;
2132 }
2133 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2134 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002135 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002136 emit_swapl_reg_reg ( reg1, s1 );
2137 break;
2138 }
njne427a662002-10-02 11:08:25 +00002139 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002140 }
njne427a662002-10-02 11:08:25 +00002141 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002142 }
2143}
2144
2145
sewardjfa492d42002-12-08 18:20:01 +00002146static void synth_nonshiftop_reg_offregmem (
2147 Bool upd_cc,
2148 Opcode opcode, Int size,
2149 Int off, Int areg, Int reg )
2150{
2151 switch (size) {
2152 case 4:
2153 emit_nonshiftopv_reg_offregmem ( upd_cc, 4, opcode, off, areg, reg );
2154 break;
2155 case 2:
2156 emit_nonshiftopv_reg_offregmem ( upd_cc, 2, opcode, off, areg, reg );
2157 break;
2158 case 1:
2159 if (reg < 4) {
2160 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, reg );
2161 } else {
2162 VG_(emit_swapl_reg_EAX) ( reg );
2163 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, R_AL );
2164 VG_(emit_swapl_reg_EAX) ( reg );
2165 }
2166 break;
2167 default:
2168 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2169 }
2170}
2171
sewardjde4a1d02002-03-22 01:27:54 +00002172static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002173 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002174 Opcode opcode, Int size,
2175 Int off, Int areg, Int reg )
2176{
2177 switch (size) {
2178 case 4:
sewardjfa492d42002-12-08 18:20:01 +00002179 emit_nonshiftopv_offregmem_reg ( upd_cc, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002180 break;
2181 case 2:
sewardjfa492d42002-12-08 18:20:01 +00002182 emit_nonshiftopv_offregmem_reg ( upd_cc, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002183 break;
2184 case 1:
2185 if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002186 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002187 } else {
njn25e49d8e72002-09-23 09:36:25 +00002188 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002189 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002190 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002191 }
2192 break;
2193 default:
njne427a662002-10-02 11:08:25 +00002194 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002195 }
2196}
2197
2198
sewardj478335c2002-10-05 02:44:47 +00002199static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002200 Opcode opcode, Int size,
2201 UInt lit, Int reg )
2202{
2203 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002204 case 4: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002205 break;
sewardjfa492d42002-12-08 18:20:01 +00002206 case 2: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002207 break;
2208 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002209 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002210 } else {
njn25e49d8e72002-09-23 09:36:25 +00002211 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002212 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002213 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002214 }
2215 break;
njne427a662002-10-02 11:08:25 +00002216 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002217 }
2218}
2219
sewardjfa492d42002-12-08 18:20:01 +00002220static void synth_nonshiftop_lit_offregmem ( Bool upd_cc,
2221 Opcode opcode, Int size,
2222 UInt lit, Int off, Int regmem )
2223{
2224 switch (size) {
2225 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 4, opcode, lit, off, regmem );
2226 break;
2227 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 2, opcode, lit, off, regmem );
2228 break;
2229 case 1: emit_nonshiftopb_lit_offregmem ( upd_cc, opcode, lit, off, regmem );
2230 break;
2231 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2232 }
2233}
2234
sewardjde4a1d02002-03-22 01:27:54 +00002235
2236static void synth_push_reg ( Int size, Int reg )
2237{
2238 switch (size) {
2239 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002240 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002241 break;
2242 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002243 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002244 break;
2245 /* Pray that we don't have to generate this really cruddy bit of
2246 code very often. Could do better, but can I be bothered? */
2247 case 1:
2248 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002249 VG_(emit_add_lit_to_esp)(-1);
2250 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002251 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002252 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002253 break;
2254 default:
njne427a662002-10-02 11:08:25 +00002255 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002256 }
2257}
2258
2259
2260static void synth_pop_reg ( Int size, Int reg )
2261{
2262 switch (size) {
2263 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002264 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002265 break;
2266 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002267 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002268 break;
2269 case 1:
2270 /* Same comment as above applies. */
2271 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002272 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002273 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002274 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2275 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002276 break;
njne427a662002-10-02 11:08:25 +00002277 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002278 }
2279}
2280
2281
sewardj478335c2002-10-05 02:44:47 +00002282static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002283 Opcode opcode, Int size,
2284 Int regs, Int regd )
2285{
2286 synth_push_reg ( size, regd );
2287 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002288 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002289 case 4: emit_shiftopv_cl_stack0 ( upd_cc, 4, opcode ); break;
2290 case 2: emit_shiftopv_cl_stack0 ( upd_cc, 2, opcode ); break;
2291 case 1: emit_shiftopb_cl_stack0 ( upd_cc, opcode ); break;
njne427a662002-10-02 11:08:25 +00002292 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002293 }
sewardjde4a1d02002-03-22 01:27:54 +00002294 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2295 synth_pop_reg ( size, regd );
2296}
2297
2298
sewardj478335c2002-10-05 02:44:47 +00002299static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002300 Opcode opcode, Int size,
2301 UInt lit, Int reg )
2302{
2303 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002304 case 4: VG_(emit_shiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002305 break;
sewardjfa492d42002-12-08 18:20:01 +00002306 case 2: VG_(emit_shiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002307 break;
2308 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002309 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002310 } else {
njn25e49d8e72002-09-23 09:36:25 +00002311 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002312 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002313 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002314 }
2315 break;
njne427a662002-10-02 11:08:25 +00002316 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002317 }
2318}
2319
2320
2321static void synth_setb_reg ( Int reg, Condcode cond )
2322{
sewardjde4a1d02002-03-22 01:27:54 +00002323 if (reg < 4) {
2324 emit_setb_reg ( reg, cond );
2325 } else {
njn25e49d8e72002-09-23 09:36:25 +00002326 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002327 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002328 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002329 }
2330}
2331
2332
sewardjfa492d42002-12-08 18:20:01 +00002333static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2334 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002335 UChar second_byte_masked,
2336 Int reg )
2337{
sewardjfa492d42002-12-08 18:20:01 +00002338 emit_fpu_regmem ( uses_flags, sets_flags, first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002339}
2340
2341
sewardjfa492d42002-12-08 18:20:01 +00002342static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2343 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002344 UChar second_byte )
2345{
sewardjfa492d42002-12-08 18:20:01 +00002346 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002347}
2348
2349
2350static void synth_movl_reg_reg ( Int src, Int dst )
2351{
2352 emit_movl_reg_reg ( src, dst );
2353}
2354
2355static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2356{
sewardjfa492d42002-12-08 18:20:01 +00002357 VG_(emit_jcondshort_delta) ( True, invertCondition(cond),
sewardjde4a1d02002-03-22 01:27:54 +00002358 2 /* length of the next insn */ );
2359 emit_movl_reg_reg ( src, dst );
2360}
2361
2362
sewardjde4a1d02002-03-22 01:27:54 +00002363/*----------------------------------------------------*/
2364/*--- Top level of the uinstr -> x86 translation. ---*/
2365/*----------------------------------------------------*/
2366
2367/* Return the byte offset from %ebp (ie, into baseBlock)
2368 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002369static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2370{
2371 if (tag == SpillNo) {
2372 vg_assert(size == 4);
2373 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2374 return 4 * (value + VGOFF_(spillslots));
2375 }
2376 if (tag == ArchReg) {
2377 switch (value) {
2378 case R_EAX: return 4 * VGOFF_(m_eax);
2379 case R_ECX: return 4 * VGOFF_(m_ecx);
2380 case R_EDX: return 4 * VGOFF_(m_edx);
2381 case R_EBX: return 4 * VGOFF_(m_ebx);
2382 case R_ESP:
2383 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2384 else return 4 * VGOFF_(m_esp);
2385 case R_EBP:
2386 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2387 else return 4 * VGOFF_(m_ebp);
2388 case R_ESI:
2389 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2390 else return 4 * VGOFF_(m_esi);
2391 case R_EDI:
2392 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2393 else return 4 * VGOFF_(m_edi);
2394 }
2395 }
njne427a662002-10-02 11:08:25 +00002396 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002397}
2398
sewardjde4a1d02002-03-22 01:27:54 +00002399static Int eflagsOffset ( void )
2400{
2401 return 4 * VGOFF_(m_eflags);
2402}
2403
sewardje1042472002-09-30 12:33:11 +00002404static Int segRegOffset ( UInt archregs )
2405{
2406 switch (archregs) {
2407 case R_CS: return 4 * VGOFF_(m_cs);
2408 case R_SS: return 4 * VGOFF_(m_ss);
2409 case R_DS: return 4 * VGOFF_(m_ds);
2410 case R_ES: return 4 * VGOFF_(m_es);
2411 case R_FS: return 4 * VGOFF_(m_fs);
2412 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002413 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002414 }
2415}
2416
sewardjde4a1d02002-03-22 01:27:54 +00002417
njn25e49d8e72002-09-23 09:36:25 +00002418/* Return the byte offset from %ebp (ie, into baseBlock)
2419 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002420Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002421{
2422 switch (arch) {
2423 case R_EAX: return 4 * VGOFF_(sh_eax);
2424 case R_ECX: return 4 * VGOFF_(sh_ecx);
2425 case R_EDX: return 4 * VGOFF_(sh_edx);
2426 case R_EBX: return 4 * VGOFF_(sh_ebx);
2427 case R_ESP: return 4 * VGOFF_(sh_esp);
2428 case R_EBP: return 4 * VGOFF_(sh_ebp);
2429 case R_ESI: return 4 * VGOFF_(sh_esi);
2430 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002431 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002432 }
2433}
2434
njn4ba5a792002-09-30 10:23:54 +00002435Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002436{
2437 return 4 * VGOFF_(sh_eflags);
2438}
2439
2440
sewardjde4a1d02002-03-22 01:27:54 +00002441
2442static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2443{
2444 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002445 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2446 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002447 }
2448 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002449 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2450 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002451 }
2452 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002453 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2454 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002455 }
2456 else
njne427a662002-10-02 11:08:25 +00002457 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002458}
2459
2460
njn25e49d8e72002-09-23 09:36:25 +00002461static void synth_handle_esp_assignment ( Int i, Int reg,
2462 RRegSet regs_live_before,
2463 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002464{
njn25e49d8e72002-09-23 09:36:25 +00002465 UInt argv[] = { reg };
2466 Tag tagv[] = { RealReg };
2467
2468 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2469 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002470}
2471
2472
sewardjde4a1d02002-03-22 01:27:54 +00002473/*----------------------------------------------------*/
2474/*--- Generate code for a single UInstr. ---*/
2475/*----------------------------------------------------*/
2476
sewardj478335c2002-10-05 02:44:47 +00002477static __inline__
2478Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002479{
2480 return (u->flags_w != FlagsEmpty);
2481}
2482
sewardjfa492d42002-12-08 18:20:01 +00002483static __inline__
2484Bool readFlagUse ( UInstr* u )
2485{
2486 /* If the UInstr writes some flags but not all, then we still need
2487 to consider it as reading flags so that the unchanged values are
2488 passed through properly. (D is special) */
2489 return
2490 (u->flags_r != FlagsEmpty) ||
2491 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2492}
2493
sewardj478335c2002-10-05 02:44:47 +00002494static __inline__
2495Bool anyFlagUse ( UInstr* u )
2496{
sewardjfa492d42002-12-08 18:20:01 +00002497 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002498}
2499
2500
sewardjb5ff83e2002-12-01 19:40:49 +00002501/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002502 the real FPU. If so we need to be very careful not to trash it.
2503 If FPU state is live and we deem it necessary to copy it back to
2504 the simulated machine's FPU state, we do so. The final state of
2505 fpliveness is returned. In short we _must_ do put_fpu_state if
2506 there is any chance at all that the code generated for a UInstr
2507 will change the real FPU state.
2508*/
sewardjb5ff83e2002-12-01 19:40:49 +00002509static void emitUInstr ( UCodeBlock* cb, Int i,
2510 RRegSet regs_live_before,
2511 /* Running state, which we update. */
2512 Bool* fplive, /* True<==>FPU state in real FPU */
2513 Addr* orig_eip, /* previous curr_eip, or zero */
2514 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002515{
njn25e49d8e72002-09-23 09:36:25 +00002516 Int old_emitted_code_used;
2517 UInstr* u = &cb->instrs[i];
2518
sewardjde4a1d02002-03-22 01:27:54 +00002519 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002520 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002521
njn25e49d8e72002-09-23 09:36:25 +00002522 old_emitted_code_used = emitted_code_used;
2523
sewardjde4a1d02002-03-22 01:27:54 +00002524 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002525 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002526
sewardjb5ff83e2002-12-01 19:40:49 +00002527 case INCEIP:
2528 /* Advance %EIP some small amount. */
2529 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002530
sewardjb5ff83e2002-12-01 19:40:49 +00002531 if (*orig_eip == 0 /* we don't know what the old value was */
2532 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2533 /* We have to update all 32 bits of the value. */
2534 VG_(emit_movv_lit_offregmem)(
2535 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2536 } else {
2537 /* Cool! we only need to update lowest 8 bits */
2538 VG_(emit_movb_lit_offregmem)(
2539 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002540 }
njn25e49d8e72002-09-23 09:36:25 +00002541
sewardjb5ff83e2002-12-01 19:40:49 +00002542 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002543 break;
sewardjde4a1d02002-03-22 01:27:54 +00002544
2545 case LEA1: {
2546 vg_assert(u->tag1 == RealReg);
2547 vg_assert(u->tag2 == RealReg);
2548 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2549 break;
2550 }
2551
2552 case LEA2: {
2553 vg_assert(u->tag1 == RealReg);
2554 vg_assert(u->tag2 == RealReg);
2555 vg_assert(u->tag3 == RealReg);
2556 emit_lea_sib_reg ( u->lit32, u->extra4b,
2557 u->val1, u->val2, u->val3 );
2558 break;
2559 }
2560
2561 case WIDEN: {
2562 vg_assert(u->tag1 == RealReg);
2563 if (u->signed_widen) {
2564 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2565 } else {
2566 /* no need to generate any code. */
2567 }
2568 break;
2569 }
2570
sewardjde4a1d02002-03-22 01:27:54 +00002571 case STORE: {
2572 vg_assert(u->tag1 == RealReg);
2573 vg_assert(u->tag2 == RealReg);
2574 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002575 break;
2576 }
2577
2578 case LOAD: {
2579 vg_assert(u->tag1 == RealReg);
2580 vg_assert(u->tag2 == RealReg);
2581 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2582 break;
2583 }
2584
sewardjde4a1d02002-03-22 01:27:54 +00002585 case GET: {
2586 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2587 vg_assert(u->tag2 == RealReg);
2588 synth_mov_offregmem_reg (
2589 u->size,
2590 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2591 R_EBP,
2592 u->val2
2593 );
2594 break;
2595 }
2596
2597 case PUT: {
2598 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2599 vg_assert(u->tag1 == RealReg);
2600 if (u->tag2 == ArchReg
2601 && u->val2 == R_ESP
2602 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002603 && (VG_(track_events).new_mem_stack ||
2604 VG_(track_events).new_mem_stack_aligned ||
2605 VG_(track_events).die_mem_stack ||
2606 VG_(track_events).die_mem_stack_aligned ||
2607 VG_(track_events).post_mem_write))
2608 {
2609 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2610 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002611 }
njn25e49d8e72002-09-23 09:36:25 +00002612 else {
2613 synth_mov_reg_offregmem (
2614 u->size,
2615 u->val1,
2616 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2617 R_EBP
2618 );
2619 }
sewardjde4a1d02002-03-22 01:27:54 +00002620 break;
2621 }
2622
sewardje1042472002-09-30 12:33:11 +00002623 case GETSEG: {
2624 vg_assert(u->tag1 == ArchRegS);
2625 vg_assert(u->tag2 == RealReg);
2626 vg_assert(u->size == 2);
2627 synth_mov_offregmem_reg (
2628 4,
2629 segRegOffset( u->val1 ),
2630 R_EBP,
2631 u->val2
2632 );
2633 break;
2634 }
2635
2636 case PUTSEG: {
2637 vg_assert(u->tag1 == RealReg);
2638 vg_assert(u->tag2 == ArchRegS);
2639 vg_assert(u->size == 2);
2640 synth_mov_reg_offregmem (
2641 4,
2642 u->val1,
2643 segRegOffset( u->val2 ),
2644 R_EBP
2645 );
2646 break;
2647 }
2648
sewardjde4a1d02002-03-22 01:27:54 +00002649 case GETF: {
2650 vg_assert(u->size == 2 || u->size == 4);
2651 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002652
2653 /* This complexity is because the D(irection) flag is stored
2654 separately from the rest of EFLAGS. */
2655
2656 /* We're only fetching from the Simd state, so make sure it's
2657 up to date. */
2658 maybe_emit_put_eflags();
2659
2660 /* get D in u->val1 (== 1 or -1) */
2661 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
2662
2663 /* u->val1 &= EFlagD (== 0 or EFlagD) */
2664 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2665
2666 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2667 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2668 eflagsOffset(), R_EBP);
2669
2670 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2671 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2672 eflagsOffset(), R_EBP);
2673
2674 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
2675 synth_nonshiftop_offregmem_reg(False, OR, u->size,
2676 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00002677 break;
2678 }
2679
2680 case PUTF: {
2681 vg_assert(u->size == 2 || u->size == 4);
2682 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002683
2684 /* When putting a value into EFLAGS, this generates the
2685 correct value for m_dflag (-1 or 1), and clears the D bit
2686 in EFLAGS. */
2687
2688 /* We're updating the whole flag state, so the old state
2689 doesn't matter; make sure that the new simulated state
2690 will be fetched when needed. */
2691 eflags_state = UPD_Simd;
2692
2693 /* store EFLAGS (with D) */
2694 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
2695
2696 /* u->val1 &= EFlagD */
2697 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2698
2699 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
2700 synth_unaryop_reg(False, NEG, u->size, u->val1);
2701 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
2702 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
2703
2704 /* save D */
2705 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
2706
2707 /* EFLAGS &= ~EFlagD */
2708 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2709 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00002710 break;
2711 }
2712
2713 case MOV: {
2714 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2715 vg_assert(u->tag2 == RealReg);
2716 switch (u->tag1) {
2717 case RealReg: vg_assert(u->size == 4);
2718 if (u->val1 != u->val2)
2719 synth_movl_reg_reg ( u->val1, u->val2 );
2720 break;
2721 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2722 break;
njne427a662002-10-02 11:08:25 +00002723 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002724 }
2725 break;
2726 }
2727
sewardje1042472002-09-30 12:33:11 +00002728 case USESEG: {
2729 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2730 ones. */
sewardjd077f532002-09-30 21:52:50 +00002731 UInt argv[] = { u->val1, u->val2 };
2732 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002733 UInt ret_reg = u->val2;
2734
2735 vg_assert(u->tag1 == RealReg);
2736 vg_assert(u->tag2 == RealReg);
2737 vg_assert(u->size == 0);
2738
sewardjb5ff83e2002-12-01 19:40:49 +00002739 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002740 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002741 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002742 }
2743
sewardje1042472002-09-30 12:33:11 +00002744 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2745 2, /* args */
2746 0, /* regparms_n */
2747 argv, tagv,
2748 ret_reg, regs_live_before, u->regs_live_after );
2749 break;
2750 }
2751
sewardj478335c2002-10-05 02:44:47 +00002752 case SBB:
2753 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002754 case XOR:
2755 case OR:
2756 case AND:
2757 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002758 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002759 vg_assert(u->tag2 == RealReg);
2760 switch (u->tag1) {
2761 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002762 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002763 u->opcode, u->size, u->lit32, u->val2 );
2764 break;
2765 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002766 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002767 u->opcode, u->size, u->val1, u->val2 );
2768 break;
2769 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002770 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002771 u->opcode, u->size,
2772 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2773 R_EBP,
2774 u->val2 );
2775 break;
njne427a662002-10-02 11:08:25 +00002776 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002777 }
2778 break;
2779 }
2780
sewardj478335c2002-10-05 02:44:47 +00002781 case RCR:
2782 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002783 case ROR:
2784 case ROL:
2785 case SAR:
2786 case SHR:
2787 case SHL: {
2788 vg_assert(u->tag2 == RealReg);
2789 switch (u->tag1) {
2790 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002791 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002792 u->opcode, u->size, u->lit32, u->val2 );
2793 break;
2794 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002795 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002796 u->opcode, u->size, u->val1, u->val2 );
2797 break;
njne427a662002-10-02 11:08:25 +00002798 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002799 }
2800 break;
2801 }
2802
2803 case INC:
2804 case DEC:
2805 case NEG:
2806 case NOT:
2807 vg_assert(u->tag1 == RealReg);
2808 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002809 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002810 break;
2811
2812 case BSWAP:
2813 vg_assert(u->tag1 == RealReg);
2814 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002815 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002816 emit_bswapl_reg ( u->val1 );
2817 break;
2818
2819 case CMOV:
2820 vg_assert(u->tag1 == RealReg);
2821 vg_assert(u->tag2 == RealReg);
2822 vg_assert(u->cond != CondAlways);
2823 vg_assert(u->size == 4);
2824 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2825 break;
2826
2827 case JMP: {
2828 vg_assert(u->tag2 == NoValue);
2829 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00002830 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002831 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002832 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002833 }
sewardjde4a1d02002-03-22 01:27:54 +00002834 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002835 switch (u->tag1) {
2836 case RealReg:
2837 synth_jmp_reg ( u->val1, u->jmpkind );
2838 break;
2839 case Literal:
2840 synth_jmp_lit ( u->lit32, u->jmpkind );
2841 break;
2842 default:
njne427a662002-10-02 11:08:25 +00002843 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002844 break;
sewardjde4a1d02002-03-22 01:27:54 +00002845 }
2846 } else {
sewardj2e93c502002-04-12 11:12:52 +00002847 switch (u->tag1) {
2848 case RealReg:
njne427a662002-10-02 11:08:25 +00002849 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002850 break;
2851 case Literal:
2852 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00002853 /* %eax had better not be live since synth_jcond_lit
2854 trashes it in some circumstances. If that turns
2855 out to be a problem we can get synth_jcond_lit to
2856 push/pop it when it is live. */
2857 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
2858 u->regs_live_after));
2859 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00002860 break;
2861 default:
njne427a662002-10-02 11:08:25 +00002862 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002863 break;
sewardjde4a1d02002-03-22 01:27:54 +00002864 }
2865 }
2866 break;
2867 }
2868
2869 case JIFZ:
2870 vg_assert(u->tag1 == RealReg);
2871 vg_assert(u->tag2 == Literal);
2872 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00002873 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002874 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002875 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002876 }
sewardjde4a1d02002-03-22 01:27:54 +00002877 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2878 break;
2879
sewardjde4a1d02002-03-22 01:27:54 +00002880 case PUSH:
2881 vg_assert(u->tag1 == RealReg);
2882 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002883 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002884 break;
2885
2886 case POP:
2887 vg_assert(u->tag1 == RealReg);
2888 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002889 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002890 break;
2891
2892 case CALLM:
2893 vg_assert(u->tag1 == Lit16);
2894 vg_assert(u->tag2 == NoValue);
2895 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00002896 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002897 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002898 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002899 }
sewardjfa492d42002-12-08 18:20:01 +00002900 /* Call to a helper which is pretending to be a real CPU
2901 instruction (and therefore operates on Real flags and
2902 registers) */
2903 VG_(synth_call) ( False, u->val1,
2904 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00002905 break;
2906
njn25e49d8e72002-09-23 09:36:25 +00002907 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002908 /* If you change this, remember to change USESEG above, since
2909 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002910 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2911 ones. */
2912 UInt argv[] = { u->val1, u->val2, u->val3 };
2913 UInt tagv[] = { RealReg, RealReg, RealReg };
2914 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2915
2916 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2917 else vg_assert(u->tag1 == NoValue);
2918 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2919 else vg_assert(u->tag2 == NoValue);
2920 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2921 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002922 vg_assert(u->size == 0);
2923
sewardjb5ff83e2002-12-01 19:40:49 +00002924 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002925 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002926 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002927 }
njn25e49d8e72002-09-23 09:36:25 +00002928 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2929 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002930 break;
njn25e49d8e72002-09-23 09:36:25 +00002931 }
sewardje1042472002-09-30 12:33:11 +00002932
sewardjde4a1d02002-03-22 01:27:54 +00002933 case CLEAR:
2934 vg_assert(u->tag1 == Lit16);
2935 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002936 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002937 break;
2938
2939 case CC2VAL:
2940 vg_assert(u->tag1 == RealReg);
2941 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00002942 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002943 synth_setb_reg ( u->val1, u->cond );
2944 break;
2945
sewardjde4a1d02002-03-22 01:27:54 +00002946 case FPU_R:
2947 case FPU_W:
2948 vg_assert(u->tag1 == Lit16);
2949 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00002950 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002951 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002952 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00002953 }
sewardjfa492d42002-12-08 18:20:01 +00002954 synth_fpu_regmem ( u->flags_r, u->flags_w,
2955 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00002956 u->val1 & 0xFF,
2957 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002958 break;
2959
2960 case FPU:
2961 vg_assert(u->tag1 == Lit16);
2962 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00002963 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002964 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00002965 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002966 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002967 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00002968 }
sewardjfa492d42002-12-08 18:20:01 +00002969 synth_fpu_no_mem ( u->flags_r, u->flags_w,
2970 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00002971 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00002972 break;
2973
2974 default:
sewardj1b7d8022002-11-30 12:35:42 +00002975 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00002976 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002977 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002978 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002979 }
njn4ba5a792002-09-30 10:23:54 +00002980 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00002981 } else {
njn25e49d8e72002-09-23 09:36:25 +00002982 VG_(printf)("\nError:\n"
2983 " unhandled opcode: %u. Perhaps "
2984 " VG_(needs).extended_UCode should be set?\n",
2985 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00002986 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00002987 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00002988 }
sewardjde4a1d02002-03-22 01:27:54 +00002989 }
2990
sewardjb5ff83e2002-12-01 19:40:49 +00002991 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002992 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002993 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002994 }
2995
njn25e49d8e72002-09-23 09:36:25 +00002996 /* Update UInstr histogram */
2997 vg_assert(u->opcode < 100);
2998 histogram[u->opcode].counts++;
2999 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003000}
3001
3002
3003/* Emit x86 for the ucode in cb, returning the address of the
3004 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003005UChar* VG_(emit_code) ( UCodeBlock* cb,
3006 Int* nbytes,
3007 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003008{
3009 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003010 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003011 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003012 Addr orig_eip, curr_eip;
3013
sewardjfa492d42002-12-08 18:20:01 +00003014 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003015
njn25e49d8e72002-09-23 09:36:25 +00003016 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003017
sewardj22854b92002-11-30 14:00:47 +00003018 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3019 zero. We have to do this regardless of whether we're t-chaining
3020 or not. */
sewardjfa492d42002-12-08 18:20:01 +00003021 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003022 VG_(emitB) (0xFF); /* decl */
3023 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3024 if (dis)
3025 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardjfa492d42002-12-08 18:20:01 +00003026 VG_(emit_jcondshort_delta)(False, CondNZ, 5+1);
sewardj22854b92002-11-30 14:00:47 +00003027 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3028 emit_ret();
3029
sewardjb5ff83e2002-12-01 19:40:49 +00003030 /* Set up running state. */
3031 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003032 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003033 curr_eip = cb->orig_eip;
3034 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3035 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003036 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003037 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003038 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003039 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003040
sewardjde4a1d02002-03-22 01:27:54 +00003041 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003042 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003043 if (!sane) {
3044 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003045 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003046 }
3047 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003048 emitUInstr( cb, i, regs_live_before,
3049 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003050 }
njn25e49d8e72002-09-23 09:36:25 +00003051 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003052 }
njn25e49d8e72002-09-23 09:36:25 +00003053 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003054 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3055 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003056
sewardj22854b92002-11-30 14:00:47 +00003057 if (j != NULL) {
3058 vg_assert(jumpidx <= VG_MAX_JUMPS);
3059 for(i = 0; i < jumpidx; i++)
3060 j[i] = jumps[i];
3061 }
3062
sewardjde4a1d02002-03-22 01:27:54 +00003063 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003064 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003065 *nbytes = emitted_code_used;
3066 return emitted_code;
3067}
3068
njn25e49d8e72002-09-23 09:36:25 +00003069#undef dis
3070
sewardjde4a1d02002-03-22 01:27:54 +00003071/*--------------------------------------------------------------------*/
3072/*--- end vg_from_ucode.c ---*/
3073/*--------------------------------------------------------------------*/