blob: 1a1fc120f8c66a10d79c163779d819e66d88b111 [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
sewardjca860012003-03-27 23:52:58 +00001402static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1403 FlagSet sets_sflags,
1404 UChar first_byte,
1405 UChar second_byte,
1406 Int ireg )
1407{
1408 VG_(new_emit)(True, uses_sflags, sets_sflags);
1409 VG_(emitB) ( 0x0F );
1410 VG_(emitB) ( first_byte );
1411 second_byte &= 0x38; /* mask out mod and rm fields */
1412 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1413 second_byte |= (ireg & 7); /* patch in our ireg */
1414 VG_(emitB) ( second_byte );
1415 if (dis)
1416 VG_(printf)("\n\t\tmmx2reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1417 (UInt)first_byte, (UInt)second_byte,
1418 nameIReg(4,ireg) );
1419}
1420
1421static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1422 FlagSet sets_sflags,
1423 UChar first_byte,
1424 UChar second_byte,
1425 UChar third_byte )
1426{
1427 VG_(new_emit)(True, uses_sflags, sets_sflags);
1428 VG_(emitB) ( 0x0F );
1429 VG_(emitB) ( first_byte );
1430 VG_(emitB) ( second_byte );
1431 VG_(emitB) ( third_byte );
1432 if (dis)
1433 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1434 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1435}
1436
sewardj3d7c9c82003-03-26 21:08:13 +00001437static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1438 FlagSet sets_sflags,
1439 UChar first_byte,
1440 UChar second_byte )
1441{
1442 VG_(new_emit)(True, uses_sflags, sets_sflags);
1443 VG_(emitB) ( 0x0F );
1444 VG_(emitB) ( first_byte );
1445 VG_(emitB) ( second_byte );
1446 if (dis)
1447 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1448 (UInt)first_byte, (UInt)second_byte );
1449}
1450
1451static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1452 FlagSet sets_sflags,
1453 UChar first_byte )
1454{
1455 VG_(new_emit)(True, uses_sflags, sets_sflags);
1456 VG_(emitB) ( 0x0F );
1457 VG_(emitB) ( first_byte );
1458 if (dis)
1459 VG_(printf)("\n\t\tmmx1-0x%x\n",
1460 (UInt)first_byte );
1461}
1462
sewardjde4a1d02002-03-22 01:27:54 +00001463
1464/*----------------------------------------------------*/
1465/*--- misc instruction emitters ---*/
1466/*----------------------------------------------------*/
1467
njn25e49d8e72002-09-23 09:36:25 +00001468void VG_(emit_call_reg) ( Int reg )
1469{
sewardjfa492d42002-12-08 18:20:01 +00001470 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001471 VG_(emitB) ( 0xFF ); /* Grp5 */
1472 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1473 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001474 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001475}
1476
sewardjf0f12aa2002-12-28 00:04:08 +00001477static
1478void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1479 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001480{
sewardjfa492d42002-12-08 18:20:01 +00001481 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001482 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001483
1484 if (byte_off < -128 || byte_off > 127) {
1485 VG_(emitB) ( 0xFF );
1486 VG_(emitB) ( 0x95 );
1487 VG_(emitL) ( byte_off );
1488 } else {
1489 VG_(emitB) ( 0xFF );
1490 VG_(emitB) ( 0x55 );
1491 VG_(emitB) ( byte_off );
1492 }
1493 if (dis)
1494 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001495}
1496
sewardja2c5a732002-12-15 03:10:42 +00001497#if 0
1498/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001499static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1500{
1501 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001502 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001503 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1504 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001505 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001506 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001507 if (dis)
1508 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1509 nameIReg(4,regmem));
1510}
sewardja2c5a732002-12-15 03:10:42 +00001511#endif
sewardjde4a1d02002-03-22 01:27:54 +00001512
njn25e49d8e72002-09-23 09:36:25 +00001513void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001514{
njne427a662002-10-02 11:08:25 +00001515 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001516 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1517 VG_(emitB) ( 0x8D );
1518 VG_(emitB) ( 0x64 );
1519 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001520 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001521 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001522 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001523}
1524
1525
1526static void emit_movb_AL_zeroESPmem ( void )
1527{
1528 /* movb %al, 0(%esp) */
1529 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001530 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001531 VG_(emitB) ( 0x88 );
1532 VG_(emitB) ( 0x44 );
1533 VG_(emitB) ( 0x24 );
1534 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001535 if (dis)
1536 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1537}
1538
1539static void emit_movb_zeroESPmem_AL ( void )
1540{
1541 /* movb 0(%esp), %al */
1542 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001543 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001544 VG_(emitB) ( 0x8A );
1545 VG_(emitB) ( 0x44 );
1546 VG_(emitB) ( 0x24 );
1547 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001548 if (dis)
1549 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1550}
1551
sewardja2113f92002-12-12 23:42:48 +00001552/* Jump target states */
1553#define TGT_UNDEF (1 << 16)
1554#define TGT_FORWARD (2 << 16)
1555#define TGT_BACKWARD (3 << 16)
1556
1557static inline Int tgt_state(Int tgt)
1558{
1559 return tgt & 0xffff0000;
1560}
1561
1562static inline Int tgt_addr(Int tgt)
1563{
1564 return tgt & 0x0000ffff;
1565}
1566
1567static inline Int mk_tgt(Int state, Int addr)
1568{
1569 vg_assert(state == TGT_UNDEF
1570 || state == TGT_FORWARD || state == TGT_BACKWARD);
1571 vg_assert((addr & 0xffff0000) == 0);
1572
1573 return state | addr;
1574}
1575
1576void VG_(init_target) ( Int *tgt )
1577{
1578 *tgt = TGT_UNDEF;
1579}
1580
1581void VG_(target_back) ( Int *tgt )
1582{
1583 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1584
1585 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1586}
1587
1588void VG_(target_forward) ( Int *tgt )
1589{
1590 Int delta;
1591
1592 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1593 tgt_state(*tgt) == TGT_UNDEF);
1594
1595 if (tgt_state(*tgt) == TGT_UNDEF)
1596 return; /* target not used */
1597
1598 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1599 vg_assert(delta >= -128 && delta <= 127);
1600 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001601 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001602 emitted_code[tgt_addr(*tgt)] = delta;
1603 if (dis)
1604 VG_(printf)("(target to jump site %d; delta: %d)\n",
1605 tgt_addr(*tgt), delta);
1606}
1607
1608void VG_(emit_target_delta) ( Int *tgt )
1609{
1610 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1611 tgt_state(*tgt) == TGT_BACKWARD);
1612
1613 if (tgt_state(*tgt) == TGT_UNDEF) {
1614 /* forward jump */
1615 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1616 VG_(emitB) (0x00);
1617 } else {
1618 /* backward jump */
1619 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1620 vg_assert(delta >= -128 && delta <= 127);
1621 VG_(emitB) (delta);
1622 }
1623}
1624
sewardjde4a1d02002-03-22 01:27:54 +00001625
1626/* Emit a jump short with an 8-bit signed offset. Note that the
1627 offset is that which should be added to %eip once %eip has been
1628 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001629void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001630{
1631 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001632 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001633 VG_(emitB) ( 0x70 + (UInt)cond );
1634 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001635 if (dis)
1636 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001637 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001638}
1639
sewardja2113f92002-12-12 23:42:48 +00001640/* Same as above, but defers emitting the delta */
1641void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1642{
sewardj706240d2002-12-26 17:10:12 +00001643 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001644 VG_(emitB) ( 0x70 + (UInt)cond );
1645 VG_(emit_target_delta) (tgt);
1646 if (dis)
1647 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001648 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001649}
1650
1651
1652
sewardjf0f12aa2002-12-28 00:04:08 +00001653static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001654{
sewardjf0f12aa2002-12-28 00:04:08 +00001655 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001656 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1657 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001658 if (dis)
1659 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001660 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001661}
1662
1663static void emit_ret ( void )
1664{
sewardjfa492d42002-12-08 18:20:01 +00001665 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001666 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001667 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001668 if (dis)
1669 VG_(printf)("\n\t\tret\n");
1670}
1671
sewardj22854b92002-11-30 14:00:47 +00001672/* Predicate used in sanity checks elsewhere - returns true if any
1673 jump-site is an actual chained jump */
1674Bool VG_(is_chained_jumpsite)(Addr a)
1675{
1676 UChar *cp = (UChar *)a;
1677
1678 return (*cp == 0xE9); /* 0xE9 -- jmp */
1679}
1680
sewardj83f11862002-12-01 02:07:08 +00001681static
1682Bool is_fresh_jumpsite(UChar *cp)
1683{
1684 return
1685 cp[0] == 0x0F && /* UD2 */
1686 cp[1] == 0x0B &&
1687 cp[2] == 0x0F && /* UD2 */
1688 cp[3] == 0x0B &&
1689 cp[4] == 0x90; /* NOP */
1690}
1691
sewardj22854b92002-11-30 14:00:47 +00001692/* Predicate used in sanity checks elsewhere - returns true if all
1693 jump-sites are calls to VG_(patch_me) */
1694Bool VG_(is_unchained_jumpsite)(Addr a)
1695{
1696 UChar *cp = (UChar *)a;
1697 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1698 Int idelta;
1699
1700 if (*cp++ != 0xE8) /* 0xE8 == call */
1701 return False;
1702
1703 idelta = (*cp++) << 0;
1704 idelta |= (*cp++) << 8;
1705 idelta |= (*cp++) << 16;
1706 idelta |= (*cp++) << 24;
1707
1708 return idelta == delta;
1709}
1710
1711/* Return target address for a direct jmp */
1712Addr VG_(get_jmp_dest)(Addr a)
1713{
1714 Int delta;
1715 UChar *cp = (UChar *)a;
1716
1717 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1718 return 0;
1719
1720 delta = (*cp++) << 0;
1721 delta |= (*cp++) << 8;
1722 delta |= (*cp++) << 16;
1723 delta |= (*cp++) << 24;
1724
1725 return a + VG_PATCHME_JMPSZ + delta;
1726}
1727
1728/* unchain a BB by generating a call to VG_(patch_me) */
1729void VG_(unchain_jumpsite)(Addr a)
1730{
1731 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1732 UChar *cp = (UChar *)a;
1733
1734 if (VG_(is_unchained_jumpsite)(a))
1735 return; /* don't write unnecessarily */
1736
sewardj83f11862002-12-01 02:07:08 +00001737 if (!is_fresh_jumpsite(cp))
1738 VG_(bb_dechain_count)++; /* update stats */
1739
sewardj22854b92002-11-30 14:00:47 +00001740 *cp++ = 0xE8; /* call */
1741 *cp++ = (delta >> 0) & 0xff;
1742 *cp++ = (delta >> 8) & 0xff;
1743 *cp++ = (delta >> 16) & 0xff;
1744 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001745}
1746
1747/* This doesn't actually generate a call to VG_(patch_me), but
1748 reserves enough space in the instruction stream for it to happen
1749 and records the offset into the jump table. This is because call
1750 is a relative jump, and so will be affected when this code gets
1751 moved about. The translation table will "unchain" this basic block
1752 on insertion (with VG_(unchain_BB)()), and thereby generate a
1753 proper call instruction. */
1754static void emit_call_patchme( void )
1755{
1756 vg_assert(VG_PATCHME_CALLSZ == 5);
1757
sewardjfa492d42002-12-08 18:20:01 +00001758 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001759 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001760
1761 if (jumpidx >= VG_MAX_JUMPS) {
1762 /* If there too many jumps in this basic block, fall back to
1763 dispatch loop. We still need to keep it the same size as the
1764 call sequence. */
1765 VG_(emitB) ( 0xC3 ); /* ret */
1766 VG_(emitB) ( 0x90 ); /* nop */
1767 VG_(emitB) ( 0x90 ); /* nop */
1768 VG_(emitB) ( 0x90 ); /* nop */
1769 VG_(emitB) ( 0x90 ); /* nop */
1770
1771 if (dis)
1772 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1773
1774 if (0 && VG_(clo_verbosity))
1775 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1776 } else {
1777 jumps[jumpidx++] = emitted_code_used;
1778
1779 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1780 VG_(emitB) ( 0x0B );
1781 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1782 VG_(emitB) ( 0x0B );
1783 VG_(emitB) ( 0x90 ); /* NOP */
1784
1785 if (dis)
1786 VG_(printf)("\n\t\tud2; ud2; nop\n");
1787 }
1788}
1789
njn25e49d8e72002-09-23 09:36:25 +00001790void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001791{
sewardjf0f12aa2002-12-28 00:04:08 +00001792 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001793 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001794 if (dis)
1795 VG_(printf)("\n\t\tpushal\n");
1796}
1797
njn25e49d8e72002-09-23 09:36:25 +00001798void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001799{
sewardjf0f12aa2002-12-28 00:04:08 +00001800 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001801 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001802 if (dis)
1803 VG_(printf)("\n\t\tpopal\n");
1804}
1805
1806static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1807{
sewardjf0f12aa2002-12-28 00:04:08 +00001808 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001809 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1810 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001811 if (dis)
1812 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1813 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1814}
1815
1816static void emit_lea_sib_reg ( UInt lit, Int scale,
1817 Int regbase, Int regindex, Int reg )
1818{
sewardjf0f12aa2002-12-28 00:04:08 +00001819 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001820 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001821 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1822 if (dis)
1823 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1824 lit, nameIReg(4,regbase),
1825 nameIReg(4,regindex), scale,
1826 nameIReg(4,reg) );
1827}
1828
njn25e49d8e72002-09-23 09:36:25 +00001829void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001830{
sewardjf0f12aa2002-12-28 00:04:08 +00001831 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001832 VG_(emitB) ( 0x0F );
1833 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001834 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1835 if (dis)
1836 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1837}
1838
1839/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001840/*--- Helper offset -> addr translation ---*/
1841/*----------------------------------------------------*/
1842
1843/* Finds the baseBlock offset of a skin-specified helper.
1844 * Searches through compacts first, then non-compacts. */
1845Int VG_(helper_offset)(Addr a)
1846{
1847 Int i;
njnf4ce3d32003-02-10 10:17:26 +00001848 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001849
1850 for (i = 0; i < VG_(n_compact_helpers); i++)
1851 if (VG_(compact_helper_addrs)[i] == a)
1852 return VG_(compact_helper_offsets)[i];
1853 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1854 if (VG_(noncompact_helper_addrs)[i] == a)
1855 return VG_(noncompact_helper_offsets)[i];
1856
1857 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001858 VG_(get_fnname) ( a, buf, 100 );
1859
njn25e49d8e72002-09-23 09:36:25 +00001860 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001861 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1862 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001863
1864 VG_(printf)(" compact helpers: ");
1865 for (i = 0; i < VG_(n_compact_helpers); i++)
1866 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1867
1868 VG_(printf)("\n non-compact helpers: ");
1869 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1870 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1871
1872 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001873 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001874}
1875
1876/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001877/*--- Instruction synthesisers ---*/
1878/*----------------------------------------------------*/
1879
1880static Condcode invertCondition ( Condcode cond )
1881{
1882 return (Condcode)(1 ^ (UInt)cond);
1883}
1884
1885
1886/* Synthesise a call to *baseBlock[offset], ie,
1887 call * (4 x offset)(%ebp).
1888*/
sewardjfa492d42002-12-08 18:20:01 +00001889void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00001890 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001891{
1892 vg_assert(word_offset >= 0);
1893 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001894 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001895 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001896 }
sewardjf0f12aa2002-12-28 00:04:08 +00001897 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001898}
1899
njn25e49d8e72002-09-23 09:36:25 +00001900static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001901{
njn25e49d8e72002-09-23 09:36:25 +00001902 if (src != dst) {
1903 VG_(emit_movv_reg_reg) ( 4, src, dst );
1904 ccall_arg_setup_instrs++;
1905 }
njn6431be72002-07-28 09:53:34 +00001906}
njn25e49d8e72002-09-23 09:36:25 +00001907
1908/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1909static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1910{
1911 if (RealReg == tag) {
1912 maybe_emit_movl_reg_reg ( litOrReg, reg );
1913 } else if (Literal == tag) {
1914 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1915 ccall_arg_setup_instrs++;
1916 }
1917 else
njne427a662002-10-02 11:08:25 +00001918 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001919}
1920
1921static
1922void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1923{
1924 if (R_EAX == reg1) {
1925 VG_(emit_swapl_reg_EAX) ( reg2 );
1926 } else if (R_EAX == reg2) {
1927 VG_(emit_swapl_reg_EAX) ( reg1 );
1928 } else {
1929 emit_swapl_reg_reg ( reg1, reg2 );
1930 }
1931 ccall_arg_setup_instrs++;
1932}
1933
1934static
1935void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1936{
1937 if (dst1 != src2) {
1938 maybe_emit_movl_reg_reg ( src1, dst1 );
1939 maybe_emit_movl_reg_reg ( src2, dst2 );
1940
1941 } else if (dst2 != src1) {
1942 maybe_emit_movl_reg_reg ( src2, dst2 );
1943 maybe_emit_movl_reg_reg ( src1, dst1 );
1944
1945 } else {
1946 /* swap to break cycle */
1947 emit_swapl_arg_regs ( dst1, dst2 );
1948 }
1949}
1950
1951static
1952void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1953 UInt dst1, UInt dst2, UInt dst3)
1954{
1955 if (dst1 != src2 && dst1 != src3) {
1956 maybe_emit_movl_reg_reg ( src1, dst1 );
1957 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1958
1959 } else if (dst2 != src1 && dst2 != src3) {
1960 maybe_emit_movl_reg_reg ( src2, dst2 );
1961 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1962
1963 } else if (dst3 != src1 && dst3 != src2) {
1964 maybe_emit_movl_reg_reg ( src3, dst3 );
1965 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1966
1967 } else {
1968 /* break cycle */
1969 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1970 emit_swapl_arg_regs ( dst1, dst2 );
1971 emit_swapl_arg_regs ( dst1, dst3 );
1972
1973 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1974 emit_swapl_arg_regs ( dst1, dst3 );
1975 emit_swapl_arg_regs ( dst1, dst2 );
1976
1977 } else {
njne427a662002-10-02 11:08:25 +00001978 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001979 }
1980 }
1981}
1982
1983static
1984void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1985 UInt src1, UInt src2,
1986 UInt dst1, UInt dst2)
1987{
1988 /* If either are lits, order doesn't matter */
1989 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1990 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1991 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1992
1993 } else {
1994 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1995 }
1996}
1997
1998static
1999void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2000 UInt src1, UInt src2, UInt src3,
2001 UInt dst1, UInt dst2, UInt dst3)
2002{
2003 // SSS: fix this eventually -- make STOREV use two RealRegs?
2004 /* Not supporting literals for 3-arg C functions -- they're only used
2005 by STOREV which has 2 args */
2006 vg_assert(RealReg == tagv[src1] &&
2007 RealReg == tagv[src2] &&
2008 RealReg == tagv[src3]);
2009 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2010 dst1, dst2, dst3 );
2011}
2012
2013/* Synthesise a call to a C function `fn' (which must be registered in
2014 baseBlock) doing all the reg saving and arg handling work.
2015
2016 WARNING: a UInstr should *not* be translated with synth_ccall followed
2017 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2018 such behaviour and everything will fall over.
2019 */
2020void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2021 Tag tagv[], Int ret_reg,
2022 RRegSet regs_live_before, RRegSet regs_live_after )
2023{
2024 Int i;
2025 Int stack_used = 0;
2026 Bool preserve_eax, preserve_ecx, preserve_edx;
2027
2028 vg_assert(0 <= regparms_n && regparms_n <= 3);
2029
2030 ccalls++;
2031
2032 /* If %e[acd]x is live before and after the C call, save/restore it.
2033 Unless the return values clobbers the reg; in this case we must not
2034 save/restore the reg, because the restore would clobber the return
2035 value. (Before and after the UInstr really constitute separate live
2036 ranges, but you miss this if you don't consider what happens during
2037 the UInstr.) */
2038# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002039 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2040 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002041 ret_reg != realReg)
2042
2043 preserve_eax = PRESERVE_REG(R_EAX);
2044 preserve_ecx = PRESERVE_REG(R_ECX);
2045 preserve_edx = PRESERVE_REG(R_EDX);
2046
2047# undef PRESERVE_REG
2048
2049 /* Save caller-save regs as required */
2050 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2051 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2052 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2053
2054 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2055 is the number of args passed in regs (maximum 3 for GCC on x86). */
2056
2057 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002058
njn25e49d8e72002-09-23 09:36:25 +00002059 /* First push stack args (RealRegs or Literals) in reverse order. */
2060 for (i = argc-1; i >= regparms_n; i--) {
2061 switch (tagv[i]) {
2062 case RealReg:
2063 VG_(emit_pushv_reg) ( 4, argv[i] );
2064 break;
2065 case Literal:
2066 /* Use short form of pushl if possible. */
2067 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2068 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2069 else
2070 VG_(emit_pushl_lit32)( argv[i] );
2071 break;
2072 default:
2073 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002074 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002075 }
2076 stack_used += 4;
2077 ccall_arg_setup_instrs++;
2078 }
njn6431be72002-07-28 09:53:34 +00002079
njn25e49d8e72002-09-23 09:36:25 +00002080 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2081 If moving values between registers, be careful not to clobber any on
2082 the way. Happily we can use xchgl to swap registers.
2083 */
2084 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002085
njn25e49d8e72002-09-23 09:36:25 +00002086 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2087 case 3:
2088 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2089 R_EAX, R_EDX, R_ECX );
2090 break;
njn6431be72002-07-28 09:53:34 +00002091
njn25e49d8e72002-09-23 09:36:25 +00002092 /* Less-tricky. Args passed in %eax and %edx. */
2093 case 2:
2094 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2095 break;
2096
2097 /* Easy. Just move arg1 into %eax (if not already in there). */
2098 case 1:
2099 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2100 break;
2101
2102 case 0:
2103 break;
2104
2105 default:
njne427a662002-10-02 11:08:25 +00002106 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002107 }
2108
sewardjfa492d42002-12-08 18:20:01 +00002109 /* Call the function - may trash all flags */
2110 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002111
2112 /* Clear any args from stack */
2113 if (0 != stack_used) {
2114 VG_(emit_add_lit_to_esp) ( stack_used );
2115 ccall_stack_clears++;
2116 }
2117
2118 /* Move return value into ret_reg if necessary and not already there */
2119 if (INVALID_REALREG != ret_reg) {
2120 ccall_retvals++;
2121 if (R_EAX != ret_reg) {
2122 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2123 ccall_retval_movs++;
2124 }
2125 }
2126
2127 /* Restore live caller-save regs as required */
2128 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2129 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2130 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002131}
sewardjde4a1d02002-03-22 01:27:54 +00002132
sewardj2e93c502002-04-12 11:12:52 +00002133static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002134{
sewardj2e93c502002-04-12 11:12:52 +00002135 switch (jmpkind) {
2136 case JmpBoring:
2137 break;
sewardj2e93c502002-04-12 11:12:52 +00002138 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002139 break;
2140 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002141 break;
2142 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002143 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002144 break;
2145 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002146 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002147 break;
2148 default:
njne427a662002-10-02 11:08:25 +00002149 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002150 }
2151}
2152
2153/* Jump to the next translation, by loading its original addr into
2154 %eax and returning to the scheduler. Signal special requirements
2155 by loading a special value into %ebp first.
2156*/
2157static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2158{
sewardjfa492d42002-12-08 18:20:01 +00002159 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002160 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002161 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002162 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002163 emit_ret();
2164}
2165
sewardj22854b92002-11-30 14:00:47 +00002166static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002167
2168/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002169static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002170{
sewardjfa492d42002-12-08 18:20:01 +00002171 maybe_emit_put_eflags(); /* save flags here */
2172
njn25e49d8e72002-09-23 09:36:25 +00002173 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002174
2175 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2176 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2177 emit_call_patchme();
2178 } else {
2179 load_ebp_from_JmpKind ( jmpkind );
2180 emit_ret();
2181 }
sewardjde4a1d02002-03-22 01:27:54 +00002182}
2183
2184
sewardj2370f3b2002-11-30 15:01:01 +00002185static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002186static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002187 Opcode opcode, Int size,
2188 UInt lit, Int reg );
2189
sewardjfa492d42002-12-08 18:20:01 +00002190static void synth_jcond_lit ( Condcode cond,
2191 Addr addr,
2192 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002193{
sewardj2370f3b2002-11-30 15:01:01 +00002194 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002195 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002196 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002197
sewardja2113f92002-12-12 23:42:48 +00002198 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002199 VG_(init_target)(&tgt2);
2200 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002201
sewardjfa492d42002-12-08 18:20:01 +00002202 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2203 if need be */
2204 maybe_emit_put_eflags();
2205 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2206
2207 if (eflags_state == UPD_Both) {
2208 /* The flags are already set up, so we just use them as is. */
2209 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002210 cond = invertCondition(cond);
2211 } else {
sewardj75f04932002-12-12 23:13:21 +00002212 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002213
2214 /* The simd state contains the most recent version, so we emit a
2215 sequence to calculate the relevant condition directly out of
2216 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2217 copying them back to the real flags via popf. Notice that
2218 some of these sequences trash %eax, but that should be free
2219 now since this is the end of a bb and therefore all regs are
2220 dead. */
2221 simd = False;
2222
2223 switch (cond) {
2224
sewardjbb6c1182002-12-12 23:54:47 +00002225 case CondLE: /* Z || S != O -> S || !P */
2226 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002227 vg_assert(eax_trashable);
2228
2229 VG_(emit_movv_offregmem_reg)
2230 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2231 /* eax == %EFLAGS */
2232
sewardjbb6c1182002-12-12 23:54:47 +00002233 VG_(emit_nonshiftopv_lit_reg)
2234 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2235 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002236
sewardjbb6c1182002-12-12 23:54:47 +00002237 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2238 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002239
sewardj09736622002-12-28 00:19:00 +00002240 /* actually set the real cpu flags, since ROR changes
2241 neither P nor Z */
2242 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2243
sewardjbb6c1182002-12-12 23:54:47 +00002244 if (cond == CondLE) {
2245 /* test Z */
2246 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2247 /* test OF != SF */
2248 cond = CondP;
2249 } else {
2250 /* test Z */
2251 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2252 /* test OF == SF */
2253 cond = CondNP;
2254 }
sewardj2370f3b2002-11-30 15:01:01 +00002255 break;
2256
sewardjfa492d42002-12-08 18:20:01 +00002257 case CondL:
2258 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002259 vg_assert(eax_trashable);
2260
2261 VG_(emit_movv_offregmem_reg)
2262 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2263 /* eax == %EFLAGS */
2264
sewardj75f04932002-12-12 23:13:21 +00002265 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2266 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002267
sewardj75f04932002-12-12 23:13:21 +00002268 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2269 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002270
sewardj09736622002-12-28 00:19:00 +00002271 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002272 if (cond == CondL) cond = CondP; else cond = CondNP;
2273 break;
sewardjfa492d42002-12-08 18:20:01 +00002274
2275 case CondB:
2276 case CondNB:
2277 mask = EFlagC; goto simple; /* C=1 */
2278
2279 case CondZ:
2280 case CondNZ:
2281 mask = EFlagZ; goto simple; /* Z=1 */
2282
2283 case CondBE:
2284 case CondNBE:
2285 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2286
2287 case CondS:
2288 case CondNS:
2289 mask = EFlagS; goto simple; /* S=1 */
2290
2291 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002292 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002293 mask = EFlagP; goto simple; /* P=1 */
2294
sewardj39542072002-12-09 22:44:00 +00002295 case CondO:
2296 case CondNO:
2297 mask = EFlagO; goto simple; /* O=1 */
2298
sewardjfa492d42002-12-08 18:20:01 +00002299 default:
2300 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002301 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002302 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2303
2304 simple:
2305 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002306 if ((mask & 0xff) == mask) {
2307 VG_(emitB) ( 0xF6 ); /* Grp3 */
2308 VG_(emit_amode_offregmem_reg)(
2309 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2310 VG_(emitB) (mask);
2311 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002312 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002313 mask, VGOFF_(m_eflags) * 4);
2314 } else {
sewardjfa492d42002-12-08 18:20:01 +00002315 /* all cond codes are in lower 16 bits */
2316 vg_assert((mask & 0xffff) == mask);
2317
2318 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002319 VG_(emitB) ( 0xF7 );
2320 VG_(emit_amode_offregmem_reg)(
2321 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002322 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002323 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002324 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002325 mask, VGOFF_(m_eflags) * 4);
2326 }
2327
sewardj75f04932002-12-12 23:13:21 +00002328 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002329 break;
2330 }
2331 }
2332
sewardja2113f92002-12-12 23:42:48 +00002333 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002334
2335 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002336 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002337
2338 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002339 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002340}
2341
2342
sewardj2370f3b2002-11-30 15:01:01 +00002343
sewardjde4a1d02002-03-22 01:27:54 +00002344static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2345{
sewardja2113f92002-12-12 23:42:48 +00002346 Int tgt;
2347
2348 VG_(init_target)(&tgt);
2349
sewardjfa492d42002-12-08 18:20:01 +00002350 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002351
2352 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002353 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002354
2355 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002356}
2357
2358
2359static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2360{
2361 /* Load the zero-extended literal into reg, at size l,
2362 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002363 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002364}
2365
2366
2367static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2368{
2369 switch (size) {
2370 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2371 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2372 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002373 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002374 }
2375}
2376
2377
2378static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2379{
2380 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002381 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2382 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2383 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002384 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002385 }
2386}
2387
2388
2389static void synth_mov_reg_offregmem ( Int size, Int reg,
2390 Int off, Int areg )
2391{
2392 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002393 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2394 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002395 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002396 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002397 }
2398 else {
njn25e49d8e72002-09-23 09:36:25 +00002399 VG_(emit_swapl_reg_EAX) ( reg );
2400 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2401 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002402 }
2403 break;
njne427a662002-10-02 11:08:25 +00002404 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002405 }
2406}
2407
2408
2409static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2410{
2411 Int s1;
2412 switch (size) {
2413 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2414 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2415 case 1: if (reg1 < 4) {
2416 emit_movb_reg_regmem ( reg1, reg2 );
2417 }
2418 else {
2419 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2420 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2421 emit_swapl_reg_reg ( s1, reg1 );
2422 emit_movb_reg_regmem ( s1, reg2 );
2423 emit_swapl_reg_reg ( s1, reg1 );
2424 }
2425 break;
njne427a662002-10-02 11:08:25 +00002426 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002427 }
2428}
2429
2430
sewardjf0f12aa2002-12-28 00:04:08 +00002431static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002432 Opcode opcode, Int size,
2433 Int reg )
2434{
2435 /* NB! opcode is a uinstr opcode, not an x86 one! */
2436 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002437 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002438 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002439 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002440 break;
2441 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002442 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002443 } else {
njn25e49d8e72002-09-23 09:36:25 +00002444 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002445 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002446 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002447 }
2448 break;
njne427a662002-10-02 11:08:25 +00002449 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002450 }
2451}
2452
2453
2454
sewardjf0f12aa2002-12-28 00:04:08 +00002455static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002456 Opcode opcode, Int size,
2457 Int reg1, Int reg2 )
2458{
2459 /* NB! opcode is a uinstr opcode, not an x86 one! */
2460 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002461 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002462 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002463 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002464 break;
2465 case 1: { /* Horrible ... */
2466 Int s1, s2;
2467 /* Choose s1 and s2 to be x86 regs which we can talk about the
2468 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2469 sure s1 != s2 and that neither of them equal either reg1 or
2470 reg2. Then use them as temporaries to make things work. */
2471 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002472 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002473 break;
2474 }
2475 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2476 if (reg1 >= 4 && reg2 < 4) {
2477 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002478 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002479 emit_swapl_reg_reg ( reg1, s1 );
2480 break;
2481 }
2482 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2483 if (reg1 < 4 && reg2 >= 4) {
2484 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002485 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002486 emit_swapl_reg_reg ( reg2, s2 );
2487 break;
2488 }
2489 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2490 emit_swapl_reg_reg ( reg1, s1 );
2491 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002492 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002493 emit_swapl_reg_reg ( reg1, s1 );
2494 emit_swapl_reg_reg ( reg2, s2 );
2495 break;
2496 }
2497 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2498 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002499 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002500 emit_swapl_reg_reg ( reg1, s1 );
2501 break;
2502 }
njne427a662002-10-02 11:08:25 +00002503 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002504 }
njne427a662002-10-02 11:08:25 +00002505 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002506 }
2507}
2508
sewardja2c5a732002-12-15 03:10:42 +00002509#if 0
2510/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002511static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002512 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002513 Opcode opcode, Int size,
2514 Int off, Int areg, Int reg )
2515{
2516 switch (size) {
2517 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002518 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002519 break;
2520 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002521 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002522 break;
2523 case 1:
2524 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002525 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002526 } else {
2527 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002528 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002529 VG_(emit_swapl_reg_EAX) ( reg );
2530 }
2531 break;
2532 default:
2533 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2534 }
2535}
sewardja2c5a732002-12-15 03:10:42 +00002536#endif
sewardjfa492d42002-12-08 18:20:01 +00002537
sewardjde4a1d02002-03-22 01:27:54 +00002538static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002539 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002540 Opcode opcode, Int size,
2541 Int off, Int areg, Int reg )
2542{
2543 switch (size) {
2544 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002545 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002546 break;
2547 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002548 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002549 break;
2550 case 1:
2551 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002552 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002553 } else {
njn25e49d8e72002-09-23 09:36:25 +00002554 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002555 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002556 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002557 }
2558 break;
2559 default:
njne427a662002-10-02 11:08:25 +00002560 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002561 }
2562}
2563
2564
sewardjf0f12aa2002-12-28 00:04:08 +00002565static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002566 Opcode opcode, Int size,
2567 UInt lit, Int reg )
2568{
2569 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002570 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002571 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002572 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002573 break;
2574 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002575 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002576 } else {
njn25e49d8e72002-09-23 09:36:25 +00002577 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002578 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002579 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002580 }
2581 break;
njne427a662002-10-02 11:08:25 +00002582 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002583 }
2584}
2585
sewardjf0f12aa2002-12-28 00:04:08 +00002586static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002587 Opcode opcode, Int size,
2588 UInt lit, Int off, Int regmem )
2589{
2590 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002591 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002592 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002593 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002594 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002595 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002596 break;
2597 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2598 }
2599}
2600
sewardjde4a1d02002-03-22 01:27:54 +00002601
2602static void synth_push_reg ( Int size, Int reg )
2603{
2604 switch (size) {
2605 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002606 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002607 break;
2608 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002609 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002610 break;
2611 /* Pray that we don't have to generate this really cruddy bit of
2612 code very often. Could do better, but can I be bothered? */
2613 case 1:
2614 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002615 VG_(emit_add_lit_to_esp)(-1);
2616 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002617 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002618 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002619 break;
2620 default:
njne427a662002-10-02 11:08:25 +00002621 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002622 }
2623}
2624
2625
2626static void synth_pop_reg ( Int size, Int reg )
2627{
2628 switch (size) {
2629 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002630 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002631 break;
2632 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002633 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002634 break;
2635 case 1:
2636 /* Same comment as above applies. */
2637 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002638 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002639 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002640 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2641 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002642 break;
njne427a662002-10-02 11:08:25 +00002643 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002644 }
2645}
2646
2647
sewardjf0f12aa2002-12-28 00:04:08 +00002648static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002649 Opcode opcode, Int size,
2650 Int regs, Int regd )
2651{
2652 synth_push_reg ( size, regd );
2653 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002654 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002655 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2656 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2657 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002658 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002659 }
sewardjde4a1d02002-03-22 01:27:54 +00002660 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2661 synth_pop_reg ( size, regd );
2662}
2663
2664
sewardjf0f12aa2002-12-28 00:04:08 +00002665static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002666 Opcode opcode, Int size,
2667 UInt lit, Int reg )
2668{
2669 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002670 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002671 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002672 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002673 break;
2674 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002675 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002676 } else {
njn25e49d8e72002-09-23 09:36:25 +00002677 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002678 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002679 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002680 }
2681 break;
njne427a662002-10-02 11:08:25 +00002682 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002683 }
2684}
2685
2686
sewardjf0f12aa2002-12-28 00:04:08 +00002687static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002688{
sewardjde4a1d02002-03-22 01:27:54 +00002689 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002690 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002691 } else {
njn25e49d8e72002-09-23 09:36:25 +00002692 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002693 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002694 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002695 }
2696}
2697
2698
sewardj3d7c9c82003-03-26 21:08:13 +00002699static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2700 UChar first_byte,
2701 UChar second_byte,
2702 Int ireg )
2703{
2704 emit_MMX2_regmem ( uses_flags, sets_flags,
2705 first_byte, second_byte, ireg );
2706}
2707
2708
sewardjca860012003-03-27 23:52:58 +00002709static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2710 UChar first_byte,
2711 UChar second_byte,
2712 Int ireg )
2713{
2714 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2715 first_byte, second_byte, ireg );
2716}
2717
sewardj3d7c9c82003-03-26 21:08:13 +00002718static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2719 UChar first_byte,
2720 UChar second_byte )
2721{
2722 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2723}
2724
2725
sewardjca860012003-03-27 23:52:58 +00002726static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2727 UChar first_byte,
2728 UChar second_byte,
2729 UChar third_byte )
2730{
2731 emit_MMX3_no_mem ( uses_flags, sets_flags,
2732 first_byte, second_byte, third_byte );
2733}
2734
2735
sewardj3d7c9c82003-03-26 21:08:13 +00002736static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2737 UChar first_byte )
2738{
2739 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2740}
2741
2742
sewardjfa492d42002-12-08 18:20:01 +00002743static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2744 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002745 UChar second_byte_masked,
2746 Int reg )
2747{
sewardj3d7c9c82003-03-26 21:08:13 +00002748 emit_fpu_regmem ( uses_flags, sets_flags,
2749 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002750}
2751
2752
sewardjfa492d42002-12-08 18:20:01 +00002753static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2754 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002755 UChar second_byte )
2756{
sewardjfa492d42002-12-08 18:20:01 +00002757 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002758}
2759
2760
2761static void synth_movl_reg_reg ( Int src, Int dst )
2762{
2763 emit_movl_reg_reg ( src, dst );
2764}
2765
2766static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2767{
sewardja2113f92002-12-12 23:42:48 +00002768 Int tgt;
2769
2770 VG_(init_target)(&tgt);
2771
2772 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002773 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002774
2775 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002776}
2777
2778
sewardjde4a1d02002-03-22 01:27:54 +00002779/*----------------------------------------------------*/
2780/*--- Top level of the uinstr -> x86 translation. ---*/
2781/*----------------------------------------------------*/
2782
2783/* Return the byte offset from %ebp (ie, into baseBlock)
2784 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002785static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2786{
2787 if (tag == SpillNo) {
2788 vg_assert(size == 4);
2789 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2790 return 4 * (value + VGOFF_(spillslots));
2791 }
2792 if (tag == ArchReg) {
2793 switch (value) {
2794 case R_EAX: return 4 * VGOFF_(m_eax);
2795 case R_ECX: return 4 * VGOFF_(m_ecx);
2796 case R_EDX: return 4 * VGOFF_(m_edx);
2797 case R_EBX: return 4 * VGOFF_(m_ebx);
2798 case R_ESP:
2799 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2800 else return 4 * VGOFF_(m_esp);
2801 case R_EBP:
2802 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2803 else return 4 * VGOFF_(m_ebp);
2804 case R_ESI:
2805 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2806 else return 4 * VGOFF_(m_esi);
2807 case R_EDI:
2808 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2809 else return 4 * VGOFF_(m_edi);
2810 }
2811 }
njne427a662002-10-02 11:08:25 +00002812 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002813}
2814
sewardjde4a1d02002-03-22 01:27:54 +00002815static Int eflagsOffset ( void )
2816{
2817 return 4 * VGOFF_(m_eflags);
2818}
2819
sewardje1042472002-09-30 12:33:11 +00002820static Int segRegOffset ( UInt archregs )
2821{
2822 switch (archregs) {
2823 case R_CS: return 4 * VGOFF_(m_cs);
2824 case R_SS: return 4 * VGOFF_(m_ss);
2825 case R_DS: return 4 * VGOFF_(m_ds);
2826 case R_ES: return 4 * VGOFF_(m_es);
2827 case R_FS: return 4 * VGOFF_(m_fs);
2828 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002829 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002830 }
2831}
2832
njnf4ce3d32003-02-10 10:17:26 +00002833UInt VG_(get_archreg) ( UInt arch )
2834{
2835 switch (arch) {
2836 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2837 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2838 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2839 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2840 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2841 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2842 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2843 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2844 default: VG_(core_panic)( "get_thread_archreg");
2845 }
2846}
2847
2848UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2849{
2850 ThreadState* tst;
2851
2852 vg_assert(VG_(is_valid_tid)(tid));
2853 tst = & VG_(threads)[tid];
2854
2855 switch (arch) {
2856 case R_EAX: return tst->m_eax;
2857 case R_ECX: return tst->m_ecx;
2858 case R_EDX: return tst->m_edx;
2859 case R_EBX: return tst->m_ebx;
2860 case R_ESP: return tst->m_esp;
2861 case R_EBP: return tst->m_ebp;
2862 case R_ESI: return tst->m_esi;
2863 case R_EDI: return tst->m_edi;
2864 default: VG_(core_panic)( "get_thread_archreg");
2865 }
2866}
2867
njnb93d1782003-02-03 12:03:22 +00002868/* Return the baseBlock index for the specified shadow register */
2869Int shadow_reg_index ( Int arch )
2870{
2871 switch (arch) {
2872 case R_EAX: return VGOFF_(sh_eax);
2873 case R_ECX: return VGOFF_(sh_ecx);
2874 case R_EDX: return VGOFF_(sh_edx);
2875 case R_EBX: return VGOFF_(sh_ebx);
2876 case R_ESP: return VGOFF_(sh_esp);
2877 case R_EBP: return VGOFF_(sh_ebp);
2878 case R_ESI: return VGOFF_(sh_esi);
2879 case R_EDI: return VGOFF_(sh_edi);
2880 default: VG_(core_panic)( "shadow_reg_index");
2881 }
2882}
sewardjde4a1d02002-03-22 01:27:54 +00002883
njn25e49d8e72002-09-23 09:36:25 +00002884/* Return the byte offset from %ebp (ie, into baseBlock)
2885 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002886Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002887{
njnb93d1782003-02-03 12:03:22 +00002888 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00002889}
2890
njn4ba5a792002-09-30 10:23:54 +00002891Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002892{
2893 return 4 * VGOFF_(sh_eflags);
2894}
2895
njnb93d1782003-02-03 12:03:22 +00002896/* Accessing shadow arch. registers */
2897UInt VG_(get_shadow_archreg) ( UInt archreg )
2898{
2899 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
2900}
2901
2902void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
2903{
2904 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
2905}
2906
njnf4ce3d32003-02-10 10:17:26 +00002907UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
2908{
2909 ThreadState* tst;
2910
2911 vg_assert(VG_(is_valid_tid)(tid));
2912 tst = & VG_(threads)[tid];
2913
2914 switch (archreg) {
2915 case R_EAX: return tst->sh_eax;
2916 case R_ECX: return tst->sh_ecx;
2917 case R_EDX: return tst->sh_edx;
2918 case R_EBX: return tst->sh_ebx;
2919 case R_ESP: return tst->sh_esp;
2920 case R_EBP: return tst->sh_ebp;
2921 case R_ESI: return tst->sh_esi;
2922 case R_EDI: return tst->sh_edi;
2923 default: VG_(core_panic)( "get_thread_shadow_archreg");
2924 }
2925}
2926
2927void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
2928{
2929 ThreadState* tst;
2930
2931 vg_assert(VG_(is_valid_tid)(tid));
2932 tst = & VG_(threads)[tid];
2933
2934 switch (archreg) {
2935 case R_EAX: tst->sh_eax = val; break;
2936 case R_ECX: tst->sh_ecx = val; break;
2937 case R_EDX: tst->sh_edx = val; break;
2938 case R_EBX: tst->sh_ebx = val; break;
2939 case R_ESP: tst->sh_esp = val; break;
2940 case R_EBP: tst->sh_ebp = val; break;
2941 case R_ESI: tst->sh_esi = val; break;
2942 case R_EDI: tst->sh_edi = val; break;
2943 default: VG_(core_panic)( "set_thread_shadow_archreg");
2944 }
2945}
2946
njnb93d1782003-02-03 12:03:22 +00002947Addr VG_(shadow_archreg_address) ( UInt archreg )
2948{
2949 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
2950}
sewardjde4a1d02002-03-22 01:27:54 +00002951
sewardjde4a1d02002-03-22 01:27:54 +00002952static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2953{
2954 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002955 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2956 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002957 }
2958 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002959 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2960 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002961 }
2962 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002963 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2964 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002965 }
2966 else
njne427a662002-10-02 11:08:25 +00002967 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002968}
2969
2970
njn25e49d8e72002-09-23 09:36:25 +00002971static void synth_handle_esp_assignment ( Int i, Int reg,
2972 RRegSet regs_live_before,
2973 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002974{
njn25e49d8e72002-09-23 09:36:25 +00002975 UInt argv[] = { reg };
2976 Tag tagv[] = { RealReg };
2977
2978 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2979 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002980}
2981
2982
sewardjde4a1d02002-03-22 01:27:54 +00002983/*----------------------------------------------------*/
2984/*--- Generate code for a single UInstr. ---*/
2985/*----------------------------------------------------*/
2986
sewardj478335c2002-10-05 02:44:47 +00002987static __inline__
2988Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002989{
2990 return (u->flags_w != FlagsEmpty);
2991}
2992
sewardjfa492d42002-12-08 18:20:01 +00002993static __inline__
2994Bool readFlagUse ( UInstr* u )
2995{
2996 /* If the UInstr writes some flags but not all, then we still need
2997 to consider it as reading flags so that the unchanged values are
2998 passed through properly. (D is special) */
2999 return
3000 (u->flags_r != FlagsEmpty) ||
3001 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3002}
3003
sewardj478335c2002-10-05 02:44:47 +00003004static __inline__
3005Bool anyFlagUse ( UInstr* u )
3006{
sewardjfa492d42002-12-08 18:20:01 +00003007 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003008}
3009
3010
sewardjb5ff83e2002-12-01 19:40:49 +00003011/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00003012 the real FPU. If so we need to be very careful not to trash it.
3013 If FPU state is live and we deem it necessary to copy it back to
3014 the simulated machine's FPU state, we do so. The final state of
3015 fpliveness is returned. In short we _must_ do put_fpu_state if
3016 there is any chance at all that the code generated for a UInstr
3017 will change the real FPU state.
3018*/
sewardjb5ff83e2002-12-01 19:40:49 +00003019static void emitUInstr ( UCodeBlock* cb, Int i,
3020 RRegSet regs_live_before,
3021 /* Running state, which we update. */
3022 Bool* fplive, /* True<==>FPU state in real FPU */
3023 Addr* orig_eip, /* previous curr_eip, or zero */
3024 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003025{
njn25e49d8e72002-09-23 09:36:25 +00003026 Int old_emitted_code_used;
3027 UInstr* u = &cb->instrs[i];
3028
sewardjde4a1d02002-03-22 01:27:54 +00003029 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003030 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003031
njn25e49d8e72002-09-23 09:36:25 +00003032 old_emitted_code_used = emitted_code_used;
3033
sewardjde4a1d02002-03-22 01:27:54 +00003034 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003035 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003036
sewardjb5ff83e2002-12-01 19:40:49 +00003037 case INCEIP:
3038 /* Advance %EIP some small amount. */
3039 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003040
sewardjb5ff83e2002-12-01 19:40:49 +00003041 if (*orig_eip == 0 /* we don't know what the old value was */
3042 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3043 /* We have to update all 32 bits of the value. */
3044 VG_(emit_movv_lit_offregmem)(
3045 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3046 } else {
3047 /* Cool! we only need to update lowest 8 bits */
3048 VG_(emit_movb_lit_offregmem)(
3049 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003050 }
njn25e49d8e72002-09-23 09:36:25 +00003051
sewardjb5ff83e2002-12-01 19:40:49 +00003052 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003053 break;
sewardjde4a1d02002-03-22 01:27:54 +00003054
3055 case LEA1: {
3056 vg_assert(u->tag1 == RealReg);
3057 vg_assert(u->tag2 == RealReg);
3058 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3059 break;
3060 }
3061
3062 case LEA2: {
3063 vg_assert(u->tag1 == RealReg);
3064 vg_assert(u->tag2 == RealReg);
3065 vg_assert(u->tag3 == RealReg);
3066 emit_lea_sib_reg ( u->lit32, u->extra4b,
3067 u->val1, u->val2, u->val3 );
3068 break;
3069 }
3070
3071 case WIDEN: {
3072 vg_assert(u->tag1 == RealReg);
3073 if (u->signed_widen) {
3074 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3075 } else {
3076 /* no need to generate any code. */
3077 }
3078 break;
3079 }
3080
sewardjde4a1d02002-03-22 01:27:54 +00003081 case STORE: {
3082 vg_assert(u->tag1 == RealReg);
3083 vg_assert(u->tag2 == RealReg);
3084 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003085 break;
3086 }
3087
3088 case LOAD: {
3089 vg_assert(u->tag1 == RealReg);
3090 vg_assert(u->tag2 == RealReg);
3091 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3092 break;
3093 }
3094
sewardjde4a1d02002-03-22 01:27:54 +00003095 case GET: {
3096 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3097 vg_assert(u->tag2 == RealReg);
3098 synth_mov_offregmem_reg (
3099 u->size,
3100 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3101 R_EBP,
3102 u->val2
3103 );
3104 break;
3105 }
3106
3107 case PUT: {
3108 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3109 vg_assert(u->tag1 == RealReg);
3110 if (u->tag2 == ArchReg
3111 && u->val2 == R_ESP
3112 && u->size == 4
njnf4ce3d32003-02-10 10:17:26 +00003113 && VG_(need_to_handle_esp_assignment)())
njn25e49d8e72002-09-23 09:36:25 +00003114 {
3115 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
3116 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00003117 }
njn25e49d8e72002-09-23 09:36:25 +00003118 else {
3119 synth_mov_reg_offregmem (
3120 u->size,
3121 u->val1,
3122 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3123 R_EBP
3124 );
3125 }
sewardjde4a1d02002-03-22 01:27:54 +00003126 break;
3127 }
3128
sewardje1042472002-09-30 12:33:11 +00003129 case GETSEG: {
3130 vg_assert(u->tag1 == ArchRegS);
3131 vg_assert(u->tag2 == RealReg);
3132 vg_assert(u->size == 2);
3133 synth_mov_offregmem_reg (
3134 4,
3135 segRegOffset( u->val1 ),
3136 R_EBP,
3137 u->val2
3138 );
3139 break;
3140 }
3141
3142 case PUTSEG: {
3143 vg_assert(u->tag1 == RealReg);
3144 vg_assert(u->tag2 == ArchRegS);
3145 vg_assert(u->size == 2);
3146 synth_mov_reg_offregmem (
3147 4,
3148 u->val1,
3149 segRegOffset( u->val2 ),
3150 R_EBP
3151 );
3152 break;
3153 }
3154
sewardjde4a1d02002-03-22 01:27:54 +00003155 case GETF: {
3156 vg_assert(u->size == 2 || u->size == 4);
3157 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003158
3159 /* This complexity is because the D(irection) flag is stored
3160 separately from the rest of EFLAGS. */
3161
3162 /* We're only fetching from the Simd state, so make sure it's
3163 up to date. */
3164 maybe_emit_put_eflags();
3165
3166 /* get D in u->val1 (== 1 or -1) */
3167 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3168
3169 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3170 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3171
3172 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3173 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3174 eflagsOffset(), R_EBP);
3175
3176 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3177 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3178 eflagsOffset(), R_EBP);
3179
3180 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3181 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3182 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003183 break;
3184 }
3185
3186 case PUTF: {
3187 vg_assert(u->size == 2 || u->size == 4);
3188 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003189
3190 /* When putting a value into EFLAGS, this generates the
3191 correct value for m_dflag (-1 or 1), and clears the D bit
3192 in EFLAGS. */
3193
3194 /* We're updating the whole flag state, so the old state
3195 doesn't matter; make sure that the new simulated state
3196 will be fetched when needed. */
3197 eflags_state = UPD_Simd;
3198
3199 /* store EFLAGS (with D) */
3200 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3201
3202 /* u->val1 &= EFlagD */
3203 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3204
3205 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3206 synth_unaryop_reg(False, NEG, u->size, u->val1);
3207 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3208 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3209
3210 /* save D */
3211 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3212
3213 /* EFLAGS &= ~EFlagD */
3214 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3215 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003216 break;
3217 }
3218
3219 case MOV: {
3220 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3221 vg_assert(u->tag2 == RealReg);
3222 switch (u->tag1) {
3223 case RealReg: vg_assert(u->size == 4);
3224 if (u->val1 != u->val2)
3225 synth_movl_reg_reg ( u->val1, u->val2 );
3226 break;
3227 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3228 break;
njne427a662002-10-02 11:08:25 +00003229 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003230 }
3231 break;
3232 }
3233
sewardje1042472002-09-30 12:33:11 +00003234 case USESEG: {
3235 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3236 ones. */
sewardjd077f532002-09-30 21:52:50 +00003237 UInt argv[] = { u->val1, u->val2 };
3238 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003239 UInt ret_reg = u->val2;
3240
3241 vg_assert(u->tag1 == RealReg);
3242 vg_assert(u->tag2 == RealReg);
3243 vg_assert(u->size == 0);
3244
sewardjb5ff83e2002-12-01 19:40:49 +00003245 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003246 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003247 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003248 }
3249
sewardje1042472002-09-30 12:33:11 +00003250 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3251 2, /* args */
3252 0, /* regparms_n */
3253 argv, tagv,
3254 ret_reg, regs_live_before, u->regs_live_after );
3255 break;
3256 }
3257
sewardj478335c2002-10-05 02:44:47 +00003258 case SBB:
3259 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003260 case XOR:
3261 case OR:
3262 case AND:
3263 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003264 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003265 vg_assert(u->tag2 == RealReg);
3266 switch (u->tag1) {
3267 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003268 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003269 u->opcode, u->size, u->lit32, u->val2 );
3270 break;
3271 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003272 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003273 u->opcode, u->size, u->val1, u->val2 );
3274 break;
3275 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003276 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003277 u->opcode, u->size,
3278 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3279 R_EBP,
3280 u->val2 );
3281 break;
njne427a662002-10-02 11:08:25 +00003282 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003283 }
3284 break;
3285 }
3286
sewardj478335c2002-10-05 02:44:47 +00003287 case RCR:
3288 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003289 case ROR:
3290 case ROL:
3291 case SAR:
3292 case SHR:
3293 case SHL: {
3294 vg_assert(u->tag2 == RealReg);
3295 switch (u->tag1) {
3296 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003297 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003298 u->opcode, u->size, u->lit32, u->val2 );
3299 break;
3300 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003301 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003302 u->opcode, u->size, u->val1, u->val2 );
3303 break;
njne427a662002-10-02 11:08:25 +00003304 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003305 }
3306 break;
3307 }
3308
3309 case INC:
3310 case DEC:
3311 case NEG:
3312 case NOT:
3313 vg_assert(u->tag1 == RealReg);
3314 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003315 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003316 break;
3317
3318 case BSWAP:
3319 vg_assert(u->tag1 == RealReg);
3320 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003321 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003322 emit_bswapl_reg ( u->val1 );
3323 break;
3324
3325 case CMOV:
3326 vg_assert(u->tag1 == RealReg);
3327 vg_assert(u->tag2 == RealReg);
3328 vg_assert(u->cond != CondAlways);
3329 vg_assert(u->size == 4);
3330 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3331 break;
3332
3333 case JMP: {
3334 vg_assert(u->tag2 == NoValue);
3335 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00003336 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003337 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003338 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003339 }
sewardjde4a1d02002-03-22 01:27:54 +00003340 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003341 switch (u->tag1) {
3342 case RealReg:
3343 synth_jmp_reg ( u->val1, u->jmpkind );
3344 break;
3345 case Literal:
3346 synth_jmp_lit ( u->lit32, u->jmpkind );
3347 break;
3348 default:
njne427a662002-10-02 11:08:25 +00003349 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003350 break;
sewardjde4a1d02002-03-22 01:27:54 +00003351 }
3352 } else {
sewardj2e93c502002-04-12 11:12:52 +00003353 switch (u->tag1) {
3354 case RealReg:
njne427a662002-10-02 11:08:25 +00003355 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003356 break;
3357 case Literal:
3358 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003359 /* %eax had better not be live since synth_jcond_lit
3360 trashes it in some circumstances. If that turns
3361 out to be a problem we can get synth_jcond_lit to
3362 push/pop it when it is live. */
3363 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3364 u->regs_live_after));
3365 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003366 break;
3367 default:
njne427a662002-10-02 11:08:25 +00003368 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003369 break;
sewardjde4a1d02002-03-22 01:27:54 +00003370 }
3371 }
3372 break;
3373 }
3374
3375 case JIFZ:
3376 vg_assert(u->tag1 == RealReg);
3377 vg_assert(u->tag2 == Literal);
3378 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00003379 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003380 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003381 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003382 }
sewardjde4a1d02002-03-22 01:27:54 +00003383 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3384 break;
3385
sewardjde4a1d02002-03-22 01:27:54 +00003386 case PUSH:
3387 vg_assert(u->tag1 == RealReg);
3388 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003389 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003390 break;
3391
3392 case POP:
3393 vg_assert(u->tag1 == RealReg);
3394 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003395 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003396 break;
3397
3398 case CALLM:
3399 vg_assert(u->tag1 == Lit16);
3400 vg_assert(u->tag2 == NoValue);
3401 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00003402 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003403 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003404 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003405 }
sewardjfa492d42002-12-08 18:20:01 +00003406 /* Call to a helper which is pretending to be a real CPU
3407 instruction (and therefore operates on Real flags and
3408 registers) */
3409 VG_(synth_call) ( False, u->val1,
3410 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003411 break;
3412
njn25e49d8e72002-09-23 09:36:25 +00003413 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003414 /* If you change this, remember to change USESEG above, since
3415 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003416 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3417 ones. */
3418 UInt argv[] = { u->val1, u->val2, u->val3 };
3419 UInt tagv[] = { RealReg, RealReg, RealReg };
3420 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3421
3422 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3423 else vg_assert(u->tag1 == NoValue);
3424 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3425 else vg_assert(u->tag2 == NoValue);
3426 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3427 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003428 vg_assert(u->size == 0);
3429
sewardjb5ff83e2002-12-01 19:40:49 +00003430 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003431 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003432 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003433 }
njn25e49d8e72002-09-23 09:36:25 +00003434 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3435 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003436 break;
njn25e49d8e72002-09-23 09:36:25 +00003437 }
sewardje1042472002-09-30 12:33:11 +00003438
sewardjde4a1d02002-03-22 01:27:54 +00003439 case CLEAR:
3440 vg_assert(u->tag1 == Lit16);
3441 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003442 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003443 break;
3444
3445 case CC2VAL:
3446 vg_assert(u->tag1 == RealReg);
3447 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003448 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003449 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003450 break;
3451
sewardjde4a1d02002-03-22 01:27:54 +00003452 case FPU_R:
3453 case FPU_W:
3454 vg_assert(u->tag1 == Lit16);
3455 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003456 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003457 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003458 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003459 }
sewardjfa492d42002-12-08 18:20:01 +00003460 synth_fpu_regmem ( u->flags_r, u->flags_w,
3461 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003462 u->val1 & 0xFF,
3463 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003464 break;
3465
3466 case FPU:
3467 vg_assert(u->tag1 == Lit16);
3468 vg_assert(u->tag2 == NoValue);
sewardjb5ff83e2002-12-01 19:40:49 +00003469 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003470 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003471 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003472 }
sewardjfa492d42002-12-08 18:20:01 +00003473 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3474 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003475 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003476 break;
3477
sewardj3d7c9c82003-03-26 21:08:13 +00003478 case MMX2_MemWr:
3479 case MMX2_MemRd:
3480 vg_assert(u->tag1 == Lit16);
3481 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003482 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003483 vg_assert(!anyFlagUse(u));
3484 if (!(*fplive)) {
3485 emit_get_fpu_state();
3486 *fplive = True;
3487 }
3488 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3489 (u->val1 >> 8) & 0xFF,
3490 u->val1 & 0xFF,
3491 u->val2 );
3492 break;
3493
sewardjca860012003-03-27 23:52:58 +00003494 case MMX2_RegRd:
3495 vg_assert(u->tag1 == Lit16);
3496 vg_assert(u->tag2 == RealReg);
3497 vg_assert(u->tag3 == NoValue);
3498 vg_assert(!anyFlagUse(u));
3499 if (!(*fplive)) {
3500 emit_get_fpu_state();
3501 *fplive = True;
3502 }
3503 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3504 (u->val1 >> 8) & 0xFF,
3505 u->val1 & 0xFF,
3506 u->val2 );
3507 break;
3508
sewardj3d7c9c82003-03-26 21:08:13 +00003509 case MMX1:
3510 vg_assert(u->tag1 == Lit16);
3511 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003512 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003513 if (!(*fplive)) {
3514 emit_get_fpu_state();
3515 *fplive = True;
3516 }
3517 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3518 u->val1 & 0xFF );
3519 break;
3520
3521 case MMX2:
3522 vg_assert(u->tag1 == Lit16);
3523 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003524 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003525 if (!(*fplive)) {
3526 emit_get_fpu_state();
3527 *fplive = True;
3528 }
3529 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3530 (u->val1 >> 8) & 0xFF,
3531 u->val1 & 0xFF );
3532 break;
3533
sewardjca860012003-03-27 23:52:58 +00003534 case MMX3:
3535 vg_assert(u->tag1 == Lit16);
3536 vg_assert(u->tag2 == Lit16);
3537 vg_assert(u->tag3 == NoValue);
3538 if (!(*fplive)) {
3539 emit_get_fpu_state();
3540 *fplive = True;
3541 }
3542 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3543 (u->val1 >> 8) & 0xFF,
3544 u->val1 & 0xFF,
3545 u->val2 & 0xFF );
3546 break;
3547
sewardjde4a1d02002-03-22 01:27:54 +00003548 default:
sewardj1b7d8022002-11-30 12:35:42 +00003549 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003550 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003551 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003552 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003553 }
njn4ba5a792002-09-30 10:23:54 +00003554 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003555 } else {
njn25e49d8e72002-09-23 09:36:25 +00003556 VG_(printf)("\nError:\n"
3557 " unhandled opcode: %u. Perhaps "
3558 " VG_(needs).extended_UCode should be set?\n",
3559 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003560 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003561 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003562 }
sewardjde4a1d02002-03-22 01:27:54 +00003563 }
3564
sewardjb5ff83e2002-12-01 19:40:49 +00003565 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003566 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003567 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003568 }
3569
njn25e49d8e72002-09-23 09:36:25 +00003570 /* Update UInstr histogram */
3571 vg_assert(u->opcode < 100);
3572 histogram[u->opcode].counts++;
3573 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003574}
3575
3576
3577/* Emit x86 for the ucode in cb, returning the address of the
3578 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003579UChar* VG_(emit_code) ( UCodeBlock* cb,
3580 Int* nbytes,
3581 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003582{
3583 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003584 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003585 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003586 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003587 Int tgt;
3588
sewardjfa492d42002-12-08 18:20:01 +00003589 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003590
njn25e49d8e72002-09-23 09:36:25 +00003591 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003592
sewardj22854b92002-11-30 14:00:47 +00003593 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3594 zero. We have to do this regardless of whether we're t-chaining
3595 or not. */
sewardja2113f92002-12-12 23:42:48 +00003596 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003597 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003598 VG_(emitB) (0xFF); /* decl */
3599 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3600 if (dis)
3601 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003602 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003603 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3604 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003605 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003606
sewardjb5ff83e2002-12-01 19:40:49 +00003607 /* Set up running state. */
3608 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003609 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003610 curr_eip = cb->orig_eip;
3611 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3612 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003613 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003614 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003615 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003616 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003617
sewardjde4a1d02002-03-22 01:27:54 +00003618 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003619 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003620 if (!sane) {
3621 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003622 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003623 }
3624 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003625 emitUInstr( cb, i, regs_live_before,
3626 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003627 }
njn25e49d8e72002-09-23 09:36:25 +00003628 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003629 }
njn25e49d8e72002-09-23 09:36:25 +00003630 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003631 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3632 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003633
sewardj22854b92002-11-30 14:00:47 +00003634 if (j != NULL) {
3635 vg_assert(jumpidx <= VG_MAX_JUMPS);
3636 for(i = 0; i < jumpidx; i++)
3637 j[i] = jumps[i];
3638 }
3639
sewardjde4a1d02002-03-22 01:27:54 +00003640 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003641 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003642 *nbytes = emitted_code_used;
3643 return emitted_code;
3644}
3645
njn25e49d8e72002-09-23 09:36:25 +00003646#undef dis
3647
sewardjde4a1d02002-03-22 01:27:54 +00003648/*--------------------------------------------------------------------*/
3649/*--- end vg_from_ucode.c ---*/
3650/*--------------------------------------------------------------------*/