blob: 311ac9e95e943faeaa963aef27c62cc46a786c57 [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
sewardja2c5a732002-12-15 03:10:42 +0000257
258/* evidently unused */
259#if 0
sewardjfa492d42002-12-08 18:20:01 +0000260static void maybe_emit_get_eflags( void )
261{
262 if (eflags_state == UPD_Simd) {
263 eflags_state = UPD_Both;
264 emit_get_eflags();
265 }
266}
sewardja2c5a732002-12-15 03:10:42 +0000267#endif
sewardjfa492d42002-12-08 18:20:01 +0000268
269/* Call this before emitting each instruction.
270
271 Arguments are:
272 upds_simd_flags:
273 if true, this instruction updates the simulated %EFLAGS state,
274 otherwise it doesn't
275 use_flags: set of (real) flags the instruction uses
276 set_flags: set of (real) flags the instruction sets
277 */
278__inline__
279void VG_(new_emit) ( Bool upds_simd_flags,
280 FlagSet use_flags, FlagSet set_flags )
281{
282 Bool use, set;
283
284 use = use_flags != FlagsEmpty
285 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
286 set = set_flags != FlagsEmpty;
287
288 if (0)
289 VG_(printf)(
290 "new_emit: state=%d upds_simd_flags=%d use_flags=%x set_flags=%x\n",
291 eflags_state, upds_simd_flags, use_flags, set_flags);
292
293 if (upds_simd_flags) {
294 if (use && eflags_state == UPD_Simd) {
295 /* we need the CPU flags set, but they're not already */
296 eflags_state = UPD_Both;
297 emit_get_eflags();
298 }
299 if (set) {
300 /* if we're setting the flags, then the CPU will have the
301 only good copy */
302 eflags_state = UPD_Real;
303 }
304 } else {
305 /* presume that if non-simd code is using flags, it knows what
306 it's doing (ie, it just set up the flags). */
307 if (set) {
308 /* This instruction is going to trash the flags, so we'd
309 better save them away and say that they're only in the
310 simulated state. */
311 maybe_emit_put_eflags();
312 eflags_state = UPD_Simd;
313 }
314 }
315
sewardjde4a1d02002-03-22 01:27:54 +0000316 if (dis)
317 VG_(printf)("\t %4d: ", emitted_code_used );
318}
319
sewardjde4a1d02002-03-22 01:27:54 +0000320
321/*----------------------------------------------------*/
322/*--- Addressing modes ---*/
323/*----------------------------------------------------*/
324
325static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
326{
327 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
328}
329
330static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
331{
332 Int shift;
333 switch (scale) {
334 case 1: shift = 0; break;
335 case 2: shift = 1; break;
336 case 4: shift = 2; break;
337 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000338 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000339 }
340 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
341}
342
343static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
344{
345 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000346 VG_(emitB) ( mkModRegRM(0, reg, 5) );
347 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000348}
349
350static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
351{
352 /* (regmem), reg */
353 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000354 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000355 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000356 VG_(emitB) ( mkModRegRM(1, reg, 5) );
357 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000358 } else {
njn25e49d8e72002-09-23 09:36:25 +0000359 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000360 }
361}
362
njn25e49d8e72002-09-23 09:36:25 +0000363void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000364{
365 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000366 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000367 if (off < -128 || off > 127) {
368 /* Use a large offset */
369 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000370 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
371 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000372 } else {
373 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000374 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
375 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000376 }
377}
378
379static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
380 Int regindex, Int reg )
381{
382 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000383 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000384 if (off < -128 || off > 127) {
385 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000386 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
387 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
388 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000389 } else {
390 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000391 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
392 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
393 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000394 }
395}
396
njn25e49d8e72002-09-23 09:36:25 +0000397void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000398{
399 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000400 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000401}
402
403static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
404{
405 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000406 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000407}
408
409
410/*----------------------------------------------------*/
411/*--- Opcode translation ---*/
412/*----------------------------------------------------*/
413
414static __inline__ Int mkGrp1opcode ( Opcode opc )
415{
416 switch (opc) {
417 case ADD: return 0;
418 case OR: return 1;
419 case ADC: return 2;
420 case SBB: return 3;
421 case AND: return 4;
422 case SUB: return 5;
423 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000424 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000425 }
426}
427
sewardjfa492d42002-12-08 18:20:01 +0000428static __inline__ FlagSet nonshiftop_use(Opcode opc)
429{
430 switch(opc) {
431 case ADC:
432 case SBB:
433 return FlagC;
434
435 case ADD:
436 case OR:
437 case AND:
438 case SUB:
439 case XOR:
440 return FlagsEmpty;
441
442 default:
443 VG_(core_panic)("nonshiftop_use");
444 }
445}
446
447static __inline__ FlagSet nonshiftop_set(Opcode opc)
448{
449 switch(opc) {
450 case ADC:
451 case SBB:
452 case ADD:
453 case OR:
454 case AND:
455 case SUB:
456 case XOR:
457 return FlagsOSZACP;
458
459 default:
460 VG_(core_panic)("nonshiftop_set");
461 }
462}
463
sewardjde4a1d02002-03-22 01:27:54 +0000464static __inline__ Int mkGrp2opcode ( Opcode opc )
465{
466 switch (opc) {
467 case ROL: return 0;
468 case ROR: return 1;
469 case RCL: return 2;
470 case RCR: return 3;
471 case SHL: return 4;
472 case SHR: return 5;
473 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000474 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000475 }
476}
477
sewardjfa492d42002-12-08 18:20:01 +0000478static __inline__ FlagSet shiftop_use(Opcode opc)
479{
480 switch(opc) {
481 case ROR:
482 case ROL:
483 case SHL:
484 case SHR:
485 case SAR:
486 return FlagsEmpty;
487
488 case RCL:
489 case RCR:
490 return FlagC;
491
492 default:
493 VG_(core_panic)("shiftop_use");
494 }
495}
496
497static __inline__ FlagSet shiftop_set(Opcode opc)
498{
499 switch(opc) {
500 case ROR:
501 case ROL:
502 case RCL:
503 case RCR:
504 return FlagsOC;
505
506 case SHL:
507 case SHR:
508 case SAR:
509 return FlagsOSZACP;
510
511 default:
512 VG_(core_panic)("shiftop_set");
513 }
514}
515
sewardjde4a1d02002-03-22 01:27:54 +0000516static __inline__ Int mkGrp3opcode ( Opcode opc )
517{
518 switch (opc) {
519 case NOT: return 2;
520 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000521 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000522 }
523}
524
525static __inline__ Int mkGrp4opcode ( Opcode opc )
526{
527 switch (opc) {
528 case INC: return 0;
529 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000530 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000531 }
532}
533
534static __inline__ Int mkGrp5opcode ( Opcode opc )
535{
536 switch (opc) {
537 case CALLM: return 2;
538 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000539 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000540 }
541}
542
543static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
544{
545 switch (opc) {
546 case ADD: return 0x00;
547 case ADC: return 0x10;
548 case AND: return 0x20;
549 case XOR: return 0x30;
550 case OR: return 0x08;
551 case SBB: return 0x18;
552 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000553 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000554 }
555}
556
557/*----------------------------------------------------*/
558/*--- v-size (4, or 2 with OSO) insn emitters ---*/
559/*----------------------------------------------------*/
560
njn25e49d8e72002-09-23 09:36:25 +0000561void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000562{
sewardjfa492d42002-12-08 18:20:01 +0000563 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000564 if (sz == 2) VG_(emitB) ( 0x66 );
565 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
566 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000567 if (dis)
568 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
569 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
570}
571
njn25e49d8e72002-09-23 09:36:25 +0000572void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000573{
sewardjfa492d42002-12-08 18:20:01 +0000574 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000575 if (sz == 2) VG_(emitB) ( 0x66 );
576 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
577 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000578 if (dis)
579 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
580 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
581}
582
583static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
584{
sewardjfa492d42002-12-08 18:20:01 +0000585 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000586 if (sz == 2) VG_(emitB) ( 0x66 );
587 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000588 emit_amode_regmem_reg ( reg1, reg2 );
589 if (dis)
590 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
591 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
592}
593
594static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
595{
sewardjfa492d42002-12-08 18:20:01 +0000596 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000597 if (sz == 2) VG_(emitB) ( 0x66 );
598 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000599 emit_amode_regmem_reg ( reg2, reg1 );
600 if (dis)
601 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
602 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
603}
604
njn25e49d8e72002-09-23 09:36:25 +0000605void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000606{
sewardjfa492d42002-12-08 18:20:01 +0000607 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000608 if (sz == 2) VG_(emitB) ( 0x66 );
609 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
610 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000611 if (dis)
612 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
613 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
614}
615
sewardjfa492d42002-12-08 18:20:01 +0000616void VG_(emit_nonshiftopv_lit_reg) ( Bool upd_cc, Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000617{
sewardjfa492d42002-12-08 18:20:01 +0000618 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
619
njn25e49d8e72002-09-23 09:36:25 +0000620 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000621 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
622 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000623 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
624 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
625 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000626 } else {
njn25e49d8e72002-09-23 09:36:25 +0000627 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
628 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
629 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000630 }
631 if (dis)
632 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000633 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000634 lit, nameIReg(sz,reg));
635}
636
sewardjfa492d42002-12-08 18:20:01 +0000637void VG_(emit_nonshiftopv_lit_offregmem) ( Bool upd_cc, Int sz, Opcode opc, UInt lit,
638 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000639{
sewardjfa492d42002-12-08 18:20:01 +0000640 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
641 if (sz == 2) VG_(emitB) ( 0x66 );
642 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
643 /* short form OK */
644 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
645 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
646 VG_(emitB) ( lit & 0x000000FF );
647 } else {
648 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
649 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
650 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
651 }
652 if (dis)
653 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
654 VG_(name_UOpcode)(False,opc), nameISize(sz),
655 lit, off, nameIReg(sz,regmem));
656}
657
658void VG_(emit_shiftopv_lit_reg) ( Bool upd_cc, Int sz, Opcode opc, UInt lit, Int reg )
659{
660 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
661
njn25e49d8e72002-09-23 09:36:25 +0000662 if (sz == 2) VG_(emitB) ( 0x66 );
663 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
664 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
665 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000666 if (dis)
667 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000668 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000669 lit, nameIReg(sz,reg));
670}
671
sewardjfa492d42002-12-08 18:20:01 +0000672static void emit_shiftopv_cl_stack0 ( Bool upd_cc, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000673{
sewardjfa492d42002-12-08 18:20:01 +0000674 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000675 if (sz == 2) VG_(emitB) ( 0x66 );
676 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
677 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
678 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
679 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000680 if (dis)
681 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000682 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000683}
684
sewardjfa492d42002-12-08 18:20:01 +0000685static void emit_shiftopb_cl_stack0 ( Bool upd_cc, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000686{
sewardjfa492d42002-12-08 18:20:01 +0000687 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000688 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
689 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
690 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
691 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000692 if (dis)
693 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000694 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000695}
696
sewardjfa492d42002-12-08 18:20:01 +0000697static void emit_nonshiftopv_offregmem_reg ( Bool upd_cc, Int sz, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000698 Int off, Int areg, Int reg )
699{
sewardjfa492d42002-12-08 18:20:01 +0000700 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000701 if (sz == 2) VG_(emitB) ( 0x66 );
702 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
703 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000704 if (dis)
705 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000706 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000707 off, nameIReg(4,areg), nameIReg(sz,reg));
708}
709
sewardja2c5a732002-12-15 03:10:42 +0000710#if 0
711/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +0000712static void emit_nonshiftopv_reg_offregmem ( Bool upd_cc, Int sz, Opcode opc,
713 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000714{
sewardjfa492d42002-12-08 18:20:01 +0000715 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
716 if (sz == 2) VG_(emitB) ( 0x66 );
717 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
718 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
719 if (dis)
720 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
721 VG_(name_UOpcode)(False,opc), nameISize(sz),
722 nameIReg(sz,reg), off, nameIReg(4,areg));
723}
sewardja2c5a732002-12-15 03:10:42 +0000724#endif
sewardjfa492d42002-12-08 18:20:01 +0000725
726void VG_(emit_nonshiftopv_reg_reg) ( Bool upd_cc, Int sz, Opcode opc,
727 Int reg1, Int reg2 )
728{
729 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000730 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000731# if 0
732 /* Perfectly correct, but the GNU assembler uses the other form.
733 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000734 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
735 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000736# else
njn25e49d8e72002-09-23 09:36:25 +0000737 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000738 emit_amode_greg_ereg ( reg1, reg2 );
739# endif
740 if (dis)
741 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000742 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000743 nameIReg(sz,reg1), nameIReg(sz,reg2));
744}
745
njn25e49d8e72002-09-23 09:36:25 +0000746void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000747{
sewardjfa492d42002-12-08 18:20:01 +0000748 if (lit == 0 && eflags_state != UPD_Real) {
749 /* Only emit this for zeroing if it won't stomp flags */
750 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000751 return;
752 }
sewardjfa492d42002-12-08 18:20:01 +0000753 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000754 if (sz == 2) VG_(emitB) ( 0x66 );
755 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
756 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000757 if (dis)
758 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
759 nameISize(sz), lit, nameIReg(sz,reg));
760}
761
sewardjfa492d42002-12-08 18:20:01 +0000762void VG_(emit_unaryopv_reg) ( Bool upd_cc, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000763{
sewardjde4a1d02002-03-22 01:27:54 +0000764 switch (opc) {
765 case NEG:
sewardjfa492d42002-12-08 18:20:01 +0000766 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
767 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000768 VG_(emitB) ( 0xF7 );
769 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000770 if (dis)
771 VG_(printf)( "\n\t\tneg%c\t%s\n",
772 nameISize(sz), nameIReg(sz,reg));
773 break;
774 case NOT:
sewardjfa492d42002-12-08 18:20:01 +0000775 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsEmpty);
776 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000777 VG_(emitB) ( 0xF7 );
778 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000779 if (dis)
780 VG_(printf)( "\n\t\tnot%c\t%s\n",
781 nameISize(sz), nameIReg(sz,reg));
782 break;
783 case DEC:
sewardjfa492d42002-12-08 18:20:01 +0000784 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
785 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000786 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000787 if (dis)
788 VG_(printf)( "\n\t\tdec%c\t%s\n",
789 nameISize(sz), nameIReg(sz,reg));
790 break;
791 case INC:
sewardjfa492d42002-12-08 18:20:01 +0000792 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
793 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000794 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000795 if (dis)
796 VG_(printf)( "\n\t\tinc%c\t%s\n",
797 nameISize(sz), nameIReg(sz,reg));
798 break;
799 default:
njne427a662002-10-02 11:08:25 +0000800 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000801 }
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjfa492d42002-12-08 18:20:01 +0000806 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000807 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000808 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000809 } else {
810 vg_assert(sz == 4);
811 }
njn25e49d8e72002-09-23 09:36:25 +0000812 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000813 if (dis)
814 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
815}
816
njn25e49d8e72002-09-23 09:36:25 +0000817void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjfa492d42002-12-08 18:20:01 +0000819 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000820 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000821 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 } else {
823 vg_assert(sz == 4);
824 }
njn25e49d8e72002-09-23 09:36:25 +0000825 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000826 if (dis)
827 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
828}
829
njn25e49d8e72002-09-23 09:36:25 +0000830void VG_(emit_pushl_lit32) ( UInt int32 )
831{
sewardjfa492d42002-12-08 18:20:01 +0000832 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000833 VG_(emitB) ( 0x68 );
834 VG_(emitL) ( int32 );
835 if (dis)
836 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
837}
838
839void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +0000840{
841 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +0000842 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000843 VG_(emitB) ( 0x6A );
844 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +0000845 if (dis)
846 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
847}
848
sewardjfa492d42002-12-08 18:20:01 +0000849void VG_(emit_cmpl_zero_reg) ( Bool upd_cc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000850{
sewardjfa492d42002-12-08 18:20:01 +0000851 VG_(new_emit)(upd_cc, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +0000852 VG_(emitB) ( 0x83 );
853 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
854 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000855 if (dis)
856 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
857}
858
859static void emit_swapl_reg_ECX ( Int reg )
860{
sewardjfa492d42002-12-08 18:20:01 +0000861 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000862 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
863 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +0000864 if (dis)
865 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
866}
867
njn25e49d8e72002-09-23 09:36:25 +0000868void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000869{
sewardjfa492d42002-12-08 18:20:01 +0000870 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000871 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +0000872 if (dis)
873 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
874}
875
876static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
877{
sewardjfa492d42002-12-08 18:20:01 +0000878 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000879 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
880 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000881 if (dis)
882 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
883 nameIReg(4,reg2));
884}
885
886static void emit_bswapl_reg ( Int reg )
887{
sewardjfa492d42002-12-08 18:20:01 +0000888 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000889 VG_(emitB) ( 0x0F );
890 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +0000891 if (dis)
892 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
893}
894
895static void emit_movl_reg_reg ( Int regs, Int regd )
896{
sewardjfa492d42002-12-08 18:20:01 +0000897 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000898 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
899 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +0000900 if (dis)
901 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
902}
903
njn25e49d8e72002-09-23 09:36:25 +0000904void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +0000905{
sewardjfa492d42002-12-08 18:20:01 +0000906 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +0000907 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000908 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000909 } else {
910 vg_assert(sz == 4);
911 }
njn25e49d8e72002-09-23 09:36:25 +0000912 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
913 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
914 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000915 if (dis)
916 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
917 nameISize(sz), lit, off, nameIReg(4,memreg) );
918}
919
920
921/*----------------------------------------------------*/
922/*--- b-size (1 byte) instruction emitters ---*/
923/*----------------------------------------------------*/
924
925/* There is some doubt as to whether C6 (Grp 11) is in the
926 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +0000927void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
928{
sewardjfa492d42002-12-08 18:20:01 +0000929 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000930 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
931 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
932 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000933 if (dis)
934 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
935 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +0000936}
937
sewardjfa492d42002-12-08 18:20:01 +0000938static void emit_nonshiftopb_offregmem_reg ( Bool upd_cc, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000939 Int off, Int areg, Int reg )
940{
sewardj75f04932002-12-12 23:13:21 +0000941 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
943 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000944 if (dis)
945 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000946 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +0000947 nameIReg(1,reg));
948}
949
sewardjfa492d42002-12-08 18:20:01 +0000950static void emit_nonshiftopb_lit_offregmem ( Bool upd_cc, Opcode opc,
951 UInt lit, Int off, Int areg )
952{
953 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
954 VG_(emitB) ( 0x80 );
955 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
956 VG_(emitB) ( lit );
957 if (dis)
958 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
959 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
960}
961
sewardja2c5a732002-12-15 03:10:42 +0000962#if 0
963/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +0000964static void emit_nonshiftopb_reg_offregmem ( Bool upd_cc, Opcode opc,
965 Int off, Int areg, Int reg )
966{
967 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
968 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
969 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
970 if (dis)
971 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
972 VG_(name_UOpcode)(False,opc),
973 nameIReg(1,reg),
974 off, nameIReg(4,areg));
975}
sewardja2c5a732002-12-15 03:10:42 +0000976#endif
sewardjfa492d42002-12-08 18:20:01 +0000977
njn25e49d8e72002-09-23 09:36:25 +0000978void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000979{
980 /* Could do better when reg == %al. */
sewardjfa492d42002-12-08 18:20:01 +0000981 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000982 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
983 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000984 if (dis)
985 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
986 nameIReg(1,reg), off, nameIReg(4,areg));
987}
988
sewardjfa492d42002-12-08 18:20:01 +0000989static void emit_nonshiftopb_reg_reg ( Bool upd_cc, Opcode opc, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000990{
sewardjfa492d42002-12-08 18:20:01 +0000991 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000992 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
993 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000996 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000997 nameIReg(1,reg1), nameIReg(1,reg2));
998}
999
1000static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1001{
sewardjfa492d42002-12-08 18:20:01 +00001002 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001003 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001004 emit_amode_regmem_reg ( reg2, reg1 );
1005 if (dis)
1006 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1007 nameIReg(4,reg2));
1008}
1009
sewardjfa492d42002-12-08 18:20:01 +00001010static void emit_nonshiftopb_lit_reg ( Bool upd_cc, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001011{
sewardjfa492d42002-12-08 18:20:01 +00001012 VG_(new_emit)(upd_cc, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001013 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1014 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1015 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001016 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001017 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001018 lit, nameIReg(1,reg));
1019}
1020
sewardjfa492d42002-12-08 18:20:01 +00001021static void emit_shiftopb_lit_reg ( Bool upd_cc, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001022{
sewardjfa492d42002-12-08 18:20:01 +00001023 VG_(new_emit)(upd_cc, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001024 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1025 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1026 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (dis)
1028 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001029 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001030 lit, nameIReg(1,reg));
1031}
1032
sewardjfa492d42002-12-08 18:20:01 +00001033void VG_(emit_unaryopb_reg) ( Bool upd_cc, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001034{
sewardjde4a1d02002-03-22 01:27:54 +00001035 switch (opc) {
1036 case INC:
sewardjfa492d42002-12-08 18:20:01 +00001037 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001038 VG_(emitB) ( 0xFE );
1039 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001040 if (dis)
1041 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1042 break;
1043 case DEC:
sewardjfa492d42002-12-08 18:20:01 +00001044 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001045 VG_(emitB) ( 0xFE );
1046 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001047 if (dis)
1048 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1049 break;
1050 case NOT:
sewardjfa492d42002-12-08 18:20:01 +00001051 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001052 VG_(emitB) ( 0xF6 );
1053 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001054 if (dis)
1055 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1056 break;
1057 case NEG:
sewardjfa492d42002-12-08 18:20:01 +00001058 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0xF6 );
1060 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001061 if (dis)
1062 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1063 break;
1064 default:
njne427a662002-10-02 11:08:25 +00001065 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001066 }
1067}
1068
sewardjfa492d42002-12-08 18:20:01 +00001069void VG_(emit_testb_lit_reg) ( Bool upd_cc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001070{
sewardjfa492d42002-12-08 18:20:01 +00001071 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001072 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1073 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1074 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001075 if (dis)
1076 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1077}
1078
sewardjde4a1d02002-03-22 01:27:54 +00001079/*----------------------------------------------------*/
1080/*--- zero-extended load emitters ---*/
1081/*----------------------------------------------------*/
1082
njn25e49d8e72002-09-23 09:36:25 +00001083void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001084{
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 */
1087 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1090 off, nameIReg(4,regmem), nameIReg(4,reg));
1091}
1092
1093static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1094{
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) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001097 emit_amode_regmem_reg ( reg1, reg2 );
1098 if (dis)
1099 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1100 nameIReg(4,reg2));
1101}
1102
njn25e49d8e72002-09-23 09:36:25 +00001103void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001104{
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 */
1107 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001108 if (dis)
1109 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1110 off, nameIReg(4,areg), nameIReg(4,reg));
1111}
1112
1113static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1114{
sewardjfa492d42002-12-08 18:20:01 +00001115 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001116 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001117 emit_amode_regmem_reg ( reg1, reg2 );
1118 if (dis)
1119 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1120 nameIReg(4,reg2));
1121}
1122
1123/*----------------------------------------------------*/
1124/*--- FPU instruction emitters ---*/
1125/*----------------------------------------------------*/
1126
1127static void emit_get_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) ( 0xA5 ); /* frstor d32(%ebp) */
1132 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001133 if (dis)
1134 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1135}
1136
1137static void emit_put_fpu_state ( void )
1138{
1139 Int off = 4 * VGOFF_(m_fpustate);
sewardjfa492d42002-12-08 18:20:01 +00001140 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001141 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1142 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001143 if (dis)
1144 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1145}
1146
sewardjfa492d42002-12-08 18:20:01 +00001147static void emit_fpu_no_mem ( FlagSet uses_flags, FlagSet sets_flags,
1148 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001149 UChar second_byte )
1150{
sewardjfa492d42002-12-08 18:20:01 +00001151 VG_(new_emit)(True, uses_flags, sets_flags);
njn25e49d8e72002-09-23 09:36:25 +00001152 VG_(emitB) ( first_byte );
1153 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001154 if (dis)
1155 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1156 (UInt)first_byte, (UInt)second_byte );
1157}
1158
sewardjfa492d42002-12-08 18:20:01 +00001159static void emit_fpu_regmem ( FlagSet uses_flags, FlagSet sets_flags,
1160 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001161 UChar second_byte_masked,
1162 Int reg )
1163{
sewardjfa492d42002-12-08 18:20:01 +00001164 VG_(new_emit)(True, uses_flags, sets_flags);
njn25e49d8e72002-09-23 09:36:25 +00001165 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001166 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1167 if (dis)
1168 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1169 (UInt)first_byte, (UInt)second_byte_masked,
1170 nameIReg(4,reg) );
1171}
1172
1173
1174/*----------------------------------------------------*/
1175/*--- misc instruction emitters ---*/
1176/*----------------------------------------------------*/
1177
njn25e49d8e72002-09-23 09:36:25 +00001178void VG_(emit_call_reg) ( Int reg )
1179{
sewardjfa492d42002-12-08 18:20:01 +00001180 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001181 VG_(emitB) ( 0xFF ); /* Grp5 */
1182 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1183 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001184 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001185}
1186
sewardjfa492d42002-12-08 18:20:01 +00001187static void emit_call_star_EBP_off ( Bool upd_cc, Int byte_off, FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001188{
sewardjfa492d42002-12-08 18:20:01 +00001189 /* Used for helpers which expect to see Simd flags in Real flags */
1190 VG_(new_emit)(upd_cc, use_flag, set_flag);
1191
1192 if (byte_off < -128 || byte_off > 127) {
1193 VG_(emitB) ( 0xFF );
1194 VG_(emitB) ( 0x95 );
1195 VG_(emitL) ( byte_off );
1196 } else {
1197 VG_(emitB) ( 0xFF );
1198 VG_(emitB) ( 0x55 );
1199 VG_(emitB) ( byte_off );
1200 }
1201 if (dis)
1202 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001203}
1204
sewardja2c5a732002-12-15 03:10:42 +00001205#if 0
1206/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001207static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1208{
1209 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001210 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1212 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001213 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001214 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001215 if (dis)
1216 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1217 nameIReg(4,regmem));
1218}
sewardja2c5a732002-12-15 03:10:42 +00001219#endif
sewardjde4a1d02002-03-22 01:27:54 +00001220
njn25e49d8e72002-09-23 09:36:25 +00001221void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001222{
njne427a662002-10-02 11:08:25 +00001223 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001224 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1225 VG_(emitB) ( 0x8D );
1226 VG_(emitB) ( 0x64 );
1227 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001228 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001229 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001230 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001231}
1232
1233
1234static void emit_movb_AL_zeroESPmem ( void )
1235{
1236 /* movb %al, 0(%esp) */
1237 /* 88442400 movb %al, 0(%esp) */
sewardjfa492d42002-12-08 18:20:01 +00001238 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001239 VG_(emitB) ( 0x88 );
1240 VG_(emitB) ( 0x44 );
1241 VG_(emitB) ( 0x24 );
1242 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001243 if (dis)
1244 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1245}
1246
1247static void emit_movb_zeroESPmem_AL ( void )
1248{
1249 /* movb 0(%esp), %al */
1250 /* 8A442400 movb 0(%esp), %al */
sewardjfa492d42002-12-08 18:20:01 +00001251 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001252 VG_(emitB) ( 0x8A );
1253 VG_(emitB) ( 0x44 );
1254 VG_(emitB) ( 0x24 );
1255 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001256 if (dis)
1257 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1258}
1259
sewardja2113f92002-12-12 23:42:48 +00001260/* Jump target states */
1261#define TGT_UNDEF (1 << 16)
1262#define TGT_FORWARD (2 << 16)
1263#define TGT_BACKWARD (3 << 16)
1264
1265static inline Int tgt_state(Int tgt)
1266{
1267 return tgt & 0xffff0000;
1268}
1269
1270static inline Int tgt_addr(Int tgt)
1271{
1272 return tgt & 0x0000ffff;
1273}
1274
1275static inline Int mk_tgt(Int state, Int addr)
1276{
1277 vg_assert(state == TGT_UNDEF
1278 || state == TGT_FORWARD || state == TGT_BACKWARD);
1279 vg_assert((addr & 0xffff0000) == 0);
1280
1281 return state | addr;
1282}
1283
1284void VG_(init_target) ( Int *tgt )
1285{
1286 *tgt = TGT_UNDEF;
1287}
1288
1289void VG_(target_back) ( Int *tgt )
1290{
1291 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1292
1293 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1294}
1295
1296void VG_(target_forward) ( Int *tgt )
1297{
1298 Int delta;
1299
1300 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1301 tgt_state(*tgt) == TGT_UNDEF);
1302
1303 if (tgt_state(*tgt) == TGT_UNDEF)
1304 return; /* target not used */
1305
1306 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1307 vg_assert(delta >= -128 && delta <= 127);
1308 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001309 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001310 emitted_code[tgt_addr(*tgt)] = delta;
1311 if (dis)
1312 VG_(printf)("(target to jump site %d; delta: %d)\n",
1313 tgt_addr(*tgt), delta);
1314}
1315
1316void VG_(emit_target_delta) ( Int *tgt )
1317{
1318 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1319 tgt_state(*tgt) == TGT_BACKWARD);
1320
1321 if (tgt_state(*tgt) == TGT_UNDEF) {
1322 /* forward jump */
1323 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1324 VG_(emitB) (0x00);
1325 } else {
1326 /* backward jump */
1327 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1328 vg_assert(delta >= -128 && delta <= 127);
1329 VG_(emitB) (delta);
1330 }
1331}
1332
sewardjde4a1d02002-03-22 01:27:54 +00001333
1334/* Emit a jump short with an 8-bit signed offset. Note that the
1335 offset is that which should be added to %eip once %eip has been
1336 advanced over this insn. */
sewardjfa492d42002-12-08 18:20:01 +00001337void VG_(emit_jcondshort_delta) ( Bool simd, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001338{
1339 vg_assert(delta >= -128 && delta <= 127);
sewardjfa492d42002-12-08 18:20:01 +00001340 VG_(new_emit)(simd, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001341 VG_(emitB) ( 0x70 + (UInt)cond );
1342 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001343 if (dis)
1344 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
1345 VG_(nameCondcode)(cond), delta );
1346}
1347
sewardja2113f92002-12-12 23:42:48 +00001348/* Same as above, but defers emitting the delta */
1349void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1350{
1351 VG_(new_emit)(simd, FlagsOSZCP, False);
1352 VG_(emitB) ( 0x70 + (UInt)cond );
1353 VG_(emit_target_delta) (tgt);
1354 if (dis)
1355 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
1356 VG_(nameCondcode)(cond), tgt_addr(*tgt) );
1357}
1358
1359
1360
sewardjde4a1d02002-03-22 01:27:54 +00001361static void emit_setb_reg ( Int reg, Condcode cond )
1362{
sewardjfa492d42002-12-08 18:20:01 +00001363 VG_(new_emit)(True, FlagsOSZCP, False);
njn25e49d8e72002-09-23 09:36:25 +00001364 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1365 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001366 if (dis)
1367 VG_(printf)("\n\t\tset%s %s\n",
1368 VG_(nameCondcode)(cond), nameIReg(1,reg));
1369}
1370
1371static void emit_ret ( void )
1372{
sewardjfa492d42002-12-08 18:20:01 +00001373 maybe_emit_put_eflags(); /* make sure flags are stored */
1374 VG_(new_emit)(False, False, False);
njn25e49d8e72002-09-23 09:36:25 +00001375 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001376 if (dis)
1377 VG_(printf)("\n\t\tret\n");
1378}
1379
sewardj22854b92002-11-30 14:00:47 +00001380/* Predicate used in sanity checks elsewhere - returns true if any
1381 jump-site is an actual chained jump */
1382Bool VG_(is_chained_jumpsite)(Addr a)
1383{
1384 UChar *cp = (UChar *)a;
1385
1386 return (*cp == 0xE9); /* 0xE9 -- jmp */
1387}
1388
sewardj83f11862002-12-01 02:07:08 +00001389static
1390Bool is_fresh_jumpsite(UChar *cp)
1391{
1392 return
1393 cp[0] == 0x0F && /* UD2 */
1394 cp[1] == 0x0B &&
1395 cp[2] == 0x0F && /* UD2 */
1396 cp[3] == 0x0B &&
1397 cp[4] == 0x90; /* NOP */
1398}
1399
sewardj22854b92002-11-30 14:00:47 +00001400/* Predicate used in sanity checks elsewhere - returns true if all
1401 jump-sites are calls to VG_(patch_me) */
1402Bool VG_(is_unchained_jumpsite)(Addr a)
1403{
1404 UChar *cp = (UChar *)a;
1405 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1406 Int idelta;
1407
1408 if (*cp++ != 0xE8) /* 0xE8 == call */
1409 return False;
1410
1411 idelta = (*cp++) << 0;
1412 idelta |= (*cp++) << 8;
1413 idelta |= (*cp++) << 16;
1414 idelta |= (*cp++) << 24;
1415
1416 return idelta == delta;
1417}
1418
1419/* Return target address for a direct jmp */
1420Addr VG_(get_jmp_dest)(Addr a)
1421{
1422 Int delta;
1423 UChar *cp = (UChar *)a;
1424
1425 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1426 return 0;
1427
1428 delta = (*cp++) << 0;
1429 delta |= (*cp++) << 8;
1430 delta |= (*cp++) << 16;
1431 delta |= (*cp++) << 24;
1432
1433 return a + VG_PATCHME_JMPSZ + delta;
1434}
1435
1436/* unchain a BB by generating a call to VG_(patch_me) */
1437void VG_(unchain_jumpsite)(Addr a)
1438{
1439 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1440 UChar *cp = (UChar *)a;
1441
1442 if (VG_(is_unchained_jumpsite)(a))
1443 return; /* don't write unnecessarily */
1444
sewardj83f11862002-12-01 02:07:08 +00001445 if (!is_fresh_jumpsite(cp))
1446 VG_(bb_dechain_count)++; /* update stats */
1447
sewardj22854b92002-11-30 14:00:47 +00001448 *cp++ = 0xE8; /* call */
1449 *cp++ = (delta >> 0) & 0xff;
1450 *cp++ = (delta >> 8) & 0xff;
1451 *cp++ = (delta >> 16) & 0xff;
1452 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001453}
1454
1455/* This doesn't actually generate a call to VG_(patch_me), but
1456 reserves enough space in the instruction stream for it to happen
1457 and records the offset into the jump table. This is because call
1458 is a relative jump, and so will be affected when this code gets
1459 moved about. The translation table will "unchain" this basic block
1460 on insertion (with VG_(unchain_BB)()), and thereby generate a
1461 proper call instruction. */
1462static void emit_call_patchme( void )
1463{
1464 vg_assert(VG_PATCHME_CALLSZ == 5);
1465
sewardjfa492d42002-12-08 18:20:01 +00001466 maybe_emit_put_eflags(); /* save flags before end of BB */
1467 VG_(new_emit)(False, False, False);
sewardj22854b92002-11-30 14:00:47 +00001468
1469 if (jumpidx >= VG_MAX_JUMPS) {
1470 /* If there too many jumps in this basic block, fall back to
1471 dispatch loop. We still need to keep it the same size as the
1472 call sequence. */
1473 VG_(emitB) ( 0xC3 ); /* ret */
1474 VG_(emitB) ( 0x90 ); /* nop */
1475 VG_(emitB) ( 0x90 ); /* nop */
1476 VG_(emitB) ( 0x90 ); /* nop */
1477 VG_(emitB) ( 0x90 ); /* nop */
1478
1479 if (dis)
1480 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1481
1482 if (0 && VG_(clo_verbosity))
1483 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1484 } else {
1485 jumps[jumpidx++] = emitted_code_used;
1486
1487 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1488 VG_(emitB) ( 0x0B );
1489 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1490 VG_(emitB) ( 0x0B );
1491 VG_(emitB) ( 0x90 ); /* NOP */
1492
1493 if (dis)
1494 VG_(printf)("\n\t\tud2; ud2; nop\n");
1495 }
1496}
1497
njn25e49d8e72002-09-23 09:36:25 +00001498void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001499{
sewardjfa492d42002-12-08 18:20:01 +00001500 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001501 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001502 if (dis)
1503 VG_(printf)("\n\t\tpushal\n");
1504}
1505
njn25e49d8e72002-09-23 09:36:25 +00001506void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001507{
sewardjfa492d42002-12-08 18:20:01 +00001508 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001509 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001510 if (dis)
1511 VG_(printf)("\n\t\tpopal\n");
1512}
1513
1514static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1515{
sewardjfa492d42002-12-08 18:20:01 +00001516 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001517 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1518 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001519 if (dis)
1520 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1521 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1522}
1523
1524static void emit_lea_sib_reg ( UInt lit, Int scale,
1525 Int regbase, Int regindex, Int reg )
1526{
sewardjfa492d42002-12-08 18:20:01 +00001527 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001528 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001529 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1530 if (dis)
1531 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1532 lit, nameIReg(4,regbase),
1533 nameIReg(4,regindex), scale,
1534 nameIReg(4,reg) );
1535}
1536
njn25e49d8e72002-09-23 09:36:25 +00001537void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001538{
sewardjfa492d42002-12-08 18:20:01 +00001539 VG_(new_emit)(True, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001540 VG_(emitB) ( 0x0F );
1541 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001542 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1543 if (dis)
1544 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1545}
1546
1547/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001548/*--- Helper offset -> addr translation ---*/
1549/*----------------------------------------------------*/
1550
1551/* Finds the baseBlock offset of a skin-specified helper.
1552 * Searches through compacts first, then non-compacts. */
1553Int VG_(helper_offset)(Addr a)
1554{
1555 Int i;
1556
1557 for (i = 0; i < VG_(n_compact_helpers); i++)
1558 if (VG_(compact_helper_addrs)[i] == a)
1559 return VG_(compact_helper_offsets)[i];
1560 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1561 if (VG_(noncompact_helper_addrs)[i] == a)
1562 return VG_(noncompact_helper_offsets)[i];
1563
1564 /* Shouldn't get here */
1565 VG_(printf)(
1566 "\nCouldn't find offset of helper from its address (%p).\n"
1567 "A helper function probably used hasn't been registered?\n\n", a);
1568
1569 VG_(printf)(" compact helpers: ");
1570 for (i = 0; i < VG_(n_compact_helpers); i++)
1571 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1572
1573 VG_(printf)("\n non-compact helpers: ");
1574 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1575 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1576
1577 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001578 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001579}
1580
1581/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001582/*--- Instruction synthesisers ---*/
1583/*----------------------------------------------------*/
1584
1585static Condcode invertCondition ( Condcode cond )
1586{
1587 return (Condcode)(1 ^ (UInt)cond);
1588}
1589
1590
1591/* Synthesise a call to *baseBlock[offset], ie,
1592 call * (4 x offset)(%ebp).
1593*/
sewardjfa492d42002-12-08 18:20:01 +00001594void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
1595 Bool upd_cc, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001596{
1597 vg_assert(word_offset >= 0);
1598 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001599 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001600 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001601 }
1602 emit_call_star_EBP_off ( upd_cc, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001603}
1604
njn25e49d8e72002-09-23 09:36:25 +00001605static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001606{
njn25e49d8e72002-09-23 09:36:25 +00001607 if (src != dst) {
1608 VG_(emit_movv_reg_reg) ( 4, src, dst );
1609 ccall_arg_setup_instrs++;
1610 }
njn6431be72002-07-28 09:53:34 +00001611}
njn25e49d8e72002-09-23 09:36:25 +00001612
1613/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1614static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1615{
1616 if (RealReg == tag) {
1617 maybe_emit_movl_reg_reg ( litOrReg, reg );
1618 } else if (Literal == tag) {
1619 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1620 ccall_arg_setup_instrs++;
1621 }
1622 else
njne427a662002-10-02 11:08:25 +00001623 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001624}
1625
1626static
1627void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1628{
1629 if (R_EAX == reg1) {
1630 VG_(emit_swapl_reg_EAX) ( reg2 );
1631 } else if (R_EAX == reg2) {
1632 VG_(emit_swapl_reg_EAX) ( reg1 );
1633 } else {
1634 emit_swapl_reg_reg ( reg1, reg2 );
1635 }
1636 ccall_arg_setup_instrs++;
1637}
1638
1639static
1640void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1641{
1642 if (dst1 != src2) {
1643 maybe_emit_movl_reg_reg ( src1, dst1 );
1644 maybe_emit_movl_reg_reg ( src2, dst2 );
1645
1646 } else if (dst2 != src1) {
1647 maybe_emit_movl_reg_reg ( src2, dst2 );
1648 maybe_emit_movl_reg_reg ( src1, dst1 );
1649
1650 } else {
1651 /* swap to break cycle */
1652 emit_swapl_arg_regs ( dst1, dst2 );
1653 }
1654}
1655
1656static
1657void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1658 UInt dst1, UInt dst2, UInt dst3)
1659{
1660 if (dst1 != src2 && dst1 != src3) {
1661 maybe_emit_movl_reg_reg ( src1, dst1 );
1662 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1663
1664 } else if (dst2 != src1 && dst2 != src3) {
1665 maybe_emit_movl_reg_reg ( src2, dst2 );
1666 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1667
1668 } else if (dst3 != src1 && dst3 != src2) {
1669 maybe_emit_movl_reg_reg ( src3, dst3 );
1670 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1671
1672 } else {
1673 /* break cycle */
1674 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1675 emit_swapl_arg_regs ( dst1, dst2 );
1676 emit_swapl_arg_regs ( dst1, dst3 );
1677
1678 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1679 emit_swapl_arg_regs ( dst1, dst3 );
1680 emit_swapl_arg_regs ( dst1, dst2 );
1681
1682 } else {
njne427a662002-10-02 11:08:25 +00001683 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001684 }
1685 }
1686}
1687
1688static
1689void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1690 UInt src1, UInt src2,
1691 UInt dst1, UInt dst2)
1692{
1693 /* If either are lits, order doesn't matter */
1694 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1695 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1696 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1697
1698 } else {
1699 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1700 }
1701}
1702
1703static
1704void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1705 UInt src1, UInt src2, UInt src3,
1706 UInt dst1, UInt dst2, UInt dst3)
1707{
1708 // SSS: fix this eventually -- make STOREV use two RealRegs?
1709 /* Not supporting literals for 3-arg C functions -- they're only used
1710 by STOREV which has 2 args */
1711 vg_assert(RealReg == tagv[src1] &&
1712 RealReg == tagv[src2] &&
1713 RealReg == tagv[src3]);
1714 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1715 dst1, dst2, dst3 );
1716}
1717
1718/* Synthesise a call to a C function `fn' (which must be registered in
1719 baseBlock) doing all the reg saving and arg handling work.
1720
1721 WARNING: a UInstr should *not* be translated with synth_ccall followed
1722 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1723 such behaviour and everything will fall over.
1724 */
1725void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1726 Tag tagv[], Int ret_reg,
1727 RRegSet regs_live_before, RRegSet regs_live_after )
1728{
1729 Int i;
1730 Int stack_used = 0;
1731 Bool preserve_eax, preserve_ecx, preserve_edx;
1732
1733 vg_assert(0 <= regparms_n && regparms_n <= 3);
1734
1735 ccalls++;
1736
1737 /* If %e[acd]x is live before and after the C call, save/restore it.
1738 Unless the return values clobbers the reg; in this case we must not
1739 save/restore the reg, because the restore would clobber the return
1740 value. (Before and after the UInstr really constitute separate live
1741 ranges, but you miss this if you don't consider what happens during
1742 the UInstr.) */
1743# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001744 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1745 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001746 ret_reg != realReg)
1747
1748 preserve_eax = PRESERVE_REG(R_EAX);
1749 preserve_ecx = PRESERVE_REG(R_ECX);
1750 preserve_edx = PRESERVE_REG(R_EDX);
1751
1752# undef PRESERVE_REG
1753
1754 /* Save caller-save regs as required */
1755 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1756 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1757 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1758
1759 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1760 is the number of args passed in regs (maximum 3 for GCC on x86). */
1761
1762 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001763
njn25e49d8e72002-09-23 09:36:25 +00001764 /* First push stack args (RealRegs or Literals) in reverse order. */
1765 for (i = argc-1; i >= regparms_n; i--) {
1766 switch (tagv[i]) {
1767 case RealReg:
1768 VG_(emit_pushv_reg) ( 4, argv[i] );
1769 break;
1770 case Literal:
1771 /* Use short form of pushl if possible. */
1772 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1773 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1774 else
1775 VG_(emit_pushl_lit32)( argv[i] );
1776 break;
1777 default:
1778 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001779 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001780 }
1781 stack_used += 4;
1782 ccall_arg_setup_instrs++;
1783 }
njn6431be72002-07-28 09:53:34 +00001784
njn25e49d8e72002-09-23 09:36:25 +00001785 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1786 If moving values between registers, be careful not to clobber any on
1787 the way. Happily we can use xchgl to swap registers.
1788 */
1789 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001790
njn25e49d8e72002-09-23 09:36:25 +00001791 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1792 case 3:
1793 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1794 R_EAX, R_EDX, R_ECX );
1795 break;
njn6431be72002-07-28 09:53:34 +00001796
njn25e49d8e72002-09-23 09:36:25 +00001797 /* Less-tricky. Args passed in %eax and %edx. */
1798 case 2:
1799 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1800 break;
1801
1802 /* Easy. Just move arg1 into %eax (if not already in there). */
1803 case 1:
1804 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1805 break;
1806
1807 case 0:
1808 break;
1809
1810 default:
njne427a662002-10-02 11:08:25 +00001811 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001812 }
1813
sewardjfa492d42002-12-08 18:20:01 +00001814 /* Call the function - may trash all flags */
1815 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00001816
1817 /* Clear any args from stack */
1818 if (0 != stack_used) {
1819 VG_(emit_add_lit_to_esp) ( stack_used );
1820 ccall_stack_clears++;
1821 }
1822
1823 /* Move return value into ret_reg if necessary and not already there */
1824 if (INVALID_REALREG != ret_reg) {
1825 ccall_retvals++;
1826 if (R_EAX != ret_reg) {
1827 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1828 ccall_retval_movs++;
1829 }
1830 }
1831
1832 /* Restore live caller-save regs as required */
1833 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1834 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1835 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001836}
sewardjde4a1d02002-03-22 01:27:54 +00001837
sewardj2e93c502002-04-12 11:12:52 +00001838static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001839{
sewardj2e93c502002-04-12 11:12:52 +00001840 switch (jmpkind) {
1841 case JmpBoring:
1842 break;
sewardj2e93c502002-04-12 11:12:52 +00001843 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001844 break;
1845 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001846 break;
1847 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001848 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001849 break;
1850 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001851 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001852 break;
1853 default:
njne427a662002-10-02 11:08:25 +00001854 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001855 }
1856}
1857
1858/* Jump to the next translation, by loading its original addr into
1859 %eax and returning to the scheduler. Signal special requirements
1860 by loading a special value into %ebp first.
1861*/
1862static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1863{
sewardjfa492d42002-12-08 18:20:01 +00001864 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00001865 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001866 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001867 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001868 emit_ret();
1869}
1870
sewardj22854b92002-11-30 14:00:47 +00001871static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00001872
1873/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001874static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001875{
sewardjfa492d42002-12-08 18:20:01 +00001876 maybe_emit_put_eflags(); /* save flags here */
1877
njn25e49d8e72002-09-23 09:36:25 +00001878 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00001879
1880 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
1881 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
1882 emit_call_patchme();
1883 } else {
1884 load_ebp_from_JmpKind ( jmpkind );
1885 emit_ret();
1886 }
sewardjde4a1d02002-03-22 01:27:54 +00001887}
1888
1889
sewardj2370f3b2002-11-30 15:01:01 +00001890static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
1891static void synth_nonshiftop_lit_reg ( Bool upd_cc,
1892 Opcode opcode, Int size,
1893 UInt lit, Int reg );
1894
sewardjfa492d42002-12-08 18:20:01 +00001895static void synth_jcond_lit ( Condcode cond,
1896 Addr addr,
1897 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00001898{
sewardj2370f3b2002-11-30 15:01:01 +00001899 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00001900 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00001901 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00001902
sewardja2113f92002-12-12 23:42:48 +00001903 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00001904 VG_(init_target)(&tgt2);
1905 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00001906
sewardjfa492d42002-12-08 18:20:01 +00001907 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
1908 if need be */
1909 maybe_emit_put_eflags();
1910 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
1911
1912 if (eflags_state == UPD_Both) {
1913 /* The flags are already set up, so we just use them as is. */
1914 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00001915 cond = invertCondition(cond);
1916 } else {
sewardj75f04932002-12-12 23:13:21 +00001917 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00001918
1919 /* The simd state contains the most recent version, so we emit a
1920 sequence to calculate the relevant condition directly out of
1921 the simd flags. This is much cheaper (on P3/P4/Athlon) than
1922 copying them back to the real flags via popf. Notice that
1923 some of these sequences trash %eax, but that should be free
1924 now since this is the end of a bb and therefore all regs are
1925 dead. */
1926 simd = False;
1927
1928 switch (cond) {
1929
sewardjbb6c1182002-12-12 23:54:47 +00001930 case CondLE: /* Z || S != O -> S || !P */
1931 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00001932 vg_assert(eax_trashable);
1933
1934 VG_(emit_movv_offregmem_reg)
1935 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1936 /* eax == %EFLAGS */
1937
sewardjbb6c1182002-12-12 23:54:47 +00001938 VG_(emit_nonshiftopv_lit_reg)
1939 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
1940 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00001941
sewardjbb6c1182002-12-12 23:54:47 +00001942 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
1943 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00001944
sewardjbb6c1182002-12-12 23:54:47 +00001945 if (cond == CondLE) {
1946 /* test Z */
1947 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
1948 /* test OF != SF */
1949 cond = CondP;
1950 } else {
1951 /* test Z */
1952 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
1953 /* test OF == SF */
1954 cond = CondNP;
1955 }
sewardj2370f3b2002-11-30 15:01:01 +00001956 break;
1957
sewardjfa492d42002-12-08 18:20:01 +00001958 case CondL:
1959 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00001960 vg_assert(eax_trashable);
1961
1962 VG_(emit_movv_offregmem_reg)
1963 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
1964 /* eax == %EFLAGS */
1965
sewardj75f04932002-12-12 23:13:21 +00001966 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
1967 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00001968
sewardj75f04932002-12-12 23:13:21 +00001969 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
1970 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00001971
sewardj75f04932002-12-12 23:13:21 +00001972 if (cond == CondL) cond = CondP; else cond = CondNP;
1973 break;
sewardjfa492d42002-12-08 18:20:01 +00001974
1975 case CondB:
1976 case CondNB:
1977 mask = EFlagC; goto simple; /* C=1 */
1978
1979 case CondZ:
1980 case CondNZ:
1981 mask = EFlagZ; goto simple; /* Z=1 */
1982
1983 case CondBE:
1984 case CondNBE:
1985 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
1986
1987 case CondS:
1988 case CondNS:
1989 mask = EFlagS; goto simple; /* S=1 */
1990
1991 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00001992 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00001993 mask = EFlagP; goto simple; /* P=1 */
1994
sewardj39542072002-12-09 22:44:00 +00001995 case CondO:
1996 case CondNO:
1997 mask = EFlagO; goto simple; /* O=1 */
1998
sewardjfa492d42002-12-08 18:20:01 +00001999 default:
2000 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
2001 (Int)cond, VG_(nameCondcode)(cond) );
2002 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2003
2004 simple:
2005 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002006 if ((mask & 0xff) == mask) {
2007 VG_(emitB) ( 0xF6 ); /* Grp3 */
2008 VG_(emit_amode_offregmem_reg)(
2009 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2010 VG_(emitB) (mask);
2011 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002012 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002013 mask, VGOFF_(m_eflags) * 4);
2014 } else {
sewardjfa492d42002-12-08 18:20:01 +00002015 /* all cond codes are in lower 16 bits */
2016 vg_assert((mask & 0xffff) == mask);
2017
2018 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002019 VG_(emitB) ( 0xF7 );
2020 VG_(emit_amode_offregmem_reg)(
2021 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002022 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002023 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002024 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002025 mask, VGOFF_(m_eflags) * 4);
2026 }
2027
sewardj75f04932002-12-12 23:13:21 +00002028 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002029 break;
2030 }
2031 }
2032
sewardja2113f92002-12-12 23:42:48 +00002033 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002034
2035 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002036 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002037
2038 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002039 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002040}
2041
2042
sewardj2370f3b2002-11-30 15:01:01 +00002043
sewardjde4a1d02002-03-22 01:27:54 +00002044static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2045{
sewardja2113f92002-12-12 23:42:48 +00002046 Int tgt;
2047
2048 VG_(init_target)(&tgt);
2049
sewardjfa492d42002-12-08 18:20:01 +00002050 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002051
2052 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002053 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002054
2055 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002056}
2057
2058
2059static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2060{
2061 /* Load the zero-extended literal into reg, at size l,
2062 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002063 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002064}
2065
2066
2067static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2068{
2069 switch (size) {
2070 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2071 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2072 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002073 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002074 }
2075}
2076
2077
2078static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2079{
2080 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002081 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2082 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2083 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002084 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002085 }
2086}
2087
2088
2089static void synth_mov_reg_offregmem ( Int size, Int reg,
2090 Int off, Int areg )
2091{
2092 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002093 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2094 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002095 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002096 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002097 }
2098 else {
njn25e49d8e72002-09-23 09:36:25 +00002099 VG_(emit_swapl_reg_EAX) ( reg );
2100 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2101 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002102 }
2103 break;
njne427a662002-10-02 11:08:25 +00002104 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002105 }
2106}
2107
2108
2109static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2110{
2111 Int s1;
2112 switch (size) {
2113 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2114 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2115 case 1: if (reg1 < 4) {
2116 emit_movb_reg_regmem ( reg1, reg2 );
2117 }
2118 else {
2119 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2120 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2121 emit_swapl_reg_reg ( s1, reg1 );
2122 emit_movb_reg_regmem ( s1, reg2 );
2123 emit_swapl_reg_reg ( s1, reg1 );
2124 }
2125 break;
njne427a662002-10-02 11:08:25 +00002126 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002127 }
2128}
2129
2130
sewardj478335c2002-10-05 02:44:47 +00002131static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002132 Opcode opcode, Int size,
2133 Int reg )
2134{
2135 /* NB! opcode is a uinstr opcode, not an x86 one! */
2136 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002137 case 4: VG_(emit_unaryopv_reg) ( upd_cc, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002138 break;
sewardjfa492d42002-12-08 18:20:01 +00002139 case 2: VG_(emit_unaryopv_reg) ( upd_cc, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002140 break;
2141 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002142 VG_(emit_unaryopb_reg) ( upd_cc, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002143 } else {
njn25e49d8e72002-09-23 09:36:25 +00002144 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002145 VG_(emit_unaryopb_reg) ( upd_cc, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002146 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002147 }
2148 break;
njne427a662002-10-02 11:08:25 +00002149 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002150 }
2151}
2152
2153
2154
sewardj478335c2002-10-05 02:44:47 +00002155static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002156 Opcode opcode, Int size,
2157 Int reg1, Int reg2 )
2158{
2159 /* NB! opcode is a uinstr opcode, not an x86 one! */
2160 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002161 case 4: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002162 break;
sewardjfa492d42002-12-08 18:20:01 +00002163 case 2: VG_(emit_nonshiftopv_reg_reg) ( upd_cc, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002164 break;
2165 case 1: { /* Horrible ... */
2166 Int s1, s2;
2167 /* Choose s1 and s2 to be x86 regs which we can talk about the
2168 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2169 sure s1 != s2 and that neither of them equal either reg1 or
2170 reg2. Then use them as temporaries to make things work. */
2171 if (reg1 < 4 && reg2 < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002172 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002173 break;
2174 }
2175 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2176 if (reg1 >= 4 && reg2 < 4) {
2177 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002178 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002179 emit_swapl_reg_reg ( reg1, s1 );
2180 break;
2181 }
2182 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2183 if (reg1 < 4 && reg2 >= 4) {
2184 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002185 emit_nonshiftopb_reg_reg(upd_cc, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002186 emit_swapl_reg_reg ( reg2, s2 );
2187 break;
2188 }
2189 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2190 emit_swapl_reg_reg ( reg1, s1 );
2191 emit_swapl_reg_reg ( reg2, s2 );
sewardjfa492d42002-12-08 18:20:01 +00002192 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002193 emit_swapl_reg_reg ( reg1, s1 );
2194 emit_swapl_reg_reg ( reg2, s2 );
2195 break;
2196 }
2197 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2198 emit_swapl_reg_reg ( reg1, s1 );
sewardjfa492d42002-12-08 18:20:01 +00002199 emit_nonshiftopb_reg_reg(upd_cc, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002200 emit_swapl_reg_reg ( reg1, s1 );
2201 break;
2202 }
njne427a662002-10-02 11:08:25 +00002203 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002204 }
njne427a662002-10-02 11:08:25 +00002205 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002206 }
2207}
2208
sewardja2c5a732002-12-15 03:10:42 +00002209#if 0
2210/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002211static void synth_nonshiftop_reg_offregmem (
2212 Bool upd_cc,
2213 Opcode opcode, Int size,
2214 Int off, Int areg, Int reg )
2215{
2216 switch (size) {
2217 case 4:
2218 emit_nonshiftopv_reg_offregmem ( upd_cc, 4, opcode, off, areg, reg );
2219 break;
2220 case 2:
2221 emit_nonshiftopv_reg_offregmem ( upd_cc, 2, opcode, off, areg, reg );
2222 break;
2223 case 1:
2224 if (reg < 4) {
2225 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, reg );
2226 } else {
2227 VG_(emit_swapl_reg_EAX) ( reg );
2228 emit_nonshiftopb_reg_offregmem ( upd_cc, opcode, off, areg, R_AL );
2229 VG_(emit_swapl_reg_EAX) ( reg );
2230 }
2231 break;
2232 default:
2233 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2234 }
2235}
sewardja2c5a732002-12-15 03:10:42 +00002236#endif
sewardjfa492d42002-12-08 18:20:01 +00002237
sewardjde4a1d02002-03-22 01:27:54 +00002238static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002239 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002240 Opcode opcode, Int size,
2241 Int off, Int areg, Int reg )
2242{
2243 switch (size) {
2244 case 4:
sewardjfa492d42002-12-08 18:20:01 +00002245 emit_nonshiftopv_offregmem_reg ( upd_cc, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002246 break;
2247 case 2:
sewardjfa492d42002-12-08 18:20:01 +00002248 emit_nonshiftopv_offregmem_reg ( upd_cc, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002249 break;
2250 case 1:
2251 if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002252 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002253 } else {
njn25e49d8e72002-09-23 09:36:25 +00002254 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002255 emit_nonshiftopb_offregmem_reg ( upd_cc, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002256 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002257 }
2258 break;
2259 default:
njne427a662002-10-02 11:08:25 +00002260 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002261 }
2262}
2263
2264
sewardj478335c2002-10-05 02:44:47 +00002265static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002266 Opcode opcode, Int size,
2267 UInt lit, Int reg )
2268{
2269 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002270 case 4: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002271 break;
sewardjfa492d42002-12-08 18:20:01 +00002272 case 2: VG_(emit_nonshiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002273 break;
2274 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002275 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002276 } else {
njn25e49d8e72002-09-23 09:36:25 +00002277 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002278 emit_nonshiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002279 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002280 }
2281 break;
njne427a662002-10-02 11:08:25 +00002282 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002283 }
2284}
2285
sewardjfa492d42002-12-08 18:20:01 +00002286static void synth_nonshiftop_lit_offregmem ( Bool upd_cc,
2287 Opcode opcode, Int size,
2288 UInt lit, Int off, Int regmem )
2289{
2290 switch (size) {
2291 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 4, opcode, lit, off, regmem );
2292 break;
2293 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( upd_cc, 2, opcode, lit, off, regmem );
2294 break;
2295 case 1: emit_nonshiftopb_lit_offregmem ( upd_cc, opcode, lit, off, regmem );
2296 break;
2297 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2298 }
2299}
2300
sewardjde4a1d02002-03-22 01:27:54 +00002301
2302static void synth_push_reg ( Int size, Int reg )
2303{
2304 switch (size) {
2305 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002306 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002307 break;
2308 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002309 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002310 break;
2311 /* Pray that we don't have to generate this really cruddy bit of
2312 code very often. Could do better, but can I be bothered? */
2313 case 1:
2314 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002315 VG_(emit_add_lit_to_esp)(-1);
2316 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002317 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002318 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002319 break;
2320 default:
njne427a662002-10-02 11:08:25 +00002321 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002322 }
2323}
2324
2325
2326static void synth_pop_reg ( Int size, Int reg )
2327{
2328 switch (size) {
2329 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002330 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002331 break;
2332 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002333 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002334 break;
2335 case 1:
2336 /* Same comment as above applies. */
2337 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002338 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002339 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002340 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2341 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002342 break;
njne427a662002-10-02 11:08:25 +00002343 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002344 }
2345}
2346
2347
sewardj478335c2002-10-05 02:44:47 +00002348static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002349 Opcode opcode, Int size,
2350 Int regs, Int regd )
2351{
2352 synth_push_reg ( size, regd );
2353 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002354 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002355 case 4: emit_shiftopv_cl_stack0 ( upd_cc, 4, opcode ); break;
2356 case 2: emit_shiftopv_cl_stack0 ( upd_cc, 2, opcode ); break;
2357 case 1: emit_shiftopb_cl_stack0 ( upd_cc, opcode ); break;
njne427a662002-10-02 11:08:25 +00002358 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002359 }
sewardjde4a1d02002-03-22 01:27:54 +00002360 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2361 synth_pop_reg ( size, regd );
2362}
2363
2364
sewardj478335c2002-10-05 02:44:47 +00002365static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00002366 Opcode opcode, Int size,
2367 UInt lit, Int reg )
2368{
2369 switch (size) {
sewardjfa492d42002-12-08 18:20:01 +00002370 case 4: VG_(emit_shiftopv_lit_reg) ( upd_cc, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002371 break;
sewardjfa492d42002-12-08 18:20:01 +00002372 case 2: VG_(emit_shiftopv_lit_reg) ( upd_cc, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002373 break;
2374 case 1: if (reg < 4) {
sewardjfa492d42002-12-08 18:20:01 +00002375 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002376 } else {
njn25e49d8e72002-09-23 09:36:25 +00002377 VG_(emit_swapl_reg_EAX) ( reg );
sewardjfa492d42002-12-08 18:20:01 +00002378 emit_shiftopb_lit_reg ( upd_cc, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002379 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002380 }
2381 break;
njne427a662002-10-02 11:08:25 +00002382 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002383 }
2384}
2385
2386
2387static void synth_setb_reg ( Int reg, Condcode cond )
2388{
sewardjde4a1d02002-03-22 01:27:54 +00002389 if (reg < 4) {
2390 emit_setb_reg ( reg, cond );
2391 } else {
njn25e49d8e72002-09-23 09:36:25 +00002392 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002393 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002394 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002395 }
2396}
2397
2398
sewardjfa492d42002-12-08 18:20:01 +00002399static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2400 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002401 UChar second_byte_masked,
2402 Int reg )
2403{
sewardjfa492d42002-12-08 18:20:01 +00002404 emit_fpu_regmem ( uses_flags, sets_flags, first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002405}
2406
2407
sewardjfa492d42002-12-08 18:20:01 +00002408static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2409 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002410 UChar second_byte )
2411{
sewardjfa492d42002-12-08 18:20:01 +00002412 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002413}
2414
2415
2416static void synth_movl_reg_reg ( Int src, Int dst )
2417{
2418 emit_movl_reg_reg ( src, dst );
2419}
2420
2421static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2422{
sewardja2113f92002-12-12 23:42:48 +00002423 Int tgt;
2424
2425 VG_(init_target)(&tgt);
2426
2427 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002428 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002429
2430 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002431}
2432
2433
sewardjde4a1d02002-03-22 01:27:54 +00002434/*----------------------------------------------------*/
2435/*--- Top level of the uinstr -> x86 translation. ---*/
2436/*----------------------------------------------------*/
2437
2438/* Return the byte offset from %ebp (ie, into baseBlock)
2439 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002440static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2441{
2442 if (tag == SpillNo) {
2443 vg_assert(size == 4);
2444 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2445 return 4 * (value + VGOFF_(spillslots));
2446 }
2447 if (tag == ArchReg) {
2448 switch (value) {
2449 case R_EAX: return 4 * VGOFF_(m_eax);
2450 case R_ECX: return 4 * VGOFF_(m_ecx);
2451 case R_EDX: return 4 * VGOFF_(m_edx);
2452 case R_EBX: return 4 * VGOFF_(m_ebx);
2453 case R_ESP:
2454 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2455 else return 4 * VGOFF_(m_esp);
2456 case R_EBP:
2457 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2458 else return 4 * VGOFF_(m_ebp);
2459 case R_ESI:
2460 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2461 else return 4 * VGOFF_(m_esi);
2462 case R_EDI:
2463 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2464 else return 4 * VGOFF_(m_edi);
2465 }
2466 }
njne427a662002-10-02 11:08:25 +00002467 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002468}
2469
sewardjde4a1d02002-03-22 01:27:54 +00002470static Int eflagsOffset ( void )
2471{
2472 return 4 * VGOFF_(m_eflags);
2473}
2474
sewardje1042472002-09-30 12:33:11 +00002475static Int segRegOffset ( UInt archregs )
2476{
2477 switch (archregs) {
2478 case R_CS: return 4 * VGOFF_(m_cs);
2479 case R_SS: return 4 * VGOFF_(m_ss);
2480 case R_DS: return 4 * VGOFF_(m_ds);
2481 case R_ES: return 4 * VGOFF_(m_es);
2482 case R_FS: return 4 * VGOFF_(m_fs);
2483 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002484 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002485 }
2486}
2487
sewardjde4a1d02002-03-22 01:27:54 +00002488
njn25e49d8e72002-09-23 09:36:25 +00002489/* Return the byte offset from %ebp (ie, into baseBlock)
2490 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002491Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002492{
2493 switch (arch) {
2494 case R_EAX: return 4 * VGOFF_(sh_eax);
2495 case R_ECX: return 4 * VGOFF_(sh_ecx);
2496 case R_EDX: return 4 * VGOFF_(sh_edx);
2497 case R_EBX: return 4 * VGOFF_(sh_ebx);
2498 case R_ESP: return 4 * VGOFF_(sh_esp);
2499 case R_EBP: return 4 * VGOFF_(sh_ebp);
2500 case R_ESI: return 4 * VGOFF_(sh_esi);
2501 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002502 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002503 }
2504}
2505
njn4ba5a792002-09-30 10:23:54 +00002506Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002507{
2508 return 4 * VGOFF_(sh_eflags);
2509}
2510
2511
sewardjde4a1d02002-03-22 01:27:54 +00002512
2513static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2514{
2515 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002516 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2517 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002518 }
2519 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002520 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2521 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002522 }
2523 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002524 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2525 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002526 }
2527 else
njne427a662002-10-02 11:08:25 +00002528 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002529}
2530
2531
njn25e49d8e72002-09-23 09:36:25 +00002532static void synth_handle_esp_assignment ( Int i, Int reg,
2533 RRegSet regs_live_before,
2534 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002535{
njn25e49d8e72002-09-23 09:36:25 +00002536 UInt argv[] = { reg };
2537 Tag tagv[] = { RealReg };
2538
2539 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2540 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002541}
2542
2543
sewardjde4a1d02002-03-22 01:27:54 +00002544/*----------------------------------------------------*/
2545/*--- Generate code for a single UInstr. ---*/
2546/*----------------------------------------------------*/
2547
sewardj478335c2002-10-05 02:44:47 +00002548static __inline__
2549Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002550{
2551 return (u->flags_w != FlagsEmpty);
2552}
2553
sewardjfa492d42002-12-08 18:20:01 +00002554static __inline__
2555Bool readFlagUse ( UInstr* u )
2556{
2557 /* If the UInstr writes some flags but not all, then we still need
2558 to consider it as reading flags so that the unchanged values are
2559 passed through properly. (D is special) */
2560 return
2561 (u->flags_r != FlagsEmpty) ||
2562 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2563}
2564
sewardj478335c2002-10-05 02:44:47 +00002565static __inline__
2566Bool anyFlagUse ( UInstr* u )
2567{
sewardjfa492d42002-12-08 18:20:01 +00002568 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002569}
2570
2571
sewardjb5ff83e2002-12-01 19:40:49 +00002572/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002573 the real FPU. If so we need to be very careful not to trash it.
2574 If FPU state is live and we deem it necessary to copy it back to
2575 the simulated machine's FPU state, we do so. The final state of
2576 fpliveness is returned. In short we _must_ do put_fpu_state if
2577 there is any chance at all that the code generated for a UInstr
2578 will change the real FPU state.
2579*/
sewardjb5ff83e2002-12-01 19:40:49 +00002580static void emitUInstr ( UCodeBlock* cb, Int i,
2581 RRegSet regs_live_before,
2582 /* Running state, which we update. */
2583 Bool* fplive, /* True<==>FPU state in real FPU */
2584 Addr* orig_eip, /* previous curr_eip, or zero */
2585 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002586{
njn25e49d8e72002-09-23 09:36:25 +00002587 Int old_emitted_code_used;
2588 UInstr* u = &cb->instrs[i];
2589
sewardjde4a1d02002-03-22 01:27:54 +00002590 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002591 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002592
njn25e49d8e72002-09-23 09:36:25 +00002593 old_emitted_code_used = emitted_code_used;
2594
sewardjde4a1d02002-03-22 01:27:54 +00002595 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002596 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002597
sewardjb5ff83e2002-12-01 19:40:49 +00002598 case INCEIP:
2599 /* Advance %EIP some small amount. */
2600 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002601
sewardjb5ff83e2002-12-01 19:40:49 +00002602 if (*orig_eip == 0 /* we don't know what the old value was */
2603 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2604 /* We have to update all 32 bits of the value. */
2605 VG_(emit_movv_lit_offregmem)(
2606 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2607 } else {
2608 /* Cool! we only need to update lowest 8 bits */
2609 VG_(emit_movb_lit_offregmem)(
2610 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002611 }
njn25e49d8e72002-09-23 09:36:25 +00002612
sewardjb5ff83e2002-12-01 19:40:49 +00002613 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002614 break;
sewardjde4a1d02002-03-22 01:27:54 +00002615
2616 case LEA1: {
2617 vg_assert(u->tag1 == RealReg);
2618 vg_assert(u->tag2 == RealReg);
2619 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2620 break;
2621 }
2622
2623 case LEA2: {
2624 vg_assert(u->tag1 == RealReg);
2625 vg_assert(u->tag2 == RealReg);
2626 vg_assert(u->tag3 == RealReg);
2627 emit_lea_sib_reg ( u->lit32, u->extra4b,
2628 u->val1, u->val2, u->val3 );
2629 break;
2630 }
2631
2632 case WIDEN: {
2633 vg_assert(u->tag1 == RealReg);
2634 if (u->signed_widen) {
2635 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2636 } else {
2637 /* no need to generate any code. */
2638 }
2639 break;
2640 }
2641
sewardjde4a1d02002-03-22 01:27:54 +00002642 case STORE: {
2643 vg_assert(u->tag1 == RealReg);
2644 vg_assert(u->tag2 == RealReg);
2645 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002646 break;
2647 }
2648
2649 case LOAD: {
2650 vg_assert(u->tag1 == RealReg);
2651 vg_assert(u->tag2 == RealReg);
2652 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2653 break;
2654 }
2655
sewardjde4a1d02002-03-22 01:27:54 +00002656 case GET: {
2657 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2658 vg_assert(u->tag2 == RealReg);
2659 synth_mov_offregmem_reg (
2660 u->size,
2661 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2662 R_EBP,
2663 u->val2
2664 );
2665 break;
2666 }
2667
2668 case PUT: {
2669 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2670 vg_assert(u->tag1 == RealReg);
2671 if (u->tag2 == ArchReg
2672 && u->val2 == R_ESP
2673 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002674 && (VG_(track_events).new_mem_stack ||
2675 VG_(track_events).new_mem_stack_aligned ||
2676 VG_(track_events).die_mem_stack ||
2677 VG_(track_events).die_mem_stack_aligned ||
2678 VG_(track_events).post_mem_write))
2679 {
2680 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2681 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002682 }
njn25e49d8e72002-09-23 09:36:25 +00002683 else {
2684 synth_mov_reg_offregmem (
2685 u->size,
2686 u->val1,
2687 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2688 R_EBP
2689 );
2690 }
sewardjde4a1d02002-03-22 01:27:54 +00002691 break;
2692 }
2693
sewardje1042472002-09-30 12:33:11 +00002694 case GETSEG: {
2695 vg_assert(u->tag1 == ArchRegS);
2696 vg_assert(u->tag2 == RealReg);
2697 vg_assert(u->size == 2);
2698 synth_mov_offregmem_reg (
2699 4,
2700 segRegOffset( u->val1 ),
2701 R_EBP,
2702 u->val2
2703 );
2704 break;
2705 }
2706
2707 case PUTSEG: {
2708 vg_assert(u->tag1 == RealReg);
2709 vg_assert(u->tag2 == ArchRegS);
2710 vg_assert(u->size == 2);
2711 synth_mov_reg_offregmem (
2712 4,
2713 u->val1,
2714 segRegOffset( u->val2 ),
2715 R_EBP
2716 );
2717 break;
2718 }
2719
sewardjde4a1d02002-03-22 01:27:54 +00002720 case GETF: {
2721 vg_assert(u->size == 2 || u->size == 4);
2722 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002723
2724 /* This complexity is because the D(irection) flag is stored
2725 separately from the rest of EFLAGS. */
2726
2727 /* We're only fetching from the Simd state, so make sure it's
2728 up to date. */
2729 maybe_emit_put_eflags();
2730
2731 /* get D in u->val1 (== 1 or -1) */
2732 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
2733
2734 /* u->val1 &= EFlagD (== 0 or EFlagD) */
2735 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2736
2737 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2738 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2739 eflagsOffset(), R_EBP);
2740
2741 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
2742 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2743 eflagsOffset(), R_EBP);
2744
2745 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
2746 synth_nonshiftop_offregmem_reg(False, OR, u->size,
2747 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00002748 break;
2749 }
2750
2751 case PUTF: {
2752 vg_assert(u->size == 2 || u->size == 4);
2753 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00002754
2755 /* When putting a value into EFLAGS, this generates the
2756 correct value for m_dflag (-1 or 1), and clears the D bit
2757 in EFLAGS. */
2758
2759 /* We're updating the whole flag state, so the old state
2760 doesn't matter; make sure that the new simulated state
2761 will be fetched when needed. */
2762 eflags_state = UPD_Simd;
2763
2764 /* store EFLAGS (with D) */
2765 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
2766
2767 /* u->val1 &= EFlagD */
2768 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
2769
2770 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
2771 synth_unaryop_reg(False, NEG, u->size, u->val1);
2772 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
2773 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
2774
2775 /* save D */
2776 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
2777
2778 /* EFLAGS &= ~EFlagD */
2779 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
2780 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00002781 break;
2782 }
2783
2784 case MOV: {
2785 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2786 vg_assert(u->tag2 == RealReg);
2787 switch (u->tag1) {
2788 case RealReg: vg_assert(u->size == 4);
2789 if (u->val1 != u->val2)
2790 synth_movl_reg_reg ( u->val1, u->val2 );
2791 break;
2792 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2793 break;
njne427a662002-10-02 11:08:25 +00002794 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002795 }
2796 break;
2797 }
2798
sewardje1042472002-09-30 12:33:11 +00002799 case USESEG: {
2800 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2801 ones. */
sewardjd077f532002-09-30 21:52:50 +00002802 UInt argv[] = { u->val1, u->val2 };
2803 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002804 UInt ret_reg = u->val2;
2805
2806 vg_assert(u->tag1 == RealReg);
2807 vg_assert(u->tag2 == RealReg);
2808 vg_assert(u->size == 0);
2809
sewardjb5ff83e2002-12-01 19:40:49 +00002810 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002811 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002812 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002813 }
2814
sewardje1042472002-09-30 12:33:11 +00002815 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2816 2, /* args */
2817 0, /* regparms_n */
2818 argv, tagv,
2819 ret_reg, regs_live_before, u->regs_live_after );
2820 break;
2821 }
2822
sewardj478335c2002-10-05 02:44:47 +00002823 case SBB:
2824 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002825 case XOR:
2826 case OR:
2827 case AND:
2828 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002829 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002830 vg_assert(u->tag2 == RealReg);
2831 switch (u->tag1) {
2832 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002833 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002834 u->opcode, u->size, u->lit32, u->val2 );
2835 break;
2836 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002837 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002838 u->opcode, u->size, u->val1, u->val2 );
2839 break;
2840 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002841 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002842 u->opcode, u->size,
2843 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2844 R_EBP,
2845 u->val2 );
2846 break;
njne427a662002-10-02 11:08:25 +00002847 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002848 }
2849 break;
2850 }
2851
sewardj478335c2002-10-05 02:44:47 +00002852 case RCR:
2853 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002854 case ROR:
2855 case ROL:
2856 case SAR:
2857 case SHR:
2858 case SHL: {
2859 vg_assert(u->tag2 == RealReg);
2860 switch (u->tag1) {
2861 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002862 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002863 u->opcode, u->size, u->lit32, u->val2 );
2864 break;
2865 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002866 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002867 u->opcode, u->size, u->val1, u->val2 );
2868 break;
njne427a662002-10-02 11:08:25 +00002869 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002870 }
2871 break;
2872 }
2873
2874 case INC:
2875 case DEC:
2876 case NEG:
2877 case NOT:
2878 vg_assert(u->tag1 == RealReg);
2879 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002880 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002881 break;
2882
2883 case BSWAP:
2884 vg_assert(u->tag1 == RealReg);
2885 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002886 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002887 emit_bswapl_reg ( u->val1 );
2888 break;
2889
2890 case CMOV:
2891 vg_assert(u->tag1 == RealReg);
2892 vg_assert(u->tag2 == RealReg);
2893 vg_assert(u->cond != CondAlways);
2894 vg_assert(u->size == 4);
2895 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2896 break;
2897
2898 case JMP: {
2899 vg_assert(u->tag2 == NoValue);
2900 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00002901 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002902 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002903 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002904 }
sewardjde4a1d02002-03-22 01:27:54 +00002905 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002906 switch (u->tag1) {
2907 case RealReg:
2908 synth_jmp_reg ( u->val1, u->jmpkind );
2909 break;
2910 case Literal:
2911 synth_jmp_lit ( u->lit32, u->jmpkind );
2912 break;
2913 default:
njne427a662002-10-02 11:08:25 +00002914 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002915 break;
sewardjde4a1d02002-03-22 01:27:54 +00002916 }
2917 } else {
sewardj2e93c502002-04-12 11:12:52 +00002918 switch (u->tag1) {
2919 case RealReg:
njne427a662002-10-02 11:08:25 +00002920 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002921 break;
2922 case Literal:
2923 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00002924 /* %eax had better not be live since synth_jcond_lit
2925 trashes it in some circumstances. If that turns
2926 out to be a problem we can get synth_jcond_lit to
2927 push/pop it when it is live. */
2928 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
2929 u->regs_live_after));
2930 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00002931 break;
2932 default:
njne427a662002-10-02 11:08:25 +00002933 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002934 break;
sewardjde4a1d02002-03-22 01:27:54 +00002935 }
2936 }
2937 break;
2938 }
2939
2940 case JIFZ:
2941 vg_assert(u->tag1 == RealReg);
2942 vg_assert(u->tag2 == Literal);
2943 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00002944 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002945 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002946 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002947 }
sewardjde4a1d02002-03-22 01:27:54 +00002948 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2949 break;
2950
sewardjde4a1d02002-03-22 01:27:54 +00002951 case PUSH:
2952 vg_assert(u->tag1 == RealReg);
2953 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002954 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002955 break;
2956
2957 case POP:
2958 vg_assert(u->tag1 == RealReg);
2959 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002960 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002961 break;
2962
2963 case CALLM:
2964 vg_assert(u->tag1 == Lit16);
2965 vg_assert(u->tag2 == NoValue);
2966 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00002967 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002968 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002969 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002970 }
sewardjfa492d42002-12-08 18:20:01 +00002971 /* Call to a helper which is pretending to be a real CPU
2972 instruction (and therefore operates on Real flags and
2973 registers) */
2974 VG_(synth_call) ( False, u->val1,
2975 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00002976 break;
2977
njn25e49d8e72002-09-23 09:36:25 +00002978 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002979 /* If you change this, remember to change USESEG above, since
2980 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002981 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2982 ones. */
2983 UInt argv[] = { u->val1, u->val2, u->val3 };
2984 UInt tagv[] = { RealReg, RealReg, RealReg };
2985 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2986
2987 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2988 else vg_assert(u->tag1 == NoValue);
2989 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2990 else vg_assert(u->tag2 == NoValue);
2991 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2992 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002993 vg_assert(u->size == 0);
2994
sewardjb5ff83e2002-12-01 19:40:49 +00002995 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002996 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002997 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002998 }
njn25e49d8e72002-09-23 09:36:25 +00002999 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3000 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003001 break;
njn25e49d8e72002-09-23 09:36:25 +00003002 }
sewardje1042472002-09-30 12:33:11 +00003003
sewardjde4a1d02002-03-22 01:27:54 +00003004 case CLEAR:
3005 vg_assert(u->tag1 == Lit16);
3006 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003007 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003008 break;
3009
3010 case CC2VAL:
3011 vg_assert(u->tag1 == RealReg);
3012 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003013 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003014 synth_setb_reg ( u->val1, u->cond );
3015 break;
3016
sewardjde4a1d02002-03-22 01:27:54 +00003017 case FPU_R:
3018 case FPU_W:
3019 vg_assert(u->tag1 == Lit16);
3020 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003021 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003022 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003023 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003024 }
sewardjfa492d42002-12-08 18:20:01 +00003025 synth_fpu_regmem ( u->flags_r, u->flags_w,
3026 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003027 u->val1 & 0xFF,
3028 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003029 break;
3030
3031 case FPU:
3032 vg_assert(u->tag1 == Lit16);
3033 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00003034 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00003035 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00003036 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003037 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003038 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003039 }
sewardjfa492d42002-12-08 18:20:01 +00003040 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3041 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003042 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003043 break;
3044
3045 default:
sewardj1b7d8022002-11-30 12:35:42 +00003046 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003047 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003048 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003049 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003050 }
njn4ba5a792002-09-30 10:23:54 +00003051 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003052 } else {
njn25e49d8e72002-09-23 09:36:25 +00003053 VG_(printf)("\nError:\n"
3054 " unhandled opcode: %u. Perhaps "
3055 " VG_(needs).extended_UCode should be set?\n",
3056 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003057 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003058 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003059 }
sewardjde4a1d02002-03-22 01:27:54 +00003060 }
3061
sewardjb5ff83e2002-12-01 19:40:49 +00003062 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003063 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003064 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003065 }
3066
njn25e49d8e72002-09-23 09:36:25 +00003067 /* Update UInstr histogram */
3068 vg_assert(u->opcode < 100);
3069 histogram[u->opcode].counts++;
3070 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003071}
3072
3073
3074/* Emit x86 for the ucode in cb, returning the address of the
3075 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003076UChar* VG_(emit_code) ( UCodeBlock* cb,
3077 Int* nbytes,
3078 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003079{
3080 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003081 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003082 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003083 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003084 Int tgt;
3085
sewardjfa492d42002-12-08 18:20:01 +00003086 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003087
njn25e49d8e72002-09-23 09:36:25 +00003088 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003089
sewardj22854b92002-11-30 14:00:47 +00003090 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3091 zero. We have to do this regardless of whether we're t-chaining
3092 or not. */
sewardja2113f92002-12-12 23:42:48 +00003093 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003094 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003095 VG_(emitB) (0xFF); /* decl */
3096 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3097 if (dis)
3098 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003099 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003100 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3101 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003102 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003103
sewardjb5ff83e2002-12-01 19:40:49 +00003104 /* Set up running state. */
3105 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003106 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003107 curr_eip = cb->orig_eip;
3108 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3109 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003110 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003111 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003112 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003113 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003114
sewardjde4a1d02002-03-22 01:27:54 +00003115 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003116 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003117 if (!sane) {
3118 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003119 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003120 }
3121 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003122 emitUInstr( cb, i, regs_live_before,
3123 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003124 }
njn25e49d8e72002-09-23 09:36:25 +00003125 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003126 }
njn25e49d8e72002-09-23 09:36:25 +00003127 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003128 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3129 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003130
sewardj22854b92002-11-30 14:00:47 +00003131 if (j != NULL) {
3132 vg_assert(jumpidx <= VG_MAX_JUMPS);
3133 for(i = 0; i < jumpidx; i++)
3134 j[i] = jumps[i];
3135 }
3136
sewardjde4a1d02002-03-22 01:27:54 +00003137 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003138 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003139 *nbytes = emitted_code_used;
3140 return emitted_code;
3141}
3142
njn25e49d8e72002-09-23 09:36:25 +00003143#undef dis
3144
sewardjde4a1d02002-03-22 01:27:54 +00003145/*--------------------------------------------------------------------*/
3146/*--- end vg_from_ucode.c ---*/
3147/*--------------------------------------------------------------------*/