blob: 5153b4b388d2631ebff3fc22a4c30b0d5f95a88d [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
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 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
sewardj05bcdcb2003-05-18 10:05:38 +0000167 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000168 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
sewardj56867352003-10-12 10:27:06 +0000209/* __inline__ */
210void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000211{
njn25e49d8e72002-09-23 09:36:25 +0000212 VG_(emitB) ( (l) & 0x000000FF );
213 VG_(emitB) ( (l >> 8) & 0x000000FF );
214 VG_(emitB) ( (l >> 16) & 0x000000FF );
215 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000216}
217
fitzhardinge98abfc72003-12-16 02:05:15 +0000218/* This bit is ORd onto the size to indicate that it's a client
219 pointer which needs bounds checking. */
220#define DO_BOUNDSCHECK (1<<8)
221
222/* If the user asks for it, generate bounds checks on application
223 pointer dereferences, in the form of a segment override. */
224static __inline__ void boundscheck()
225{
226 if (VG_(clo_pointercheck))
227 VG_(emitB)(0x64); /* %fs prefix - see vg_dispatch.S */
228}
229
230
sewardjfa492d42002-12-08 18:20:01 +0000231static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000232{
sewardjfa492d42002-12-08 18:20:01 +0000233 Int off = 4 * VGOFF_(m_eflags);
234 vg_assert(off >= 0 && off < 128);
235
236 if (dis)
237 VG_(printf)("\t %4d: ", emitted_code_used );
238
239 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
240 VG_(emitB) ( 0x75 );
241 VG_(emitB) ( off );
242 VG_(emitB) ( 0x9D ); /* POPFL */
243 if (dis)
244 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
245}
246
247static void emit_put_eflags ( void )
248{
249 Int off = 4 * VGOFF_(m_eflags);
250 vg_assert(off >= 0 && off < 128);
251
252 if (dis)
253 VG_(printf)("\t %4d: ", emitted_code_used );
254
255 VG_(emitB) ( 0x9C ); /* PUSHFL */
256 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
257 VG_(emitB) ( 0x45 );
258 VG_(emitB) ( off );
259 if (dis)
260 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
261}
262
263static void maybe_emit_put_eflags( void )
264{
265 if (eflags_state == UPD_Real) {
266 eflags_state = UPD_Both;
267 emit_put_eflags();
268 }
269}
270
sewardja2c5a732002-12-15 03:10:42 +0000271
272/* evidently unused */
273#if 0
sewardjfa492d42002-12-08 18:20:01 +0000274static void maybe_emit_get_eflags( void )
275{
276 if (eflags_state == UPD_Simd) {
277 eflags_state = UPD_Both;
278 emit_get_eflags();
279 }
280}
sewardja2c5a732002-12-15 03:10:42 +0000281#endif
sewardjfa492d42002-12-08 18:20:01 +0000282
sewardjf0f12aa2002-12-28 00:04:08 +0000283
284#if 0
285/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
286/* An alternative implementation of new_emit in which the
287 state space is explicitly enumerated. */
288__inline__
289void VG_(new_emit) ( Bool upds_simd_flags,
290 FlagSet use_flags, FlagSet set_flags )
291{
292 Bool simd = upds_simd_flags;
293 enum _eflags_state where = eflags_state;
294
295 enum { WNone, WSome, WAll } ww;
296 Bool rr;
297
298#define DIS_HEADER \
299 if (dis) \
300 VG_(printf)("\t %4d: ", emitted_code_used );
301
302 if (use_flags == FlagsEmpty) {
303 rr = False;
304 } else {
305 rr = True;
306 }
307
308 if (set_flags == FlagsEmpty) {
309 ww = WNone;
310 } else
311 if (set_flags == FlagsOSZACP) {
312 ww = WAll;
313 } else {
314 ww = WSome;
315 }
316
317 /* If we're not wanting to interact with simd flags, and the simd
318 flags are not in the real flags, then do nothing. */
319 if (simd == False && where == UPD_Simd)
320 goto noaction;
321
322 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
323 /* We're going to generate a complete new simd flag state without
324 consulting the old one first, so just deem this insn to create
325 the state in the real flags. */
326 eflags_state = UPD_Real;
327 DIS_HEADER;
328 return;
329 }
330
331 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
332 /* Want to partially update the flags state, but is in simd. So
333 fetch it first, then declare that the real state is the most
334 recent. */
335 emit_get_eflags();
336 eflags_state = UPD_Real;
337 DIS_HEADER;
338 return;
339 }
340
341 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
342 /* want to read simd flags, but not in real -> copy to real. */
343 emit_get_eflags();
344 eflags_state = UPD_Both;
345 DIS_HEADER;
346 return;
347 }
348
349 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
350 /* want to read and write simd flags, but not in real -> copy to
351 real. State is then Real since they get updated. */
352 emit_get_eflags();
353 eflags_state = UPD_Real;
354 DIS_HEADER;
355 return;
356 }
357
358 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
359 /* Doesn't really make sense. Want to interact with simd flags,
360 but insn doesn't modify them. So don't do anything. ??? */
361 goto noaction;
362 }
363
364 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
365 /* Doesn't really make sense. Want to interact with simd flags,
366 but insn doesn't modify them. So don't do anything. ??? */
367 goto noaction;
368 }
369
370 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
371 /* simd is in real. Insn reads real but does not change. --> do
372 nothing. */
373 goto noaction;
374 }
375
376 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
377 /* simd is in real. we want to capture changes made by it. -->
378 do nothing */
379 goto noaction;
380 }
381
382 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
383 /* simd is in real. Insn creates new simd state. --> leave in
384 real */
385 goto noaction;
386 }
387
388 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
389 /* simd is in both. Insn creates new simd state. --> change
390 state to Real. */
391 narrow_Both_to_Real:
392 eflags_state = UPD_Real;
393 DIS_HEADER;
394 return;
395 }
396
397 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
398 /* simd is in both. Insn creates partial new simd state. -->
399 change state to Real. No need to get, since Both holds. */
400 goto narrow_Both_to_Real;
401 }
402
403 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
404 /* simd is in real. Insn creates new simd state. --> leave in
405 real */
406 goto noaction;
407 }
408
409 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
410 /* want to read the simd flags, but already have a copy in real,
411 and not planning to modify it --> do nothing. */
412 goto noaction;
413
414 ////////////////
415
416 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
417 /* simd state is in real, but insn doesn't touch it --> do nothing */
418 goto noaction;
419
420 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
421 /* simd state is in both, insn doesn't touch it --> do nothing */
422 goto noaction;
423
424 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
425 /* simd state is in both. insn trashes real, therefore declare
426 simd state only in simd. */
427 narrow_Both_to_Simd:
428 eflags_state = UPD_Simd;
429 DIS_HEADER;
430 return;
431 }
432
433 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
434 /* simd state is in both. insn trashes real, therefore declare
435 simd state only in simd. */
436 goto narrow_Both_to_Simd;
437 }
438
439 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
440 /* simd state is in real; we don't want simd state changed, but
441 insn writes the flags. Therefore have to copy back first. */
442 put_flags_and_continue:
443 emit_put_eflags();
444 eflags_state = UPD_Simd;
445 DIS_HEADER;
446 return;
447 }
448
449 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
450 /* simd state is in real; we don't want simd state changed, but
451 insn writes the flags. Therefore have to copy back first. */
452 goto put_flags_and_continue;
453 }
454
455 goto unhandled;
456
457 noaction:
458 DIS_HEADER;
459 return;
460
461 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
462 // return;
463 //}
464
465 unhandled:
466 VG_(printf)("simd %s, where %s, read %s, write %s\n",
467 simd ? "True " : "False",
468 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
469 ? "Real" : "Both")),
470 rr ? "True " : "False",
471 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
472 );
473
474 VG_(core_panic)("new_emit");
475}
476/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
477#endif
478
479
sewardjfa492d42002-12-08 18:20:01 +0000480/* Call this before emitting each instruction.
481
482 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000483 interacts_with_simd_flags:
484 if true, this instruction wants to interact (read and/or write)
485 the simulated %EFLAGS state,
486 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000487 use_flags: set of (real) flags the instruction uses
488 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000489*/
sewardjf0f12aa2002-12-28 00:04:08 +0000490void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000491 FlagSet use_flags, FlagSet set_flags )
492{
493 Bool use, set;
494
495 use = use_flags != FlagsEmpty
496 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
497 set = set_flags != FlagsEmpty;
498
499 if (0)
500 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000501 "new_emit: state=%d interacts_with_simd_flags=%d "
502 "use_flags=%x set_flags=%x\n",
503 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000504
sewardjf0f12aa2002-12-28 00:04:08 +0000505 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000506 if (use && eflags_state == UPD_Simd) {
507 /* we need the CPU flags set, but they're not already */
508 eflags_state = UPD_Both;
509 emit_get_eflags();
510 }
511 if (set) {
512 /* if we're setting the flags, then the CPU will have the
513 only good copy */
514 eflags_state = UPD_Real;
515 }
516 } else {
517 /* presume that if non-simd code is using flags, it knows what
518 it's doing (ie, it just set up the flags). */
519 if (set) {
520 /* This instruction is going to trash the flags, so we'd
521 better save them away and say that they're only in the
522 simulated state. */
523 maybe_emit_put_eflags();
524 eflags_state = UPD_Simd;
525 }
526 }
527
sewardjde4a1d02002-03-22 01:27:54 +0000528 if (dis)
529 VG_(printf)("\t %4d: ", emitted_code_used );
530}
531
sewardjde4a1d02002-03-22 01:27:54 +0000532
533/*----------------------------------------------------*/
534/*--- Addressing modes ---*/
535/*----------------------------------------------------*/
536
537static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
538{
539 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
540}
541
542static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
543{
544 Int shift;
545 switch (scale) {
546 case 1: shift = 0; break;
547 case 2: shift = 1; break;
548 case 4: shift = 2; break;
549 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000550 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000551 }
552 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
553}
554
555static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
556{
557 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB) ( mkModRegRM(0, reg, 5) );
559 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000560}
561
562static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
563{
564 /* (regmem), reg */
565 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000566 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000567 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000568 VG_(emitB) ( mkModRegRM(1, reg, 5) );
569 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000570 } else {
njn25e49d8e72002-09-23 09:36:25 +0000571 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000572 }
573}
574
njn25e49d8e72002-09-23 09:36:25 +0000575void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000576{
577 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000578 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000579 if (off < -128 || off > 127) {
580 /* Use a large offset */
581 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000582 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
583 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000584 } else {
585 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000586 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
587 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000588 }
589}
590
591static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
592 Int regindex, Int reg )
593{
594 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000595 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000596 if (off < -128 || off > 127) {
597 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000598 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
599 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
600 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000601 } else {
602 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000603 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
604 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
605 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000606 }
607}
608
njn25e49d8e72002-09-23 09:36:25 +0000609void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000610{
611 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000612 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000613}
614
615static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
616{
617 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000618 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000619}
620
621
622/*----------------------------------------------------*/
623/*--- Opcode translation ---*/
624/*----------------------------------------------------*/
625
626static __inline__ Int mkGrp1opcode ( Opcode opc )
627{
628 switch (opc) {
629 case ADD: return 0;
630 case OR: return 1;
631 case ADC: return 2;
632 case SBB: return 3;
633 case AND: return 4;
634 case SUB: return 5;
635 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000636 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000637 }
638}
639
sewardjfa492d42002-12-08 18:20:01 +0000640static __inline__ FlagSet nonshiftop_use(Opcode opc)
641{
642 switch(opc) {
643 case ADC:
644 case SBB:
645 return FlagC;
646
647 case ADD:
648 case OR:
649 case AND:
650 case SUB:
651 case XOR:
652 return FlagsEmpty;
653
654 default:
655 VG_(core_panic)("nonshiftop_use");
656 }
657}
658
659static __inline__ FlagSet nonshiftop_set(Opcode opc)
660{
661 switch(opc) {
662 case ADC:
663 case SBB:
664 case ADD:
665 case OR:
666 case AND:
667 case SUB:
668 case XOR:
669 return FlagsOSZACP;
670
671 default:
672 VG_(core_panic)("nonshiftop_set");
673 }
674}
675
sewardjde4a1d02002-03-22 01:27:54 +0000676static __inline__ Int mkGrp2opcode ( Opcode opc )
677{
678 switch (opc) {
679 case ROL: return 0;
680 case ROR: return 1;
681 case RCL: return 2;
682 case RCR: return 3;
683 case SHL: return 4;
684 case SHR: return 5;
685 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000686 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000687 }
688}
689
sewardjfa492d42002-12-08 18:20:01 +0000690static __inline__ FlagSet shiftop_use(Opcode opc)
691{
692 switch(opc) {
693 case ROR:
694 case ROL:
695 case SHL:
696 case SHR:
697 case SAR:
698 return FlagsEmpty;
699
700 case RCL:
701 case RCR:
702 return FlagC;
703
704 default:
705 VG_(core_panic)("shiftop_use");
706 }
707}
708
709static __inline__ FlagSet shiftop_set(Opcode opc)
710{
711 switch(opc) {
712 case ROR:
713 case ROL:
714 case RCL:
715 case RCR:
716 return FlagsOC;
717
718 case SHL:
719 case SHR:
720 case SAR:
721 return FlagsOSZACP;
722
723 default:
724 VG_(core_panic)("shiftop_set");
725 }
726}
727
sewardjde4a1d02002-03-22 01:27:54 +0000728static __inline__ Int mkGrp3opcode ( Opcode opc )
729{
730 switch (opc) {
731 case NOT: return 2;
732 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000733 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000734 }
735}
736
737static __inline__ Int mkGrp4opcode ( Opcode opc )
738{
739 switch (opc) {
740 case INC: return 0;
741 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000742 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000743 }
744}
745
746static __inline__ Int mkGrp5opcode ( Opcode opc )
747{
748 switch (opc) {
749 case CALLM: return 2;
750 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000751 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000752 }
753}
754
755static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
756{
757 switch (opc) {
758 case ADD: return 0x00;
759 case ADC: return 0x10;
760 case AND: return 0x20;
761 case XOR: return 0x30;
762 case OR: return 0x08;
763 case SBB: return 0x18;
764 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000765 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000766 }
767}
768
769/*----------------------------------------------------*/
770/*--- v-size (4, or 2 with OSO) insn emitters ---*/
771/*----------------------------------------------------*/
772
njn25e49d8e72002-09-23 09:36:25 +0000773void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000774{
sewardjf0f12aa2002-12-28 00:04:08 +0000775 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000776 if (sz == 2) VG_(emitB) ( 0x66 );
777 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
778 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000779 if (dis)
780 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
781 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
782}
783
njn25e49d8e72002-09-23 09:36:25 +0000784void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000785{
sewardjf0f12aa2002-12-28 00:04:08 +0000786 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000787
788 if (sz & DO_BOUNDSCHECK) {
789 boundscheck();
790 sz &= ~DO_BOUNDSCHECK;
791 }
792
njn25e49d8e72002-09-23 09:36:25 +0000793 if (sz == 2) VG_(emitB) ( 0x66 );
794 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
795 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000796 if (dis)
797 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
798 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
799}
800
801static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
802{
sewardjf0f12aa2002-12-28 00:04:08 +0000803 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000804
805 if (sz & DO_BOUNDSCHECK) {
806 boundscheck();
807 sz &= ~DO_BOUNDSCHECK;
808 }
809
njn25e49d8e72002-09-23 09:36:25 +0000810 if (sz == 2) VG_(emitB) ( 0x66 );
811 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000812 emit_amode_regmem_reg ( reg1, reg2 );
813 if (dis)
814 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
815 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
816}
817
818static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
819{
sewardjf0f12aa2002-12-28 00:04:08 +0000820 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000821
822 if (sz & DO_BOUNDSCHECK) {
823 boundscheck();
824 sz &= ~DO_BOUNDSCHECK;
825 }
826
njn25e49d8e72002-09-23 09:36:25 +0000827 if (sz == 2) VG_(emitB) ( 0x66 );
828 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000829 emit_amode_regmem_reg ( reg2, reg1 );
830 if (dis)
831 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
832 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
833}
834
njn25e49d8e72002-09-23 09:36:25 +0000835void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000836{
sewardjf0f12aa2002-12-28 00:04:08 +0000837 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000838 if (sz == 2) VG_(emitB) ( 0x66 );
839 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
840 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000841 if (dis)
842 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
843 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
844}
845
sewardjf0f12aa2002-12-28 00:04:08 +0000846void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
847 Int sz, Opcode opc,
848 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000849{
sewardjf0f12aa2002-12-28 00:04:08 +0000850 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000851
njn25e49d8e72002-09-23 09:36:25 +0000852 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000853 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
854 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000855 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
856 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
857 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000858 } else {
njn25e49d8e72002-09-23 09:36:25 +0000859 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
860 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
861 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000862 }
863 if (dis)
864 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000865 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000866 lit, nameIReg(sz,reg));
867}
868
sewardjf0f12aa2002-12-28 00:04:08 +0000869void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
870 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000871 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000872{
sewardjf0f12aa2002-12-28 00:04:08 +0000873 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000874 if (sz == 2) VG_(emitB) ( 0x66 );
875 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
876 /* short form OK */
877 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
878 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
879 VG_(emitB) ( lit & 0x000000FF );
880 } else {
881 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
882 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
883 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
884 }
885 if (dis)
886 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
887 VG_(name_UOpcode)(False,opc), nameISize(sz),
888 lit, off, nameIReg(sz,regmem));
889}
890
sewardjf0f12aa2002-12-28 00:04:08 +0000891void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
892 Int sz, Opcode opc,
893 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000894{
sewardjf0f12aa2002-12-28 00:04:08 +0000895 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000896
njn25e49d8e72002-09-23 09:36:25 +0000897 if (sz == 2) VG_(emitB) ( 0x66 );
898 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
899 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
900 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000901 if (dis)
902 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000903 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000904 lit, nameIReg(sz,reg));
905}
906
sewardjf0f12aa2002-12-28 00:04:08 +0000907static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000908{
sewardjf0f12aa2002-12-28 00:04:08 +0000909 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000910 if (sz == 2) VG_(emitB) ( 0x66 );
911 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
912 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
913 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
914 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000915 if (dis)
916 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000917 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000918}
919
sewardjf0f12aa2002-12-28 00:04:08 +0000920static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000921{
sewardjf0f12aa2002-12-28 00:04:08 +0000922 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000923 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
924 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
925 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
926 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000927 if (dis)
928 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000929 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000930}
931
sewardjf0f12aa2002-12-28 00:04:08 +0000932static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
933 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000934 Int off, Int areg, Int reg )
935{
sewardjf0f12aa2002-12-28 00:04:08 +0000936 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000937 if (sz == 2) VG_(emitB) ( 0x66 );
938 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
939 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000940 if (dis)
941 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000942 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000943 off, nameIReg(4,areg), nameIReg(sz,reg));
944}
945
sewardja2c5a732002-12-15 03:10:42 +0000946#if 0
947/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000948static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000949 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000950{
sewardjf0f12aa2002-12-28 00:04:08 +0000951 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000952 if (sz == 2) VG_(emitB) ( 0x66 );
953 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
954 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
955 if (dis)
956 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
957 VG_(name_UOpcode)(False,opc), nameISize(sz),
958 nameIReg(sz,reg), off, nameIReg(4,areg));
959}
sewardja2c5a732002-12-15 03:10:42 +0000960#endif
sewardjfa492d42002-12-08 18:20:01 +0000961
sewardjf0f12aa2002-12-28 00:04:08 +0000962void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000963 Int reg1, Int reg2 )
964{
sewardjf0f12aa2002-12-28 00:04:08 +0000965 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000966 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000967# if 0
968 /* Perfectly correct, but the GNU assembler uses the other form.
969 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000970 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
971 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000972# else
njn25e49d8e72002-09-23 09:36:25 +0000973 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000974 emit_amode_greg_ereg ( reg1, reg2 );
975# endif
976 if (dis)
977 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000978 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000979 nameIReg(sz,reg1), nameIReg(sz,reg2));
980}
981
njn25e49d8e72002-09-23 09:36:25 +0000982void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000983{
sewardjf0f12aa2002-12-28 00:04:08 +0000984#if 0
sewardjfa492d42002-12-08 18:20:01 +0000985 if (lit == 0 && eflags_state != UPD_Real) {
986 /* Only emit this for zeroing if it won't stomp flags */
987 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000988 return;
989 }
sewardjf0f12aa2002-12-28 00:04:08 +0000990#endif
991 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
993 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
994 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000995 if (dis)
996 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
997 nameISize(sz), lit, nameIReg(sz,reg));
998}
999
sewardjf0f12aa2002-12-28 00:04:08 +00001000void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001001{
sewardjde4a1d02002-03-22 01:27:54 +00001002 switch (opc) {
1003 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001004 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +00001005 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001006 VG_(emitB) ( 0xF7 );
1007 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001008 if (dis)
1009 VG_(printf)( "\n\t\tneg%c\t%s\n",
1010 nameISize(sz), nameIReg(sz,reg));
1011 break;
1012 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +00001014 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0xF7 );
1016 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001017 if (dis)
1018 VG_(printf)( "\n\t\tnot%c\t%s\n",
1019 nameISize(sz), nameIReg(sz,reg));
1020 break;
1021 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001022 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001023 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001024 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001025 if (dis)
1026 VG_(printf)( "\n\t\tdec%c\t%s\n",
1027 nameISize(sz), nameIReg(sz,reg));
1028 break;
1029 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001030 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001031 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)( "\n\t\tinc%c\t%s\n",
1035 nameISize(sz), nameIReg(sz,reg));
1036 break;
1037 default:
njne427a662002-10-02 11:08:25 +00001038 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001039 }
1040}
1041
njn25e49d8e72002-09-23 09:36:25 +00001042void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001043{
sewardjf0f12aa2002-12-28 00:04:08 +00001044 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001045 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001046 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001047 } else {
1048 vg_assert(sz == 4);
1049 }
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001051 if (dis)
1052 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1053}
1054
njn25e49d8e72002-09-23 09:36:25 +00001055void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001056{
sewardjf0f12aa2002-12-28 00:04:08 +00001057 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001058 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001060 } else {
1061 vg_assert(sz == 4);
1062 }
njn25e49d8e72002-09-23 09:36:25 +00001063 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001064 if (dis)
1065 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1066}
1067
njn25e49d8e72002-09-23 09:36:25 +00001068void VG_(emit_pushl_lit32) ( UInt int32 )
1069{
sewardjf0f12aa2002-12-28 00:04:08 +00001070 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001071 VG_(emitB) ( 0x68 );
1072 VG_(emitL) ( int32 );
1073 if (dis)
1074 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1075}
1076
1077void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001078{
1079 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001080 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001081 VG_(emitB) ( 0x6A );
1082 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001083 if (dis)
1084 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1085}
1086
sewardjf0f12aa2002-12-28 00:04:08 +00001087void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001088{
sewardjf0f12aa2002-12-28 00:04:08 +00001089 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001090 VG_(emitB) ( 0x83 );
1091 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1092 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001093 if (dis)
1094 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1095}
1096
1097static void emit_swapl_reg_ECX ( Int reg )
1098{
sewardjf0f12aa2002-12-28 00:04:08 +00001099 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001100 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1101 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001102 if (dis)
1103 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1104}
1105
njn25e49d8e72002-09-23 09:36:25 +00001106void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001107{
sewardjf0f12aa2002-12-28 00:04:08 +00001108 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001109 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001110 if (dis)
1111 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1112}
1113
1114static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1115{
sewardjf0f12aa2002-12-28 00:04:08 +00001116 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001117 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1118 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001119 if (dis)
1120 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1121 nameIReg(4,reg2));
1122}
1123
1124static void emit_bswapl_reg ( Int reg )
1125{
sewardjf0f12aa2002-12-28 00:04:08 +00001126 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001127 VG_(emitB) ( 0x0F );
1128 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001129 if (dis)
1130 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1131}
1132
1133static void emit_movl_reg_reg ( Int regs, Int regd )
1134{
sewardjf0f12aa2002-12-28 00:04:08 +00001135 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001136 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1137 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001138 if (dis)
1139 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1140}
1141
njn25e49d8e72002-09-23 09:36:25 +00001142void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001143{
sewardjf0f12aa2002-12-28 00:04:08 +00001144 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001145 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001146 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001147 } else {
1148 vg_assert(sz == 4);
1149 }
njn25e49d8e72002-09-23 09:36:25 +00001150 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1151 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1152 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001153 if (dis)
1154 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1155 nameISize(sz), lit, off, nameIReg(4,memreg) );
1156}
1157
1158
1159/*----------------------------------------------------*/
1160/*--- b-size (1 byte) instruction emitters ---*/
1161/*----------------------------------------------------*/
1162
1163/* There is some doubt as to whether C6 (Grp 11) is in the
1164 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001165void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1166{
sewardjf0f12aa2002-12-28 00:04:08 +00001167 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001168 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1169 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1170 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001171 if (dis)
1172 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1173 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001174}
1175
sewardjf0f12aa2002-12-28 00:04:08 +00001176static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001177 Int off, Int areg, Int reg )
1178{
sewardjf0f12aa2002-12-28 00:04:08 +00001179 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001180 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1181 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001182 if (dis)
1183 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001184 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001185 nameIReg(1,reg));
1186}
1187
sewardjf0f12aa2002-12-28 00:04:08 +00001188static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001189 UInt lit, Int off, Int areg )
1190{
sewardjf0f12aa2002-12-28 00:04:08 +00001191 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001192 VG_(emitB) ( 0x80 );
1193 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1194 VG_(emitB) ( lit );
1195 if (dis)
1196 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1197 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1198}
1199
sewardja2c5a732002-12-15 03:10:42 +00001200#if 0
1201/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001202static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001203 Int off, Int areg, Int reg )
1204{
sewardjf0f12aa2002-12-28 00:04:08 +00001205 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001206 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1207 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1208 if (dis)
1209 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1210 VG_(name_UOpcode)(False,opc),
1211 nameIReg(1,reg),
1212 off, nameIReg(4,areg));
1213}
sewardja2c5a732002-12-15 03:10:42 +00001214#endif
sewardjfa492d42002-12-08 18:20:01 +00001215
njn25e49d8e72002-09-23 09:36:25 +00001216void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001217{
1218 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001219 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001220 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1221 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001222 if (dis)
1223 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1224 nameIReg(1,reg), off, nameIReg(4,areg));
1225}
1226
sewardjf0f12aa2002-12-28 00:04:08 +00001227static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1228 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001229{
sewardjf0f12aa2002-12-28 00:04:08 +00001230 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001231 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1232 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001233 if (dis)
1234 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001235 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001236 nameIReg(1,reg1), nameIReg(1,reg2));
1237}
1238
fitzhardinge98abfc72003-12-16 02:05:15 +00001239static void emit_movb_reg_regmem ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001240{
sewardjf0f12aa2002-12-28 00:04:08 +00001241 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001242
1243 if (bounds)
1244 boundscheck();
1245
njn25e49d8e72002-09-23 09:36:25 +00001246 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001247 emit_amode_regmem_reg ( reg2, reg1 );
1248 if (dis)
1249 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1250 nameIReg(4,reg2));
1251}
1252
sewardjf0f12aa2002-12-28 00:04:08 +00001253static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1254 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001255{
sewardjf0f12aa2002-12-28 00:04:08 +00001256 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001257 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1258 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1259 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001260 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001261 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001262 lit, nameIReg(1,reg));
1263}
1264
sewardjf0f12aa2002-12-28 00:04:08 +00001265static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1266 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001267{
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1271 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001272 if (dis)
1273 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001274 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001275 lit, nameIReg(1,reg));
1276}
1277
sewardjf0f12aa2002-12-28 00:04:08 +00001278void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001279{
sewardjde4a1d02002-03-22 01:27:54 +00001280 switch (opc) {
1281 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001282 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001283 VG_(emitB) ( 0xFE );
1284 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1287 break;
1288 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001289 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001290 VG_(emitB) ( 0xFE );
1291 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001292 if (dis)
1293 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1294 break;
1295 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001296 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001297 VG_(emitB) ( 0xF6 );
1298 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001299 if (dis)
1300 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1301 break;
1302 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001303 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001304 VG_(emitB) ( 0xF6 );
1305 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001306 if (dis)
1307 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1308 break;
1309 default:
njne427a662002-10-02 11:08:25 +00001310 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001311 }
1312}
1313
sewardjf0f12aa2002-12-28 00:04:08 +00001314void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001315{
sewardjf0f12aa2002-12-28 00:04:08 +00001316 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001317 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1318 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1319 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001320 if (dis)
1321 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1322}
1323
sewardjde4a1d02002-03-22 01:27:54 +00001324/*----------------------------------------------------*/
1325/*--- zero-extended load emitters ---*/
1326/*----------------------------------------------------*/
1327
fitzhardinge98abfc72003-12-16 02:05:15 +00001328void VG_(emit_movzbl_offregmem_reg) ( Bool bounds, Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001329{
sewardjf0f12aa2002-12-28 00:04:08 +00001330 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001331 if (bounds)
1332 boundscheck();
njn25e49d8e72002-09-23 09:36:25 +00001333 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1334 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001335 if (dis)
1336 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1337 off, nameIReg(4,regmem), nameIReg(4,reg));
1338}
1339
fitzhardinge98abfc72003-12-16 02:05:15 +00001340static void emit_movzbl_regmem_reg ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001341{
sewardjf0f12aa2002-12-28 00:04:08 +00001342 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001343
1344 if (bounds)
1345 boundscheck();
1346
njn25e49d8e72002-09-23 09:36:25 +00001347 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001348 emit_amode_regmem_reg ( reg1, reg2 );
1349 if (dis)
1350 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1351 nameIReg(4,reg2));
1352}
1353
fitzhardinge98abfc72003-12-16 02:05:15 +00001354void VG_(emit_movzwl_offregmem_reg) ( Bool bounds, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001355{
sewardjf0f12aa2002-12-28 00:04:08 +00001356 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001357
1358 if (bounds)
1359 boundscheck();
1360
njn25e49d8e72002-09-23 09:36:25 +00001361 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1362 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001363 if (dis)
1364 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1365 off, nameIReg(4,areg), nameIReg(4,reg));
1366}
1367
fitzhardinge98abfc72003-12-16 02:05:15 +00001368void VG_( emit_movzwl_regmem_reg ) ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001369{
sewardjf0f12aa2002-12-28 00:04:08 +00001370 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001371
1372 if (bounds)
1373 boundscheck();
1374
njn25e49d8e72002-09-23 09:36:25 +00001375 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001376 emit_amode_regmem_reg ( reg1, reg2 );
1377 if (dis)
1378 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1379 nameIReg(4,reg2));
1380}
1381
1382/*----------------------------------------------------*/
1383/*--- FPU instruction emitters ---*/
1384/*----------------------------------------------------*/
1385
sewardjb91ae7f2003-04-29 23:50:00 +00001386static void emit_get_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001387{
sewardjb91ae7f2003-04-29 23:50:00 +00001388 Int off = 4 * VGOFF_(m_ssestate);
1389 if (VG_(have_ssestate)) {
1390 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1391 VG_(emitB) ( 0x0F );
1392 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x8D ); /* fxrstor d32(%ebp) */
1393 VG_(emitL) ( off );
1394 if (dis)
1395 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1396 } else {
1397 /* Not a SSE-capable CPU. Just do frstor. */
1398 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1399 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1400 VG_(emitL) ( off );
1401 if (dis)
1402 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1403 }
sewardjde4a1d02002-03-22 01:27:54 +00001404}
1405
sewardjb91ae7f2003-04-29 23:50:00 +00001406static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001407{
sewardjb91ae7f2003-04-29 23:50:00 +00001408 Int off = 4 * VGOFF_(m_ssestate);
1409 if (VG_(have_ssestate)) {
1410 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1411 VG_(emitB) ( 0x0F );
1412 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1413 VG_(emitL) ( off );
1414 if (dis)
1415 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1416 } else {
1417 /* Not a SSE-capable CPU. Just do fnsave. */
1418 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1419 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1420 VG_(emitL) ( off );
1421 if (dis)
1422 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1423 }
sewardjde4a1d02002-03-22 01:27:54 +00001424}
1425
sewardjf0f12aa2002-12-28 00:04:08 +00001426static void emit_fpu_no_mem ( FlagSet uses_sflags,
1427 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001428 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001429 UChar second_byte )
1430{
sewardjf0f12aa2002-12-28 00:04:08 +00001431 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001432 VG_(emitB) ( first_byte );
1433 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001434 if (dis)
1435 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1436 (UInt)first_byte, (UInt)second_byte );
1437}
1438
sewardjf0f12aa2002-12-28 00:04:08 +00001439static void emit_fpu_regmem ( FlagSet uses_sflags,
1440 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001441 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001442 UChar second_byte_masked,
1443 Int reg )
1444{
sewardjf0f12aa2002-12-28 00:04:08 +00001445 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001446
1447 boundscheck(); /* assume all FPU ops are the client's */
1448
njn25e49d8e72002-09-23 09:36:25 +00001449 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001450 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1451 if (dis)
1452 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1453 (UInt)first_byte, (UInt)second_byte_masked,
1454 nameIReg(4,reg) );
1455}
1456
sewardj3d7c9c82003-03-26 21:08:13 +00001457static void emit_MMX2_regmem ( FlagSet uses_sflags,
1458 FlagSet sets_sflags,
1459 UChar first_byte,
1460 UChar second_byte,
1461 Int ireg )
1462{
1463 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001464
1465 boundscheck();
1466
sewardj3d7c9c82003-03-26 21:08:13 +00001467 VG_(emitB) ( 0x0F );
1468 VG_(emitB) ( first_byte );
1469 second_byte &= 0x38; /* mask out mod and rm fields */
1470 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1471 if (dis)
1472 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1473 (UInt)first_byte, (UInt)second_byte,
1474 nameIReg(4,ireg) );
1475}
1476
sewardjfebaa3b2003-05-25 01:07:34 +00001477static void emit_SSE2a ( FlagSet uses_sflags,
1478 FlagSet sets_sflags,
1479 UChar first_byte,
1480 UChar second_byte,
1481 UChar third_byte,
1482 Int ireg )
1483{
1484 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001485
1486 boundscheck();
1487
sewardjfebaa3b2003-05-25 01:07:34 +00001488 VG_(emitB) ( first_byte );
1489 VG_(emitB) ( second_byte );
1490 third_byte &= 0x38; /* mask out mod and rm fields */
1491 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1492 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001493 VG_(printf)("\n\t\tsse2a-0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001494 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1495 nameIReg(4,ireg) );
1496}
1497
sewardj9dd209f2003-06-18 23:30:52 +00001498static void emit_SSE2a1 ( FlagSet uses_sflags,
1499 FlagSet sets_sflags,
1500 UChar first_byte,
1501 UChar second_byte,
1502 UChar third_byte,
1503 UChar fourth_byte,
1504 Int ireg )
1505{
1506 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001507
1508 boundscheck();
1509
sewardj9dd209f2003-06-18 23:30:52 +00001510 VG_(emitB) ( first_byte );
1511 VG_(emitB) ( second_byte );
1512 third_byte &= 0x38; /* mask out mod and rm fields */
1513 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1514 VG_(emitB) ( fourth_byte );
1515 if (dis)
1516 VG_(printf)("\n\t\tsse2a1-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1517 (UInt)first_byte, (UInt)second_byte,
1518 (UInt)third_byte, (UInt)fourth_byte,
1519 nameIReg(4,ireg) );
1520}
1521
sewardjfebaa3b2003-05-25 01:07:34 +00001522static void emit_SSE3a ( FlagSet uses_sflags,
1523 FlagSet sets_sflags,
1524 UChar first_byte,
1525 UChar second_byte,
1526 UChar third_byte,
1527 UChar fourth_byte,
1528 Int ireg )
1529{
1530 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001531
1532 boundscheck();
1533
sewardjfebaa3b2003-05-25 01:07:34 +00001534 VG_(emitB) ( first_byte );
1535 VG_(emitB) ( second_byte );
1536 VG_(emitB) ( third_byte );
1537 fourth_byte &= 0x38; /* mask out mod and rm fields */
1538 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1539 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001540 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001541 (UInt)first_byte, (UInt)second_byte,
1542 (UInt)third_byte, (UInt)fourth_byte,
1543 nameIReg(4,ireg) );
1544}
1545
sewardjabf8bf82003-06-15 22:28:05 +00001546static void emit_SSE3e ( FlagSet uses_sflags,
1547 FlagSet sets_sflags,
1548 UChar first_byte,
1549 UChar second_byte,
1550 UChar third_byte,
1551 UChar fourth_byte,
1552 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001553{
1554 VG_(new_emit)(True, uses_sflags, sets_sflags);
1555 VG_(emitB) ( first_byte );
1556 VG_(emitB) ( second_byte );
1557 VG_(emitB) ( third_byte );
1558 fourth_byte &= 0x38; /* mask out mod and rm fields */
1559 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1560 fourth_byte |= (ireg & 7); /* patch in our ireg */
1561 VG_(emitB) ( fourth_byte );
1562 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001563 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001564 "\n\t\tsse3e--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001565 (UInt)first_byte, (UInt)second_byte,
1566 (UInt)third_byte, (UInt)fourth_byte,
1567 nameIReg(4,ireg)
1568 );
sewardjfebaa3b2003-05-25 01:07:34 +00001569}
1570
sewardjabf8bf82003-06-15 22:28:05 +00001571static void emit_SSE3e1 ( FlagSet uses_sflags,
1572 FlagSet sets_sflags,
1573 UChar first_byte,
1574 UChar second_byte,
1575 UChar third_byte,
1576 UChar fourth_byte,
1577 UChar fifth_byte,
1578 Int ireg )
sewardj8f33ba62003-06-14 12:00:45 +00001579{
1580 VG_(new_emit)(True, uses_sflags, sets_sflags);
1581 VG_(emitB) ( first_byte );
1582 VG_(emitB) ( second_byte );
1583 VG_(emitB) ( third_byte );
1584 fourth_byte &= 0x38; /* mask out mod and rm fields */
1585 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1586 fourth_byte |= (ireg & 7); /* patch in our ireg */
1587 VG_(emitB) ( fourth_byte );
1588 VG_(emitB) ( fifth_byte );
1589 if (dis)
1590 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001591 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001592 (UInt)first_byte, (UInt)second_byte,
1593 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1594 nameIReg(4,ireg)
1595 );
1596}
1597
sewardjabf8bf82003-06-15 22:28:05 +00001598static void emit_SSE3g1 ( FlagSet uses_sflags,
1599 FlagSet sets_sflags,
1600 UChar first_byte,
1601 UChar second_byte,
1602 UChar third_byte,
1603 UChar fourth_byte,
1604 UChar fifth_byte,
1605 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001606{
1607 VG_(new_emit)(True, uses_sflags, sets_sflags);
1608 VG_(emitB) ( first_byte );
1609 VG_(emitB) ( second_byte );
1610 VG_(emitB) ( third_byte );
1611 fourth_byte &= 0xC7; /* mask out reg field */
1612 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1613 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1614 VG_(emitB) ( fourth_byte );
1615 VG_(emitB) ( fifth_byte );
1616 if (dis)
1617 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001618 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001619 (UInt)first_byte, (UInt)second_byte,
1620 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1621 nameIReg(4,ireg)
1622 );
1623}
1624
sewardjabf8bf82003-06-15 22:28:05 +00001625static void emit_SSE3g ( FlagSet uses_sflags,
1626 FlagSet sets_sflags,
1627 UChar first_byte,
1628 UChar second_byte,
1629 UChar third_byte,
1630 UChar fourth_byte,
1631 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001632{
1633 VG_(new_emit)(True, uses_sflags, sets_sflags);
1634 VG_(emitB) ( first_byte );
1635 VG_(emitB) ( second_byte );
1636 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001637 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001638 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001639 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001640 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001641 if (dis)
1642 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001643 "\n\t\tsse3g--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001644 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001645 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001646 nameIReg(4,ireg)
1647 );
1648}
1649
sewardj77d30a22003-10-19 08:18:52 +00001650static void emit_SSE3a1 ( FlagSet uses_sflags,
1651 FlagSet sets_sflags,
1652 UChar first_byte,
1653 UChar second_byte,
1654 UChar third_byte,
1655 UChar fourth_byte,
1656 UChar fifth_byte,
1657 Int ireg )
1658{
1659 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001660
1661 boundscheck();
1662
sewardj77d30a22003-10-19 08:18:52 +00001663 VG_(emitB) ( first_byte );
1664 VG_(emitB) ( second_byte );
1665 VG_(emitB) ( third_byte );
1666 fourth_byte &= 0x38; /* mask out mod and rm fields */
1667 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1668 VG_(emitB) ( fifth_byte );
1669 if (dis)
1670 VG_(printf)("\n\t\tsse3a1-0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1671 (UInt)first_byte, (UInt)second_byte,
1672 (UInt)third_byte, (UInt)fourth_byte,
1673 (UInt)fifth_byte,
1674 nameIReg(4,ireg) );
1675}
1676
sewardjfebaa3b2003-05-25 01:07:34 +00001677static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001678 FlagSet sets_sflags,
1679 UChar first_byte,
1680 UChar second_byte,
1681 UChar third_byte,
1682 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001683{
1684 VG_(new_emit)(True, uses_sflags, sets_sflags);
1685 VG_(emitB) ( first_byte );
1686 VG_(emitB) ( second_byte );
1687 VG_(emitB) ( third_byte );
1688 VG_(emitB) ( fourth_byte );
1689 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001690 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001691 (UInt)first_byte, (UInt)second_byte,
1692 (UInt)third_byte, (UInt)fourth_byte );
1693}
1694
sewardja453fb02003-06-14 13:22:36 +00001695static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001696 FlagSet sets_sflags,
1697 UChar first_byte,
1698 UChar second_byte,
1699 UChar third_byte,
1700 UChar fourth_byte,
1701 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001702{
1703 VG_(new_emit)(True, uses_sflags, sets_sflags);
1704 VG_(emitB) ( first_byte );
1705 VG_(emitB) ( second_byte );
1706 VG_(emitB) ( third_byte );
1707 VG_(emitB) ( fourth_byte );
1708 VG_(emitB) ( fifth_byte );
1709 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001710 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001711 (UInt)first_byte, (UInt)second_byte,
1712 (UInt)third_byte, (UInt)fourth_byte,
1713 (UInt)fifth_byte );
1714}
1715
sewardja60be0e2003-05-26 08:47:27 +00001716static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001717 FlagSet sets_sflags,
1718 UChar first_byte,
1719 UChar second_byte,
1720 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001721{
1722 VG_(new_emit)(True, uses_sflags, sets_sflags);
1723 VG_(emitB) ( first_byte );
1724 VG_(emitB) ( second_byte );
1725 VG_(emitB) ( third_byte );
1726 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001727 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001728 (UInt)first_byte, (UInt)second_byte,
1729 (UInt)third_byte );
1730}
1731
sewardje3891fa2003-06-15 03:13:48 +00001732static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1733 FlagSet sets_sflags,
1734 UChar first_byte,
1735 UChar second_byte,
1736 UChar third_byte,
1737 Int addr_reg,
1738 Int dest_reg )
1739{
1740 VG_(new_emit)(True, uses_sflags, sets_sflags);
1741 VG_(emitB) ( first_byte );
1742 VG_(emitB) ( second_byte );
1743 VG_(emitB) ( third_byte );
1744 /* 4th byte can be completely synthesised from addr_reg and
1745 dest_reg. */
1746 emit_amode_regmem_reg ( addr_reg, dest_reg );
1747 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001748 VG_(printf)("\n\t\tsse3ag_mem_rd_reg_wr-0x%x:0x%x:0x%x(addr=%s, dest=%s)\n",
sewardje3891fa2003-06-15 03:13:48 +00001749 (UInt)first_byte, (UInt)second_byte,
1750 (UInt)third_byte, nameIReg(4, addr_reg),
1751 nameIReg(4, dest_reg));
1752}
1753
sewardjca860012003-03-27 23:52:58 +00001754static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1755 FlagSet sets_sflags,
1756 UChar first_byte,
1757 UChar second_byte,
1758 Int ireg )
1759{
1760 VG_(new_emit)(True, uses_sflags, sets_sflags);
1761 VG_(emitB) ( 0x0F );
1762 VG_(emitB) ( first_byte );
1763 second_byte &= 0x38; /* mask out mod and rm fields */
1764 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1765 second_byte |= (ireg & 7); /* patch in our ireg */
1766 VG_(emitB) ( second_byte );
1767 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001768 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1769 (UInt)first_byte, (UInt)second_byte,
1770 nameIReg(4,ireg) );
1771}
1772
1773static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1774 FlagSet sets_sflags,
1775 UChar first_byte,
1776 UChar second_byte,
1777 Int ireg )
1778{
1779 VG_(new_emit)(True, uses_sflags, sets_sflags);
1780 VG_(emitB) ( 0x0F );
1781 VG_(emitB) ( first_byte );
1782 second_byte &= 0x38; /* mask out mod and rm fields */
1783 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1784 second_byte |= (ireg & 7); /* patch in our ireg */
1785 VG_(emitB) ( second_byte );
1786 if (dis)
1787 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001788 (UInt)first_byte, (UInt)second_byte,
1789 nameIReg(4,ireg) );
1790}
1791
1792static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1793 FlagSet sets_sflags,
1794 UChar first_byte,
1795 UChar second_byte,
1796 UChar third_byte )
1797{
1798 VG_(new_emit)(True, uses_sflags, sets_sflags);
1799 VG_(emitB) ( 0x0F );
1800 VG_(emitB) ( first_byte );
1801 VG_(emitB) ( second_byte );
1802 VG_(emitB) ( third_byte );
1803 if (dis)
1804 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1805 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1806}
1807
sewardj3d7c9c82003-03-26 21:08:13 +00001808static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1809 FlagSet sets_sflags,
1810 UChar first_byte,
1811 UChar second_byte )
1812{
1813 VG_(new_emit)(True, uses_sflags, sets_sflags);
1814 VG_(emitB) ( 0x0F );
1815 VG_(emitB) ( first_byte );
1816 VG_(emitB) ( second_byte );
1817 if (dis)
1818 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1819 (UInt)first_byte, (UInt)second_byte );
1820}
1821
1822static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1823 FlagSet sets_sflags,
1824 UChar first_byte )
1825{
1826 VG_(new_emit)(True, uses_sflags, sets_sflags);
1827 VG_(emitB) ( 0x0F );
1828 VG_(emitB) ( first_byte );
1829 if (dis)
1830 VG_(printf)("\n\t\tmmx1-0x%x\n",
1831 (UInt)first_byte );
1832}
1833
sewardjde4a1d02002-03-22 01:27:54 +00001834
1835/*----------------------------------------------------*/
1836/*--- misc instruction emitters ---*/
1837/*----------------------------------------------------*/
1838
njn25e49d8e72002-09-23 09:36:25 +00001839void VG_(emit_call_reg) ( Int reg )
1840{
sewardjfa492d42002-12-08 18:20:01 +00001841 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001842 VG_(emitB) ( 0xFF ); /* Grp5 */
1843 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1844 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001845 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001846}
1847
sewardjf0f12aa2002-12-28 00:04:08 +00001848static
1849void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1850 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001851{
sewardjfa492d42002-12-08 18:20:01 +00001852 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001853 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001854
1855 if (byte_off < -128 || byte_off > 127) {
1856 VG_(emitB) ( 0xFF );
1857 VG_(emitB) ( 0x95 );
1858 VG_(emitL) ( byte_off );
1859 } else {
1860 VG_(emitB) ( 0xFF );
1861 VG_(emitB) ( 0x55 );
1862 VG_(emitB) ( byte_off );
1863 }
1864 if (dis)
1865 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001866}
1867
sewardja2c5a732002-12-15 03:10:42 +00001868#if 0
1869/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001870static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1871{
1872 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001873 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001874 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1875 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001876 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001877 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001878 if (dis)
1879 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1880 nameIReg(4,regmem));
1881}
sewardja2c5a732002-12-15 03:10:42 +00001882#endif
sewardjde4a1d02002-03-22 01:27:54 +00001883
njn25e49d8e72002-09-23 09:36:25 +00001884void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001885{
njne427a662002-10-02 11:08:25 +00001886 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001887 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1888 VG_(emitB) ( 0x8D );
1889 VG_(emitB) ( 0x64 );
1890 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001891 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001892 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001893 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001894}
1895
1896
1897static void emit_movb_AL_zeroESPmem ( void )
1898{
1899 /* movb %al, 0(%esp) */
1900 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001901 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001902 VG_(emitB) ( 0x88 );
1903 VG_(emitB) ( 0x44 );
1904 VG_(emitB) ( 0x24 );
1905 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001906 if (dis)
1907 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1908}
1909
1910static void emit_movb_zeroESPmem_AL ( void )
1911{
1912 /* movb 0(%esp), %al */
1913 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001914 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001915 VG_(emitB) ( 0x8A );
1916 VG_(emitB) ( 0x44 );
1917 VG_(emitB) ( 0x24 );
1918 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001919 if (dis)
1920 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1921}
1922
sewardja2113f92002-12-12 23:42:48 +00001923/* Jump target states */
1924#define TGT_UNDEF (1 << 16)
1925#define TGT_FORWARD (2 << 16)
1926#define TGT_BACKWARD (3 << 16)
1927
1928static inline Int tgt_state(Int tgt)
1929{
1930 return tgt & 0xffff0000;
1931}
1932
1933static inline Int tgt_addr(Int tgt)
1934{
1935 return tgt & 0x0000ffff;
1936}
1937
1938static inline Int mk_tgt(Int state, Int addr)
1939{
1940 vg_assert(state == TGT_UNDEF
1941 || state == TGT_FORWARD || state == TGT_BACKWARD);
1942 vg_assert((addr & 0xffff0000) == 0);
1943
1944 return state | addr;
1945}
1946
1947void VG_(init_target) ( Int *tgt )
1948{
1949 *tgt = TGT_UNDEF;
1950}
1951
1952void VG_(target_back) ( Int *tgt )
1953{
1954 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1955
1956 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1957}
1958
1959void VG_(target_forward) ( Int *tgt )
1960{
1961 Int delta;
1962
1963 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1964 tgt_state(*tgt) == TGT_UNDEF);
1965
1966 if (tgt_state(*tgt) == TGT_UNDEF)
1967 return; /* target not used */
1968
1969 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1970 vg_assert(delta >= -128 && delta <= 127);
1971 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001972 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001973 emitted_code[tgt_addr(*tgt)] = delta;
1974 if (dis)
1975 VG_(printf)("(target to jump site %d; delta: %d)\n",
1976 tgt_addr(*tgt), delta);
1977}
1978
1979void VG_(emit_target_delta) ( Int *tgt )
1980{
1981 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1982 tgt_state(*tgt) == TGT_BACKWARD);
1983
1984 if (tgt_state(*tgt) == TGT_UNDEF) {
1985 /* forward jump */
1986 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1987 VG_(emitB) (0x00);
1988 } else {
1989 /* backward jump */
1990 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1991 vg_assert(delta >= -128 && delta <= 127);
1992 VG_(emitB) (delta);
1993 }
1994}
1995
sewardjde4a1d02002-03-22 01:27:54 +00001996
1997/* Emit a jump short with an 8-bit signed offset. Note that the
1998 offset is that which should be added to %eip once %eip has been
1999 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00002000void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00002001{
2002 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00002003 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002004 VG_(emitB) ( 0x70 + (UInt)cond );
2005 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00002006 if (dis)
2007 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00002008 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00002009}
2010
sewardja2113f92002-12-12 23:42:48 +00002011/* Same as above, but defers emitting the delta */
2012void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
2013{
sewardj706240d2002-12-26 17:10:12 +00002014 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00002015 VG_(emitB) ( 0x70 + (UInt)cond );
2016 VG_(emit_target_delta) (tgt);
2017 if (dis)
2018 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00002019 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00002020}
2021
2022
2023
sewardjf0f12aa2002-12-28 00:04:08 +00002024static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002025{
sewardjf0f12aa2002-12-28 00:04:08 +00002026 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002027 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
2028 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00002029 if (dis)
2030 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00002031 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00002032}
2033
2034static void emit_ret ( void )
2035{
sewardjfa492d42002-12-08 18:20:01 +00002036 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00002037 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002038 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00002039 if (dis)
2040 VG_(printf)("\n\t\tret\n");
2041}
2042
sewardj22854b92002-11-30 14:00:47 +00002043/* Predicate used in sanity checks elsewhere - returns true if any
2044 jump-site is an actual chained jump */
2045Bool VG_(is_chained_jumpsite)(Addr a)
2046{
2047 UChar *cp = (UChar *)a;
2048
2049 return (*cp == 0xE9); /* 0xE9 -- jmp */
2050}
2051
sewardj83f11862002-12-01 02:07:08 +00002052static
2053Bool is_fresh_jumpsite(UChar *cp)
2054{
2055 return
2056 cp[0] == 0x0F && /* UD2 */
2057 cp[1] == 0x0B &&
2058 cp[2] == 0x0F && /* UD2 */
2059 cp[3] == 0x0B &&
2060 cp[4] == 0x90; /* NOP */
2061}
2062
sewardj22854b92002-11-30 14:00:47 +00002063/* Predicate used in sanity checks elsewhere - returns true if all
2064 jump-sites are calls to VG_(patch_me) */
2065Bool VG_(is_unchained_jumpsite)(Addr a)
2066{
2067 UChar *cp = (UChar *)a;
2068 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2069 Int idelta;
2070
2071 if (*cp++ != 0xE8) /* 0xE8 == call */
2072 return False;
2073
2074 idelta = (*cp++) << 0;
2075 idelta |= (*cp++) << 8;
2076 idelta |= (*cp++) << 16;
2077 idelta |= (*cp++) << 24;
2078
2079 return idelta == delta;
2080}
2081
2082/* Return target address for a direct jmp */
2083Addr VG_(get_jmp_dest)(Addr a)
2084{
2085 Int delta;
2086 UChar *cp = (UChar *)a;
2087
2088 if (*cp++ != 0xE9) /* 0xE9 == jmp */
2089 return 0;
2090
2091 delta = (*cp++) << 0;
2092 delta |= (*cp++) << 8;
2093 delta |= (*cp++) << 16;
2094 delta |= (*cp++) << 24;
2095
2096 return a + VG_PATCHME_JMPSZ + delta;
2097}
2098
2099/* unchain a BB by generating a call to VG_(patch_me) */
2100void VG_(unchain_jumpsite)(Addr a)
2101{
2102 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2103 UChar *cp = (UChar *)a;
2104
2105 if (VG_(is_unchained_jumpsite)(a))
2106 return; /* don't write unnecessarily */
2107
sewardj83f11862002-12-01 02:07:08 +00002108 if (!is_fresh_jumpsite(cp))
2109 VG_(bb_dechain_count)++; /* update stats */
2110
sewardj22854b92002-11-30 14:00:47 +00002111 *cp++ = 0xE8; /* call */
2112 *cp++ = (delta >> 0) & 0xff;
2113 *cp++ = (delta >> 8) & 0xff;
2114 *cp++ = (delta >> 16) & 0xff;
2115 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002116}
2117
2118/* This doesn't actually generate a call to VG_(patch_me), but
2119 reserves enough space in the instruction stream for it to happen
2120 and records the offset into the jump table. This is because call
2121 is a relative jump, and so will be affected when this code gets
2122 moved about. The translation table will "unchain" this basic block
2123 on insertion (with VG_(unchain_BB)()), and thereby generate a
2124 proper call instruction. */
2125static void emit_call_patchme( void )
2126{
2127 vg_assert(VG_PATCHME_CALLSZ == 5);
2128
sewardjfa492d42002-12-08 18:20:01 +00002129 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002130 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002131
2132 if (jumpidx >= VG_MAX_JUMPS) {
2133 /* If there too many jumps in this basic block, fall back to
2134 dispatch loop. We still need to keep it the same size as the
2135 call sequence. */
2136 VG_(emitB) ( 0xC3 ); /* ret */
fitzhardinge98abfc72003-12-16 02:05:15 +00002137 VG_(emitB) ( 0x8d ); /* 4 byte nop (lea 0x0(%esi,1),%esi) */
2138 VG_(emitB) ( 0x74 );
2139 VG_(emitB) ( 0x26 );
2140 VG_(emitB) ( 0x00 );
sewardj22854b92002-11-30 14:00:47 +00002141
2142 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002143 VG_(printf)("\n\t\tret; nop4\n");
sewardj22854b92002-11-30 14:00:47 +00002144
2145 if (0 && VG_(clo_verbosity))
2146 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2147 } else {
2148 jumps[jumpidx++] = emitted_code_used;
2149
2150 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2151 VG_(emitB) ( 0x0B );
2152 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2153 VG_(emitB) ( 0x0B );
2154 VG_(emitB) ( 0x90 ); /* NOP */
2155
2156 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002157 VG_(printf)("\n\t\tud2; ud2; nop /* call VG_(patchme) */\n");
sewardj22854b92002-11-30 14:00:47 +00002158 }
2159}
2160
njn25e49d8e72002-09-23 09:36:25 +00002161void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002162{
sewardjf0f12aa2002-12-28 00:04:08 +00002163 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002164 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002165 if (dis)
2166 VG_(printf)("\n\t\tpushal\n");
2167}
2168
njn25e49d8e72002-09-23 09:36:25 +00002169void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002170{
sewardjf0f12aa2002-12-28 00:04:08 +00002171 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002172 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002173 if (dis)
2174 VG_(printf)("\n\t\tpopal\n");
2175}
2176
2177static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2178{
sewardjf0f12aa2002-12-28 00:04:08 +00002179 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002180 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2181 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002182 if (dis)
2183 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2184 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2185}
2186
2187static void emit_lea_sib_reg ( UInt lit, Int scale,
2188 Int regbase, Int regindex, Int reg )
2189{
sewardjf0f12aa2002-12-28 00:04:08 +00002190 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002191 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002192 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2193 if (dis)
2194 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2195 lit, nameIReg(4,regbase),
2196 nameIReg(4,regindex), scale,
2197 nameIReg(4,reg) );
2198}
2199
njn25e49d8e72002-09-23 09:36:25 +00002200void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002201{
sewardjf0f12aa2002-12-28 00:04:08 +00002202 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002203 VG_(emitB) ( 0x0F );
2204 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002205 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2206 if (dis)
2207 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2208}
2209
2210/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002211/*--- Helper offset -> addr translation ---*/
2212/*----------------------------------------------------*/
2213
2214/* Finds the baseBlock offset of a skin-specified helper.
2215 * Searches through compacts first, then non-compacts. */
2216Int VG_(helper_offset)(Addr a)
2217{
sewardj05bcdcb2003-05-18 10:05:38 +00002218 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002219 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002220
2221 for (i = 0; i < VG_(n_compact_helpers); i++)
2222 if (VG_(compact_helper_addrs)[i] == a)
2223 return VG_(compact_helper_offsets)[i];
2224 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2225 if (VG_(noncompact_helper_addrs)[i] == a)
2226 return VG_(noncompact_helper_offsets)[i];
2227
2228 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002229 VG_(get_fnname) ( a, buf, 100 );
2230
njn25e49d8e72002-09-23 09:36:25 +00002231 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002232 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2233 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002234
2235 VG_(printf)(" compact helpers: ");
2236 for (i = 0; i < VG_(n_compact_helpers); i++)
2237 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2238
2239 VG_(printf)("\n non-compact helpers: ");
2240 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2241 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2242
2243 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002244 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002245}
2246
2247/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002248/*--- Instruction synthesisers ---*/
2249/*----------------------------------------------------*/
2250
2251static Condcode invertCondition ( Condcode cond )
2252{
2253 return (Condcode)(1 ^ (UInt)cond);
2254}
2255
2256
2257/* Synthesise a call to *baseBlock[offset], ie,
2258 call * (4 x offset)(%ebp).
2259*/
sewardjfa492d42002-12-08 18:20:01 +00002260void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002261 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002262{
2263 vg_assert(word_offset >= 0);
2264 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002265 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002266 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002267 }
sewardjf0f12aa2002-12-28 00:04:08 +00002268 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002269}
2270
njn25e49d8e72002-09-23 09:36:25 +00002271static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002272{
njn25e49d8e72002-09-23 09:36:25 +00002273 if (src != dst) {
2274 VG_(emit_movv_reg_reg) ( 4, src, dst );
2275 ccall_arg_setup_instrs++;
2276 }
njn6431be72002-07-28 09:53:34 +00002277}
njn25e49d8e72002-09-23 09:36:25 +00002278
2279/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2280static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2281{
2282 if (RealReg == tag) {
2283 maybe_emit_movl_reg_reg ( litOrReg, reg );
2284 } else if (Literal == tag) {
2285 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2286 ccall_arg_setup_instrs++;
2287 }
2288 else
njne427a662002-10-02 11:08:25 +00002289 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002290}
2291
2292static
2293void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2294{
2295 if (R_EAX == reg1) {
2296 VG_(emit_swapl_reg_EAX) ( reg2 );
2297 } else if (R_EAX == reg2) {
2298 VG_(emit_swapl_reg_EAX) ( reg1 );
2299 } else {
2300 emit_swapl_reg_reg ( reg1, reg2 );
2301 }
2302 ccall_arg_setup_instrs++;
2303}
2304
2305static
2306void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2307{
2308 if (dst1 != src2) {
2309 maybe_emit_movl_reg_reg ( src1, dst1 );
2310 maybe_emit_movl_reg_reg ( src2, dst2 );
2311
2312 } else if (dst2 != src1) {
2313 maybe_emit_movl_reg_reg ( src2, dst2 );
2314 maybe_emit_movl_reg_reg ( src1, dst1 );
2315
2316 } else {
2317 /* swap to break cycle */
2318 emit_swapl_arg_regs ( dst1, dst2 );
2319 }
2320}
2321
2322static
2323void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2324 UInt dst1, UInt dst2, UInt dst3)
2325{
2326 if (dst1 != src2 && dst1 != src3) {
2327 maybe_emit_movl_reg_reg ( src1, dst1 );
2328 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2329
2330 } else if (dst2 != src1 && dst2 != src3) {
2331 maybe_emit_movl_reg_reg ( src2, dst2 );
2332 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2333
2334 } else if (dst3 != src1 && dst3 != src2) {
2335 maybe_emit_movl_reg_reg ( src3, dst3 );
2336 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2337
2338 } else {
2339 /* break cycle */
2340 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2341 emit_swapl_arg_regs ( dst1, dst2 );
2342 emit_swapl_arg_regs ( dst1, dst3 );
2343
2344 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2345 emit_swapl_arg_regs ( dst1, dst3 );
2346 emit_swapl_arg_regs ( dst1, dst2 );
2347
2348 } else {
njne427a662002-10-02 11:08:25 +00002349 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002350 }
2351 }
2352}
2353
2354static
2355void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2356 UInt src1, UInt src2,
2357 UInt dst1, UInt dst2)
2358{
2359 /* If either are lits, order doesn't matter */
2360 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2361 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2362 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2363
2364 } else {
2365 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2366 }
2367}
2368
2369static
2370void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2371 UInt src1, UInt src2, UInt src3,
2372 UInt dst1, UInt dst2, UInt dst3)
2373{
2374 // SSS: fix this eventually -- make STOREV use two RealRegs?
2375 /* Not supporting literals for 3-arg C functions -- they're only used
2376 by STOREV which has 2 args */
2377 vg_assert(RealReg == tagv[src1] &&
2378 RealReg == tagv[src2] &&
2379 RealReg == tagv[src3]);
2380 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2381 dst1, dst2, dst3 );
2382}
2383
2384/* Synthesise a call to a C function `fn' (which must be registered in
2385 baseBlock) doing all the reg saving and arg handling work.
2386
2387 WARNING: a UInstr should *not* be translated with synth_ccall followed
2388 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2389 such behaviour and everything will fall over.
2390 */
2391void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2392 Tag tagv[], Int ret_reg,
2393 RRegSet regs_live_before, RRegSet regs_live_after )
2394{
2395 Int i;
2396 Int stack_used = 0;
2397 Bool preserve_eax, preserve_ecx, preserve_edx;
2398
2399 vg_assert(0 <= regparms_n && regparms_n <= 3);
2400
2401 ccalls++;
2402
2403 /* If %e[acd]x is live before and after the C call, save/restore it.
2404 Unless the return values clobbers the reg; in this case we must not
2405 save/restore the reg, because the restore would clobber the return
2406 value. (Before and after the UInstr really constitute separate live
2407 ranges, but you miss this if you don't consider what happens during
2408 the UInstr.) */
2409# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002410 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2411 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002412 ret_reg != realReg)
2413
2414 preserve_eax = PRESERVE_REG(R_EAX);
2415 preserve_ecx = PRESERVE_REG(R_ECX);
2416 preserve_edx = PRESERVE_REG(R_EDX);
2417
2418# undef PRESERVE_REG
2419
2420 /* Save caller-save regs as required */
2421 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2422 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2423 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2424
2425 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2426 is the number of args passed in regs (maximum 3 for GCC on x86). */
2427
2428 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002429
njn25e49d8e72002-09-23 09:36:25 +00002430 /* First push stack args (RealRegs or Literals) in reverse order. */
2431 for (i = argc-1; i >= regparms_n; i--) {
2432 switch (tagv[i]) {
2433 case RealReg:
2434 VG_(emit_pushv_reg) ( 4, argv[i] );
2435 break;
2436 case Literal:
2437 /* Use short form of pushl if possible. */
2438 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2439 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2440 else
2441 VG_(emit_pushl_lit32)( argv[i] );
2442 break;
2443 default:
2444 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002445 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002446 }
2447 stack_used += 4;
2448 ccall_arg_setup_instrs++;
2449 }
njn6431be72002-07-28 09:53:34 +00002450
njn25e49d8e72002-09-23 09:36:25 +00002451 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2452 If moving values between registers, be careful not to clobber any on
2453 the way. Happily we can use xchgl to swap registers.
2454 */
2455 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002456
njn25e49d8e72002-09-23 09:36:25 +00002457 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2458 case 3:
2459 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2460 R_EAX, R_EDX, R_ECX );
2461 break;
njn6431be72002-07-28 09:53:34 +00002462
njn25e49d8e72002-09-23 09:36:25 +00002463 /* Less-tricky. Args passed in %eax and %edx. */
2464 case 2:
2465 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2466 break;
2467
2468 /* Easy. Just move arg1 into %eax (if not already in there). */
2469 case 1:
2470 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2471 break;
2472
2473 case 0:
2474 break;
2475
2476 default:
njne427a662002-10-02 11:08:25 +00002477 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002478 }
2479
sewardjfa492d42002-12-08 18:20:01 +00002480 /* Call the function - may trash all flags */
2481 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002482
2483 /* Clear any args from stack */
2484 if (0 != stack_used) {
2485 VG_(emit_add_lit_to_esp) ( stack_used );
2486 ccall_stack_clears++;
2487 }
2488
2489 /* Move return value into ret_reg if necessary and not already there */
2490 if (INVALID_REALREG != ret_reg) {
2491 ccall_retvals++;
2492 if (R_EAX != ret_reg) {
2493 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2494 ccall_retval_movs++;
2495 }
2496 }
2497
2498 /* Restore live caller-save regs as required */
2499 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2500 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2501 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002502}
sewardjde4a1d02002-03-22 01:27:54 +00002503
sewardj2e93c502002-04-12 11:12:52 +00002504static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002505{
sewardj2e93c502002-04-12 11:12:52 +00002506 switch (jmpkind) {
2507 case JmpBoring:
2508 break;
sewardj2e93c502002-04-12 11:12:52 +00002509 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002510 break;
2511 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002512 break;
2513 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002514 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002515 break;
2516 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002517 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002518 break;
2519 default:
njne427a662002-10-02 11:08:25 +00002520 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002521 }
2522}
2523
2524/* Jump to the next translation, by loading its original addr into
2525 %eax and returning to the scheduler. Signal special requirements
2526 by loading a special value into %ebp first.
2527*/
2528static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2529{
sewardjfa492d42002-12-08 18:20:01 +00002530 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002531 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002532 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002533 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002534 emit_ret();
2535}
2536
sewardj22854b92002-11-30 14:00:47 +00002537static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002538
2539/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002540static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002541{
sewardjfa492d42002-12-08 18:20:01 +00002542 maybe_emit_put_eflags(); /* save flags here */
2543
njn25e49d8e72002-09-23 09:36:25 +00002544 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002545
2546 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2547 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2548 emit_call_patchme();
2549 } else {
2550 load_ebp_from_JmpKind ( jmpkind );
2551 emit_ret();
2552 }
sewardjde4a1d02002-03-22 01:27:54 +00002553}
2554
2555
sewardj2370f3b2002-11-30 15:01:01 +00002556static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002557static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002558 Opcode opcode, Int size,
2559 UInt lit, Int reg );
2560
sewardjfa492d42002-12-08 18:20:01 +00002561static void synth_jcond_lit ( Condcode cond,
2562 Addr addr,
2563 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002564{
sewardj2370f3b2002-11-30 15:01:01 +00002565 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002566 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002567 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002568
sewardja2113f92002-12-12 23:42:48 +00002569 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002570 VG_(init_target)(&tgt2);
2571 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002572
sewardjfa492d42002-12-08 18:20:01 +00002573 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2574 if need be */
2575 maybe_emit_put_eflags();
2576 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2577
2578 if (eflags_state == UPD_Both) {
2579 /* The flags are already set up, so we just use them as is. */
2580 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002581 cond = invertCondition(cond);
2582 } else {
sewardj75f04932002-12-12 23:13:21 +00002583 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002584
2585 /* The simd state contains the most recent version, so we emit a
2586 sequence to calculate the relevant condition directly out of
2587 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2588 copying them back to the real flags via popf. Notice that
2589 some of these sequences trash %eax, but that should be free
2590 now since this is the end of a bb and therefore all regs are
2591 dead. */
2592 simd = False;
2593
2594 switch (cond) {
2595
sewardjbb6c1182002-12-12 23:54:47 +00002596 case CondLE: /* Z || S != O -> S || !P */
2597 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002598 vg_assert(eax_trashable);
2599
2600 VG_(emit_movv_offregmem_reg)
2601 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2602 /* eax == %EFLAGS */
2603
sewardjbb6c1182002-12-12 23:54:47 +00002604 VG_(emit_nonshiftopv_lit_reg)
2605 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2606 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002607
sewardjbb6c1182002-12-12 23:54:47 +00002608 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2609 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002610
sewardj09736622002-12-28 00:19:00 +00002611 /* actually set the real cpu flags, since ROR changes
2612 neither P nor Z */
2613 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2614
sewardjbb6c1182002-12-12 23:54:47 +00002615 if (cond == CondLE) {
2616 /* test Z */
2617 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2618 /* test OF != SF */
2619 cond = CondP;
2620 } else {
2621 /* test Z */
2622 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2623 /* test OF == SF */
2624 cond = CondNP;
2625 }
sewardj2370f3b2002-11-30 15:01:01 +00002626 break;
2627
sewardjfa492d42002-12-08 18:20:01 +00002628 case CondL:
2629 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002630 vg_assert(eax_trashable);
2631
2632 VG_(emit_movv_offregmem_reg)
2633 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2634 /* eax == %EFLAGS */
2635
sewardj75f04932002-12-12 23:13:21 +00002636 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2637 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002638
sewardj75f04932002-12-12 23:13:21 +00002639 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2640 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002641
sewardj09736622002-12-28 00:19:00 +00002642 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002643 if (cond == CondL) cond = CondP; else cond = CondNP;
2644 break;
sewardjfa492d42002-12-08 18:20:01 +00002645
2646 case CondB:
2647 case CondNB:
2648 mask = EFlagC; goto simple; /* C=1 */
2649
2650 case CondZ:
2651 case CondNZ:
2652 mask = EFlagZ; goto simple; /* Z=1 */
2653
2654 case CondBE:
2655 case CondNBE:
2656 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2657
2658 case CondS:
2659 case CondNS:
2660 mask = EFlagS; goto simple; /* S=1 */
2661
2662 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002663 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002664 mask = EFlagP; goto simple; /* P=1 */
2665
sewardj39542072002-12-09 22:44:00 +00002666 case CondO:
2667 case CondNO:
2668 mask = EFlagO; goto simple; /* O=1 */
2669
sewardjfa492d42002-12-08 18:20:01 +00002670 default:
2671 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002672 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002673 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2674
2675 simple:
2676 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002677 if ((mask & 0xff) == mask) {
2678 VG_(emitB) ( 0xF6 ); /* Grp3 */
2679 VG_(emit_amode_offregmem_reg)(
2680 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2681 VG_(emitB) (mask);
2682 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002683 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002684 mask, VGOFF_(m_eflags) * 4);
2685 } else {
sewardjfa492d42002-12-08 18:20:01 +00002686 /* all cond codes are in lower 16 bits */
2687 vg_assert((mask & 0xffff) == mask);
2688
2689 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002690 VG_(emitB) ( 0xF7 );
2691 VG_(emit_amode_offregmem_reg)(
2692 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002693 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002694 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002695 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002696 mask, VGOFF_(m_eflags) * 4);
2697 }
2698
sewardj75f04932002-12-12 23:13:21 +00002699 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002700 break;
2701 }
2702 }
2703
sewardja2113f92002-12-12 23:42:48 +00002704 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002705
2706 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002707 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002708
2709 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002710 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002711}
2712
2713
sewardj2370f3b2002-11-30 15:01:01 +00002714
sewardjde4a1d02002-03-22 01:27:54 +00002715static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2716{
sewardja2113f92002-12-12 23:42:48 +00002717 Int tgt;
2718
2719 VG_(init_target)(&tgt);
2720
sewardjfa492d42002-12-08 18:20:01 +00002721 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002722
2723 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002724 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002725
2726 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002727}
2728
2729
2730static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2731{
2732 /* Load the zero-extended literal into reg, at size l,
2733 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002734 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002735}
2736
2737
2738static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2739{
fitzhardinge98abfc72003-12-16 02:05:15 +00002740 switch (size & ~DO_BOUNDSCHECK) {
2741 case 4: emit_movv_regmem_reg ( size, reg1, reg2 ); break;
2742 case 2: VG_(emit_movzwl_regmem_reg) ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
2743 case 1: emit_movzbl_regmem_reg ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002744 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002745 }
2746}
2747
2748
2749static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2750{
fitzhardinge98abfc72003-12-16 02:05:15 +00002751 switch (size & ~DO_BOUNDSCHECK) {
njn25e49d8e72002-09-23 09:36:25 +00002752 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
fitzhardinge98abfc72003-12-16 02:05:15 +00002753 case 2: VG_(emit_movzwl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
2754 case 1: VG_(emit_movzbl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002755 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002756 }
2757}
2758
2759
2760static void synth_mov_reg_offregmem ( Int size, Int reg,
2761 Int off, Int areg )
2762{
2763 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002764 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2765 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002766 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002767 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002768 }
2769 else {
njn25e49d8e72002-09-23 09:36:25 +00002770 VG_(emit_swapl_reg_EAX) ( reg );
2771 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2772 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002773 }
2774 break;
njne427a662002-10-02 11:08:25 +00002775 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002776 }
2777}
2778
2779
2780static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2781{
2782 Int s1;
fitzhardinge98abfc72003-12-16 02:05:15 +00002783 switch (size & ~DO_BOUNDSCHECK) {
2784 case 4:
2785 case 2: emit_movv_reg_regmem ( size, reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002786 case 1: if (reg1 < 4) {
fitzhardinge98abfc72003-12-16 02:05:15 +00002787 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002788 }
2789 else {
2790 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2791 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2792 emit_swapl_reg_reg ( s1, reg1 );
fitzhardinge98abfc72003-12-16 02:05:15 +00002793 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, s1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002794 emit_swapl_reg_reg ( s1, reg1 );
2795 }
2796 break;
njne427a662002-10-02 11:08:25 +00002797 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002798 }
2799}
2800
2801
sewardjf0f12aa2002-12-28 00:04:08 +00002802static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002803 Opcode opcode, Int size,
2804 Int reg )
2805{
2806 /* NB! opcode is a uinstr opcode, not an x86 one! */
2807 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002808 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002809 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002810 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002811 break;
2812 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002813 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002814 } else {
njn25e49d8e72002-09-23 09:36:25 +00002815 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002816 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002817 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002818 }
2819 break;
njne427a662002-10-02 11:08:25 +00002820 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002821 }
2822}
2823
2824
2825
sewardjf0f12aa2002-12-28 00:04:08 +00002826static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002827 Opcode opcode, Int size,
2828 Int reg1, Int reg2 )
2829{
2830 /* NB! opcode is a uinstr opcode, not an x86 one! */
2831 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002832 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002833 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002834 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002835 break;
2836 case 1: { /* Horrible ... */
2837 Int s1, s2;
2838 /* Choose s1 and s2 to be x86 regs which we can talk about the
2839 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2840 sure s1 != s2 and that neither of them equal either reg1 or
2841 reg2. Then use them as temporaries to make things work. */
2842 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002843 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002844 break;
2845 }
2846 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2847 if (reg1 >= 4 && reg2 < 4) {
2848 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002849 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002850 emit_swapl_reg_reg ( reg1, s1 );
2851 break;
2852 }
2853 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2854 if (reg1 < 4 && reg2 >= 4) {
2855 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002856 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002857 emit_swapl_reg_reg ( reg2, s2 );
2858 break;
2859 }
2860 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2861 emit_swapl_reg_reg ( reg1, s1 );
2862 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002863 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002864 emit_swapl_reg_reg ( reg1, s1 );
2865 emit_swapl_reg_reg ( reg2, s2 );
2866 break;
2867 }
2868 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2869 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002870 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002871 emit_swapl_reg_reg ( reg1, s1 );
2872 break;
2873 }
njne427a662002-10-02 11:08:25 +00002874 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002875 }
njne427a662002-10-02 11:08:25 +00002876 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002877 }
2878}
2879
sewardja2c5a732002-12-15 03:10:42 +00002880#if 0
2881/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002882static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002883 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002884 Opcode opcode, Int size,
2885 Int off, Int areg, Int reg )
2886{
2887 switch (size) {
2888 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002889 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002890 break;
2891 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002892 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002893 break;
2894 case 1:
2895 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002896 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002897 } else {
2898 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002899 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002900 VG_(emit_swapl_reg_EAX) ( reg );
2901 }
2902 break;
2903 default:
2904 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2905 }
2906}
sewardja2c5a732002-12-15 03:10:42 +00002907#endif
sewardjfa492d42002-12-08 18:20:01 +00002908
sewardjde4a1d02002-03-22 01:27:54 +00002909static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002910 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002911 Opcode opcode, Int size,
2912 Int off, Int areg, Int reg )
2913{
2914 switch (size) {
2915 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002916 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002917 break;
2918 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002919 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002920 break;
2921 case 1:
2922 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002923 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002924 } else {
njn25e49d8e72002-09-23 09:36:25 +00002925 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002926 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002927 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002928 }
2929 break;
2930 default:
njne427a662002-10-02 11:08:25 +00002931 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002932 }
2933}
2934
2935
sewardjf0f12aa2002-12-28 00:04:08 +00002936static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002937 Opcode opcode, Int size,
2938 UInt lit, Int reg )
2939{
2940 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002941 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002942 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002943 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002944 break;
2945 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002946 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002947 } else {
njn25e49d8e72002-09-23 09:36:25 +00002948 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002949 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002950 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002951 }
2952 break;
njne427a662002-10-02 11:08:25 +00002953 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002954 }
2955}
2956
sewardjf0f12aa2002-12-28 00:04:08 +00002957static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002958 Opcode opcode, Int size,
2959 UInt lit, Int off, Int regmem )
2960{
2961 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002962 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002963 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002964 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002965 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002966 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002967 break;
2968 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2969 }
2970}
2971
sewardjde4a1d02002-03-22 01:27:54 +00002972
jsgf5efa4fd2003-10-14 21:49:11 +00002973static void synth_mul_reg_reg ( Bool upd_cc,
2974 Opcode opcode, Int size,
2975 Int reg1, Int reg2 )
2976{
2977 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2978
2979 switch (size) {
2980 case 2:
2981 VG_(emitB)(0x66);
2982 /* FALLTHROUGH */
2983 case 4:
2984 VG_(emitB)(0x0F);
2985 VG_(emitB)(0xAF);
2986 VG_(emit_amode_ereg_greg)(reg1, reg2);
2987 break;
2988
2989 case 1:
2990 VG_(core_panic)("can't do byte mul");
2991 break;
2992 }
2993 if (dis)
2994 VG_(printf)("\n\t\timul%c\t%s, %s\n",
2995 nameISize(size),
2996 nameIReg(size, reg1),
2997 nameIReg(size, reg2));
2998}
2999
3000static void synth_mul_lit_reg ( Bool upd_cc,
3001 Opcode opcode, Int size,
3002 UInt lit, Int reg )
3003{
3004 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3005
3006 switch (size) {
3007 case 2:
3008 VG_(emitB)(0x66);
3009 /* FALLTHROUGH */
3010 case 4:
3011 VG_(emitB)(0x69);
3012 VG_(emit_amode_ereg_greg)(reg, 0);
3013 if (size == 2)
3014 VG_(emitW)(lit);
3015 else
3016 VG_(emitL)(lit);
3017 break;
3018
3019 case 1:
3020 VG_(core_panic)("can't do byte mul");
3021 break;
3022 }
3023 if (dis)
3024 VG_(printf)("\n\t\timul%c\t%d, %s\n",
3025 nameISize(size),
3026 lit,
3027 nameIReg(size, reg));
3028}
3029
3030static void synth_mul_offregmem_reg (
3031 Bool upd_cc,
3032 Opcode opcode, Int size,
3033 Int off, Int areg, Int reg )
3034{
3035 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3036
3037 switch(size) {
3038 case 2:
3039 VG_(emitB)(0x66);
3040 /* FALLTHROUGH */
3041 case 4:
3042 VG_(emitB)(0x0F);
3043 VG_(emitB)(0xAF);
3044 VG_(emit_amode_offregmem_reg)(off, areg, reg);
3045 break;
3046
3047 case 1:
3048 VG_(core_panic)("can't do byte mul");
3049 }
3050
3051 if (dis)
3052 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
3053 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
3054
3055}
3056
3057
sewardjde4a1d02002-03-22 01:27:54 +00003058static void synth_push_reg ( Int size, Int reg )
3059{
3060 switch (size) {
3061 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003062 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003063 break;
3064 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003065 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003066 break;
3067 /* Pray that we don't have to generate this really cruddy bit of
3068 code very often. Could do better, but can I be bothered? */
3069 case 1:
3070 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003071 VG_(emit_add_lit_to_esp)(-1);
3072 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003073 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00003074 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003075 break;
3076 default:
njne427a662002-10-02 11:08:25 +00003077 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003078 }
3079}
3080
3081
3082static void synth_pop_reg ( Int size, Int reg )
3083{
3084 switch (size) {
3085 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003086 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003087 break;
3088 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003089 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003090 break;
3091 case 1:
3092 /* Same comment as above applies. */
3093 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003094 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003095 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003096 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3097 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003098 break;
njne427a662002-10-02 11:08:25 +00003099 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003100 }
3101}
3102
3103
sewardjf0f12aa2002-12-28 00:04:08 +00003104static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003105 Opcode opcode, Int size,
3106 Int regs, Int regd )
3107{
3108 synth_push_reg ( size, regd );
3109 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003110 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003111 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3112 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3113 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003114 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003115 }
sewardjde4a1d02002-03-22 01:27:54 +00003116 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3117 synth_pop_reg ( size, regd );
3118}
3119
3120
sewardjf0f12aa2002-12-28 00:04:08 +00003121static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003122 Opcode opcode, Int size,
3123 UInt lit, Int reg )
3124{
3125 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003126 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003127 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003128 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003129 break;
3130 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003131 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003132 } else {
njn25e49d8e72002-09-23 09:36:25 +00003133 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003134 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003135 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003136 }
3137 break;
njne427a662002-10-02 11:08:25 +00003138 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003139 }
3140}
3141
3142
sewardjf0f12aa2002-12-28 00:04:08 +00003143static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003144{
sewardjde4a1d02002-03-22 01:27:54 +00003145 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003146 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003147 } else {
njn25e49d8e72002-09-23 09:36:25 +00003148 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003149 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003150 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003151 }
3152}
3153
3154
sewardj3d7c9c82003-03-26 21:08:13 +00003155static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3156 UChar first_byte,
3157 UChar second_byte,
3158 Int ireg )
3159{
3160 emit_MMX2_regmem ( uses_flags, sets_flags,
3161 first_byte, second_byte, ireg );
3162}
3163
3164
sewardjca860012003-03-27 23:52:58 +00003165static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3166 UChar first_byte,
3167 UChar second_byte,
3168 Int ireg )
3169{
3170 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3171 first_byte, second_byte, ireg );
3172}
3173
sewardjd1c9e432003-04-04 20:40:34 +00003174static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3175 UChar first_byte,
3176 UChar second_byte,
3177 Int ireg )
3178{
3179 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3180 first_byte, second_byte, ireg );
3181}
3182
sewardj3d7c9c82003-03-26 21:08:13 +00003183static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3184 UChar first_byte,
3185 UChar second_byte )
3186{
3187 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3188}
3189
3190
sewardjca860012003-03-27 23:52:58 +00003191static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3192 UChar first_byte,
3193 UChar second_byte,
3194 UChar third_byte )
3195{
3196 emit_MMX3_no_mem ( uses_flags, sets_flags,
3197 first_byte, second_byte, third_byte );
3198}
3199
3200
sewardj3d7c9c82003-03-26 21:08:13 +00003201static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3202 UChar first_byte )
3203{
3204 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3205}
3206
3207
sewardjfa492d42002-12-08 18:20:01 +00003208static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3209 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003210 UChar second_byte_masked,
3211 Int reg )
3212{
sewardj3d7c9c82003-03-26 21:08:13 +00003213 emit_fpu_regmem ( uses_flags, sets_flags,
3214 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003215}
3216
3217
sewardjfa492d42002-12-08 18:20:01 +00003218static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3219 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003220 UChar second_byte )
3221{
sewardjfa492d42002-12-08 18:20:01 +00003222 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003223}
3224
3225
3226static void synth_movl_reg_reg ( Int src, Int dst )
3227{
3228 emit_movl_reg_reg ( src, dst );
3229}
3230
3231static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3232{
sewardja2113f92002-12-12 23:42:48 +00003233 Int tgt;
3234
3235 VG_(init_target)(&tgt);
3236
3237 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003238 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003239
3240 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003241}
3242
3243
sewardjde4a1d02002-03-22 01:27:54 +00003244/*----------------------------------------------------*/
3245/*--- Top level of the uinstr -> x86 translation. ---*/
3246/*----------------------------------------------------*/
3247
3248/* Return the byte offset from %ebp (ie, into baseBlock)
3249 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003250static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3251{
3252 if (tag == SpillNo) {
3253 vg_assert(size == 4);
3254 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3255 return 4 * (value + VGOFF_(spillslots));
3256 }
3257 if (tag == ArchReg) {
3258 switch (value) {
3259 case R_EAX: return 4 * VGOFF_(m_eax);
3260 case R_ECX: return 4 * VGOFF_(m_ecx);
3261 case R_EDX: return 4 * VGOFF_(m_edx);
3262 case R_EBX: return 4 * VGOFF_(m_ebx);
3263 case R_ESP:
3264 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3265 else return 4 * VGOFF_(m_esp);
3266 case R_EBP:
3267 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3268 else return 4 * VGOFF_(m_ebp);
3269 case R_ESI:
3270 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3271 else return 4 * VGOFF_(m_esi);
3272 case R_EDI:
3273 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3274 else return 4 * VGOFF_(m_edi);
3275 }
3276 }
njne427a662002-10-02 11:08:25 +00003277 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003278}
3279
sewardjde4a1d02002-03-22 01:27:54 +00003280static Int eflagsOffset ( void )
3281{
3282 return 4 * VGOFF_(m_eflags);
3283}
3284
sewardje1042472002-09-30 12:33:11 +00003285static Int segRegOffset ( UInt archregs )
3286{
3287 switch (archregs) {
3288 case R_CS: return 4 * VGOFF_(m_cs);
3289 case R_SS: return 4 * VGOFF_(m_ss);
3290 case R_DS: return 4 * VGOFF_(m_ds);
3291 case R_ES: return 4 * VGOFF_(m_es);
3292 case R_FS: return 4 * VGOFF_(m_fs);
3293 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003294 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003295 }
3296}
3297
njnf4ce3d32003-02-10 10:17:26 +00003298UInt VG_(get_archreg) ( UInt arch )
3299{
3300 switch (arch) {
3301 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3302 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3303 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3304 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3305 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3306 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3307 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3308 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003309 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003310 }
3311}
3312
3313UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3314{
3315 ThreadState* tst;
3316
3317 vg_assert(VG_(is_valid_tid)(tid));
3318 tst = & VG_(threads)[tid];
3319
3320 switch (arch) {
3321 case R_EAX: return tst->m_eax;
3322 case R_ECX: return tst->m_ecx;
3323 case R_EDX: return tst->m_edx;
3324 case R_EBX: return tst->m_ebx;
3325 case R_ESP: return tst->m_esp;
3326 case R_EBP: return tst->m_ebp;
3327 case R_ESI: return tst->m_esi;
3328 case R_EDI: return tst->m_edi;
3329 default: VG_(core_panic)( "get_thread_archreg");
3330 }
3331}
3332
njnb93d1782003-02-03 12:03:22 +00003333/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003334static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003335{
3336 switch (arch) {
3337 case R_EAX: return VGOFF_(sh_eax);
3338 case R_ECX: return VGOFF_(sh_ecx);
3339 case R_EDX: return VGOFF_(sh_edx);
3340 case R_EBX: return VGOFF_(sh_ebx);
3341 case R_ESP: return VGOFF_(sh_esp);
3342 case R_EBP: return VGOFF_(sh_ebp);
3343 case R_ESI: return VGOFF_(sh_esi);
3344 case R_EDI: return VGOFF_(sh_edi);
3345 default: VG_(core_panic)( "shadow_reg_index");
3346 }
3347}
sewardjde4a1d02002-03-22 01:27:54 +00003348
njn25e49d8e72002-09-23 09:36:25 +00003349/* Return the byte offset from %ebp (ie, into baseBlock)
3350 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003351Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003352{
njnb93d1782003-02-03 12:03:22 +00003353 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003354}
3355
njn4ba5a792002-09-30 10:23:54 +00003356Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003357{
3358 return 4 * VGOFF_(sh_eflags);
3359}
3360
njnb93d1782003-02-03 12:03:22 +00003361/* Accessing shadow arch. registers */
3362UInt VG_(get_shadow_archreg) ( UInt archreg )
3363{
3364 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3365}
3366
3367void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3368{
3369 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3370}
3371
njnd3040452003-05-19 15:04:06 +00003372void VG_(set_shadow_eflags) ( UInt val )
3373{
3374 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3375}
3376
njnf4ce3d32003-02-10 10:17:26 +00003377UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3378{
3379 ThreadState* tst;
3380
3381 vg_assert(VG_(is_valid_tid)(tid));
3382 tst = & VG_(threads)[tid];
3383
3384 switch (archreg) {
3385 case R_EAX: return tst->sh_eax;
3386 case R_ECX: return tst->sh_ecx;
3387 case R_EDX: return tst->sh_edx;
3388 case R_EBX: return tst->sh_ebx;
3389 case R_ESP: return tst->sh_esp;
3390 case R_EBP: return tst->sh_ebp;
3391 case R_ESI: return tst->sh_esi;
3392 case R_EDI: return tst->sh_edi;
3393 default: VG_(core_panic)( "get_thread_shadow_archreg");
3394 }
3395}
3396
3397void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3398{
3399 ThreadState* tst;
3400
3401 vg_assert(VG_(is_valid_tid)(tid));
3402 tst = & VG_(threads)[tid];
3403
3404 switch (archreg) {
3405 case R_EAX: tst->sh_eax = val; break;
3406 case R_ECX: tst->sh_ecx = val; break;
3407 case R_EDX: tst->sh_edx = val; break;
3408 case R_EBX: tst->sh_ebx = val; break;
3409 case R_ESP: tst->sh_esp = val; break;
3410 case R_EBP: tst->sh_ebp = val; break;
3411 case R_ESI: tst->sh_esi = val; break;
3412 case R_EDI: tst->sh_edi = val; break;
3413 default: VG_(core_panic)( "set_thread_shadow_archreg");
3414 }
3415}
3416
njnb93d1782003-02-03 12:03:22 +00003417Addr VG_(shadow_archreg_address) ( UInt archreg )
3418{
3419 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3420}
sewardjde4a1d02002-03-22 01:27:54 +00003421
sewardjde4a1d02002-03-22 01:27:54 +00003422static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3423{
3424 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003425 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3426 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003427 }
3428 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003429 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3430 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003431 }
3432 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003433 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3434 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003435 }
3436 else
njne427a662002-10-02 11:08:25 +00003437 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003438}
3439
3440
sewardjde4a1d02002-03-22 01:27:54 +00003441/*----------------------------------------------------*/
3442/*--- Generate code for a single UInstr. ---*/
3443/*----------------------------------------------------*/
3444
sewardj478335c2002-10-05 02:44:47 +00003445static __inline__
3446Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003447{
3448 return (u->flags_w != FlagsEmpty);
3449}
3450
sewardjfa492d42002-12-08 18:20:01 +00003451static __inline__
3452Bool readFlagUse ( UInstr* u )
3453{
3454 /* If the UInstr writes some flags but not all, then we still need
3455 to consider it as reading flags so that the unchanged values are
3456 passed through properly. (D is special) */
3457 return
3458 (u->flags_r != FlagsEmpty) ||
3459 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3460}
3461
sewardj478335c2002-10-05 02:44:47 +00003462static __inline__
3463Bool anyFlagUse ( UInstr* u )
3464{
sewardjfa492d42002-12-08 18:20:01 +00003465 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003466}
3467
3468
sewardjb91ae7f2003-04-29 23:50:00 +00003469/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3470 the real machine's cpu. If so we need to be very careful not to trash it.
3471 If FPU/SSE state is live and we deem it necessary to copy it back to
3472 the simulated machine's FPU/SSE state, we do so. The final state of
3473 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003474 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003475 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003476*/
sewardjb5ff83e2002-12-01 19:40:49 +00003477static void emitUInstr ( UCodeBlock* cb, Int i,
3478 RRegSet regs_live_before,
3479 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003480 Bool* sselive, /* True<==>FPU/SSE
3481 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003482 Addr* orig_eip, /* previous curr_eip, or zero */
3483 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003484{
njn25e49d8e72002-09-23 09:36:25 +00003485 Int old_emitted_code_used;
3486 UInstr* u = &cb->instrs[i];
3487
sewardjde4a1d02002-03-22 01:27:54 +00003488 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003489 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003490
njn25e49d8e72002-09-23 09:36:25 +00003491 old_emitted_code_used = emitted_code_used;
3492
sewardjde4a1d02002-03-22 01:27:54 +00003493 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003494 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003495
sewardjb5ff83e2002-12-01 19:40:49 +00003496 case INCEIP:
3497 /* Advance %EIP some small amount. */
3498 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003499
sewardjb5ff83e2002-12-01 19:40:49 +00003500 if (*orig_eip == 0 /* we don't know what the old value was */
3501 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3502 /* We have to update all 32 bits of the value. */
3503 VG_(emit_movv_lit_offregmem)(
3504 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3505 } else {
3506 /* Cool! we only need to update lowest 8 bits */
3507 VG_(emit_movb_lit_offregmem)(
3508 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003509 }
njn25e49d8e72002-09-23 09:36:25 +00003510
sewardjb5ff83e2002-12-01 19:40:49 +00003511 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003512 break;
sewardjde4a1d02002-03-22 01:27:54 +00003513
3514 case LEA1: {
3515 vg_assert(u->tag1 == RealReg);
3516 vg_assert(u->tag2 == RealReg);
3517 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3518 break;
3519 }
3520
3521 case LEA2: {
3522 vg_assert(u->tag1 == RealReg);
3523 vg_assert(u->tag2 == RealReg);
3524 vg_assert(u->tag3 == RealReg);
3525 emit_lea_sib_reg ( u->lit32, u->extra4b,
3526 u->val1, u->val2, u->val3 );
3527 break;
3528 }
3529
3530 case WIDEN: {
3531 vg_assert(u->tag1 == RealReg);
3532 if (u->signed_widen) {
3533 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3534 } else {
3535 /* no need to generate any code. */
3536 }
3537 break;
3538 }
3539
sewardjde4a1d02002-03-22 01:27:54 +00003540 case STORE: {
3541 vg_assert(u->tag1 == RealReg);
3542 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003543 synth_mov_reg_memreg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003544 break;
3545 }
3546
3547 case LOAD: {
3548 vg_assert(u->tag1 == RealReg);
3549 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003550 synth_mov_regmem_reg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003551 break;
3552 }
3553
sewardjde4a1d02002-03-22 01:27:54 +00003554 case GET: {
3555 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3556 vg_assert(u->tag2 == RealReg);
3557 synth_mov_offregmem_reg (
3558 u->size,
3559 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3560 R_EBP,
3561 u->val2
3562 );
3563 break;
3564 }
3565
3566 case PUT: {
3567 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3568 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003569 synth_mov_reg_offregmem (
3570 u->size,
3571 u->val1,
3572 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3573 R_EBP
3574 );
sewardjde4a1d02002-03-22 01:27:54 +00003575 break;
3576 }
3577
sewardje1042472002-09-30 12:33:11 +00003578 case GETSEG: {
3579 vg_assert(u->tag1 == ArchRegS);
3580 vg_assert(u->tag2 == RealReg);
3581 vg_assert(u->size == 2);
3582 synth_mov_offregmem_reg (
3583 4,
3584 segRegOffset( u->val1 ),
3585 R_EBP,
3586 u->val2
3587 );
3588 break;
3589 }
3590
3591 case PUTSEG: {
3592 vg_assert(u->tag1 == RealReg);
3593 vg_assert(u->tag2 == ArchRegS);
3594 vg_assert(u->size == 2);
3595 synth_mov_reg_offregmem (
3596 4,
3597 u->val1,
3598 segRegOffset( u->val2 ),
3599 R_EBP
3600 );
3601 break;
3602 }
3603
sewardjde4a1d02002-03-22 01:27:54 +00003604 case GETF: {
3605 vg_assert(u->size == 2 || u->size == 4);
3606 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003607
3608 /* This complexity is because the D(irection) flag is stored
3609 separately from the rest of EFLAGS. */
3610
3611 /* We're only fetching from the Simd state, so make sure it's
3612 up to date. */
3613 maybe_emit_put_eflags();
3614
3615 /* get D in u->val1 (== 1 or -1) */
3616 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3617
3618 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3619 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3620
3621 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3622 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3623 eflagsOffset(), R_EBP);
3624
3625 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3626 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3627 eflagsOffset(), R_EBP);
3628
3629 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3630 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3631 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003632 break;
3633 }
3634
3635 case PUTF: {
3636 vg_assert(u->size == 2 || u->size == 4);
3637 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003638
3639 /* When putting a value into EFLAGS, this generates the
3640 correct value for m_dflag (-1 or 1), and clears the D bit
3641 in EFLAGS. */
3642
3643 /* We're updating the whole flag state, so the old state
3644 doesn't matter; make sure that the new simulated state
3645 will be fetched when needed. */
3646 eflags_state = UPD_Simd;
3647
3648 /* store EFLAGS (with D) */
3649 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3650
3651 /* u->val1 &= EFlagD */
3652 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3653
3654 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3655 synth_unaryop_reg(False, NEG, u->size, u->val1);
3656 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3657 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3658
3659 /* save D */
3660 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3661
3662 /* EFLAGS &= ~EFlagD */
3663 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3664 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003665 break;
3666 }
3667
3668 case MOV: {
3669 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3670 vg_assert(u->tag2 == RealReg);
3671 switch (u->tag1) {
3672 case RealReg: vg_assert(u->size == 4);
3673 if (u->val1 != u->val2)
3674 synth_movl_reg_reg ( u->val1, u->val2 );
3675 break;
3676 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3677 break;
njne427a662002-10-02 11:08:25 +00003678 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003679 }
3680 break;
3681 }
3682
sewardje1042472002-09-30 12:33:11 +00003683 case USESEG: {
3684 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3685 ones. */
sewardjd077f532002-09-30 21:52:50 +00003686 UInt argv[] = { u->val1, u->val2 };
3687 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003688 UInt ret_reg = u->val2;
3689
3690 vg_assert(u->tag1 == RealReg);
3691 vg_assert(u->tag2 == RealReg);
3692 vg_assert(u->size == 0);
3693
sewardjb91ae7f2003-04-29 23:50:00 +00003694 if (*sselive) {
3695 emit_put_sse_state();
3696 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003697 }
3698
sewardje1042472002-09-30 12:33:11 +00003699 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3700 2, /* args */
3701 0, /* regparms_n */
3702 argv, tagv,
3703 ret_reg, regs_live_before, u->regs_live_after );
3704 break;
3705 }
3706
jsgf5efa4fd2003-10-14 21:49:11 +00003707 case MUL: {
3708 vg_assert(u->tag2 == RealReg);
3709
3710 switch(u->tag1) {
3711 case Literal:
3712 synth_mul_lit_reg(anyFlagUse(u),
3713 u->opcode, u->size, u->lit32, u->val2);
3714 break;
3715 case RealReg:
3716 synth_mul_reg_reg(anyFlagUse(u),
3717 u->opcode, u->size, u->val1, u->val2);
3718 break;
3719 case ArchReg:
3720 synth_mul_offregmem_reg(anyFlagUse(u),
3721 u->opcode, u->size,
3722 spillOrArchOffset(u->size, u->tag1, u->val1),
3723 R_EBP, u->val2);
3724 break;
3725
3726 default: VG_(core_panic)("emitUInstr:MUL");
3727 }
3728 break;
3729 }
3730
sewardj478335c2002-10-05 02:44:47 +00003731 case SBB:
3732 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003733 case XOR:
3734 case OR:
3735 case AND:
3736 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003737 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003738 vg_assert(u->tag2 == RealReg);
3739 switch (u->tag1) {
3740 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003741 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003742 u->opcode, u->size, u->lit32, u->val2 );
3743 break;
3744 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003745 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003746 u->opcode, u->size, u->val1, u->val2 );
3747 break;
3748 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003749 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003750 u->opcode, u->size,
3751 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3752 R_EBP,
3753 u->val2 );
3754 break;
njne427a662002-10-02 11:08:25 +00003755 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003756 }
3757 break;
3758 }
3759
sewardj478335c2002-10-05 02:44:47 +00003760 case RCR:
3761 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003762 case ROR:
3763 case ROL:
3764 case SAR:
3765 case SHR:
3766 case SHL: {
3767 vg_assert(u->tag2 == RealReg);
3768 switch (u->tag1) {
3769 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003770 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003771 u->opcode, u->size, u->lit32, u->val2 );
3772 break;
3773 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003774 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003775 u->opcode, u->size, u->val1, u->val2 );
3776 break;
njne427a662002-10-02 11:08:25 +00003777 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003778 }
3779 break;
3780 }
3781
3782 case INC:
3783 case DEC:
3784 case NEG:
3785 case NOT:
3786 vg_assert(u->tag1 == RealReg);
3787 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003788 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003789 break;
3790
3791 case BSWAP:
3792 vg_assert(u->tag1 == RealReg);
3793 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003794 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003795 emit_bswapl_reg ( u->val1 );
3796 break;
3797
3798 case CMOV:
3799 vg_assert(u->tag1 == RealReg);
3800 vg_assert(u->tag2 == RealReg);
3801 vg_assert(u->cond != CondAlways);
3802 vg_assert(u->size == 4);
3803 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3804 break;
3805
3806 case JMP: {
3807 vg_assert(u->tag2 == NoValue);
3808 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003809 if (*sselive) {
3810 emit_put_sse_state();
3811 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003812 }
sewardjde4a1d02002-03-22 01:27:54 +00003813 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003814 switch (u->tag1) {
3815 case RealReg:
3816 synth_jmp_reg ( u->val1, u->jmpkind );
3817 break;
3818 case Literal:
3819 synth_jmp_lit ( u->lit32, u->jmpkind );
3820 break;
3821 default:
njne427a662002-10-02 11:08:25 +00003822 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003823 break;
sewardjde4a1d02002-03-22 01:27:54 +00003824 }
3825 } else {
sewardj2e93c502002-04-12 11:12:52 +00003826 switch (u->tag1) {
3827 case RealReg:
njne427a662002-10-02 11:08:25 +00003828 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003829 break;
3830 case Literal:
3831 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003832 /* %eax had better not be live since synth_jcond_lit
3833 trashes it in some circumstances. If that turns
3834 out to be a problem we can get synth_jcond_lit to
3835 push/pop it when it is live. */
3836 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3837 u->regs_live_after));
3838 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003839 break;
3840 default:
njne427a662002-10-02 11:08:25 +00003841 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003842 break;
sewardjde4a1d02002-03-22 01:27:54 +00003843 }
3844 }
3845 break;
3846 }
3847
3848 case JIFZ:
3849 vg_assert(u->tag1 == RealReg);
3850 vg_assert(u->tag2 == Literal);
3851 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003852 if (*sselive) {
3853 emit_put_sse_state();
3854 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003855 }
sewardjde4a1d02002-03-22 01:27:54 +00003856 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3857 break;
3858
sewardjde4a1d02002-03-22 01:27:54 +00003859 case PUSH:
3860 vg_assert(u->tag1 == RealReg);
3861 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003862 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003863 break;
3864
3865 case POP:
3866 vg_assert(u->tag1 == RealReg);
3867 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003868 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003869 break;
3870
3871 case CALLM:
3872 vg_assert(u->tag1 == Lit16);
3873 vg_assert(u->tag2 == NoValue);
3874 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003875 if (*sselive) {
3876 emit_put_sse_state();
3877 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003878 }
sewardjfa492d42002-12-08 18:20:01 +00003879 /* Call to a helper which is pretending to be a real CPU
3880 instruction (and therefore operates on Real flags and
3881 registers) */
3882 VG_(synth_call) ( False, u->val1,
3883 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003884 break;
3885
njn25e49d8e72002-09-23 09:36:25 +00003886 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003887 /* If you change this, remember to change USESEG above, since
3888 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003889 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3890 ones. */
3891 UInt argv[] = { u->val1, u->val2, u->val3 };
3892 UInt tagv[] = { RealReg, RealReg, RealReg };
3893 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3894
3895 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3896 else vg_assert(u->tag1 == NoValue);
3897 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3898 else vg_assert(u->tag2 == NoValue);
3899 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3900 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003901 vg_assert(u->size == 0);
3902
sewardjb91ae7f2003-04-29 23:50:00 +00003903 if (*sselive) {
3904 emit_put_sse_state();
3905 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003906 }
njn25e49d8e72002-09-23 09:36:25 +00003907 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3908 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003909 break;
njn25e49d8e72002-09-23 09:36:25 +00003910 }
sewardje1042472002-09-30 12:33:11 +00003911
sewardjde4a1d02002-03-22 01:27:54 +00003912 case CLEAR:
3913 vg_assert(u->tag1 == Lit16);
3914 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003915 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003916 break;
3917
3918 case CC2VAL:
3919 vg_assert(u->tag1 == RealReg);
3920 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003921 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003922 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003923 break;
3924
sewardjde4a1d02002-03-22 01:27:54 +00003925 case FPU_R:
3926 case FPU_W:
3927 vg_assert(u->tag1 == Lit16);
3928 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003929 if (!(*sselive)) {
3930 emit_get_sse_state();
3931 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003932 }
sewardjfa492d42002-12-08 18:20:01 +00003933 synth_fpu_regmem ( u->flags_r, u->flags_w,
3934 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003935 u->val1 & 0xFF,
3936 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003937 break;
3938
3939 case FPU:
3940 vg_assert(u->tag1 == Lit16);
3941 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003942 if (!(*sselive)) {
3943 emit_get_sse_state();
3944 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003945 }
sewardjfa492d42002-12-08 18:20:01 +00003946 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3947 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003948 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003949 break;
3950
sewardj3d7c9c82003-03-26 21:08:13 +00003951 case MMX2_MemWr:
3952 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003953 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003954 vg_assert(u->tag1 == Lit16);
3955 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003956 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003957 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003958 if (!(*sselive)) {
3959 emit_get_sse_state();
3960 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003961 }
3962 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3963 (u->val1 >> 8) & 0xFF,
3964 u->val1 & 0xFF,
3965 u->val2 );
3966 break;
3967
sewardj4fbe6e92003-06-15 21:54:34 +00003968 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00003969 vg_assert(u->tag1 == Lit16);
3970 vg_assert(u->tag2 == RealReg);
3971 vg_assert(u->tag3 == NoValue);
3972 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003973 if (!(*sselive)) {
3974 emit_get_sse_state();
3975 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003976 }
3977 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3978 (u->val1 >> 8) & 0xFF,
3979 u->val1 & 0xFF,
3980 u->val2 );
3981 break;
3982
sewardj4fbe6e92003-06-15 21:54:34 +00003983 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00003984 vg_assert(u->tag1 == Lit16);
3985 vg_assert(u->tag2 == RealReg);
3986 vg_assert(u->tag3 == NoValue);
3987 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003988 if (!(*sselive)) {
3989 emit_get_sse_state();
3990 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003991 }
3992 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3993 (u->val1 >> 8) & 0xFF,
3994 u->val1 & 0xFF,
3995 u->val2 );
3996 break;
3997
sewardj3d7c9c82003-03-26 21:08:13 +00003998 case MMX1:
3999 vg_assert(u->tag1 == Lit16);
4000 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004001 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004002 if (!(*sselive)) {
4003 emit_get_sse_state();
4004 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004005 }
4006 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
4007 u->val1 & 0xFF );
4008 break;
4009
4010 case MMX2:
4011 vg_assert(u->tag1 == Lit16);
4012 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004013 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004014 if (!(*sselive)) {
4015 emit_get_sse_state();
4016 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004017 }
4018 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
4019 (u->val1 >> 8) & 0xFF,
4020 u->val1 & 0xFF );
4021 break;
4022
sewardjca860012003-03-27 23:52:58 +00004023 case MMX3:
4024 vg_assert(u->tag1 == Lit16);
4025 vg_assert(u->tag2 == Lit16);
4026 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004027 if (!(*sselive)) {
4028 emit_get_sse_state();
4029 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004030 }
4031 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
4032 (u->val1 >> 8) & 0xFF,
4033 u->val1 & 0xFF,
4034 u->val2 & 0xFF );
4035 break;
4036
sewardjfebaa3b2003-05-25 01:07:34 +00004037 case SSE2a_MemWr:
4038 case SSE2a_MemRd:
4039 vg_assert(u->size == 4 || u->size == 16);
4040 vg_assert(u->tag1 == Lit16);
4041 vg_assert(u->tag2 == Lit16);
4042 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004043 if (!(*sselive)) {
4044 emit_get_sse_state();
4045 *sselive = True;
4046 }
4047 emit_SSE2a ( u->flags_r, u->flags_w,
4048 (u->val1 >> 8) & 0xFF,
4049 u->val1 & 0xFF,
4050 u->val2 & 0xFF,
4051 u->val3 );
4052 break;
4053
sewardj9dd209f2003-06-18 23:30:52 +00004054 case SSE2a1_MemRd:
4055 vg_assert(u->size == 4 || u->size == 16);
4056 vg_assert(u->tag1 == Lit16);
4057 vg_assert(u->tag2 == Lit16);
4058 vg_assert(u->tag3 == RealReg);
4059 vg_assert(!anyFlagUse(u));
4060 if (!(*sselive)) {
4061 emit_get_sse_state();
4062 *sselive = True;
4063 }
4064 emit_SSE2a1 ( u->flags_r, u->flags_w,
4065 (u->val1 >> 8) & 0xFF,
4066 u->val1 & 0xFF,
4067 (u->val2 >> 8) & 0xFF,
4068 u->val2 & 0xFF,
4069 u->val3 );
4070 break;
4071
sewardjfebaa3b2003-05-25 01:07:34 +00004072 case SSE3a_MemWr:
4073 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00004074 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00004075 vg_assert(u->tag1 == Lit16);
4076 vg_assert(u->tag2 == Lit16);
4077 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004078 if (!(*sselive)) {
4079 emit_get_sse_state();
4080 *sselive = True;
4081 }
4082 emit_SSE3a ( u->flags_r, u->flags_w,
4083 (u->val1 >> 8) & 0xFF,
4084 u->val1 & 0xFF,
4085 (u->val2 >> 8) & 0xFF,
4086 u->val2 & 0xFF,
4087 u->val3 );
4088 break;
4089
sewardjabf8bf82003-06-15 22:28:05 +00004090 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004091 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004092 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004093 vg_assert(u->size == 4);
4094 vg_assert(u->tag1 == Lit16);
4095 vg_assert(u->tag2 == Lit16);
4096 vg_assert(u->tag3 == RealReg);
4097 vg_assert(!anyFlagUse(u));
4098 if (!(*sselive)) {
4099 emit_get_sse_state();
4100 *sselive = True;
4101 }
sewardjabf8bf82003-06-15 22:28:05 +00004102 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4103 emit_SSE3e ( u->flags_r, u->flags_w,
4104 (u->val1 >> 8) & 0xFF,
4105 u->val1 & 0xFF,
4106 (u->val2 >> 8) & 0xFF,
4107 u->val2 & 0xFF,
4108 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004109 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004110 emit_SSE3g ( u->flags_r, u->flags_w,
4111 (u->val1 >> 8) & 0xFF,
4112 u->val1 & 0xFF,
4113 (u->val2 >> 8) & 0xFF,
4114 u->val2 & 0xFF,
4115 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004116 }
sewardjfebaa3b2003-05-25 01:07:34 +00004117 break;
4118
sewardjb31b06d2003-06-13 00:26:02 +00004119 case SSE3g1_RegWr:
4120 vg_assert(u->size == 4);
4121 vg_assert(u->tag1 == Lit16);
4122 vg_assert(u->tag2 == Lit16);
4123 vg_assert(u->tag3 == RealReg);
4124 vg_assert(!anyFlagUse(u));
4125 if (!(*sselive)) {
4126 emit_get_sse_state();
4127 *sselive = True;
4128 }
sewardjabf8bf82003-06-15 22:28:05 +00004129 emit_SSE3g1 ( u->flags_r, u->flags_w,
4130 (u->val1 >> 8) & 0xFF,
4131 u->val1 & 0xFF,
4132 (u->val2 >> 8) & 0xFF,
4133 u->val2 & 0xFF,
4134 u->lit32 & 0xFF,
4135 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004136 break;
4137
sewardj4fbe6e92003-06-15 21:54:34 +00004138 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004139 vg_assert(u->size == 2);
4140 vg_assert(u->tag1 == Lit16);
4141 vg_assert(u->tag2 == Lit16);
4142 vg_assert(u->tag3 == RealReg);
4143 vg_assert(!anyFlagUse(u));
4144 if (!(*sselive)) {
4145 emit_get_sse_state();
4146 *sselive = True;
4147 }
sewardjabf8bf82003-06-15 22:28:05 +00004148 emit_SSE3e1 ( u->flags_r, u->flags_w,
4149 (u->val1 >> 8) & 0xFF,
4150 u->val1 & 0xFF,
4151 (u->val2 >> 8) & 0xFF,
4152 u->val2 & 0xFF,
4153 u->lit32 & 0xFF,
4154 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004155 break;
4156
sewardj77d30a22003-10-19 08:18:52 +00004157 case SSE3a1_MemRd:
4158 vg_assert(u->size == 16);
4159 vg_assert(u->tag1 == Lit16);
4160 vg_assert(u->tag2 == Lit16);
4161 vg_assert(u->tag3 == RealReg);
4162 vg_assert(!anyFlagUse(u));
4163 if (!(*sselive)) {
4164 emit_get_sse_state();
4165 *sselive = True;
4166 }
4167 emit_SSE3a1 ( u->flags_r, u->flags_w,
4168 (u->val1 >> 8) & 0xFF,
4169 u->val1 & 0xFF,
4170 (u->val2 >> 8) & 0xFF,
4171 u->val2 & 0xFF,
4172 (u->lit32 >> 8) & 0xFF,
4173 u->val3 );
4174 break;
4175
sewardja453fb02003-06-14 13:22:36 +00004176 case SSE5:
4177 vg_assert(u->size == 0);
4178 vg_assert(u->tag1 == Lit16);
4179 vg_assert(u->tag2 == Lit16);
4180 vg_assert(u->tag3 == Lit16);
4181 vg_assert(!anyFlagUse(u));
4182 if (!(*sselive)) {
4183 emit_get_sse_state();
4184 *sselive = True;
4185 }
4186 emit_SSE5 ( u->flags_r, u->flags_w,
4187 (u->val1 >> 8) & 0xFF,
4188 u->val1 & 0xFF,
4189 (u->val2 >> 8) & 0xFF,
4190 u->val2 & 0xFF,
4191 u->val3 & 0xFF );
4192 break;
4193
sewardjfebaa3b2003-05-25 01:07:34 +00004194 case SSE4:
4195 vg_assert(u->size == 0);
4196 vg_assert(u->tag1 == Lit16);
4197 vg_assert(u->tag2 == Lit16);
4198 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004199 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004200 if (!(*sselive)) {
4201 emit_get_sse_state();
4202 *sselive = True;
4203 }
4204 emit_SSE4 ( u->flags_r, u->flags_w,
4205 (u->val1 >> 8) & 0xFF,
4206 u->val1 & 0xFF,
4207 (u->val2 >> 8) & 0xFF,
4208 u->val2 & 0xFF );
4209 break;
4210
sewardja60be0e2003-05-26 08:47:27 +00004211 case SSE3:
4212 vg_assert(u->size == 0);
4213 vg_assert(u->tag1 == Lit16);
4214 vg_assert(u->tag2 == Lit16);
4215 vg_assert(u->tag3 == NoValue);
sewardj77d30a22003-10-19 08:18:52 +00004216 vg_assert(!readFlagUse(u));
sewardja60be0e2003-05-26 08:47:27 +00004217 if (!(*sselive)) {
4218 emit_get_sse_state();
4219 *sselive = True;
4220 }
4221 emit_SSE3 ( u->flags_r, u->flags_w,
4222 (u->val1 >> 8) & 0xFF,
4223 u->val1 & 0xFF,
4224 u->val2 & 0xFF );
4225 break;
4226
sewardje3891fa2003-06-15 03:13:48 +00004227 case SSE3ag_MemRd_RegWr:
4228 vg_assert(u->size == 4 || u->size == 8);
4229 vg_assert(u->tag1 == RealReg);
4230 vg_assert(u->tag2 == RealReg);
4231 vg_assert(u->tag3 == NoValue);
4232 vg_assert(!anyFlagUse(u));
4233 if (!(*sselive)) {
4234 emit_get_sse_state();
4235 *sselive = True;
4236 }
4237 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4238 (u->lit32 >> 24) & 0xFF,
4239 (u->lit32 >> 16) & 0xFF,
4240 (u->lit32 >> 8) & 0xFF,
4241 u->val1, u->val2 );
4242 break;
4243
sewardjde4a1d02002-03-22 01:27:54 +00004244 default:
sewardj1b7d8022002-11-30 12:35:42 +00004245 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004246 if (*sselive) {
4247 emit_put_sse_state();
4248 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004249 }
njn4ba5a792002-09-30 10:23:54 +00004250 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004251 } else {
njn25e49d8e72002-09-23 09:36:25 +00004252 VG_(printf)("\nError:\n"
4253 " unhandled opcode: %u. Perhaps "
4254 " VG_(needs).extended_UCode should be set?\n",
4255 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004256 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004257 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004258 }
sewardjde4a1d02002-03-22 01:27:54 +00004259 }
4260
sewardjb91ae7f2003-04-29 23:50:00 +00004261 if (0 && (*sselive)) {
4262 emit_put_sse_state();
4263 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004264 }
4265
njn25e49d8e72002-09-23 09:36:25 +00004266 /* Update UInstr histogram */
4267 vg_assert(u->opcode < 100);
4268 histogram[u->opcode].counts++;
4269 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004270}
4271
4272
4273/* Emit x86 for the ucode in cb, returning the address of the
4274 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004275UChar* VG_(emit_code) ( UCodeBlock* cb,
4276 Int* nbytes,
4277 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004278{
4279 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004280 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004281 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004282 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004283 Int tgt;
4284
sewardjfa492d42002-12-08 18:20:01 +00004285 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004286
njn25e49d8e72002-09-23 09:36:25 +00004287 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004288
sewardj22854b92002-11-30 14:00:47 +00004289 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
4290 zero. We have to do this regardless of whether we're t-chaining
4291 or not. */
sewardja2113f92002-12-12 23:42:48 +00004292 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004293 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00004294 VG_(emitB) (0xFF); /* decl */
4295 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
4296 if (dis)
4297 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00004298 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00004299 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4300 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004301 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004302
sewardjb5ff83e2002-12-01 19:40:49 +00004303 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004304 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004305 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004306 curr_eip = cb->orig_eip;
4307 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4308 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004309 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004310 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004311 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004312 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004313
sewardjde4a1d02002-03-22 01:27:54 +00004314 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004315 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004316 if (!sane) {
4317 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004318 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004319 }
4320 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004321 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004322 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004323 }
njn25e49d8e72002-09-23 09:36:25 +00004324 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004325 }
njn25e49d8e72002-09-23 09:36:25 +00004326 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004327 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004328 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004329
sewardj22854b92002-11-30 14:00:47 +00004330 if (j != NULL) {
4331 vg_assert(jumpidx <= VG_MAX_JUMPS);
4332 for(i = 0; i < jumpidx; i++)
4333 j[i] = jumps[i];
4334 }
4335
sewardjde4a1d02002-03-22 01:27:54 +00004336 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004337 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004338 *nbytes = emitted_code_used;
4339 return emitted_code;
4340}
4341
njn25e49d8e72002-09-23 09:36:25 +00004342#undef dis
4343
sewardjde4a1d02002-03-22 01:27:54 +00004344/*--------------------------------------------------------------------*/
4345/*--- end vg_from_ucode.c ---*/
4346/*--------------------------------------------------------------------*/