blob: 4a48bdd1007ab816133762b45b3fd3b69d0e3c3c [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
sewardj3d7c9c82003-03-26 21:08:13 +00001385static void emit_MMX2_regmem ( FlagSet uses_sflags,
1386 FlagSet sets_sflags,
1387 UChar first_byte,
1388 UChar second_byte,
1389 Int ireg )
1390{
1391 VG_(new_emit)(True, uses_sflags, sets_sflags);
1392 VG_(emitB) ( 0x0F );
1393 VG_(emitB) ( first_byte );
1394 second_byte &= 0x38; /* mask out mod and rm fields */
1395 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1396 if (dis)
1397 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1398 (UInt)first_byte, (UInt)second_byte,
1399 nameIReg(4,ireg) );
1400}
1401
1402static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1403 FlagSet sets_sflags,
1404 UChar first_byte,
1405 UChar second_byte )
1406{
1407 VG_(new_emit)(True, uses_sflags, sets_sflags);
1408 VG_(emitB) ( 0x0F );
1409 VG_(emitB) ( first_byte );
1410 VG_(emitB) ( second_byte );
1411 if (dis)
1412 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1413 (UInt)first_byte, (UInt)second_byte );
1414}
1415
1416static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1417 FlagSet sets_sflags,
1418 UChar first_byte )
1419{
1420 VG_(new_emit)(True, uses_sflags, sets_sflags);
1421 VG_(emitB) ( 0x0F );
1422 VG_(emitB) ( first_byte );
1423 if (dis)
1424 VG_(printf)("\n\t\tmmx1-0x%x\n",
1425 (UInt)first_byte );
1426}
1427
sewardjde4a1d02002-03-22 01:27:54 +00001428
1429/*----------------------------------------------------*/
1430/*--- misc instruction emitters ---*/
1431/*----------------------------------------------------*/
1432
njn25e49d8e72002-09-23 09:36:25 +00001433void VG_(emit_call_reg) ( Int reg )
1434{
sewardjfa492d42002-12-08 18:20:01 +00001435 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001436 VG_(emitB) ( 0xFF ); /* Grp5 */
1437 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1438 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001439 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001440}
1441
sewardjf0f12aa2002-12-28 00:04:08 +00001442static
1443void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1444 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001445{
sewardjfa492d42002-12-08 18:20:01 +00001446 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001447 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001448
1449 if (byte_off < -128 || byte_off > 127) {
1450 VG_(emitB) ( 0xFF );
1451 VG_(emitB) ( 0x95 );
1452 VG_(emitL) ( byte_off );
1453 } else {
1454 VG_(emitB) ( 0xFF );
1455 VG_(emitB) ( 0x55 );
1456 VG_(emitB) ( byte_off );
1457 }
1458 if (dis)
1459 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001460}
1461
sewardja2c5a732002-12-15 03:10:42 +00001462#if 0
1463/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001464static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1465{
1466 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001467 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001468 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1469 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001470 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001471 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001472 if (dis)
1473 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1474 nameIReg(4,regmem));
1475}
sewardja2c5a732002-12-15 03:10:42 +00001476#endif
sewardjde4a1d02002-03-22 01:27:54 +00001477
njn25e49d8e72002-09-23 09:36:25 +00001478void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001479{
njne427a662002-10-02 11:08:25 +00001480 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001481 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1482 VG_(emitB) ( 0x8D );
1483 VG_(emitB) ( 0x64 );
1484 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001485 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001486 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001487 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001488}
1489
1490
1491static void emit_movb_AL_zeroESPmem ( void )
1492{
1493 /* movb %al, 0(%esp) */
1494 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001495 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001496 VG_(emitB) ( 0x88 );
1497 VG_(emitB) ( 0x44 );
1498 VG_(emitB) ( 0x24 );
1499 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001500 if (dis)
1501 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1502}
1503
1504static void emit_movb_zeroESPmem_AL ( void )
1505{
1506 /* movb 0(%esp), %al */
1507 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001508 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001509 VG_(emitB) ( 0x8A );
1510 VG_(emitB) ( 0x44 );
1511 VG_(emitB) ( 0x24 );
1512 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001513 if (dis)
1514 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1515}
1516
sewardja2113f92002-12-12 23:42:48 +00001517/* Jump target states */
1518#define TGT_UNDEF (1 << 16)
1519#define TGT_FORWARD (2 << 16)
1520#define TGT_BACKWARD (3 << 16)
1521
1522static inline Int tgt_state(Int tgt)
1523{
1524 return tgt & 0xffff0000;
1525}
1526
1527static inline Int tgt_addr(Int tgt)
1528{
1529 return tgt & 0x0000ffff;
1530}
1531
1532static inline Int mk_tgt(Int state, Int addr)
1533{
1534 vg_assert(state == TGT_UNDEF
1535 || state == TGT_FORWARD || state == TGT_BACKWARD);
1536 vg_assert((addr & 0xffff0000) == 0);
1537
1538 return state | addr;
1539}
1540
1541void VG_(init_target) ( Int *tgt )
1542{
1543 *tgt = TGT_UNDEF;
1544}
1545
1546void VG_(target_back) ( Int *tgt )
1547{
1548 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1549
1550 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1551}
1552
1553void VG_(target_forward) ( Int *tgt )
1554{
1555 Int delta;
1556
1557 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1558 tgt_state(*tgt) == TGT_UNDEF);
1559
1560 if (tgt_state(*tgt) == TGT_UNDEF)
1561 return; /* target not used */
1562
1563 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1564 vg_assert(delta >= -128 && delta <= 127);
1565 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001566 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001567 emitted_code[tgt_addr(*tgt)] = delta;
1568 if (dis)
1569 VG_(printf)("(target to jump site %d; delta: %d)\n",
1570 tgt_addr(*tgt), delta);
1571}
1572
1573void VG_(emit_target_delta) ( Int *tgt )
1574{
1575 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1576 tgt_state(*tgt) == TGT_BACKWARD);
1577
1578 if (tgt_state(*tgt) == TGT_UNDEF) {
1579 /* forward jump */
1580 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1581 VG_(emitB) (0x00);
1582 } else {
1583 /* backward jump */
1584 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1585 vg_assert(delta >= -128 && delta <= 127);
1586 VG_(emitB) (delta);
1587 }
1588}
1589
sewardjde4a1d02002-03-22 01:27:54 +00001590
1591/* Emit a jump short with an 8-bit signed offset. Note that the
1592 offset is that which should be added to %eip once %eip has been
1593 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001594void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001595{
1596 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001597 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001598 VG_(emitB) ( 0x70 + (UInt)cond );
1599 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001600 if (dis)
1601 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001602 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001603}
1604
sewardja2113f92002-12-12 23:42:48 +00001605/* Same as above, but defers emitting the delta */
1606void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1607{
sewardj706240d2002-12-26 17:10:12 +00001608 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001609 VG_(emitB) ( 0x70 + (UInt)cond );
1610 VG_(emit_target_delta) (tgt);
1611 if (dis)
1612 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001613 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001614}
1615
1616
1617
sewardjf0f12aa2002-12-28 00:04:08 +00001618static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001619{
sewardjf0f12aa2002-12-28 00:04:08 +00001620 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001621 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1622 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001623 if (dis)
1624 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001625 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001626}
1627
1628static void emit_ret ( void )
1629{
sewardjfa492d42002-12-08 18:20:01 +00001630 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001631 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001632 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001633 if (dis)
1634 VG_(printf)("\n\t\tret\n");
1635}
1636
sewardj22854b92002-11-30 14:00:47 +00001637/* Predicate used in sanity checks elsewhere - returns true if any
1638 jump-site is an actual chained jump */
1639Bool VG_(is_chained_jumpsite)(Addr a)
1640{
1641 UChar *cp = (UChar *)a;
1642
1643 return (*cp == 0xE9); /* 0xE9 -- jmp */
1644}
1645
sewardj83f11862002-12-01 02:07:08 +00001646static
1647Bool is_fresh_jumpsite(UChar *cp)
1648{
1649 return
1650 cp[0] == 0x0F && /* UD2 */
1651 cp[1] == 0x0B &&
1652 cp[2] == 0x0F && /* UD2 */
1653 cp[3] == 0x0B &&
1654 cp[4] == 0x90; /* NOP */
1655}
1656
sewardj22854b92002-11-30 14:00:47 +00001657/* Predicate used in sanity checks elsewhere - returns true if all
1658 jump-sites are calls to VG_(patch_me) */
1659Bool VG_(is_unchained_jumpsite)(Addr a)
1660{
1661 UChar *cp = (UChar *)a;
1662 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1663 Int idelta;
1664
1665 if (*cp++ != 0xE8) /* 0xE8 == call */
1666 return False;
1667
1668 idelta = (*cp++) << 0;
1669 idelta |= (*cp++) << 8;
1670 idelta |= (*cp++) << 16;
1671 idelta |= (*cp++) << 24;
1672
1673 return idelta == delta;
1674}
1675
1676/* Return target address for a direct jmp */
1677Addr VG_(get_jmp_dest)(Addr a)
1678{
1679 Int delta;
1680 UChar *cp = (UChar *)a;
1681
1682 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1683 return 0;
1684
1685 delta = (*cp++) << 0;
1686 delta |= (*cp++) << 8;
1687 delta |= (*cp++) << 16;
1688 delta |= (*cp++) << 24;
1689
1690 return a + VG_PATCHME_JMPSZ + delta;
1691}
1692
1693/* unchain a BB by generating a call to VG_(patch_me) */
1694void VG_(unchain_jumpsite)(Addr a)
1695{
1696 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1697 UChar *cp = (UChar *)a;
1698
1699 if (VG_(is_unchained_jumpsite)(a))
1700 return; /* don't write unnecessarily */
1701
sewardj83f11862002-12-01 02:07:08 +00001702 if (!is_fresh_jumpsite(cp))
1703 VG_(bb_dechain_count)++; /* update stats */
1704
sewardj22854b92002-11-30 14:00:47 +00001705 *cp++ = 0xE8; /* call */
1706 *cp++ = (delta >> 0) & 0xff;
1707 *cp++ = (delta >> 8) & 0xff;
1708 *cp++ = (delta >> 16) & 0xff;
1709 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001710}
1711
1712/* This doesn't actually generate a call to VG_(patch_me), but
1713 reserves enough space in the instruction stream for it to happen
1714 and records the offset into the jump table. This is because call
1715 is a relative jump, and so will be affected when this code gets
1716 moved about. The translation table will "unchain" this basic block
1717 on insertion (with VG_(unchain_BB)()), and thereby generate a
1718 proper call instruction. */
1719static void emit_call_patchme( void )
1720{
1721 vg_assert(VG_PATCHME_CALLSZ == 5);
1722
sewardjfa492d42002-12-08 18:20:01 +00001723 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001724 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001725
1726 if (jumpidx >= VG_MAX_JUMPS) {
1727 /* If there too many jumps in this basic block, fall back to
1728 dispatch loop. We still need to keep it the same size as the
1729 call sequence. */
1730 VG_(emitB) ( 0xC3 ); /* ret */
1731 VG_(emitB) ( 0x90 ); /* nop */
1732 VG_(emitB) ( 0x90 ); /* nop */
1733 VG_(emitB) ( 0x90 ); /* nop */
1734 VG_(emitB) ( 0x90 ); /* nop */
1735
1736 if (dis)
1737 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1738
1739 if (0 && VG_(clo_verbosity))
1740 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1741 } else {
1742 jumps[jumpidx++] = emitted_code_used;
1743
1744 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1745 VG_(emitB) ( 0x0B );
1746 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1747 VG_(emitB) ( 0x0B );
1748 VG_(emitB) ( 0x90 ); /* NOP */
1749
1750 if (dis)
1751 VG_(printf)("\n\t\tud2; ud2; nop\n");
1752 }
1753}
1754
njn25e49d8e72002-09-23 09:36:25 +00001755void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001756{
sewardjf0f12aa2002-12-28 00:04:08 +00001757 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001758 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001759 if (dis)
1760 VG_(printf)("\n\t\tpushal\n");
1761}
1762
njn25e49d8e72002-09-23 09:36:25 +00001763void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001764{
sewardjf0f12aa2002-12-28 00:04:08 +00001765 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001766 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001767 if (dis)
1768 VG_(printf)("\n\t\tpopal\n");
1769}
1770
1771static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1772{
sewardjf0f12aa2002-12-28 00:04:08 +00001773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001774 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1775 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001776 if (dis)
1777 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1778 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1779}
1780
1781static void emit_lea_sib_reg ( UInt lit, Int scale,
1782 Int regbase, Int regindex, Int reg )
1783{
sewardjf0f12aa2002-12-28 00:04:08 +00001784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001785 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001786 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1787 if (dis)
1788 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1789 lit, nameIReg(4,regbase),
1790 nameIReg(4,regindex), scale,
1791 nameIReg(4,reg) );
1792}
1793
njn25e49d8e72002-09-23 09:36:25 +00001794void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001795{
sewardjf0f12aa2002-12-28 00:04:08 +00001796 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001797 VG_(emitB) ( 0x0F );
1798 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001799 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1800 if (dis)
1801 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1802}
1803
1804/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001805/*--- Helper offset -> addr translation ---*/
1806/*----------------------------------------------------*/
1807
1808/* Finds the baseBlock offset of a skin-specified helper.
1809 * Searches through compacts first, then non-compacts. */
1810Int VG_(helper_offset)(Addr a)
1811{
1812 Int i;
njnf4ce3d32003-02-10 10:17:26 +00001813 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001814
1815 for (i = 0; i < VG_(n_compact_helpers); i++)
1816 if (VG_(compact_helper_addrs)[i] == a)
1817 return VG_(compact_helper_offsets)[i];
1818 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1819 if (VG_(noncompact_helper_addrs)[i] == a)
1820 return VG_(noncompact_helper_offsets)[i];
1821
1822 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001823 VG_(get_fnname) ( a, buf, 100 );
1824
njn25e49d8e72002-09-23 09:36:25 +00001825 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001826 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1827 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001828
1829 VG_(printf)(" compact helpers: ");
1830 for (i = 0; i < VG_(n_compact_helpers); i++)
1831 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1832
1833 VG_(printf)("\n non-compact helpers: ");
1834 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1835 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1836
1837 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001838 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001839}
1840
1841/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001842/*--- Instruction synthesisers ---*/
1843/*----------------------------------------------------*/
1844
1845static Condcode invertCondition ( Condcode cond )
1846{
1847 return (Condcode)(1 ^ (UInt)cond);
1848}
1849
1850
1851/* Synthesise a call to *baseBlock[offset], ie,
1852 call * (4 x offset)(%ebp).
1853*/
sewardjfa492d42002-12-08 18:20:01 +00001854void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00001855 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001856{
1857 vg_assert(word_offset >= 0);
1858 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001859 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001860 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001861 }
sewardjf0f12aa2002-12-28 00:04:08 +00001862 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001863}
1864
njn25e49d8e72002-09-23 09:36:25 +00001865static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001866{
njn25e49d8e72002-09-23 09:36:25 +00001867 if (src != dst) {
1868 VG_(emit_movv_reg_reg) ( 4, src, dst );
1869 ccall_arg_setup_instrs++;
1870 }
njn6431be72002-07-28 09:53:34 +00001871}
njn25e49d8e72002-09-23 09:36:25 +00001872
1873/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1874static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1875{
1876 if (RealReg == tag) {
1877 maybe_emit_movl_reg_reg ( litOrReg, reg );
1878 } else if (Literal == tag) {
1879 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1880 ccall_arg_setup_instrs++;
1881 }
1882 else
njne427a662002-10-02 11:08:25 +00001883 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001884}
1885
1886static
1887void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1888{
1889 if (R_EAX == reg1) {
1890 VG_(emit_swapl_reg_EAX) ( reg2 );
1891 } else if (R_EAX == reg2) {
1892 VG_(emit_swapl_reg_EAX) ( reg1 );
1893 } else {
1894 emit_swapl_reg_reg ( reg1, reg2 );
1895 }
1896 ccall_arg_setup_instrs++;
1897}
1898
1899static
1900void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1901{
1902 if (dst1 != src2) {
1903 maybe_emit_movl_reg_reg ( src1, dst1 );
1904 maybe_emit_movl_reg_reg ( src2, dst2 );
1905
1906 } else if (dst2 != src1) {
1907 maybe_emit_movl_reg_reg ( src2, dst2 );
1908 maybe_emit_movl_reg_reg ( src1, dst1 );
1909
1910 } else {
1911 /* swap to break cycle */
1912 emit_swapl_arg_regs ( dst1, dst2 );
1913 }
1914}
1915
1916static
1917void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1918 UInt dst1, UInt dst2, UInt dst3)
1919{
1920 if (dst1 != src2 && dst1 != src3) {
1921 maybe_emit_movl_reg_reg ( src1, dst1 );
1922 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1923
1924 } else if (dst2 != src1 && dst2 != src3) {
1925 maybe_emit_movl_reg_reg ( src2, dst2 );
1926 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1927
1928 } else if (dst3 != src1 && dst3 != src2) {
1929 maybe_emit_movl_reg_reg ( src3, dst3 );
1930 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1931
1932 } else {
1933 /* break cycle */
1934 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1935 emit_swapl_arg_regs ( dst1, dst2 );
1936 emit_swapl_arg_regs ( dst1, dst3 );
1937
1938 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1939 emit_swapl_arg_regs ( dst1, dst3 );
1940 emit_swapl_arg_regs ( dst1, dst2 );
1941
1942 } else {
njne427a662002-10-02 11:08:25 +00001943 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001944 }
1945 }
1946}
1947
1948static
1949void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1950 UInt src1, UInt src2,
1951 UInt dst1, UInt dst2)
1952{
1953 /* If either are lits, order doesn't matter */
1954 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1955 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1956 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1957
1958 } else {
1959 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1960 }
1961}
1962
1963static
1964void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1965 UInt src1, UInt src2, UInt src3,
1966 UInt dst1, UInt dst2, UInt dst3)
1967{
1968 // SSS: fix this eventually -- make STOREV use two RealRegs?
1969 /* Not supporting literals for 3-arg C functions -- they're only used
1970 by STOREV which has 2 args */
1971 vg_assert(RealReg == tagv[src1] &&
1972 RealReg == tagv[src2] &&
1973 RealReg == tagv[src3]);
1974 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1975 dst1, dst2, dst3 );
1976}
1977
1978/* Synthesise a call to a C function `fn' (which must be registered in
1979 baseBlock) doing all the reg saving and arg handling work.
1980
1981 WARNING: a UInstr should *not* be translated with synth_ccall followed
1982 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1983 such behaviour and everything will fall over.
1984 */
1985void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1986 Tag tagv[], Int ret_reg,
1987 RRegSet regs_live_before, RRegSet regs_live_after )
1988{
1989 Int i;
1990 Int stack_used = 0;
1991 Bool preserve_eax, preserve_ecx, preserve_edx;
1992
1993 vg_assert(0 <= regparms_n && regparms_n <= 3);
1994
1995 ccalls++;
1996
1997 /* If %e[acd]x is live before and after the C call, save/restore it.
1998 Unless the return values clobbers the reg; in this case we must not
1999 save/restore the reg, because the restore would clobber the return
2000 value. (Before and after the UInstr really constitute separate live
2001 ranges, but you miss this if you don't consider what happens during
2002 the UInstr.) */
2003# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002004 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2005 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002006 ret_reg != realReg)
2007
2008 preserve_eax = PRESERVE_REG(R_EAX);
2009 preserve_ecx = PRESERVE_REG(R_ECX);
2010 preserve_edx = PRESERVE_REG(R_EDX);
2011
2012# undef PRESERVE_REG
2013
2014 /* Save caller-save regs as required */
2015 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2016 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2017 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2018
2019 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2020 is the number of args passed in regs (maximum 3 for GCC on x86). */
2021
2022 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002023
njn25e49d8e72002-09-23 09:36:25 +00002024 /* First push stack args (RealRegs or Literals) in reverse order. */
2025 for (i = argc-1; i >= regparms_n; i--) {
2026 switch (tagv[i]) {
2027 case RealReg:
2028 VG_(emit_pushv_reg) ( 4, argv[i] );
2029 break;
2030 case Literal:
2031 /* Use short form of pushl if possible. */
2032 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2033 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2034 else
2035 VG_(emit_pushl_lit32)( argv[i] );
2036 break;
2037 default:
2038 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002039 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002040 }
2041 stack_used += 4;
2042 ccall_arg_setup_instrs++;
2043 }
njn6431be72002-07-28 09:53:34 +00002044
njn25e49d8e72002-09-23 09:36:25 +00002045 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2046 If moving values between registers, be careful not to clobber any on
2047 the way. Happily we can use xchgl to swap registers.
2048 */
2049 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002050
njn25e49d8e72002-09-23 09:36:25 +00002051 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2052 case 3:
2053 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2054 R_EAX, R_EDX, R_ECX );
2055 break;
njn6431be72002-07-28 09:53:34 +00002056
njn25e49d8e72002-09-23 09:36:25 +00002057 /* Less-tricky. Args passed in %eax and %edx. */
2058 case 2:
2059 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2060 break;
2061
2062 /* Easy. Just move arg1 into %eax (if not already in there). */
2063 case 1:
2064 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2065 break;
2066
2067 case 0:
2068 break;
2069
2070 default:
njne427a662002-10-02 11:08:25 +00002071 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002072 }
2073
sewardjfa492d42002-12-08 18:20:01 +00002074 /* Call the function - may trash all flags */
2075 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002076
2077 /* Clear any args from stack */
2078 if (0 != stack_used) {
2079 VG_(emit_add_lit_to_esp) ( stack_used );
2080 ccall_stack_clears++;
2081 }
2082
2083 /* Move return value into ret_reg if necessary and not already there */
2084 if (INVALID_REALREG != ret_reg) {
2085 ccall_retvals++;
2086 if (R_EAX != ret_reg) {
2087 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2088 ccall_retval_movs++;
2089 }
2090 }
2091
2092 /* Restore live caller-save regs as required */
2093 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2094 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2095 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002096}
sewardjde4a1d02002-03-22 01:27:54 +00002097
sewardj2e93c502002-04-12 11:12:52 +00002098static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002099{
sewardj2e93c502002-04-12 11:12:52 +00002100 switch (jmpkind) {
2101 case JmpBoring:
2102 break;
sewardj2e93c502002-04-12 11:12:52 +00002103 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002104 break;
2105 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002106 break;
2107 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002108 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002109 break;
2110 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002111 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002112 break;
2113 default:
njne427a662002-10-02 11:08:25 +00002114 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002115 }
2116}
2117
2118/* Jump to the next translation, by loading its original addr into
2119 %eax and returning to the scheduler. Signal special requirements
2120 by loading a special value into %ebp first.
2121*/
2122static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2123{
sewardjfa492d42002-12-08 18:20:01 +00002124 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002125 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002126 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002127 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002128 emit_ret();
2129}
2130
sewardj22854b92002-11-30 14:00:47 +00002131static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002132
2133/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002134static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002135{
sewardjfa492d42002-12-08 18:20:01 +00002136 maybe_emit_put_eflags(); /* save flags here */
2137
njn25e49d8e72002-09-23 09:36:25 +00002138 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002139
2140 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2141 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2142 emit_call_patchme();
2143 } else {
2144 load_ebp_from_JmpKind ( jmpkind );
2145 emit_ret();
2146 }
sewardjde4a1d02002-03-22 01:27:54 +00002147}
2148
2149
sewardj2370f3b2002-11-30 15:01:01 +00002150static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002151static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002152 Opcode opcode, Int size,
2153 UInt lit, Int reg );
2154
sewardjfa492d42002-12-08 18:20:01 +00002155static void synth_jcond_lit ( Condcode cond,
2156 Addr addr,
2157 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002158{
sewardj2370f3b2002-11-30 15:01:01 +00002159 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002160 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002161 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002162
sewardja2113f92002-12-12 23:42:48 +00002163 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002164 VG_(init_target)(&tgt2);
2165 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002166
sewardjfa492d42002-12-08 18:20:01 +00002167 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2168 if need be */
2169 maybe_emit_put_eflags();
2170 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2171
2172 if (eflags_state == UPD_Both) {
2173 /* The flags are already set up, so we just use them as is. */
2174 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002175 cond = invertCondition(cond);
2176 } else {
sewardj75f04932002-12-12 23:13:21 +00002177 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002178
2179 /* The simd state contains the most recent version, so we emit a
2180 sequence to calculate the relevant condition directly out of
2181 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2182 copying them back to the real flags via popf. Notice that
2183 some of these sequences trash %eax, but that should be free
2184 now since this is the end of a bb and therefore all regs are
2185 dead. */
2186 simd = False;
2187
2188 switch (cond) {
2189
sewardjbb6c1182002-12-12 23:54:47 +00002190 case CondLE: /* Z || S != O -> S || !P */
2191 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002192 vg_assert(eax_trashable);
2193
2194 VG_(emit_movv_offregmem_reg)
2195 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2196 /* eax == %EFLAGS */
2197
sewardjbb6c1182002-12-12 23:54:47 +00002198 VG_(emit_nonshiftopv_lit_reg)
2199 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2200 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002201
sewardjbb6c1182002-12-12 23:54:47 +00002202 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2203 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002204
sewardj09736622002-12-28 00:19:00 +00002205 /* actually set the real cpu flags, since ROR changes
2206 neither P nor Z */
2207 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2208
sewardjbb6c1182002-12-12 23:54:47 +00002209 if (cond == CondLE) {
2210 /* test Z */
2211 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2212 /* test OF != SF */
2213 cond = CondP;
2214 } else {
2215 /* test Z */
2216 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2217 /* test OF == SF */
2218 cond = CondNP;
2219 }
sewardj2370f3b2002-11-30 15:01:01 +00002220 break;
2221
sewardjfa492d42002-12-08 18:20:01 +00002222 case CondL:
2223 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002224 vg_assert(eax_trashable);
2225
2226 VG_(emit_movv_offregmem_reg)
2227 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2228 /* eax == %EFLAGS */
2229
sewardj75f04932002-12-12 23:13:21 +00002230 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2231 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002232
sewardj75f04932002-12-12 23:13:21 +00002233 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2234 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002235
sewardj09736622002-12-28 00:19:00 +00002236 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002237 if (cond == CondL) cond = CondP; else cond = CondNP;
2238 break;
sewardjfa492d42002-12-08 18:20:01 +00002239
2240 case CondB:
2241 case CondNB:
2242 mask = EFlagC; goto simple; /* C=1 */
2243
2244 case CondZ:
2245 case CondNZ:
2246 mask = EFlagZ; goto simple; /* Z=1 */
2247
2248 case CondBE:
2249 case CondNBE:
2250 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2251
2252 case CondS:
2253 case CondNS:
2254 mask = EFlagS; goto simple; /* S=1 */
2255
2256 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002257 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002258 mask = EFlagP; goto simple; /* P=1 */
2259
sewardj39542072002-12-09 22:44:00 +00002260 case CondO:
2261 case CondNO:
2262 mask = EFlagO; goto simple; /* O=1 */
2263
sewardjfa492d42002-12-08 18:20:01 +00002264 default:
2265 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002266 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002267 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2268
2269 simple:
2270 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002271 if ((mask & 0xff) == mask) {
2272 VG_(emitB) ( 0xF6 ); /* Grp3 */
2273 VG_(emit_amode_offregmem_reg)(
2274 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2275 VG_(emitB) (mask);
2276 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002277 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002278 mask, VGOFF_(m_eflags) * 4);
2279 } else {
sewardjfa492d42002-12-08 18:20:01 +00002280 /* all cond codes are in lower 16 bits */
2281 vg_assert((mask & 0xffff) == mask);
2282
2283 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002284 VG_(emitB) ( 0xF7 );
2285 VG_(emit_amode_offregmem_reg)(
2286 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002287 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002288 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002289 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002290 mask, VGOFF_(m_eflags) * 4);
2291 }
2292
sewardj75f04932002-12-12 23:13:21 +00002293 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002294 break;
2295 }
2296 }
2297
sewardja2113f92002-12-12 23:42:48 +00002298 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002299
2300 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002301 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002302
2303 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002304 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002305}
2306
2307
sewardj2370f3b2002-11-30 15:01:01 +00002308
sewardjde4a1d02002-03-22 01:27:54 +00002309static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2310{
sewardja2113f92002-12-12 23:42:48 +00002311 Int tgt;
2312
2313 VG_(init_target)(&tgt);
2314
sewardjfa492d42002-12-08 18:20:01 +00002315 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002316
2317 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002318 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002319
2320 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002321}
2322
2323
2324static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2325{
2326 /* Load the zero-extended literal into reg, at size l,
2327 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002328 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002329}
2330
2331
2332static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2333{
2334 switch (size) {
2335 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2336 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2337 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002338 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002339 }
2340}
2341
2342
2343static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2344{
2345 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002346 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2347 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2348 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002349 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002350 }
2351}
2352
2353
2354static void synth_mov_reg_offregmem ( Int size, Int reg,
2355 Int off, Int areg )
2356{
2357 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002358 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2359 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002360 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002361 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002362 }
2363 else {
njn25e49d8e72002-09-23 09:36:25 +00002364 VG_(emit_swapl_reg_EAX) ( reg );
2365 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2366 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002367 }
2368 break;
njne427a662002-10-02 11:08:25 +00002369 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002370 }
2371}
2372
2373
2374static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2375{
2376 Int s1;
2377 switch (size) {
2378 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2379 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2380 case 1: if (reg1 < 4) {
2381 emit_movb_reg_regmem ( reg1, reg2 );
2382 }
2383 else {
2384 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2385 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2386 emit_swapl_reg_reg ( s1, reg1 );
2387 emit_movb_reg_regmem ( s1, reg2 );
2388 emit_swapl_reg_reg ( s1, reg1 );
2389 }
2390 break;
njne427a662002-10-02 11:08:25 +00002391 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002392 }
2393}
2394
2395
sewardjf0f12aa2002-12-28 00:04:08 +00002396static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002397 Opcode opcode, Int size,
2398 Int reg )
2399{
2400 /* NB! opcode is a uinstr opcode, not an x86 one! */
2401 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002402 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002403 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002404 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002405 break;
2406 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002407 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002408 } else {
njn25e49d8e72002-09-23 09:36:25 +00002409 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002410 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002411 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002412 }
2413 break;
njne427a662002-10-02 11:08:25 +00002414 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002415 }
2416}
2417
2418
2419
sewardjf0f12aa2002-12-28 00:04:08 +00002420static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002421 Opcode opcode, Int size,
2422 Int reg1, Int reg2 )
2423{
2424 /* NB! opcode is a uinstr opcode, not an x86 one! */
2425 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002426 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002427 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002428 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002429 break;
2430 case 1: { /* Horrible ... */
2431 Int s1, s2;
2432 /* Choose s1 and s2 to be x86 regs which we can talk about the
2433 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2434 sure s1 != s2 and that neither of them equal either reg1 or
2435 reg2. Then use them as temporaries to make things work. */
2436 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002437 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002438 break;
2439 }
2440 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2441 if (reg1 >= 4 && reg2 < 4) {
2442 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002443 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002444 emit_swapl_reg_reg ( reg1, s1 );
2445 break;
2446 }
2447 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2448 if (reg1 < 4 && reg2 >= 4) {
2449 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002450 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002451 emit_swapl_reg_reg ( reg2, s2 );
2452 break;
2453 }
2454 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2455 emit_swapl_reg_reg ( reg1, s1 );
2456 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002457 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002458 emit_swapl_reg_reg ( reg1, s1 );
2459 emit_swapl_reg_reg ( reg2, s2 );
2460 break;
2461 }
2462 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2463 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002464 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002465 emit_swapl_reg_reg ( reg1, s1 );
2466 break;
2467 }
njne427a662002-10-02 11:08:25 +00002468 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002469 }
njne427a662002-10-02 11:08:25 +00002470 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002471 }
2472}
2473
sewardja2c5a732002-12-15 03:10:42 +00002474#if 0
2475/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002476static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002477 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002478 Opcode opcode, Int size,
2479 Int off, Int areg, Int reg )
2480{
2481 switch (size) {
2482 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002483 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002484 break;
2485 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002486 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002487 break;
2488 case 1:
2489 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002490 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002491 } else {
2492 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002493 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002494 VG_(emit_swapl_reg_EAX) ( reg );
2495 }
2496 break;
2497 default:
2498 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2499 }
2500}
sewardja2c5a732002-12-15 03:10:42 +00002501#endif
sewardjfa492d42002-12-08 18:20:01 +00002502
sewardjde4a1d02002-03-22 01:27:54 +00002503static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002504 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002505 Opcode opcode, Int size,
2506 Int off, Int areg, Int reg )
2507{
2508 switch (size) {
2509 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002510 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002511 break;
2512 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002513 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002514 break;
2515 case 1:
2516 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002517 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002518 } else {
njn25e49d8e72002-09-23 09:36:25 +00002519 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002520 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002521 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002522 }
2523 break;
2524 default:
njne427a662002-10-02 11:08:25 +00002525 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002526 }
2527}
2528
2529
sewardjf0f12aa2002-12-28 00:04:08 +00002530static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002531 Opcode opcode, Int size,
2532 UInt lit, Int reg )
2533{
2534 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002535 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002536 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002537 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002538 break;
2539 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002540 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002541 } else {
njn25e49d8e72002-09-23 09:36:25 +00002542 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002543 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002544 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002545 }
2546 break;
njne427a662002-10-02 11:08:25 +00002547 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002548 }
2549}
2550
sewardjf0f12aa2002-12-28 00:04:08 +00002551static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002552 Opcode opcode, Int size,
2553 UInt lit, Int off, Int regmem )
2554{
2555 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002556 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002557 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002558 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002559 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002560 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002561 break;
2562 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2563 }
2564}
2565
sewardjde4a1d02002-03-22 01:27:54 +00002566
2567static void synth_push_reg ( Int size, Int reg )
2568{
2569 switch (size) {
2570 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002571 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002572 break;
2573 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002574 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002575 break;
2576 /* Pray that we don't have to generate this really cruddy bit of
2577 code very often. Could do better, but can I be bothered? */
2578 case 1:
2579 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002580 VG_(emit_add_lit_to_esp)(-1);
2581 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002582 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002583 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002584 break;
2585 default:
njne427a662002-10-02 11:08:25 +00002586 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002587 }
2588}
2589
2590
2591static void synth_pop_reg ( Int size, Int reg )
2592{
2593 switch (size) {
2594 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002595 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002596 break;
2597 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002598 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002599 break;
2600 case 1:
2601 /* Same comment as above applies. */
2602 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002603 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002604 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002605 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2606 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002607 break;
njne427a662002-10-02 11:08:25 +00002608 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002609 }
2610}
2611
2612
sewardjf0f12aa2002-12-28 00:04:08 +00002613static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002614 Opcode opcode, Int size,
2615 Int regs, Int regd )
2616{
2617 synth_push_reg ( size, regd );
2618 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002619 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002620 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2621 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2622 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002623 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002624 }
sewardjde4a1d02002-03-22 01:27:54 +00002625 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2626 synth_pop_reg ( size, regd );
2627}
2628
2629
sewardjf0f12aa2002-12-28 00:04:08 +00002630static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002631 Opcode opcode, Int size,
2632 UInt lit, Int reg )
2633{
2634 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002635 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002636 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002637 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002638 break;
2639 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002640 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002641 } else {
njn25e49d8e72002-09-23 09:36:25 +00002642 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002643 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002644 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002645 }
2646 break;
njne427a662002-10-02 11:08:25 +00002647 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002648 }
2649}
2650
2651
sewardjf0f12aa2002-12-28 00:04:08 +00002652static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002653{
sewardjde4a1d02002-03-22 01:27:54 +00002654 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002655 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002656 } else {
njn25e49d8e72002-09-23 09:36:25 +00002657 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002658 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002659 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002660 }
2661}
2662
2663
sewardj3d7c9c82003-03-26 21:08:13 +00002664static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2665 UChar first_byte,
2666 UChar second_byte,
2667 Int ireg )
2668{
2669 emit_MMX2_regmem ( uses_flags, sets_flags,
2670 first_byte, second_byte, ireg );
2671}
2672
2673
2674static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2675 UChar first_byte,
2676 UChar second_byte )
2677{
2678 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2679}
2680
2681
2682static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2683 UChar first_byte )
2684{
2685 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2686}
2687
2688
sewardjfa492d42002-12-08 18:20:01 +00002689static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2690 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002691 UChar second_byte_masked,
2692 Int reg )
2693{
sewardj3d7c9c82003-03-26 21:08:13 +00002694 emit_fpu_regmem ( uses_flags, sets_flags,
2695 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002696}
2697
2698
sewardjfa492d42002-12-08 18:20:01 +00002699static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2700 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002701 UChar second_byte )
2702{
sewardjfa492d42002-12-08 18:20:01 +00002703 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002704}
2705
2706
2707static void synth_movl_reg_reg ( Int src, Int dst )
2708{
2709 emit_movl_reg_reg ( src, dst );
2710}
2711
2712static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2713{
sewardja2113f92002-12-12 23:42:48 +00002714 Int tgt;
2715
2716 VG_(init_target)(&tgt);
2717
2718 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002719 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002720
2721 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002722}
2723
2724
sewardjde4a1d02002-03-22 01:27:54 +00002725/*----------------------------------------------------*/
2726/*--- Top level of the uinstr -> x86 translation. ---*/
2727/*----------------------------------------------------*/
2728
2729/* Return the byte offset from %ebp (ie, into baseBlock)
2730 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002731static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2732{
2733 if (tag == SpillNo) {
2734 vg_assert(size == 4);
2735 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2736 return 4 * (value + VGOFF_(spillslots));
2737 }
2738 if (tag == ArchReg) {
2739 switch (value) {
2740 case R_EAX: return 4 * VGOFF_(m_eax);
2741 case R_ECX: return 4 * VGOFF_(m_ecx);
2742 case R_EDX: return 4 * VGOFF_(m_edx);
2743 case R_EBX: return 4 * VGOFF_(m_ebx);
2744 case R_ESP:
2745 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2746 else return 4 * VGOFF_(m_esp);
2747 case R_EBP:
2748 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2749 else return 4 * VGOFF_(m_ebp);
2750 case R_ESI:
2751 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2752 else return 4 * VGOFF_(m_esi);
2753 case R_EDI:
2754 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2755 else return 4 * VGOFF_(m_edi);
2756 }
2757 }
njne427a662002-10-02 11:08:25 +00002758 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002759}
2760
sewardjde4a1d02002-03-22 01:27:54 +00002761static Int eflagsOffset ( void )
2762{
2763 return 4 * VGOFF_(m_eflags);
2764}
2765
sewardje1042472002-09-30 12:33:11 +00002766static Int segRegOffset ( UInt archregs )
2767{
2768 switch (archregs) {
2769 case R_CS: return 4 * VGOFF_(m_cs);
2770 case R_SS: return 4 * VGOFF_(m_ss);
2771 case R_DS: return 4 * VGOFF_(m_ds);
2772 case R_ES: return 4 * VGOFF_(m_es);
2773 case R_FS: return 4 * VGOFF_(m_fs);
2774 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002775 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002776 }
2777}
2778
njnf4ce3d32003-02-10 10:17:26 +00002779UInt VG_(get_archreg) ( UInt arch )
2780{
2781 switch (arch) {
2782 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2783 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2784 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2785 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2786 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2787 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2788 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2789 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2790 default: VG_(core_panic)( "get_thread_archreg");
2791 }
2792}
2793
2794UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2795{
2796 ThreadState* tst;
2797
2798 vg_assert(VG_(is_valid_tid)(tid));
2799 tst = & VG_(threads)[tid];
2800
2801 switch (arch) {
2802 case R_EAX: return tst->m_eax;
2803 case R_ECX: return tst->m_ecx;
2804 case R_EDX: return tst->m_edx;
2805 case R_EBX: return tst->m_ebx;
2806 case R_ESP: return tst->m_esp;
2807 case R_EBP: return tst->m_ebp;
2808 case R_ESI: return tst->m_esi;
2809 case R_EDI: return tst->m_edi;
2810 default: VG_(core_panic)( "get_thread_archreg");
2811 }
2812}
2813
njnb93d1782003-02-03 12:03:22 +00002814/* Return the baseBlock index for the specified shadow register */
2815Int shadow_reg_index ( Int arch )
2816{
2817 switch (arch) {
2818 case R_EAX: return VGOFF_(sh_eax);
2819 case R_ECX: return VGOFF_(sh_ecx);
2820 case R_EDX: return VGOFF_(sh_edx);
2821 case R_EBX: return VGOFF_(sh_ebx);
2822 case R_ESP: return VGOFF_(sh_esp);
2823 case R_EBP: return VGOFF_(sh_ebp);
2824 case R_ESI: return VGOFF_(sh_esi);
2825 case R_EDI: return VGOFF_(sh_edi);
2826 default: VG_(core_panic)( "shadow_reg_index");
2827 }
2828}
sewardjde4a1d02002-03-22 01:27:54 +00002829
njn25e49d8e72002-09-23 09:36:25 +00002830/* Return the byte offset from %ebp (ie, into baseBlock)
2831 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002832Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002833{
njnb93d1782003-02-03 12:03:22 +00002834 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00002835}
2836
njn4ba5a792002-09-30 10:23:54 +00002837Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002838{
2839 return 4 * VGOFF_(sh_eflags);
2840}
2841
njnb93d1782003-02-03 12:03:22 +00002842/* Accessing shadow arch. registers */
2843UInt VG_(get_shadow_archreg) ( UInt archreg )
2844{
2845 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
2846}
2847
2848void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
2849{
2850 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
2851}
2852
njnf4ce3d32003-02-10 10:17:26 +00002853UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
2854{
2855 ThreadState* tst;
2856
2857 vg_assert(VG_(is_valid_tid)(tid));
2858 tst = & VG_(threads)[tid];
2859
2860 switch (archreg) {
2861 case R_EAX: return tst->sh_eax;
2862 case R_ECX: return tst->sh_ecx;
2863 case R_EDX: return tst->sh_edx;
2864 case R_EBX: return tst->sh_ebx;
2865 case R_ESP: return tst->sh_esp;
2866 case R_EBP: return tst->sh_ebp;
2867 case R_ESI: return tst->sh_esi;
2868 case R_EDI: return tst->sh_edi;
2869 default: VG_(core_panic)( "get_thread_shadow_archreg");
2870 }
2871}
2872
2873void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
2874{
2875 ThreadState* tst;
2876
2877 vg_assert(VG_(is_valid_tid)(tid));
2878 tst = & VG_(threads)[tid];
2879
2880 switch (archreg) {
2881 case R_EAX: tst->sh_eax = val; break;
2882 case R_ECX: tst->sh_ecx = val; break;
2883 case R_EDX: tst->sh_edx = val; break;
2884 case R_EBX: tst->sh_ebx = val; break;
2885 case R_ESP: tst->sh_esp = val; break;
2886 case R_EBP: tst->sh_ebp = val; break;
2887 case R_ESI: tst->sh_esi = val; break;
2888 case R_EDI: tst->sh_edi = val; break;
2889 default: VG_(core_panic)( "set_thread_shadow_archreg");
2890 }
2891}
2892
njnb93d1782003-02-03 12:03:22 +00002893Addr VG_(shadow_archreg_address) ( UInt archreg )
2894{
2895 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
2896}
sewardjde4a1d02002-03-22 01:27:54 +00002897
sewardjde4a1d02002-03-22 01:27:54 +00002898static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2899{
2900 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002901 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2902 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002903 }
2904 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002905 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2906 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002907 }
2908 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002909 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2910 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002911 }
2912 else
njne427a662002-10-02 11:08:25 +00002913 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002914}
2915
2916
njn25e49d8e72002-09-23 09:36:25 +00002917static void synth_handle_esp_assignment ( Int i, Int reg,
2918 RRegSet regs_live_before,
2919 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002920{
njn25e49d8e72002-09-23 09:36:25 +00002921 UInt argv[] = { reg };
2922 Tag tagv[] = { RealReg };
2923
2924 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2925 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002926}
2927
2928
sewardjde4a1d02002-03-22 01:27:54 +00002929/*----------------------------------------------------*/
2930/*--- Generate code for a single UInstr. ---*/
2931/*----------------------------------------------------*/
2932
sewardj478335c2002-10-05 02:44:47 +00002933static __inline__
2934Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002935{
2936 return (u->flags_w != FlagsEmpty);
2937}
2938
sewardjfa492d42002-12-08 18:20:01 +00002939static __inline__
2940Bool readFlagUse ( UInstr* u )
2941{
2942 /* If the UInstr writes some flags but not all, then we still need
2943 to consider it as reading flags so that the unchanged values are
2944 passed through properly. (D is special) */
2945 return
2946 (u->flags_r != FlagsEmpty) ||
2947 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
2948}
2949
sewardj478335c2002-10-05 02:44:47 +00002950static __inline__
2951Bool anyFlagUse ( UInstr* u )
2952{
sewardjfa492d42002-12-08 18:20:01 +00002953 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00002954}
2955
2956
sewardjb5ff83e2002-12-01 19:40:49 +00002957/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002958 the real FPU. If so we need to be very careful not to trash it.
2959 If FPU state is live and we deem it necessary to copy it back to
2960 the simulated machine's FPU state, we do so. The final state of
2961 fpliveness is returned. In short we _must_ do put_fpu_state if
2962 there is any chance at all that the code generated for a UInstr
2963 will change the real FPU state.
2964*/
sewardjb5ff83e2002-12-01 19:40:49 +00002965static void emitUInstr ( UCodeBlock* cb, Int i,
2966 RRegSet regs_live_before,
2967 /* Running state, which we update. */
2968 Bool* fplive, /* True<==>FPU state in real FPU */
2969 Addr* orig_eip, /* previous curr_eip, or zero */
2970 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002971{
njn25e49d8e72002-09-23 09:36:25 +00002972 Int old_emitted_code_used;
2973 UInstr* u = &cb->instrs[i];
2974
sewardjde4a1d02002-03-22 01:27:54 +00002975 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002976 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002977
njn25e49d8e72002-09-23 09:36:25 +00002978 old_emitted_code_used = emitted_code_used;
2979
sewardjde4a1d02002-03-22 01:27:54 +00002980 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002981 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002982
sewardjb5ff83e2002-12-01 19:40:49 +00002983 case INCEIP:
2984 /* Advance %EIP some small amount. */
2985 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002986
sewardjb5ff83e2002-12-01 19:40:49 +00002987 if (*orig_eip == 0 /* we don't know what the old value was */
2988 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2989 /* We have to update all 32 bits of the value. */
2990 VG_(emit_movv_lit_offregmem)(
2991 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2992 } else {
2993 /* Cool! we only need to update lowest 8 bits */
2994 VG_(emit_movb_lit_offregmem)(
2995 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002996 }
njn25e49d8e72002-09-23 09:36:25 +00002997
sewardjb5ff83e2002-12-01 19:40:49 +00002998 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002999 break;
sewardjde4a1d02002-03-22 01:27:54 +00003000
3001 case LEA1: {
3002 vg_assert(u->tag1 == RealReg);
3003 vg_assert(u->tag2 == RealReg);
3004 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3005 break;
3006 }
3007
3008 case LEA2: {
3009 vg_assert(u->tag1 == RealReg);
3010 vg_assert(u->tag2 == RealReg);
3011 vg_assert(u->tag3 == RealReg);
3012 emit_lea_sib_reg ( u->lit32, u->extra4b,
3013 u->val1, u->val2, u->val3 );
3014 break;
3015 }
3016
3017 case WIDEN: {
3018 vg_assert(u->tag1 == RealReg);
3019 if (u->signed_widen) {
3020 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3021 } else {
3022 /* no need to generate any code. */
3023 }
3024 break;
3025 }
3026
sewardjde4a1d02002-03-22 01:27:54 +00003027 case STORE: {
3028 vg_assert(u->tag1 == RealReg);
3029 vg_assert(u->tag2 == RealReg);
3030 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003031 break;
3032 }
3033
3034 case LOAD: {
3035 vg_assert(u->tag1 == RealReg);
3036 vg_assert(u->tag2 == RealReg);
3037 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3038 break;
3039 }
3040
sewardjde4a1d02002-03-22 01:27:54 +00003041 case GET: {
3042 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3043 vg_assert(u->tag2 == RealReg);
3044 synth_mov_offregmem_reg (
3045 u->size,
3046 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3047 R_EBP,
3048 u->val2
3049 );
3050 break;
3051 }
3052
3053 case PUT: {
3054 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3055 vg_assert(u->tag1 == RealReg);
3056 if (u->tag2 == ArchReg
3057 && u->val2 == R_ESP
3058 && u->size == 4
njnf4ce3d32003-02-10 10:17:26 +00003059 && VG_(need_to_handle_esp_assignment)())
njn25e49d8e72002-09-23 09:36:25 +00003060 {
3061 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
3062 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00003063 }
njn25e49d8e72002-09-23 09:36:25 +00003064 else {
3065 synth_mov_reg_offregmem (
3066 u->size,
3067 u->val1,
3068 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3069 R_EBP
3070 );
3071 }
sewardjde4a1d02002-03-22 01:27:54 +00003072 break;
3073 }
3074
sewardje1042472002-09-30 12:33:11 +00003075 case GETSEG: {
3076 vg_assert(u->tag1 == ArchRegS);
3077 vg_assert(u->tag2 == RealReg);
3078 vg_assert(u->size == 2);
3079 synth_mov_offregmem_reg (
3080 4,
3081 segRegOffset( u->val1 ),
3082 R_EBP,
3083 u->val2
3084 );
3085 break;
3086 }
3087
3088 case PUTSEG: {
3089 vg_assert(u->tag1 == RealReg);
3090 vg_assert(u->tag2 == ArchRegS);
3091 vg_assert(u->size == 2);
3092 synth_mov_reg_offregmem (
3093 4,
3094 u->val1,
3095 segRegOffset( u->val2 ),
3096 R_EBP
3097 );
3098 break;
3099 }
3100
sewardjde4a1d02002-03-22 01:27:54 +00003101 case GETF: {
3102 vg_assert(u->size == 2 || u->size == 4);
3103 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003104
3105 /* This complexity is because the D(irection) flag is stored
3106 separately from the rest of EFLAGS. */
3107
3108 /* We're only fetching from the Simd state, so make sure it's
3109 up to date. */
3110 maybe_emit_put_eflags();
3111
3112 /* get D in u->val1 (== 1 or -1) */
3113 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3114
3115 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3116 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3117
3118 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3119 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3120 eflagsOffset(), R_EBP);
3121
3122 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3123 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3124 eflagsOffset(), R_EBP);
3125
3126 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3127 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3128 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003129 break;
3130 }
3131
3132 case PUTF: {
3133 vg_assert(u->size == 2 || u->size == 4);
3134 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003135
3136 /* When putting a value into EFLAGS, this generates the
3137 correct value for m_dflag (-1 or 1), and clears the D bit
3138 in EFLAGS. */
3139
3140 /* We're updating the whole flag state, so the old state
3141 doesn't matter; make sure that the new simulated state
3142 will be fetched when needed. */
3143 eflags_state = UPD_Simd;
3144
3145 /* store EFLAGS (with D) */
3146 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3147
3148 /* u->val1 &= EFlagD */
3149 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3150
3151 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3152 synth_unaryop_reg(False, NEG, u->size, u->val1);
3153 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3154 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3155
3156 /* save D */
3157 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3158
3159 /* EFLAGS &= ~EFlagD */
3160 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3161 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003162 break;
3163 }
3164
3165 case MOV: {
3166 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3167 vg_assert(u->tag2 == RealReg);
3168 switch (u->tag1) {
3169 case RealReg: vg_assert(u->size == 4);
3170 if (u->val1 != u->val2)
3171 synth_movl_reg_reg ( u->val1, u->val2 );
3172 break;
3173 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3174 break;
njne427a662002-10-02 11:08:25 +00003175 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003176 }
3177 break;
3178 }
3179
sewardje1042472002-09-30 12:33:11 +00003180 case USESEG: {
3181 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3182 ones. */
sewardjd077f532002-09-30 21:52:50 +00003183 UInt argv[] = { u->val1, u->val2 };
3184 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003185 UInt ret_reg = u->val2;
3186
3187 vg_assert(u->tag1 == RealReg);
3188 vg_assert(u->tag2 == RealReg);
3189 vg_assert(u->size == 0);
3190
sewardjb5ff83e2002-12-01 19:40:49 +00003191 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003192 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003193 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003194 }
3195
sewardje1042472002-09-30 12:33:11 +00003196 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3197 2, /* args */
3198 0, /* regparms_n */
3199 argv, tagv,
3200 ret_reg, regs_live_before, u->regs_live_after );
3201 break;
3202 }
3203
sewardj478335c2002-10-05 02:44:47 +00003204 case SBB:
3205 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003206 case XOR:
3207 case OR:
3208 case AND:
3209 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003210 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003211 vg_assert(u->tag2 == RealReg);
3212 switch (u->tag1) {
3213 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003214 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003215 u->opcode, u->size, u->lit32, u->val2 );
3216 break;
3217 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003218 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003219 u->opcode, u->size, u->val1, u->val2 );
3220 break;
3221 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003222 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003223 u->opcode, u->size,
3224 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3225 R_EBP,
3226 u->val2 );
3227 break;
njne427a662002-10-02 11:08:25 +00003228 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003229 }
3230 break;
3231 }
3232
sewardj478335c2002-10-05 02:44:47 +00003233 case RCR:
3234 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003235 case ROR:
3236 case ROL:
3237 case SAR:
3238 case SHR:
3239 case SHL: {
3240 vg_assert(u->tag2 == RealReg);
3241 switch (u->tag1) {
3242 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003243 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003244 u->opcode, u->size, u->lit32, u->val2 );
3245 break;
3246 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003247 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003248 u->opcode, u->size, u->val1, u->val2 );
3249 break;
njne427a662002-10-02 11:08:25 +00003250 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003251 }
3252 break;
3253 }
3254
3255 case INC:
3256 case DEC:
3257 case NEG:
3258 case NOT:
3259 vg_assert(u->tag1 == RealReg);
3260 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003261 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003262 break;
3263
3264 case BSWAP:
3265 vg_assert(u->tag1 == RealReg);
3266 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003267 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003268 emit_bswapl_reg ( u->val1 );
3269 break;
3270
3271 case CMOV:
3272 vg_assert(u->tag1 == RealReg);
3273 vg_assert(u->tag2 == RealReg);
3274 vg_assert(u->cond != CondAlways);
3275 vg_assert(u->size == 4);
3276 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3277 break;
3278
3279 case JMP: {
3280 vg_assert(u->tag2 == NoValue);
3281 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00003282 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003283 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003284 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003285 }
sewardjde4a1d02002-03-22 01:27:54 +00003286 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003287 switch (u->tag1) {
3288 case RealReg:
3289 synth_jmp_reg ( u->val1, u->jmpkind );
3290 break;
3291 case Literal:
3292 synth_jmp_lit ( u->lit32, u->jmpkind );
3293 break;
3294 default:
njne427a662002-10-02 11:08:25 +00003295 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003296 break;
sewardjde4a1d02002-03-22 01:27:54 +00003297 }
3298 } else {
sewardj2e93c502002-04-12 11:12:52 +00003299 switch (u->tag1) {
3300 case RealReg:
njne427a662002-10-02 11:08:25 +00003301 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003302 break;
3303 case Literal:
3304 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003305 /* %eax had better not be live since synth_jcond_lit
3306 trashes it in some circumstances. If that turns
3307 out to be a problem we can get synth_jcond_lit to
3308 push/pop it when it is live. */
3309 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3310 u->regs_live_after));
3311 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003312 break;
3313 default:
njne427a662002-10-02 11:08:25 +00003314 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003315 break;
sewardjde4a1d02002-03-22 01:27:54 +00003316 }
3317 }
3318 break;
3319 }
3320
3321 case JIFZ:
3322 vg_assert(u->tag1 == RealReg);
3323 vg_assert(u->tag2 == Literal);
3324 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00003325 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003326 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003327 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003328 }
sewardjde4a1d02002-03-22 01:27:54 +00003329 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3330 break;
3331
sewardjde4a1d02002-03-22 01:27:54 +00003332 case PUSH:
3333 vg_assert(u->tag1 == RealReg);
3334 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003335 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003336 break;
3337
3338 case POP:
3339 vg_assert(u->tag1 == RealReg);
3340 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003341 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003342 break;
3343
3344 case CALLM:
3345 vg_assert(u->tag1 == Lit16);
3346 vg_assert(u->tag2 == NoValue);
3347 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00003348 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003349 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003350 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003351 }
sewardjfa492d42002-12-08 18:20:01 +00003352 /* Call to a helper which is pretending to be a real CPU
3353 instruction (and therefore operates on Real flags and
3354 registers) */
3355 VG_(synth_call) ( False, u->val1,
3356 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003357 break;
3358
njn25e49d8e72002-09-23 09:36:25 +00003359 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003360 /* If you change this, remember to change USESEG above, since
3361 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003362 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3363 ones. */
3364 UInt argv[] = { u->val1, u->val2, u->val3 };
3365 UInt tagv[] = { RealReg, RealReg, RealReg };
3366 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3367
3368 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3369 else vg_assert(u->tag1 == NoValue);
3370 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3371 else vg_assert(u->tag2 == NoValue);
3372 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3373 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003374 vg_assert(u->size == 0);
3375
sewardjb5ff83e2002-12-01 19:40:49 +00003376 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003377 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003378 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003379 }
njn25e49d8e72002-09-23 09:36:25 +00003380 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3381 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003382 break;
njn25e49d8e72002-09-23 09:36:25 +00003383 }
sewardje1042472002-09-30 12:33:11 +00003384
sewardjde4a1d02002-03-22 01:27:54 +00003385 case CLEAR:
3386 vg_assert(u->tag1 == Lit16);
3387 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003388 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003389 break;
3390
3391 case CC2VAL:
3392 vg_assert(u->tag1 == RealReg);
3393 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003394 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003395 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003396 break;
3397
sewardjde4a1d02002-03-22 01:27:54 +00003398 case FPU_R:
3399 case FPU_W:
3400 vg_assert(u->tag1 == Lit16);
3401 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003402 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003403 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003404 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003405 }
sewardjfa492d42002-12-08 18:20:01 +00003406 synth_fpu_regmem ( u->flags_r, u->flags_w,
3407 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003408 u->val1 & 0xFF,
3409 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003410 break;
3411
3412 case FPU:
3413 vg_assert(u->tag1 == Lit16);
3414 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00003415 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00003416 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00003417 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003418 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003419 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003420 }
sewardjfa492d42002-12-08 18:20:01 +00003421 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3422 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003423 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003424 break;
3425
sewardj3d7c9c82003-03-26 21:08:13 +00003426 case MMX2_MemWr:
3427 case MMX2_MemRd:
3428 vg_assert(u->tag1 == Lit16);
3429 vg_assert(u->tag2 == RealReg);
3430 vg_assert(!anyFlagUse(u));
3431 if (!(*fplive)) {
3432 emit_get_fpu_state();
3433 *fplive = True;
3434 }
3435 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3436 (u->val1 >> 8) & 0xFF,
3437 u->val1 & 0xFF,
3438 u->val2 );
3439 break;
3440
3441 case MMX1:
3442 vg_assert(u->tag1 == Lit16);
3443 vg_assert(u->tag2 == NoValue);
3444 if (!(*fplive)) {
3445 emit_get_fpu_state();
3446 *fplive = True;
3447 }
3448 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3449 u->val1 & 0xFF );
3450 break;
3451
3452 case MMX2:
3453 vg_assert(u->tag1 == Lit16);
3454 vg_assert(u->tag2 == NoValue);
3455 if (!(*fplive)) {
3456 emit_get_fpu_state();
3457 *fplive = True;
3458 }
3459 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3460 (u->val1 >> 8) & 0xFF,
3461 u->val1 & 0xFF );
3462 break;
3463
sewardjde4a1d02002-03-22 01:27:54 +00003464 default:
sewardj1b7d8022002-11-30 12:35:42 +00003465 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003466 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003467 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003468 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003469 }
njn4ba5a792002-09-30 10:23:54 +00003470 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003471 } else {
njn25e49d8e72002-09-23 09:36:25 +00003472 VG_(printf)("\nError:\n"
3473 " unhandled opcode: %u. Perhaps "
3474 " VG_(needs).extended_UCode should be set?\n",
3475 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003476 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003477 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003478 }
sewardjde4a1d02002-03-22 01:27:54 +00003479 }
3480
sewardjb5ff83e2002-12-01 19:40:49 +00003481 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003482 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003483 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003484 }
3485
njn25e49d8e72002-09-23 09:36:25 +00003486 /* Update UInstr histogram */
3487 vg_assert(u->opcode < 100);
3488 histogram[u->opcode].counts++;
3489 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003490}
3491
3492
3493/* Emit x86 for the ucode in cb, returning the address of the
3494 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003495UChar* VG_(emit_code) ( UCodeBlock* cb,
3496 Int* nbytes,
3497 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003498{
3499 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003500 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003501 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003502 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003503 Int tgt;
3504
sewardjfa492d42002-12-08 18:20:01 +00003505 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003506
njn25e49d8e72002-09-23 09:36:25 +00003507 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003508
sewardj22854b92002-11-30 14:00:47 +00003509 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3510 zero. We have to do this regardless of whether we're t-chaining
3511 or not. */
sewardja2113f92002-12-12 23:42:48 +00003512 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003513 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003514 VG_(emitB) (0xFF); /* decl */
3515 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3516 if (dis)
3517 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003518 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003519 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3520 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003521 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003522
sewardjb5ff83e2002-12-01 19:40:49 +00003523 /* Set up running state. */
3524 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003525 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003526 curr_eip = cb->orig_eip;
3527 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3528 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003529 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003530 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003531 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003532 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003533
sewardjde4a1d02002-03-22 01:27:54 +00003534 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003535 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003536 if (!sane) {
3537 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003538 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003539 }
3540 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003541 emitUInstr( cb, i, regs_live_before,
3542 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003543 }
njn25e49d8e72002-09-23 09:36:25 +00003544 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003545 }
njn25e49d8e72002-09-23 09:36:25 +00003546 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003547 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3548 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003549
sewardj22854b92002-11-30 14:00:47 +00003550 if (j != NULL) {
3551 vg_assert(jumpidx <= VG_MAX_JUMPS);
3552 for(i = 0; i < jumpidx; i++)
3553 j[i] = jumps[i];
3554 }
3555
sewardjde4a1d02002-03-22 01:27:54 +00003556 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003557 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003558 *nbytes = emitted_code_used;
3559 return emitted_code;
3560}
3561
njn25e49d8e72002-09-23 09:36:25 +00003562#undef dis
3563
sewardjde4a1d02002-03-22 01:27:54 +00003564/*--------------------------------------------------------------------*/
3565/*--- end vg_from_ucode.c ---*/
3566/*--------------------------------------------------------------------*/