blob: a70f157d1c43b7666f2aa9902a99ea1d4f814d92 [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
sewardjf0f12aa2002-12-28 00:04:08 +000077static enum _eflags_state {
sewardjfa492d42002-12-08 18:20:01 +000078 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
sewardjf0f12aa2002-12-28 00:04:08 +0000269
270#if 0
271/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
272/* An alternative implementation of new_emit in which the
273 state space is explicitly enumerated. */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool simd = upds_simd_flags;
279 enum _eflags_state where = eflags_state;
280
281 enum { WNone, WSome, WAll } ww;
282 Bool rr;
283
284#define DIS_HEADER \
285 if (dis) \
286 VG_(printf)("\t %4d: ", emitted_code_used );
287
288 if (use_flags == FlagsEmpty) {
289 rr = False;
290 } else {
291 rr = True;
292 }
293
294 if (set_flags == FlagsEmpty) {
295 ww = WNone;
296 } else
297 if (set_flags == FlagsOSZACP) {
298 ww = WAll;
299 } else {
300 ww = WSome;
301 }
302
303 /* If we're not wanting to interact with simd flags, and the simd
304 flags are not in the real flags, then do nothing. */
305 if (simd == False && where == UPD_Simd)
306 goto noaction;
307
308 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
309 /* We're going to generate a complete new simd flag state without
310 consulting the old one first, so just deem this insn to create
311 the state in the real flags. */
312 eflags_state = UPD_Real;
313 DIS_HEADER;
314 return;
315 }
316
317 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
318 /* Want to partially update the flags state, but is in simd. So
319 fetch it first, then declare that the real state is the most
320 recent. */
321 emit_get_eflags();
322 eflags_state = UPD_Real;
323 DIS_HEADER;
324 return;
325 }
326
327 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
328 /* want to read simd flags, but not in real -> copy to real. */
329 emit_get_eflags();
330 eflags_state = UPD_Both;
331 DIS_HEADER;
332 return;
333 }
334
335 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
336 /* want to read and write simd flags, but not in real -> copy to
337 real. State is then Real since they get updated. */
338 emit_get_eflags();
339 eflags_state = UPD_Real;
340 DIS_HEADER;
341 return;
342 }
343
344 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
345 /* Doesn't really make sense. Want to interact with simd flags,
346 but insn doesn't modify them. So don't do anything. ??? */
347 goto noaction;
348 }
349
350 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
351 /* Doesn't really make sense. Want to interact with simd flags,
352 but insn doesn't modify them. So don't do anything. ??? */
353 goto noaction;
354 }
355
356 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
357 /* simd is in real. Insn reads real but does not change. --> do
358 nothing. */
359 goto noaction;
360 }
361
362 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
363 /* simd is in real. we want to capture changes made by it. -->
364 do nothing */
365 goto noaction;
366 }
367
368 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
369 /* simd is in real. Insn creates new simd state. --> leave in
370 real */
371 goto noaction;
372 }
373
374 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
375 /* simd is in both. Insn creates new simd state. --> change
376 state to Real. */
377 narrow_Both_to_Real:
378 eflags_state = UPD_Real;
379 DIS_HEADER;
380 return;
381 }
382
383 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
384 /* simd is in both. Insn creates partial new simd state. -->
385 change state to Real. No need to get, since Both holds. */
386 goto narrow_Both_to_Real;
387 }
388
389 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
390 /* simd is in real. Insn creates new simd state. --> leave in
391 real */
392 goto noaction;
393 }
394
395 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
396 /* want to read the simd flags, but already have a copy in real,
397 and not planning to modify it --> do nothing. */
398 goto noaction;
399
400 ////////////////
401
402 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
403 /* simd state is in real, but insn doesn't touch it --> do nothing */
404 goto noaction;
405
406 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
407 /* simd state is in both, insn doesn't touch it --> do nothing */
408 goto noaction;
409
410 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
411 /* simd state is in both. insn trashes real, therefore declare
412 simd state only in simd. */
413 narrow_Both_to_Simd:
414 eflags_state = UPD_Simd;
415 DIS_HEADER;
416 return;
417 }
418
419 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
420 /* simd state is in both. insn trashes real, therefore declare
421 simd state only in simd. */
422 goto narrow_Both_to_Simd;
423 }
424
425 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
426 /* simd state is in real; we don't want simd state changed, but
427 insn writes the flags. Therefore have to copy back first. */
428 put_flags_and_continue:
429 emit_put_eflags();
430 eflags_state = UPD_Simd;
431 DIS_HEADER;
432 return;
433 }
434
435 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
436 /* simd state is in real; we don't want simd state changed, but
437 insn writes the flags. Therefore have to copy back first. */
438 goto put_flags_and_continue;
439 }
440
441 goto unhandled;
442
443 noaction:
444 DIS_HEADER;
445 return;
446
447 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
448 // return;
449 //}
450
451 unhandled:
452 VG_(printf)("simd %s, where %s, read %s, write %s\n",
453 simd ? "True " : "False",
454 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
455 ? "Real" : "Both")),
456 rr ? "True " : "False",
457 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
458 );
459
460 VG_(core_panic)("new_emit");
461}
462/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
463#endif
464
465
sewardjfa492d42002-12-08 18:20:01 +0000466/* Call this before emitting each instruction.
467
468 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000469 interacts_with_simd_flags:
470 if true, this instruction wants to interact (read and/or write)
471 the simulated %EFLAGS state,
472 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000473 use_flags: set of (real) flags the instruction uses
474 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000475*/
sewardjfa492d42002-12-08 18:20:01 +0000476__inline__
sewardjf0f12aa2002-12-28 00:04:08 +0000477void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000478 FlagSet use_flags, FlagSet set_flags )
479{
480 Bool use, set;
481
482 use = use_flags != FlagsEmpty
483 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
484 set = set_flags != FlagsEmpty;
485
486 if (0)
487 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000488 "new_emit: state=%d interacts_with_simd_flags=%d "
489 "use_flags=%x set_flags=%x\n",
490 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000491
sewardjf0f12aa2002-12-28 00:04:08 +0000492 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000493 if (use && eflags_state == UPD_Simd) {
494 /* we need the CPU flags set, but they're not already */
495 eflags_state = UPD_Both;
496 emit_get_eflags();
497 }
498 if (set) {
499 /* if we're setting the flags, then the CPU will have the
500 only good copy */
501 eflags_state = UPD_Real;
502 }
503 } else {
504 /* presume that if non-simd code is using flags, it knows what
505 it's doing (ie, it just set up the flags). */
506 if (set) {
507 /* This instruction is going to trash the flags, so we'd
508 better save them away and say that they're only in the
509 simulated state. */
510 maybe_emit_put_eflags();
511 eflags_state = UPD_Simd;
512 }
513 }
514
sewardjde4a1d02002-03-22 01:27:54 +0000515 if (dis)
516 VG_(printf)("\t %4d: ", emitted_code_used );
517}
518
sewardjde4a1d02002-03-22 01:27:54 +0000519
520/*----------------------------------------------------*/
521/*--- Addressing modes ---*/
522/*----------------------------------------------------*/
523
524static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
525{
526 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
527}
528
529static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
530{
531 Int shift;
532 switch (scale) {
533 case 1: shift = 0; break;
534 case 2: shift = 1; break;
535 case 4: shift = 2; break;
536 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000537 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
540}
541
542static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
543{
544 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000545 VG_(emitB) ( mkModRegRM(0, reg, 5) );
546 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000547}
548
549static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
550{
551 /* (regmem), reg */
552 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000553 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( mkModRegRM(1, reg, 5) );
556 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000557 } else {
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000559 }
560}
561
njn25e49d8e72002-09-23 09:36:25 +0000562void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000563{
564 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 if (off < -128 || off > 127) {
567 /* Use a large offset */
568 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
570 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000571 } else {
572 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
574 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000575 }
576}
577
578static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
579 Int regindex, Int reg )
580{
581 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000582 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (off < -128 || off > 127) {
584 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000585 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
586 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
587 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000588 } else {
589 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
591 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
592 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000593 }
594}
595
njn25e49d8e72002-09-23 09:36:25 +0000596void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000597{
598 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000599 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000600}
601
602static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
603{
604 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000606}
607
608
609/*----------------------------------------------------*/
610/*--- Opcode translation ---*/
611/*----------------------------------------------------*/
612
613static __inline__ Int mkGrp1opcode ( Opcode opc )
614{
615 switch (opc) {
616 case ADD: return 0;
617 case OR: return 1;
618 case ADC: return 2;
619 case SBB: return 3;
620 case AND: return 4;
621 case SUB: return 5;
622 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000623 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000624 }
625}
626
sewardjfa492d42002-12-08 18:20:01 +0000627static __inline__ FlagSet nonshiftop_use(Opcode opc)
628{
629 switch(opc) {
630 case ADC:
631 case SBB:
632 return FlagC;
633
634 case ADD:
635 case OR:
636 case AND:
637 case SUB:
638 case XOR:
639 return FlagsEmpty;
640
641 default:
642 VG_(core_panic)("nonshiftop_use");
643 }
644}
645
646static __inline__ FlagSet nonshiftop_set(Opcode opc)
647{
648 switch(opc) {
649 case ADC:
650 case SBB:
651 case ADD:
652 case OR:
653 case AND:
654 case SUB:
655 case XOR:
656 return FlagsOSZACP;
657
658 default:
659 VG_(core_panic)("nonshiftop_set");
660 }
661}
662
sewardjde4a1d02002-03-22 01:27:54 +0000663static __inline__ Int mkGrp2opcode ( Opcode opc )
664{
665 switch (opc) {
666 case ROL: return 0;
667 case ROR: return 1;
668 case RCL: return 2;
669 case RCR: return 3;
670 case SHL: return 4;
671 case SHR: return 5;
672 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000673 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000674 }
675}
676
sewardjfa492d42002-12-08 18:20:01 +0000677static __inline__ FlagSet shiftop_use(Opcode opc)
678{
679 switch(opc) {
680 case ROR:
681 case ROL:
682 case SHL:
683 case SHR:
684 case SAR:
685 return FlagsEmpty;
686
687 case RCL:
688 case RCR:
689 return FlagC;
690
691 default:
692 VG_(core_panic)("shiftop_use");
693 }
694}
695
696static __inline__ FlagSet shiftop_set(Opcode opc)
697{
698 switch(opc) {
699 case ROR:
700 case ROL:
701 case RCL:
702 case RCR:
703 return FlagsOC;
704
705 case SHL:
706 case SHR:
707 case SAR:
708 return FlagsOSZACP;
709
710 default:
711 VG_(core_panic)("shiftop_set");
712 }
713}
714
sewardjde4a1d02002-03-22 01:27:54 +0000715static __inline__ Int mkGrp3opcode ( Opcode opc )
716{
717 switch (opc) {
718 case NOT: return 2;
719 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000720 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000721 }
722}
723
724static __inline__ Int mkGrp4opcode ( Opcode opc )
725{
726 switch (opc) {
727 case INC: return 0;
728 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000729 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000730 }
731}
732
733static __inline__ Int mkGrp5opcode ( Opcode opc )
734{
735 switch (opc) {
736 case CALLM: return 2;
737 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000738 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000739 }
740}
741
742static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
743{
744 switch (opc) {
745 case ADD: return 0x00;
746 case ADC: return 0x10;
747 case AND: return 0x20;
748 case XOR: return 0x30;
749 case OR: return 0x08;
750 case SBB: return 0x18;
751 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000752 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000753 }
754}
755
756/*----------------------------------------------------*/
757/*--- v-size (4, or 2 with OSO) insn emitters ---*/
758/*----------------------------------------------------*/
759
njn25e49d8e72002-09-23 09:36:25 +0000760void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000761{
sewardjf0f12aa2002-12-28 00:04:08 +0000762 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000763 if (sz == 2) VG_(emitB) ( 0x66 );
764 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
765 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000766 if (dis)
767 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
768 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
769}
770
njn25e49d8e72002-09-23 09:36:25 +0000771void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000772{
sewardjf0f12aa2002-12-28 00:04:08 +0000773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000774 if (sz == 2) VG_(emitB) ( 0x66 );
775 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
776 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
779 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
780}
781
782static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
783{
sewardjf0f12aa2002-12-28 00:04:08 +0000784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000785 if (sz == 2) VG_(emitB) ( 0x66 );
786 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000787 emit_amode_regmem_reg ( reg1, reg2 );
788 if (dis)
789 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
790 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
791}
792
793static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000798 emit_amode_regmem_reg ( reg2, reg1 );
799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
801 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000807 if (sz == 2) VG_(emitB) ( 0x66 );
808 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
809 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000810 if (dis)
811 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
812 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
813}
814
sewardjf0f12aa2002-12-28 00:04:08 +0000815void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
816 Int sz, Opcode opc,
817 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjf0f12aa2002-12-28 00:04:08 +0000819 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000820
njn25e49d8e72002-09-23 09:36:25 +0000821 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
823 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000824 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
825 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
826 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000827 } else {
njn25e49d8e72002-09-23 09:36:25 +0000828 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
829 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
830 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000831 }
832 if (dis)
833 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000834 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000835 lit, nameIReg(sz,reg));
836}
837
sewardjf0f12aa2002-12-28 00:04:08 +0000838void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
839 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000840 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000841{
sewardjf0f12aa2002-12-28 00:04:08 +0000842 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000843 if (sz == 2) VG_(emitB) ( 0x66 );
844 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
845 /* short form OK */
846 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
847 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
848 VG_(emitB) ( lit & 0x000000FF );
849 } else {
850 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
851 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
852 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
853 }
854 if (dis)
855 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
856 VG_(name_UOpcode)(False,opc), nameISize(sz),
857 lit, off, nameIReg(sz,regmem));
858}
859
sewardjf0f12aa2002-12-28 00:04:08 +0000860void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
861 Int sz, Opcode opc,
862 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000863{
sewardjf0f12aa2002-12-28 00:04:08 +0000864 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000865
njn25e49d8e72002-09-23 09:36:25 +0000866 if (sz == 2) VG_(emitB) ( 0x66 );
867 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
868 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
869 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000870 if (dis)
871 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000872 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000873 lit, nameIReg(sz,reg));
874}
875
sewardjf0f12aa2002-12-28 00:04:08 +0000876static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000877{
sewardjf0f12aa2002-12-28 00:04:08 +0000878 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000879 if (sz == 2) VG_(emitB) ( 0x66 );
880 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
881 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
882 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
883 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000886 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000890{
sewardjf0f12aa2002-12-28 00:04:08 +0000891 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000892 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
893 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
894 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
895 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000896 if (dis)
897 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000898 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000899}
900
sewardjf0f12aa2002-12-28 00:04:08 +0000901static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
902 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000903 Int off, Int areg, Int reg )
904{
sewardjf0f12aa2002-12-28 00:04:08 +0000905 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000906 if (sz == 2) VG_(emitB) ( 0x66 );
907 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
908 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000909 if (dis)
910 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000911 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000912 off, nameIReg(4,areg), nameIReg(sz,reg));
913}
914
sewardja2c5a732002-12-15 03:10:42 +0000915#if 0
916/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000917static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000918 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000919{
sewardjf0f12aa2002-12-28 00:04:08 +0000920 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000921 if (sz == 2) VG_(emitB) ( 0x66 );
922 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
923 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
926 VG_(name_UOpcode)(False,opc), nameISize(sz),
927 nameIReg(sz,reg), off, nameIReg(4,areg));
928}
sewardja2c5a732002-12-15 03:10:42 +0000929#endif
sewardjfa492d42002-12-08 18:20:01 +0000930
sewardjf0f12aa2002-12-28 00:04:08 +0000931void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000932 Int reg1, Int reg2 )
933{
sewardjf0f12aa2002-12-28 00:04:08 +0000934 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000936# if 0
937 /* Perfectly correct, but the GNU assembler uses the other form.
938 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
940 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000941# else
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000943 emit_amode_greg_ereg ( reg1, reg2 );
944# endif
945 if (dis)
946 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000947 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000948 nameIReg(sz,reg1), nameIReg(sz,reg2));
949}
950
njn25e49d8e72002-09-23 09:36:25 +0000951void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000952{
sewardjf0f12aa2002-12-28 00:04:08 +0000953#if 0
sewardjfa492d42002-12-08 18:20:01 +0000954 if (lit == 0 && eflags_state != UPD_Real) {
955 /* Only emit this for zeroing if it won't stomp flags */
956 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000957 return;
958 }
sewardjf0f12aa2002-12-28 00:04:08 +0000959#endif
960 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000961 if (sz == 2) VG_(emitB) ( 0x66 );
962 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
963 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000964 if (dis)
965 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
966 nameISize(sz), lit, nameIReg(sz,reg));
967}
968
sewardjf0f12aa2002-12-28 00:04:08 +0000969void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjde4a1d02002-03-22 01:27:54 +0000971 switch (opc) {
972 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +0000973 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +0000974 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000975 VG_(emitB) ( 0xF7 );
976 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000977 if (dis)
978 VG_(printf)( "\n\t\tneg%c\t%s\n",
979 nameISize(sz), nameIReg(sz,reg));
980 break;
981 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +0000982 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +0000983 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000984 VG_(emitB) ( 0xF7 );
985 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000986 if (dis)
987 VG_(printf)( "\n\t\tnot%c\t%s\n",
988 nameISize(sz), nameIReg(sz,reg));
989 break;
990 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +0000991 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tdec%c\t%s\n",
996 nameISize(sz), nameIReg(sz,reg));
997 break;
998 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +0000999 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001000 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001001 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (dis)
1003 VG_(printf)( "\n\t\tinc%c\t%s\n",
1004 nameISize(sz), nameIReg(sz,reg));
1005 break;
1006 default:
njne427a662002-10-02 11:08:25 +00001007 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001008 }
1009}
1010
njn25e49d8e72002-09-23 09:36:25 +00001011void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001014 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001016 } else {
1017 vg_assert(sz == 4);
1018 }
njn25e49d8e72002-09-23 09:36:25 +00001019 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001020 if (dis)
1021 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1022}
1023
njn25e49d8e72002-09-23 09:36:25 +00001024void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001025{
sewardjf0f12aa2002-12-28 00:04:08 +00001026 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001029 } else {
1030 vg_assert(sz == 4);
1031 }
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1035}
1036
njn25e49d8e72002-09-23 09:36:25 +00001037void VG_(emit_pushl_lit32) ( UInt int32 )
1038{
sewardjf0f12aa2002-12-28 00:04:08 +00001039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001040 VG_(emitB) ( 0x68 );
1041 VG_(emitL) ( int32 );
1042 if (dis)
1043 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1044}
1045
1046void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001047{
1048 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001049 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x6A );
1051 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001052 if (dis)
1053 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1054}
1055
sewardjf0f12aa2002-12-28 00:04:08 +00001056void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001057{
sewardjf0f12aa2002-12-28 00:04:08 +00001058 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x83 );
1060 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1061 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001062 if (dis)
1063 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1064}
1065
1066static void emit_swapl_reg_ECX ( Int reg )
1067{
sewardjf0f12aa2002-12-28 00:04:08 +00001068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1070 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001078 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001079 if (dis)
1080 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1081}
1082
1083static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1084{
sewardjf0f12aa2002-12-28 00:04:08 +00001085 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1087 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
1093static void emit_bswapl_reg ( Int reg )
1094{
sewardjf0f12aa2002-12-28 00:04:08 +00001095 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F );
1097 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1100}
1101
1102static void emit_movl_reg_reg ( Int regs, Int regd )
1103{
sewardjf0f12aa2002-12-28 00:04:08 +00001104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001105 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1106 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001107 if (dis)
1108 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1109}
1110
njn25e49d8e72002-09-23 09:36:25 +00001111void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001112{
sewardjf0f12aa2002-12-28 00:04:08 +00001113 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001114 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001115 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 } else {
1117 vg_assert(sz == 4);
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1120 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1121 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1124 nameISize(sz), lit, off, nameIReg(4,memreg) );
1125}
1126
1127
1128/*----------------------------------------------------*/
1129/*--- b-size (1 byte) instruction emitters ---*/
1130/*----------------------------------------------------*/
1131
1132/* There is some doubt as to whether C6 (Grp 11) is in the
1133 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001134void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1138 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1139 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (dis)
1141 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1142 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001143}
1144
sewardjf0f12aa2002-12-28 00:04:08 +00001145static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001146 Int off, Int areg, Int reg )
1147{
sewardjf0f12aa2002-12-28 00:04:08 +00001148 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001149 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1150 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001151 if (dis)
1152 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001154 nameIReg(1,reg));
1155}
1156
sewardjf0f12aa2002-12-28 00:04:08 +00001157static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001158 UInt lit, Int off, Int areg )
1159{
sewardjf0f12aa2002-12-28 00:04:08 +00001160 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001161 VG_(emitB) ( 0x80 );
1162 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1163 VG_(emitB) ( lit );
1164 if (dis)
1165 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1166 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1167}
1168
sewardja2c5a732002-12-15 03:10:42 +00001169#if 0
1170/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001171static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001172 Int off, Int areg, Int reg )
1173{
sewardjf0f12aa2002-12-28 00:04:08 +00001174 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001175 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1176 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1177 if (dis)
1178 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1179 VG_(name_UOpcode)(False,opc),
1180 nameIReg(1,reg),
1181 off, nameIReg(4,areg));
1182}
sewardja2c5a732002-12-15 03:10:42 +00001183#endif
sewardjfa492d42002-12-08 18:20:01 +00001184
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001186{
1187 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001188 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001189 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1190 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1193 nameIReg(1,reg), off, nameIReg(4,areg));
1194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1197 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg1), nameIReg(1,reg2));
1206}
1207
1208static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1209{
sewardjf0f12aa2002-12-28 00:04:08 +00001210 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001212 emit_amode_regmem_reg ( reg2, reg1 );
1213 if (dis)
1214 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1215 nameIReg(4,reg2));
1216}
1217
sewardjf0f12aa2002-12-28 00:04:08 +00001218static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1219 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001220{
sewardjf0f12aa2002-12-28 00:04:08 +00001221 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001222 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1223 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1224 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001225 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001226 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001227 lit, nameIReg(1,reg));
1228}
1229
sewardjf0f12aa2002-12-28 00:04:08 +00001230static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1231 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001232{
sewardjf0f12aa2002-12-28 00:04:08 +00001233 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001234 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1235 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1236 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001237 if (dis)
1238 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001239 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001240 lit, nameIReg(1,reg));
1241}
1242
sewardjf0f12aa2002-12-28 00:04:08 +00001243void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001244{
sewardjde4a1d02002-03-22 01:27:54 +00001245 switch (opc) {
1246 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001247 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001248 VG_(emitB) ( 0xFE );
1249 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001250 if (dis)
1251 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1252 break;
1253 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001254 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001255 VG_(emitB) ( 0xFE );
1256 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001257 if (dis)
1258 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1259 break;
1260 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001262 VG_(emitB) ( 0xF6 );
1263 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001264 if (dis)
1265 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1266 break;
1267 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xF6 );
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001271 if (dis)
1272 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1273 break;
1274 default:
njne427a662002-10-02 11:08:25 +00001275 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001276 }
1277}
1278
sewardjf0f12aa2002-12-28 00:04:08 +00001279void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001280{
sewardjf0f12aa2002-12-28 00:04:08 +00001281 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001282 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1283 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1284 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1287}
1288
sewardjde4a1d02002-03-22 01:27:54 +00001289/*----------------------------------------------------*/
1290/*--- zero-extended load emitters ---*/
1291/*----------------------------------------------------*/
1292
njn25e49d8e72002-09-23 09:36:25 +00001293void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001294{
sewardjf0f12aa2002-12-28 00:04:08 +00001295 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001296 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1297 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001298 if (dis)
1299 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1300 off, nameIReg(4,regmem), nameIReg(4,reg));
1301}
1302
1303static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1304{
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001307 emit_amode_regmem_reg ( reg1, reg2 );
1308 if (dis)
1309 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1310 nameIReg(4,reg2));
1311}
1312
njn25e49d8e72002-09-23 09:36:25 +00001313void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001314{
sewardjf0f12aa2002-12-28 00:04:08 +00001315 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001316 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1317 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001318 if (dis)
1319 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1320 off, nameIReg(4,areg), nameIReg(4,reg));
1321}
1322
1323static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1324{
sewardjf0f12aa2002-12-28 00:04:08 +00001325 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001327 emit_amode_regmem_reg ( reg1, reg2 );
1328 if (dis)
1329 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1330 nameIReg(4,reg2));
1331}
1332
1333/*----------------------------------------------------*/
1334/*--- FPU instruction emitters ---*/
1335/*----------------------------------------------------*/
1336
1337static void emit_get_fpu_state ( void )
1338{
1339 Int off = 4 * VGOFF_(m_fpustate);
sewardjf0f12aa2002-12-28 00:04:08 +00001340 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001341 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1342 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001343 if (dis)
1344 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1345}
1346
1347static void emit_put_fpu_state ( void )
1348{
1349 Int off = 4 * VGOFF_(m_fpustate);
sewardjf0f12aa2002-12-28 00:04:08 +00001350 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001351 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1352 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001353 if (dis)
1354 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1355}
1356
sewardjf0f12aa2002-12-28 00:04:08 +00001357static void emit_fpu_no_mem ( FlagSet uses_sflags,
1358 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001359 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001360 UChar second_byte )
1361{
sewardjf0f12aa2002-12-28 00:04:08 +00001362 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001363 VG_(emitB) ( first_byte );
1364 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001365 if (dis)
1366 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1367 (UInt)first_byte, (UInt)second_byte );
1368}
1369
sewardjf0f12aa2002-12-28 00:04:08 +00001370static void emit_fpu_regmem ( FlagSet uses_sflags,
1371 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001372 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001373 UChar second_byte_masked,
1374 Int reg )
1375{
sewardjf0f12aa2002-12-28 00:04:08 +00001376 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001377 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001378 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1379 if (dis)
1380 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1381 (UInt)first_byte, (UInt)second_byte_masked,
1382 nameIReg(4,reg) );
1383}
1384
1385
1386/*----------------------------------------------------*/
1387/*--- misc instruction emitters ---*/
1388/*----------------------------------------------------*/
1389
njn25e49d8e72002-09-23 09:36:25 +00001390void VG_(emit_call_reg) ( Int reg )
1391{
sewardjfa492d42002-12-08 18:20:01 +00001392 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001393 VG_(emitB) ( 0xFF ); /* Grp5 */
1394 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1395 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001396 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001397}
1398
sewardjf0f12aa2002-12-28 00:04:08 +00001399static
1400void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1401 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001402{
sewardjfa492d42002-12-08 18:20:01 +00001403 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001404 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001405
1406 if (byte_off < -128 || byte_off > 127) {
1407 VG_(emitB) ( 0xFF );
1408 VG_(emitB) ( 0x95 );
1409 VG_(emitL) ( byte_off );
1410 } else {
1411 VG_(emitB) ( 0xFF );
1412 VG_(emitB) ( 0x55 );
1413 VG_(emitB) ( byte_off );
1414 }
1415 if (dis)
1416 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001417}
1418
sewardja2c5a732002-12-15 03:10:42 +00001419#if 0
1420/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001421static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1422{
1423 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001424 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001425 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1426 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001427 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001428 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001429 if (dis)
1430 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1431 nameIReg(4,regmem));
1432}
sewardja2c5a732002-12-15 03:10:42 +00001433#endif
sewardjde4a1d02002-03-22 01:27:54 +00001434
njn25e49d8e72002-09-23 09:36:25 +00001435void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001436{
njne427a662002-10-02 11:08:25 +00001437 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001438 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1439 VG_(emitB) ( 0x8D );
1440 VG_(emitB) ( 0x64 );
1441 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001442 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001443 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001444 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001445}
1446
1447
1448static void emit_movb_AL_zeroESPmem ( void )
1449{
1450 /* movb %al, 0(%esp) */
1451 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001452 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001453 VG_(emitB) ( 0x88 );
1454 VG_(emitB) ( 0x44 );
1455 VG_(emitB) ( 0x24 );
1456 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001457 if (dis)
1458 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1459}
1460
1461static void emit_movb_zeroESPmem_AL ( void )
1462{
1463 /* movb 0(%esp), %al */
1464 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001465 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001466 VG_(emitB) ( 0x8A );
1467 VG_(emitB) ( 0x44 );
1468 VG_(emitB) ( 0x24 );
1469 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001470 if (dis)
1471 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1472}
1473
sewardja2113f92002-12-12 23:42:48 +00001474/* Jump target states */
1475#define TGT_UNDEF (1 << 16)
1476#define TGT_FORWARD (2 << 16)
1477#define TGT_BACKWARD (3 << 16)
1478
1479static inline Int tgt_state(Int tgt)
1480{
1481 return tgt & 0xffff0000;
1482}
1483
1484static inline Int tgt_addr(Int tgt)
1485{
1486 return tgt & 0x0000ffff;
1487}
1488
1489static inline Int mk_tgt(Int state, Int addr)
1490{
1491 vg_assert(state == TGT_UNDEF
1492 || state == TGT_FORWARD || state == TGT_BACKWARD);
1493 vg_assert((addr & 0xffff0000) == 0);
1494
1495 return state | addr;
1496}
1497
1498void VG_(init_target) ( Int *tgt )
1499{
1500 *tgt = TGT_UNDEF;
1501}
1502
1503void VG_(target_back) ( Int *tgt )
1504{
1505 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1506
1507 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1508}
1509
1510void VG_(target_forward) ( Int *tgt )
1511{
1512 Int delta;
1513
1514 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1515 tgt_state(*tgt) == TGT_UNDEF);
1516
1517 if (tgt_state(*tgt) == TGT_UNDEF)
1518 return; /* target not used */
1519
1520 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1521 vg_assert(delta >= -128 && delta <= 127);
1522 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001523 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001524 emitted_code[tgt_addr(*tgt)] = delta;
1525 if (dis)
1526 VG_(printf)("(target to jump site %d; delta: %d)\n",
1527 tgt_addr(*tgt), delta);
1528}
1529
1530void VG_(emit_target_delta) ( Int *tgt )
1531{
1532 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1533 tgt_state(*tgt) == TGT_BACKWARD);
1534
1535 if (tgt_state(*tgt) == TGT_UNDEF) {
1536 /* forward jump */
1537 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1538 VG_(emitB) (0x00);
1539 } else {
1540 /* backward jump */
1541 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1542 vg_assert(delta >= -128 && delta <= 127);
1543 VG_(emitB) (delta);
1544 }
1545}
1546
sewardjde4a1d02002-03-22 01:27:54 +00001547
1548/* Emit a jump short with an 8-bit signed offset. Note that the
1549 offset is that which should be added to %eip once %eip has been
1550 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001551void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001552{
1553 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001554 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001555 VG_(emitB) ( 0x70 + (UInt)cond );
1556 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001557 if (dis)
1558 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001559 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001560}
1561
sewardja2113f92002-12-12 23:42:48 +00001562/* Same as above, but defers emitting the delta */
1563void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1564{
sewardj706240d2002-12-26 17:10:12 +00001565 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001566 VG_(emitB) ( 0x70 + (UInt)cond );
1567 VG_(emit_target_delta) (tgt);
1568 if (dis)
1569 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001570 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001571}
1572
1573
1574
sewardjf0f12aa2002-12-28 00:04:08 +00001575static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001576{
sewardjf0f12aa2002-12-28 00:04:08 +00001577 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001578 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1579 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001580 if (dis)
1581 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001582 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001583}
1584
1585static void emit_ret ( void )
1586{
sewardjfa492d42002-12-08 18:20:01 +00001587 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001588 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001589 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001590 if (dis)
1591 VG_(printf)("\n\t\tret\n");
1592}
1593
sewardj22854b92002-11-30 14:00:47 +00001594/* Predicate used in sanity checks elsewhere - returns true if any
1595 jump-site is an actual chained jump */
1596Bool VG_(is_chained_jumpsite)(Addr a)
1597{
1598 UChar *cp = (UChar *)a;
1599
1600 return (*cp == 0xE9); /* 0xE9 -- jmp */
1601}
1602
sewardj83f11862002-12-01 02:07:08 +00001603static
1604Bool is_fresh_jumpsite(UChar *cp)
1605{
1606 return
1607 cp[0] == 0x0F && /* UD2 */
1608 cp[1] == 0x0B &&
1609 cp[2] == 0x0F && /* UD2 */
1610 cp[3] == 0x0B &&
1611 cp[4] == 0x90; /* NOP */
1612}
1613
sewardj22854b92002-11-30 14:00:47 +00001614/* Predicate used in sanity checks elsewhere - returns true if all
1615 jump-sites are calls to VG_(patch_me) */
1616Bool VG_(is_unchained_jumpsite)(Addr a)
1617{
1618 UChar *cp = (UChar *)a;
1619 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1620 Int idelta;
1621
1622 if (*cp++ != 0xE8) /* 0xE8 == call */
1623 return False;
1624
1625 idelta = (*cp++) << 0;
1626 idelta |= (*cp++) << 8;
1627 idelta |= (*cp++) << 16;
1628 idelta |= (*cp++) << 24;
1629
1630 return idelta == delta;
1631}
1632
1633/* Return target address for a direct jmp */
1634Addr VG_(get_jmp_dest)(Addr a)
1635{
1636 Int delta;
1637 UChar *cp = (UChar *)a;
1638
1639 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1640 return 0;
1641
1642 delta = (*cp++) << 0;
1643 delta |= (*cp++) << 8;
1644 delta |= (*cp++) << 16;
1645 delta |= (*cp++) << 24;
1646
1647 return a + VG_PATCHME_JMPSZ + delta;
1648}
1649
1650/* unchain a BB by generating a call to VG_(patch_me) */
1651void VG_(unchain_jumpsite)(Addr a)
1652{
1653 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1654 UChar *cp = (UChar *)a;
1655
1656 if (VG_(is_unchained_jumpsite)(a))
1657 return; /* don't write unnecessarily */
1658
sewardj83f11862002-12-01 02:07:08 +00001659 if (!is_fresh_jumpsite(cp))
1660 VG_(bb_dechain_count)++; /* update stats */
1661
sewardj22854b92002-11-30 14:00:47 +00001662 *cp++ = 0xE8; /* call */
1663 *cp++ = (delta >> 0) & 0xff;
1664 *cp++ = (delta >> 8) & 0xff;
1665 *cp++ = (delta >> 16) & 0xff;
1666 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001667}
1668
1669/* This doesn't actually generate a call to VG_(patch_me), but
1670 reserves enough space in the instruction stream for it to happen
1671 and records the offset into the jump table. This is because call
1672 is a relative jump, and so will be affected when this code gets
1673 moved about. The translation table will "unchain" this basic block
1674 on insertion (with VG_(unchain_BB)()), and thereby generate a
1675 proper call instruction. */
1676static void emit_call_patchme( void )
1677{
1678 vg_assert(VG_PATCHME_CALLSZ == 5);
1679
sewardjfa492d42002-12-08 18:20:01 +00001680 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001681 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001682
1683 if (jumpidx >= VG_MAX_JUMPS) {
1684 /* If there too many jumps in this basic block, fall back to
1685 dispatch loop. We still need to keep it the same size as the
1686 call sequence. */
1687 VG_(emitB) ( 0xC3 ); /* ret */
1688 VG_(emitB) ( 0x90 ); /* nop */
1689 VG_(emitB) ( 0x90 ); /* nop */
1690 VG_(emitB) ( 0x90 ); /* nop */
1691 VG_(emitB) ( 0x90 ); /* nop */
1692
1693 if (dis)
1694 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1695
1696 if (0 && VG_(clo_verbosity))
1697 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1698 } else {
1699 jumps[jumpidx++] = emitted_code_used;
1700
1701 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1702 VG_(emitB) ( 0x0B );
1703 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1704 VG_(emitB) ( 0x0B );
1705 VG_(emitB) ( 0x90 ); /* NOP */
1706
1707 if (dis)
1708 VG_(printf)("\n\t\tud2; ud2; nop\n");
1709 }
1710}
1711
njn25e49d8e72002-09-23 09:36:25 +00001712void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001713{
sewardjf0f12aa2002-12-28 00:04:08 +00001714 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001715 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001716 if (dis)
1717 VG_(printf)("\n\t\tpushal\n");
1718}
1719
njn25e49d8e72002-09-23 09:36:25 +00001720void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001721{
sewardjf0f12aa2002-12-28 00:04:08 +00001722 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001723 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001724 if (dis)
1725 VG_(printf)("\n\t\tpopal\n");
1726}
1727
1728static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1729{
sewardjf0f12aa2002-12-28 00:04:08 +00001730 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001731 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1732 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001733 if (dis)
1734 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1735 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1736}
1737
1738static void emit_lea_sib_reg ( UInt lit, Int scale,
1739 Int regbase, Int regindex, Int reg )
1740{
sewardjf0f12aa2002-12-28 00:04:08 +00001741 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001742 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001743 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1744 if (dis)
1745 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1746 lit, nameIReg(4,regbase),
1747 nameIReg(4,regindex), scale,
1748 nameIReg(4,reg) );
1749}
1750
njn25e49d8e72002-09-23 09:36:25 +00001751void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001752{
sewardjf0f12aa2002-12-28 00:04:08 +00001753 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001754 VG_(emitB) ( 0x0F );
1755 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001756 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1757 if (dis)
1758 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1759}
1760
1761/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001762/*--- Helper offset -> addr translation ---*/
1763/*----------------------------------------------------*/
1764
1765/* Finds the baseBlock offset of a skin-specified helper.
1766 * Searches through compacts first, then non-compacts. */
1767Int VG_(helper_offset)(Addr a)
1768{
1769 Int i;
njnf4ce3d32003-02-10 10:17:26 +00001770 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001771
1772 for (i = 0; i < VG_(n_compact_helpers); i++)
1773 if (VG_(compact_helper_addrs)[i] == a)
1774 return VG_(compact_helper_offsets)[i];
1775 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1776 if (VG_(noncompact_helper_addrs)[i] == a)
1777 return VG_(noncompact_helper_offsets)[i];
1778
1779 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001780 VG_(get_fnname) ( a, buf, 100 );
1781
njn25e49d8e72002-09-23 09:36:25 +00001782 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001783 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1784 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001785
1786 VG_(printf)(" compact helpers: ");
1787 for (i = 0; i < VG_(n_compact_helpers); i++)
1788 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1789
1790 VG_(printf)("\n non-compact helpers: ");
1791 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1792 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1793
1794 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001795 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001796}
1797
1798/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001799/*--- Instruction synthesisers ---*/
1800/*----------------------------------------------------*/
1801
1802static Condcode invertCondition ( Condcode cond )
1803{
1804 return (Condcode)(1 ^ (UInt)cond);
1805}
1806
1807
1808/* Synthesise a call to *baseBlock[offset], ie,
1809 call * (4 x offset)(%ebp).
1810*/
sewardjfa492d42002-12-08 18:20:01 +00001811void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00001812 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001813{
1814 vg_assert(word_offset >= 0);
1815 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001816 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001817 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001818 }
sewardjf0f12aa2002-12-28 00:04:08 +00001819 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001820}
1821
njn25e49d8e72002-09-23 09:36:25 +00001822static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001823{
njn25e49d8e72002-09-23 09:36:25 +00001824 if (src != dst) {
1825 VG_(emit_movv_reg_reg) ( 4, src, dst );
1826 ccall_arg_setup_instrs++;
1827 }
njn6431be72002-07-28 09:53:34 +00001828}
njn25e49d8e72002-09-23 09:36:25 +00001829
1830/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1831static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1832{
1833 if (RealReg == tag) {
1834 maybe_emit_movl_reg_reg ( litOrReg, reg );
1835 } else if (Literal == tag) {
1836 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1837 ccall_arg_setup_instrs++;
1838 }
1839 else
njne427a662002-10-02 11:08:25 +00001840 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001841}
1842
1843static
1844void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1845{
1846 if (R_EAX == reg1) {
1847 VG_(emit_swapl_reg_EAX) ( reg2 );
1848 } else if (R_EAX == reg2) {
1849 VG_(emit_swapl_reg_EAX) ( reg1 );
1850 } else {
1851 emit_swapl_reg_reg ( reg1, reg2 );
1852 }
1853 ccall_arg_setup_instrs++;
1854}
1855
1856static
1857void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1858{
1859 if (dst1 != src2) {
1860 maybe_emit_movl_reg_reg ( src1, dst1 );
1861 maybe_emit_movl_reg_reg ( src2, dst2 );
1862
1863 } else if (dst2 != src1) {
1864 maybe_emit_movl_reg_reg ( src2, dst2 );
1865 maybe_emit_movl_reg_reg ( src1, dst1 );
1866
1867 } else {
1868 /* swap to break cycle */
1869 emit_swapl_arg_regs ( dst1, dst2 );
1870 }
1871}
1872
1873static
1874void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1875 UInt dst1, UInt dst2, UInt dst3)
1876{
1877 if (dst1 != src2 && dst1 != src3) {
1878 maybe_emit_movl_reg_reg ( src1, dst1 );
1879 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1880
1881 } else if (dst2 != src1 && dst2 != src3) {
1882 maybe_emit_movl_reg_reg ( src2, dst2 );
1883 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1884
1885 } else if (dst3 != src1 && dst3 != src2) {
1886 maybe_emit_movl_reg_reg ( src3, dst3 );
1887 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1888
1889 } else {
1890 /* break cycle */
1891 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1892 emit_swapl_arg_regs ( dst1, dst2 );
1893 emit_swapl_arg_regs ( dst1, dst3 );
1894
1895 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1896 emit_swapl_arg_regs ( dst1, dst3 );
1897 emit_swapl_arg_regs ( dst1, dst2 );
1898
1899 } else {
njne427a662002-10-02 11:08:25 +00001900 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001901 }
1902 }
1903}
1904
1905static
1906void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1907 UInt src1, UInt src2,
1908 UInt dst1, UInt dst2)
1909{
1910 /* If either are lits, order doesn't matter */
1911 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1912 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1913 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1914
1915 } else {
1916 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1917 }
1918}
1919
1920static
1921void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1922 UInt src1, UInt src2, UInt src3,
1923 UInt dst1, UInt dst2, UInt dst3)
1924{
1925 // SSS: fix this eventually -- make STOREV use two RealRegs?
1926 /* Not supporting literals for 3-arg C functions -- they're only used
1927 by STOREV which has 2 args */
1928 vg_assert(RealReg == tagv[src1] &&
1929 RealReg == tagv[src2] &&
1930 RealReg == tagv[src3]);
1931 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1932 dst1, dst2, dst3 );
1933}
1934
1935/* Synthesise a call to a C function `fn' (which must be registered in
1936 baseBlock) doing all the reg saving and arg handling work.
1937
1938 WARNING: a UInstr should *not* be translated with synth_ccall followed
1939 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1940 such behaviour and everything will fall over.
1941 */
1942void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1943 Tag tagv[], Int ret_reg,
1944 RRegSet regs_live_before, RRegSet regs_live_after )
1945{
1946 Int i;
1947 Int stack_used = 0;
1948 Bool preserve_eax, preserve_ecx, preserve_edx;
1949
1950 vg_assert(0 <= regparms_n && regparms_n <= 3);
1951
1952 ccalls++;
1953
1954 /* If %e[acd]x is live before and after the C call, save/restore it.
1955 Unless the return values clobbers the reg; in this case we must not
1956 save/restore the reg, because the restore would clobber the return
1957 value. (Before and after the UInstr really constitute separate live
1958 ranges, but you miss this if you don't consider what happens during
1959 the UInstr.) */
1960# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001961 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1962 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001963 ret_reg != realReg)
1964
1965 preserve_eax = PRESERVE_REG(R_EAX);
1966 preserve_ecx = PRESERVE_REG(R_ECX);
1967 preserve_edx = PRESERVE_REG(R_EDX);
1968
1969# undef PRESERVE_REG
1970
1971 /* Save caller-save regs as required */
1972 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1973 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1974 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1975
1976 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1977 is the number of args passed in regs (maximum 3 for GCC on x86). */
1978
1979 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001980
njn25e49d8e72002-09-23 09:36:25 +00001981 /* First push stack args (RealRegs or Literals) in reverse order. */
1982 for (i = argc-1; i >= regparms_n; i--) {
1983 switch (tagv[i]) {
1984 case RealReg:
1985 VG_(emit_pushv_reg) ( 4, argv[i] );
1986 break;
1987 case Literal:
1988 /* Use short form of pushl if possible. */
1989 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1990 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1991 else
1992 VG_(emit_pushl_lit32)( argv[i] );
1993 break;
1994 default:
1995 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001996 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001997 }
1998 stack_used += 4;
1999 ccall_arg_setup_instrs++;
2000 }
njn6431be72002-07-28 09:53:34 +00002001
njn25e49d8e72002-09-23 09:36:25 +00002002 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2003 If moving values between registers, be careful not to clobber any on
2004 the way. Happily we can use xchgl to swap registers.
2005 */
2006 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002007
njn25e49d8e72002-09-23 09:36:25 +00002008 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2009 case 3:
2010 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2011 R_EAX, R_EDX, R_ECX );
2012 break;
njn6431be72002-07-28 09:53:34 +00002013
njn25e49d8e72002-09-23 09:36:25 +00002014 /* Less-tricky. Args passed in %eax and %edx. */
2015 case 2:
2016 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2017 break;
2018
2019 /* Easy. Just move arg1 into %eax (if not already in there). */
2020 case 1:
2021 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2022 break;
2023
2024 case 0:
2025 break;
2026
2027 default:
njne427a662002-10-02 11:08:25 +00002028 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002029 }
2030
sewardjfa492d42002-12-08 18:20:01 +00002031 /* Call the function - may trash all flags */
2032 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002033
2034 /* Clear any args from stack */
2035 if (0 != stack_used) {
2036 VG_(emit_add_lit_to_esp) ( stack_used );
2037 ccall_stack_clears++;
2038 }
2039
2040 /* Move return value into ret_reg if necessary and not already there */
2041 if (INVALID_REALREG != ret_reg) {
2042 ccall_retvals++;
2043 if (R_EAX != ret_reg) {
2044 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2045 ccall_retval_movs++;
2046 }
2047 }
2048
2049 /* Restore live caller-save regs as required */
2050 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2051 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2052 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002053}
sewardjde4a1d02002-03-22 01:27:54 +00002054
sewardj2e93c502002-04-12 11:12:52 +00002055static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002056{
sewardj2e93c502002-04-12 11:12:52 +00002057 switch (jmpkind) {
2058 case JmpBoring:
2059 break;
sewardj2e93c502002-04-12 11:12:52 +00002060 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002061 break;
2062 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002063 break;
2064 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002065 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002066 break;
2067 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002068 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002069 break;
2070 default:
njne427a662002-10-02 11:08:25 +00002071 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002072 }
2073}
2074
2075/* Jump to the next translation, by loading its original addr into
2076 %eax and returning to the scheduler. Signal special requirements
2077 by loading a special value into %ebp first.
2078*/
2079static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2080{
sewardjfa492d42002-12-08 18:20:01 +00002081 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002082 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002083 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002084 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002085 emit_ret();
2086}
2087
sewardj22854b92002-11-30 14:00:47 +00002088static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002089
2090/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002091static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002092{
sewardjfa492d42002-12-08 18:20:01 +00002093 maybe_emit_put_eflags(); /* save flags here */
2094
njn25e49d8e72002-09-23 09:36:25 +00002095 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002096
2097 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2098 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2099 emit_call_patchme();
2100 } else {
2101 load_ebp_from_JmpKind ( jmpkind );
2102 emit_ret();
2103 }
sewardjde4a1d02002-03-22 01:27:54 +00002104}
2105
2106
sewardj2370f3b2002-11-30 15:01:01 +00002107static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002108static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002109 Opcode opcode, Int size,
2110 UInt lit, Int reg );
2111
sewardjfa492d42002-12-08 18:20:01 +00002112static void synth_jcond_lit ( Condcode cond,
2113 Addr addr,
2114 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002115{
sewardj2370f3b2002-11-30 15:01:01 +00002116 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002117 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002118 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002119
sewardja2113f92002-12-12 23:42:48 +00002120 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002121 VG_(init_target)(&tgt2);
2122 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002123
sewardjfa492d42002-12-08 18:20:01 +00002124 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2125 if need be */
2126 maybe_emit_put_eflags();
2127 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2128
2129 if (eflags_state == UPD_Both) {
2130 /* The flags are already set up, so we just use them as is. */
2131 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002132 cond = invertCondition(cond);
2133 } else {
sewardj75f04932002-12-12 23:13:21 +00002134 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002135
2136 /* The simd state contains the most recent version, so we emit a
2137 sequence to calculate the relevant condition directly out of
2138 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2139 copying them back to the real flags via popf. Notice that
2140 some of these sequences trash %eax, but that should be free
2141 now since this is the end of a bb and therefore all regs are
2142 dead. */
2143 simd = False;
2144
2145 switch (cond) {
2146
sewardjbb6c1182002-12-12 23:54:47 +00002147 case CondLE: /* Z || S != O -> S || !P */
2148 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002149 vg_assert(eax_trashable);
2150
2151 VG_(emit_movv_offregmem_reg)
2152 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2153 /* eax == %EFLAGS */
2154
sewardjbb6c1182002-12-12 23:54:47 +00002155 VG_(emit_nonshiftopv_lit_reg)
2156 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2157 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002158
sewardjbb6c1182002-12-12 23:54:47 +00002159 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2160 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002161
sewardj09736622002-12-28 00:19:00 +00002162 /* actually set the real cpu flags, since ROR changes
2163 neither P nor Z */
2164 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2165
sewardjbb6c1182002-12-12 23:54:47 +00002166 if (cond == CondLE) {
2167 /* test Z */
2168 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2169 /* test OF != SF */
2170 cond = CondP;
2171 } else {
2172 /* test Z */
2173 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2174 /* test OF == SF */
2175 cond = CondNP;
2176 }
sewardj2370f3b2002-11-30 15:01:01 +00002177 break;
2178
sewardjfa492d42002-12-08 18:20:01 +00002179 case CondL:
2180 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002181 vg_assert(eax_trashable);
2182
2183 VG_(emit_movv_offregmem_reg)
2184 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2185 /* eax == %EFLAGS */
2186
sewardj75f04932002-12-12 23:13:21 +00002187 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2188 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002189
sewardj75f04932002-12-12 23:13:21 +00002190 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2191 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002192
sewardj09736622002-12-28 00:19:00 +00002193 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002194 if (cond == CondL) cond = CondP; else cond = CondNP;
2195 break;
sewardjfa492d42002-12-08 18:20:01 +00002196
2197 case CondB:
2198 case CondNB:
2199 mask = EFlagC; goto simple; /* C=1 */
2200
2201 case CondZ:
2202 case CondNZ:
2203 mask = EFlagZ; goto simple; /* Z=1 */
2204
2205 case CondBE:
2206 case CondNBE:
2207 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2208
2209 case CondS:
2210 case CondNS:
2211 mask = EFlagS; goto simple; /* S=1 */
2212
2213 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002214 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002215 mask = EFlagP; goto simple; /* P=1 */
2216
sewardj39542072002-12-09 22:44:00 +00002217 case CondO:
2218 case CondNO:
2219 mask = EFlagO; goto simple; /* O=1 */
2220
sewardjfa492d42002-12-08 18:20:01 +00002221 default:
2222 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002223 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002224 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2225
2226 simple:
2227 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002228 if ((mask & 0xff) == mask) {
2229 VG_(emitB) ( 0xF6 ); /* Grp3 */
2230 VG_(emit_amode_offregmem_reg)(
2231 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2232 VG_(emitB) (mask);
2233 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002234 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002235 mask, VGOFF_(m_eflags) * 4);
2236 } else {
sewardjfa492d42002-12-08 18:20:01 +00002237 /* all cond codes are in lower 16 bits */
2238 vg_assert((mask & 0xffff) == mask);
2239
2240 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002241 VG_(emitB) ( 0xF7 );
2242 VG_(emit_amode_offregmem_reg)(
2243 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002244 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002245 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002246 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002247 mask, VGOFF_(m_eflags) * 4);
2248 }
2249
sewardj75f04932002-12-12 23:13:21 +00002250 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002251 break;
2252 }
2253 }
2254
sewardja2113f92002-12-12 23:42:48 +00002255 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002256
2257 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002258 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002259
2260 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002261 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002262}
2263
2264
sewardj2370f3b2002-11-30 15:01:01 +00002265
sewardjde4a1d02002-03-22 01:27:54 +00002266static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2267{
sewardja2113f92002-12-12 23:42:48 +00002268 Int tgt;
2269
2270 VG_(init_target)(&tgt);
2271
sewardjfa492d42002-12-08 18:20:01 +00002272 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002273
2274 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002275 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002276
2277 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002278}
2279
2280
2281static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2282{
2283 /* Load the zero-extended literal into reg, at size l,
2284 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002285 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002286}
2287
2288
2289static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2290{
2291 switch (size) {
2292 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2293 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2294 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002295 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002296 }
2297}
2298
2299
2300static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2301{
2302 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002303 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2304 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2305 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002306 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002307 }
2308}
2309
2310
2311static void synth_mov_reg_offregmem ( Int size, Int reg,
2312 Int off, Int areg )
2313{
2314 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002315 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2316 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002317 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002318 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002319 }
2320 else {
njn25e49d8e72002-09-23 09:36:25 +00002321 VG_(emit_swapl_reg_EAX) ( reg );
2322 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2323 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002324 }
2325 break;
njne427a662002-10-02 11:08:25 +00002326 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002327 }
2328}
2329
2330
2331static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2332{
2333 Int s1;
2334 switch (size) {
2335 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2336 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2337 case 1: if (reg1 < 4) {
2338 emit_movb_reg_regmem ( reg1, reg2 );
2339 }
2340 else {
2341 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2342 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2343 emit_swapl_reg_reg ( s1, reg1 );
2344 emit_movb_reg_regmem ( s1, reg2 );
2345 emit_swapl_reg_reg ( s1, reg1 );
2346 }
2347 break;
njne427a662002-10-02 11:08:25 +00002348 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002349 }
2350}
2351
2352
sewardjf0f12aa2002-12-28 00:04:08 +00002353static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002354 Opcode opcode, Int size,
2355 Int reg )
2356{
2357 /* NB! opcode is a uinstr opcode, not an x86 one! */
2358 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002359 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002360 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002361 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002362 break;
2363 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002364 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002365 } else {
njn25e49d8e72002-09-23 09:36:25 +00002366 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002367 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002368 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002369 }
2370 break;
njne427a662002-10-02 11:08:25 +00002371 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002372 }
2373}
2374
2375
2376
sewardjf0f12aa2002-12-28 00:04:08 +00002377static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002378 Opcode opcode, Int size,
2379 Int reg1, Int reg2 )
2380{
2381 /* NB! opcode is a uinstr opcode, not an x86 one! */
2382 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002383 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002384 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002385 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002386 break;
2387 case 1: { /* Horrible ... */
2388 Int s1, s2;
2389 /* Choose s1 and s2 to be x86 regs which we can talk about the
2390 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2391 sure s1 != s2 and that neither of them equal either reg1 or
2392 reg2. Then use them as temporaries to make things work. */
2393 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002394 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002395 break;
2396 }
2397 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2398 if (reg1 >= 4 && reg2 < 4) {
2399 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002400 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002401 emit_swapl_reg_reg ( reg1, s1 );
2402 break;
2403 }
2404 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2405 if (reg1 < 4 && reg2 >= 4) {
2406 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002407 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002408 emit_swapl_reg_reg ( reg2, s2 );
2409 break;
2410 }
2411 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2412 emit_swapl_reg_reg ( reg1, s1 );
2413 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002414 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002415 emit_swapl_reg_reg ( reg1, s1 );
2416 emit_swapl_reg_reg ( reg2, s2 );
2417 break;
2418 }
2419 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2420 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002421 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002422 emit_swapl_reg_reg ( reg1, s1 );
2423 break;
2424 }
njne427a662002-10-02 11:08:25 +00002425 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002426 }
njne427a662002-10-02 11:08:25 +00002427 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002428 }
2429}
2430
sewardja2c5a732002-12-15 03:10:42 +00002431#if 0
2432/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002433static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002434 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002435 Opcode opcode, Int size,
2436 Int off, Int areg, Int reg )
2437{
2438 switch (size) {
2439 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002440 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002441 break;
2442 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002443 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002444 break;
2445 case 1:
2446 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002447 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002448 } else {
2449 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002450 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002451 VG_(emit_swapl_reg_EAX) ( reg );
2452 }
2453 break;
2454 default:
2455 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2456 }
2457}
sewardja2c5a732002-12-15 03:10:42 +00002458#endif
sewardjfa492d42002-12-08 18:20:01 +00002459
sewardjde4a1d02002-03-22 01:27:54 +00002460static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002461 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002462 Opcode opcode, Int size,
2463 Int off, Int areg, Int reg )
2464{
2465 switch (size) {
2466 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002467 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002468 break;
2469 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002470 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002471 break;
2472 case 1:
2473 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002474 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002475 } else {
njn25e49d8e72002-09-23 09:36:25 +00002476 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002477 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002478 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002479 }
2480 break;
2481 default:
njne427a662002-10-02 11:08:25 +00002482 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002483 }
2484}
2485
2486
sewardjf0f12aa2002-12-28 00:04:08 +00002487static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002488 Opcode opcode, Int size,
2489 UInt lit, Int reg )
2490{
2491 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002492 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002493 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002494 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002495 break;
2496 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002497 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002498 } else {
njn25e49d8e72002-09-23 09:36:25 +00002499 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002500 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002501 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002502 }
2503 break;
njne427a662002-10-02 11:08:25 +00002504 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002505 }
2506}
2507
sewardjf0f12aa2002-12-28 00:04:08 +00002508static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002509 Opcode opcode, Int size,
2510 UInt lit, Int off, Int regmem )
2511{
2512 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002513 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002514 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002515 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002516 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002517 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002518 break;
2519 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2520 }
2521}
2522
sewardjde4a1d02002-03-22 01:27:54 +00002523
2524static void synth_push_reg ( Int size, Int reg )
2525{
2526 switch (size) {
2527 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002528 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002529 break;
2530 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002531 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002532 break;
2533 /* Pray that we don't have to generate this really cruddy bit of
2534 code very often. Could do better, but can I be bothered? */
2535 case 1:
2536 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002537 VG_(emit_add_lit_to_esp)(-1);
2538 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002539 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002540 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002541 break;
2542 default:
njne427a662002-10-02 11:08:25 +00002543 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002544 }
2545}
2546
2547
2548static void synth_pop_reg ( Int size, Int reg )
2549{
2550 switch (size) {
2551 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002552 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002553 break;
2554 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002555 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002556 break;
2557 case 1:
2558 /* Same comment as above applies. */
2559 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002560 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002561 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002562 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2563 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002564 break;
njne427a662002-10-02 11:08:25 +00002565 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002566 }
2567}
2568
2569
sewardjf0f12aa2002-12-28 00:04:08 +00002570static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002571 Opcode opcode, Int size,
2572 Int regs, Int regd )
2573{
2574 synth_push_reg ( size, regd );
2575 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002576 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002577 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2578 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2579 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002580 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002581 }
sewardjde4a1d02002-03-22 01:27:54 +00002582 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2583 synth_pop_reg ( size, regd );
2584}
2585
2586
sewardjf0f12aa2002-12-28 00:04:08 +00002587static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002588 Opcode opcode, Int size,
2589 UInt lit, Int reg )
2590{
2591 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002592 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002593 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002594 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002595 break;
2596 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002597 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002598 } else {
njn25e49d8e72002-09-23 09:36:25 +00002599 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002600 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002601 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002602 }
2603 break;
njne427a662002-10-02 11:08:25 +00002604 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002605 }
2606}
2607
2608
sewardjf0f12aa2002-12-28 00:04:08 +00002609static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002610{
sewardjde4a1d02002-03-22 01:27:54 +00002611 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002612 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002613 } else {
njn25e49d8e72002-09-23 09:36:25 +00002614 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002615 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002616 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002617 }
2618}
2619
2620
sewardjfa492d42002-12-08 18:20:01 +00002621static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2622 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002623 UChar second_byte_masked,
2624 Int reg )
2625{
sewardjfa492d42002-12-08 18:20:01 +00002626 emit_fpu_regmem ( uses_flags, sets_flags, first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002627}
2628
2629
sewardjfa492d42002-12-08 18:20:01 +00002630static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2631 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002632 UChar second_byte )
2633{
sewardjfa492d42002-12-08 18:20:01 +00002634 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002635}
2636
2637
2638static void synth_movl_reg_reg ( Int src, Int dst )
2639{
2640 emit_movl_reg_reg ( src, dst );
2641}
2642
2643static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2644{
sewardja2113f92002-12-12 23:42:48 +00002645 Int tgt;
2646
2647 VG_(init_target)(&tgt);
2648
2649 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002650 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002651
2652 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002653}
2654
2655
sewardjde4a1d02002-03-22 01:27:54 +00002656/*----------------------------------------------------*/
2657/*--- Top level of the uinstr -> x86 translation. ---*/
2658/*----------------------------------------------------*/
2659
2660/* Return the byte offset from %ebp (ie, into baseBlock)
2661 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002662static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2663{
2664 if (tag == SpillNo) {
2665 vg_assert(size == 4);
2666 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2667 return 4 * (value + VGOFF_(spillslots));
2668 }
2669 if (tag == ArchReg) {
2670 switch (value) {
2671 case R_EAX: return 4 * VGOFF_(m_eax);
2672 case R_ECX: return 4 * VGOFF_(m_ecx);
2673 case R_EDX: return 4 * VGOFF_(m_edx);
2674 case R_EBX: return 4 * VGOFF_(m_ebx);
2675 case R_ESP:
2676 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2677 else return 4 * VGOFF_(m_esp);
2678 case R_EBP:
2679 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2680 else return 4 * VGOFF_(m_ebp);
2681 case R_ESI:
2682 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2683 else return 4 * VGOFF_(m_esi);
2684 case R_EDI:
2685 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2686 else return 4 * VGOFF_(m_edi);
2687 }
2688 }
njne427a662002-10-02 11:08:25 +00002689 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002690}
2691
sewardjde4a1d02002-03-22 01:27:54 +00002692static Int eflagsOffset ( void )
2693{
2694 return 4 * VGOFF_(m_eflags);
2695}
2696
sewardje1042472002-09-30 12:33:11 +00002697static Int segRegOffset ( UInt archregs )
2698{
2699 switch (archregs) {
2700 case R_CS: return 4 * VGOFF_(m_cs);
2701 case R_SS: return 4 * VGOFF_(m_ss);
2702 case R_DS: return 4 * VGOFF_(m_ds);
2703 case R_ES: return 4 * VGOFF_(m_es);
2704 case R_FS: return 4 * VGOFF_(m_fs);
2705 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002706 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002707 }
2708}
2709
njnf4ce3d32003-02-10 10:17:26 +00002710UInt VG_(get_archreg) ( UInt arch )
2711{
2712 switch (arch) {
2713 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2714 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2715 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2716 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2717 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2718 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2719 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2720 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2721 default: VG_(core_panic)( "get_thread_archreg");
2722 }
2723}
2724
2725UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2726{
2727 ThreadState* tst;
2728
2729 vg_assert(VG_(is_valid_tid)(tid));
2730 tst = & VG_(threads)[tid];
2731
2732 switch (arch) {
2733 case R_EAX: return tst->m_eax;
2734 case R_ECX: return tst->m_ecx;
2735 case R_EDX: return tst->m_edx;
2736 case R_EBX: return tst->m_ebx;
2737 case R_ESP: return tst->m_esp;
2738 case R_EBP: return tst->m_ebp;
2739 case R_ESI: return tst->m_esi;
2740 case R_EDI: return tst->m_edi;
2741 default: VG_(core_panic)( "get_thread_archreg");
2742 }
2743}
2744
njnb93d1782003-02-03 12:03:22 +00002745/* Return the baseBlock index for the specified shadow register */
2746Int shadow_reg_index ( Int arch )
2747{
2748 switch (arch) {
2749 case R_EAX: return VGOFF_(sh_eax);
2750 case R_ECX: return VGOFF_(sh_ecx);
2751 case R_EDX: return VGOFF_(sh_edx);
2752 case R_EBX: return VGOFF_(sh_ebx);
2753 case R_ESP: return VGOFF_(sh_esp);
2754 case R_EBP: return VGOFF_(sh_ebp);
2755 case R_ESI: return VGOFF_(sh_esi);
2756 case R_EDI: return VGOFF_(sh_edi);
2757 default: VG_(core_panic)( "shadow_reg_index");
2758 }
2759}
sewardjde4a1d02002-03-22 01:27:54 +00002760
njn25e49d8e72002-09-23 09:36:25 +00002761/* Return the byte offset from %ebp (ie, into baseBlock)
2762 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002763Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002764{
njnb93d1782003-02-03 12:03:22 +00002765 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00002766}
2767
njn4ba5a792002-09-30 10:23:54 +00002768Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002769{
2770 return 4 * VGOFF_(sh_eflags);
2771}
2772
njnb93d1782003-02-03 12:03:22 +00002773/* Accessing shadow arch. registers */
2774UInt VG_(get_shadow_archreg) ( UInt archreg )
2775{
2776 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
2777}
2778
2779void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
2780{
2781 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
2782}
2783
njnf4ce3d32003-02-10 10:17:26 +00002784UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
2785{
2786 ThreadState* tst;
2787
2788 vg_assert(VG_(is_valid_tid)(tid));
2789 tst = & VG_(threads)[tid];
2790
2791 switch (archreg) {
2792 case R_EAX: return tst->sh_eax;
2793 case R_ECX: return tst->sh_ecx;
2794 case R_EDX: return tst->sh_edx;
2795 case R_EBX: return tst->sh_ebx;
2796 case R_ESP: return tst->sh_esp;
2797 case R_EBP: return tst->sh_ebp;
2798 case R_ESI: return tst->sh_esi;
2799 case R_EDI: return tst->sh_edi;
2800 default: VG_(core_panic)( "get_thread_shadow_archreg");
2801 }
2802}
2803
2804void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
2805{
2806 ThreadState* tst;
2807
2808 vg_assert(VG_(is_valid_tid)(tid));
2809 tst = & VG_(threads)[tid];
2810
2811 switch (archreg) {
2812 case R_EAX: tst->sh_eax = val; break;
2813 case R_ECX: tst->sh_ecx = val; break;
2814 case R_EDX: tst->sh_edx = val; break;
2815 case R_EBX: tst->sh_ebx = val; break;
2816 case R_ESP: tst->sh_esp = val; break;
2817 case R_EBP: tst->sh_ebp = val; break;
2818 case R_ESI: tst->sh_esi = val; break;
2819 case R_EDI: tst->sh_edi = val; break;
2820 default: VG_(core_panic)( "set_thread_shadow_archreg");
2821 }
2822}
2823
njnb93d1782003-02-03 12:03:22 +00002824Addr VG_(shadow_archreg_address) ( UInt archreg )
2825{
2826 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
2827}
sewardjde4a1d02002-03-22 01:27:54 +00002828
sewardjde4a1d02002-03-22 01:27:54 +00002829static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2830{
2831 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002832 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2833 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002834 }
2835 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002836 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2837 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002838 }
2839 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002840 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2841 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002842 }
2843 else
njne427a662002-10-02 11:08:25 +00002844 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002845}
2846
2847
njn25e49d8e72002-09-23 09:36:25 +00002848static void synth_handle_esp_assignment ( Int i, Int reg,
2849 RRegSet regs_live_before,
2850 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002851{
njn25e49d8e72002-09-23 09:36:25 +00002852 UInt argv[] = { reg };
2853 Tag tagv[] = { RealReg };
2854
2855 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2856 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002857}
2858
2859
sewardjde4a1d02002-03-22 01:27:54 +00002860/*----------------------------------------------------*/
2861/*--- Generate code for a single UInstr. ---*/
2862/*----------------------------------------------------*/
2863
sewardj478335c2002-10-05 02:44:47 +00002864static __inline__
2865Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002866{
2867 return (u->flags_w != FlagsEmpty);
2868}
2869
sewardjfa492d42002-12-08 18:20:01 +00002870static __inline__
2871Bool readFlagUse ( UInstr* u )
2872{
2873 /* If the UInstr writes some flags but not all, then we still need
2874 to consider it as reading flags so that the unchanged values are
2875 passed through properly. (D is special) */
2876 return
2877 (u->flags_r != FlagsEmpty) ||
2878 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2879}
2880
sewardj478335c2002-10-05 02:44:47 +00002881static __inline__
2882Bool anyFlagUse ( UInstr* u )
2883{
sewardjfa492d42002-12-08 18:20:01 +00002884 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002885}
2886
2887
sewardjb5ff83e2002-12-01 19:40:49 +00002888/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002889 the real FPU. If so we need to be very careful not to trash it.
2890 If FPU state is live and we deem it necessary to copy it back to
2891 the simulated machine's FPU state, we do so. The final state of
2892 fpliveness is returned. In short we _must_ do put_fpu_state if
2893 there is any chance at all that the code generated for a UInstr
2894 will change the real FPU state.
2895*/
sewardjb5ff83e2002-12-01 19:40:49 +00002896static void emitUInstr ( UCodeBlock* cb, Int i,
2897 RRegSet regs_live_before,
2898 /* Running state, which we update. */
2899 Bool* fplive, /* True<==>FPU state in real FPU */
2900 Addr* orig_eip, /* previous curr_eip, or zero */
2901 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002902{
njn25e49d8e72002-09-23 09:36:25 +00002903 Int old_emitted_code_used;
2904 UInstr* u = &cb->instrs[i];
2905
sewardjde4a1d02002-03-22 01:27:54 +00002906 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002907 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002908
njn25e49d8e72002-09-23 09:36:25 +00002909 old_emitted_code_used = emitted_code_used;
2910
sewardjde4a1d02002-03-22 01:27:54 +00002911 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002912 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002913
sewardjb5ff83e2002-12-01 19:40:49 +00002914 case INCEIP:
2915 /* Advance %EIP some small amount. */
2916 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002917
sewardjb5ff83e2002-12-01 19:40:49 +00002918 if (*orig_eip == 0 /* we don't know what the old value was */
2919 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2920 /* We have to update all 32 bits of the value. */
2921 VG_(emit_movv_lit_offregmem)(
2922 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2923 } else {
2924 /* Cool! we only need to update lowest 8 bits */
2925 VG_(emit_movb_lit_offregmem)(
2926 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002927 }
njn25e49d8e72002-09-23 09:36:25 +00002928
sewardjb5ff83e2002-12-01 19:40:49 +00002929 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002930 break;
sewardjde4a1d02002-03-22 01:27:54 +00002931
2932 case LEA1: {
2933 vg_assert(u->tag1 == RealReg);
2934 vg_assert(u->tag2 == RealReg);
2935 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2936 break;
2937 }
2938
2939 case LEA2: {
2940 vg_assert(u->tag1 == RealReg);
2941 vg_assert(u->tag2 == RealReg);
2942 vg_assert(u->tag3 == RealReg);
2943 emit_lea_sib_reg ( u->lit32, u->extra4b,
2944 u->val1, u->val2, u->val3 );
2945 break;
2946 }
2947
2948 case WIDEN: {
2949 vg_assert(u->tag1 == RealReg);
2950 if (u->signed_widen) {
2951 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2952 } else {
2953 /* no need to generate any code. */
2954 }
2955 break;
2956 }
2957
sewardjde4a1d02002-03-22 01:27:54 +00002958 case STORE: {
2959 vg_assert(u->tag1 == RealReg);
2960 vg_assert(u->tag2 == RealReg);
2961 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002962 break;
2963 }
2964
2965 case LOAD: {
2966 vg_assert(u->tag1 == RealReg);
2967 vg_assert(u->tag2 == RealReg);
2968 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2969 break;
2970 }
2971
sewardjde4a1d02002-03-22 01:27:54 +00002972 case GET: {
2973 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2974 vg_assert(u->tag2 == RealReg);
2975 synth_mov_offregmem_reg (
2976 u->size,
2977 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2978 R_EBP,
2979 u->val2
2980 );
2981 break;
2982 }
2983
2984 case PUT: {
2985 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2986 vg_assert(u->tag1 == RealReg);
2987 if (u->tag2 == ArchReg
2988 && u->val2 == R_ESP
2989 && u->size == 4
njnf4ce3d32003-02-10 10:17:26 +00002990 && VG_(need_to_handle_esp_assignment)())
njn25e49d8e72002-09-23 09:36:25 +00002991 {
2992 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2993 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002994 }
njn25e49d8e72002-09-23 09:36:25 +00002995 else {
2996 synth_mov_reg_offregmem (
2997 u->size,
2998 u->val1,
2999 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3000 R_EBP
3001 );
3002 }
sewardjde4a1d02002-03-22 01:27:54 +00003003 break;
3004 }
3005
sewardje1042472002-09-30 12:33:11 +00003006 case GETSEG: {
3007 vg_assert(u->tag1 == ArchRegS);
3008 vg_assert(u->tag2 == RealReg);
3009 vg_assert(u->size == 2);
3010 synth_mov_offregmem_reg (
3011 4,
3012 segRegOffset( u->val1 ),
3013 R_EBP,
3014 u->val2
3015 );
3016 break;
3017 }
3018
3019 case PUTSEG: {
3020 vg_assert(u->tag1 == RealReg);
3021 vg_assert(u->tag2 == ArchRegS);
3022 vg_assert(u->size == 2);
3023 synth_mov_reg_offregmem (
3024 4,
3025 u->val1,
3026 segRegOffset( u->val2 ),
3027 R_EBP
3028 );
3029 break;
3030 }
3031
sewardjde4a1d02002-03-22 01:27:54 +00003032 case GETF: {
3033 vg_assert(u->size == 2 || u->size == 4);
3034 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003035
3036 /* This complexity is because the D(irection) flag is stored
3037 separately from the rest of EFLAGS. */
3038
3039 /* We're only fetching from the Simd state, so make sure it's
3040 up to date. */
3041 maybe_emit_put_eflags();
3042
3043 /* get D in u->val1 (== 1 or -1) */
3044 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3045
3046 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3047 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3048
3049 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3050 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3051 eflagsOffset(), R_EBP);
3052
3053 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3054 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3055 eflagsOffset(), R_EBP);
3056
3057 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3058 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3059 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003060 break;
3061 }
3062
3063 case PUTF: {
3064 vg_assert(u->size == 2 || u->size == 4);
3065 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003066
3067 /* When putting a value into EFLAGS, this generates the
3068 correct value for m_dflag (-1 or 1), and clears the D bit
3069 in EFLAGS. */
3070
3071 /* We're updating the whole flag state, so the old state
3072 doesn't matter; make sure that the new simulated state
3073 will be fetched when needed. */
3074 eflags_state = UPD_Simd;
3075
3076 /* store EFLAGS (with D) */
3077 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3078
3079 /* u->val1 &= EFlagD */
3080 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3081
3082 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3083 synth_unaryop_reg(False, NEG, u->size, u->val1);
3084 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3085 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3086
3087 /* save D */
3088 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3089
3090 /* EFLAGS &= ~EFlagD */
3091 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3092 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003093 break;
3094 }
3095
3096 case MOV: {
3097 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3098 vg_assert(u->tag2 == RealReg);
3099 switch (u->tag1) {
3100 case RealReg: vg_assert(u->size == 4);
3101 if (u->val1 != u->val2)
3102 synth_movl_reg_reg ( u->val1, u->val2 );
3103 break;
3104 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3105 break;
njne427a662002-10-02 11:08:25 +00003106 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003107 }
3108 break;
3109 }
3110
sewardje1042472002-09-30 12:33:11 +00003111 case USESEG: {
3112 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3113 ones. */
sewardjd077f532002-09-30 21:52:50 +00003114 UInt argv[] = { u->val1, u->val2 };
3115 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003116 UInt ret_reg = u->val2;
3117
3118 vg_assert(u->tag1 == RealReg);
3119 vg_assert(u->tag2 == RealReg);
3120 vg_assert(u->size == 0);
3121
sewardjb5ff83e2002-12-01 19:40:49 +00003122 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003123 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003124 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003125 }
3126
sewardje1042472002-09-30 12:33:11 +00003127 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3128 2, /* args */
3129 0, /* regparms_n */
3130 argv, tagv,
3131 ret_reg, regs_live_before, u->regs_live_after );
3132 break;
3133 }
3134
sewardj478335c2002-10-05 02:44:47 +00003135 case SBB:
3136 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003137 case XOR:
3138 case OR:
3139 case AND:
3140 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003141 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003142 vg_assert(u->tag2 == RealReg);
3143 switch (u->tag1) {
3144 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003145 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003146 u->opcode, u->size, u->lit32, u->val2 );
3147 break;
3148 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003149 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003150 u->opcode, u->size, u->val1, u->val2 );
3151 break;
3152 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003153 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003154 u->opcode, u->size,
3155 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3156 R_EBP,
3157 u->val2 );
3158 break;
njne427a662002-10-02 11:08:25 +00003159 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003160 }
3161 break;
3162 }
3163
sewardj478335c2002-10-05 02:44:47 +00003164 case RCR:
3165 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003166 case ROR:
3167 case ROL:
3168 case SAR:
3169 case SHR:
3170 case SHL: {
3171 vg_assert(u->tag2 == RealReg);
3172 switch (u->tag1) {
3173 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003174 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003175 u->opcode, u->size, u->lit32, u->val2 );
3176 break;
3177 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003178 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003179 u->opcode, u->size, u->val1, u->val2 );
3180 break;
njne427a662002-10-02 11:08:25 +00003181 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003182 }
3183 break;
3184 }
3185
3186 case INC:
3187 case DEC:
3188 case NEG:
3189 case NOT:
3190 vg_assert(u->tag1 == RealReg);
3191 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003192 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003193 break;
3194
3195 case BSWAP:
3196 vg_assert(u->tag1 == RealReg);
3197 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003198 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003199 emit_bswapl_reg ( u->val1 );
3200 break;
3201
3202 case CMOV:
3203 vg_assert(u->tag1 == RealReg);
3204 vg_assert(u->tag2 == RealReg);
3205 vg_assert(u->cond != CondAlways);
3206 vg_assert(u->size == 4);
3207 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3208 break;
3209
3210 case JMP: {
3211 vg_assert(u->tag2 == NoValue);
3212 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00003213 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003214 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003215 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003216 }
sewardjde4a1d02002-03-22 01:27:54 +00003217 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003218 switch (u->tag1) {
3219 case RealReg:
3220 synth_jmp_reg ( u->val1, u->jmpkind );
3221 break;
3222 case Literal:
3223 synth_jmp_lit ( u->lit32, u->jmpkind );
3224 break;
3225 default:
njne427a662002-10-02 11:08:25 +00003226 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003227 break;
sewardjde4a1d02002-03-22 01:27:54 +00003228 }
3229 } else {
sewardj2e93c502002-04-12 11:12:52 +00003230 switch (u->tag1) {
3231 case RealReg:
njne427a662002-10-02 11:08:25 +00003232 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003233 break;
3234 case Literal:
3235 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003236 /* %eax had better not be live since synth_jcond_lit
3237 trashes it in some circumstances. If that turns
3238 out to be a problem we can get synth_jcond_lit to
3239 push/pop it when it is live. */
3240 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3241 u->regs_live_after));
3242 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003243 break;
3244 default:
njne427a662002-10-02 11:08:25 +00003245 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003246 break;
sewardjde4a1d02002-03-22 01:27:54 +00003247 }
3248 }
3249 break;
3250 }
3251
3252 case JIFZ:
3253 vg_assert(u->tag1 == RealReg);
3254 vg_assert(u->tag2 == Literal);
3255 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00003256 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003257 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003258 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003259 }
sewardjde4a1d02002-03-22 01:27:54 +00003260 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3261 break;
3262
sewardjde4a1d02002-03-22 01:27:54 +00003263 case PUSH:
3264 vg_assert(u->tag1 == RealReg);
3265 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003266 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003267 break;
3268
3269 case POP:
3270 vg_assert(u->tag1 == RealReg);
3271 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003272 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003273 break;
3274
3275 case CALLM:
3276 vg_assert(u->tag1 == Lit16);
3277 vg_assert(u->tag2 == NoValue);
3278 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00003279 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003280 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003281 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003282 }
sewardjfa492d42002-12-08 18:20:01 +00003283 /* Call to a helper which is pretending to be a real CPU
3284 instruction (and therefore operates on Real flags and
3285 registers) */
3286 VG_(synth_call) ( False, u->val1,
3287 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003288 break;
3289
njn25e49d8e72002-09-23 09:36:25 +00003290 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003291 /* If you change this, remember to change USESEG above, since
3292 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003293 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3294 ones. */
3295 UInt argv[] = { u->val1, u->val2, u->val3 };
3296 UInt tagv[] = { RealReg, RealReg, RealReg };
3297 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3298
3299 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3300 else vg_assert(u->tag1 == NoValue);
3301 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3302 else vg_assert(u->tag2 == NoValue);
3303 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3304 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003305 vg_assert(u->size == 0);
3306
sewardjb5ff83e2002-12-01 19:40:49 +00003307 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003308 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003309 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003310 }
njn25e49d8e72002-09-23 09:36:25 +00003311 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3312 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003313 break;
njn25e49d8e72002-09-23 09:36:25 +00003314 }
sewardje1042472002-09-30 12:33:11 +00003315
sewardjde4a1d02002-03-22 01:27:54 +00003316 case CLEAR:
3317 vg_assert(u->tag1 == Lit16);
3318 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003319 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003320 break;
3321
3322 case CC2VAL:
3323 vg_assert(u->tag1 == RealReg);
3324 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003325 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003326 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003327 break;
3328
sewardjde4a1d02002-03-22 01:27:54 +00003329 case FPU_R:
3330 case FPU_W:
3331 vg_assert(u->tag1 == Lit16);
3332 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003333 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003334 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003335 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003336 }
sewardjfa492d42002-12-08 18:20:01 +00003337 synth_fpu_regmem ( u->flags_r, u->flags_w,
3338 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003339 u->val1 & 0xFF,
3340 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003341 break;
3342
3343 case FPU:
3344 vg_assert(u->tag1 == Lit16);
3345 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00003346 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00003347 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00003348 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003349 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003350 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003351 }
sewardjfa492d42002-12-08 18:20:01 +00003352 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3353 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003354 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003355 break;
3356
3357 default:
sewardj1b7d8022002-11-30 12:35:42 +00003358 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003359 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003360 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003361 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003362 }
njn4ba5a792002-09-30 10:23:54 +00003363 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003364 } else {
njn25e49d8e72002-09-23 09:36:25 +00003365 VG_(printf)("\nError:\n"
3366 " unhandled opcode: %u. Perhaps "
3367 " VG_(needs).extended_UCode should be set?\n",
3368 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003369 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003370 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003371 }
sewardjde4a1d02002-03-22 01:27:54 +00003372 }
3373
sewardjb5ff83e2002-12-01 19:40:49 +00003374 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003375 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003376 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003377 }
3378
njn25e49d8e72002-09-23 09:36:25 +00003379 /* Update UInstr histogram */
3380 vg_assert(u->opcode < 100);
3381 histogram[u->opcode].counts++;
3382 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003383}
3384
3385
3386/* Emit x86 for the ucode in cb, returning the address of the
3387 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003388UChar* VG_(emit_code) ( UCodeBlock* cb,
3389 Int* nbytes,
3390 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003391{
3392 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003393 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003394 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003395 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003396 Int tgt;
3397
sewardjfa492d42002-12-08 18:20:01 +00003398 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003399
njn25e49d8e72002-09-23 09:36:25 +00003400 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003401
sewardj22854b92002-11-30 14:00:47 +00003402 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3403 zero. We have to do this regardless of whether we're t-chaining
3404 or not. */
sewardja2113f92002-12-12 23:42:48 +00003405 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003406 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003407 VG_(emitB) (0xFF); /* decl */
3408 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3409 if (dis)
3410 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003411 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003412 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3413 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003414 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003415
sewardjb5ff83e2002-12-01 19:40:49 +00003416 /* Set up running state. */
3417 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003418 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003419 curr_eip = cb->orig_eip;
3420 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3421 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003422 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003423 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003424 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003425 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003426
sewardjde4a1d02002-03-22 01:27:54 +00003427 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003428 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003429 if (!sane) {
3430 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003431 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003432 }
3433 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003434 emitUInstr( cb, i, regs_live_before,
3435 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003436 }
njn25e49d8e72002-09-23 09:36:25 +00003437 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003438 }
njn25e49d8e72002-09-23 09:36:25 +00003439 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003440 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3441 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003442
sewardj22854b92002-11-30 14:00:47 +00003443 if (j != NULL) {
3444 vg_assert(jumpidx <= VG_MAX_JUMPS);
3445 for(i = 0; i < jumpidx; i++)
3446 j[i] = jumps[i];
3447 }
3448
sewardjde4a1d02002-03-22 01:27:54 +00003449 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003450 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003451 *nbytes = emitted_code_used;
3452 return emitted_code;
3453}
3454
njn25e49d8e72002-09-23 09:36:25 +00003455#undef dis
3456
sewardjde4a1d02002-03-22 01:27:54 +00003457/*--------------------------------------------------------------------*/
3458/*--- end vg_from_ucode.c ---*/
3459/*--------------------------------------------------------------------*/