blob: ff93b29923226a73928f102b35dcec954b9c0891 [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
fitzhardinge462f4f92003-12-18 02:10:54 +000083/* ia32 static prediction is very simple. Other implementations are
84 more complex, so we get the condition anyway. */
85static JumpPred static_pred(Condcode cond, Int forward)
86{
87 if (cond == CondAlways)
88 return JP_TAKEN;
89
90 return forward ? JP_NOT_TAKEN : JP_TAKEN;
91}
92
93static const Char *predstr(JumpPred p)
94{
95 switch(p) {
96 default:
97 case JP_NONE: return "";
98 case JP_TAKEN: return ",pt";
99 case JP_NOT_TAKEN: return ",pn";
100 }
101}
102
sewardjfa492d42002-12-08 18:20:01 +0000103/* single site for resetting state */
104static void reset_state(void)
105{
106 emitted_code_used = 0;
107 emitted_code_size = 500; /* reasonable initial size */
108 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
109 jumpidx = 0;
110 eflags_state = UPD_Simd;
111}
112
113
njn25e49d8e72002-09-23 09:36:25 +0000114/* Statistics about C functions called from generated code. */
115static UInt ccalls = 0;
116static UInt ccall_reg_saves = 0;
117static UInt ccall_args = 0;
118static UInt ccall_arg_setup_instrs = 0;
119static UInt ccall_stack_clears = 0;
120static UInt ccall_retvals = 0;
121static UInt ccall_retval_movs = 0;
122
123/* Statistics about frequency of each UInstr */
124typedef
125 struct {
126 UInt counts;
127 UInt size;
128 } Histogram;
129
130/* Automatically zeroed because it's static. */
131static Histogram histogram[100];
132
133void VG_(print_ccall_stats)(void)
134{
135 VG_(message)(Vg_DebugMsg,
136 " ccalls: %u C calls, %u%% saves+restores avoided"
137 " (%d bytes)",
138 ccalls,
139 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
140 ((ccalls*3) - ccall_reg_saves)*2);
141 VG_(message)(Vg_DebugMsg,
142 " %u args, avg 0.%d setup instrs each (%d bytes)",
143 ccall_args,
144 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
145 (ccall_args - ccall_arg_setup_instrs)*2);
146 VG_(message)(Vg_DebugMsg,
147 " %d%% clear the stack (%d bytes)",
148 (UInt)(ccall_stack_clears/(double)ccalls*100),
149 (ccalls - ccall_stack_clears)*3);
150 VG_(message)(Vg_DebugMsg,
151 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
152 ccall_retvals,
153 ( ccall_retvals == 0
154 ? 100
155 : 100-(UInt)(ccall_retval_movs /
156 (double)ccall_retvals*100)),
157 (ccall_retvals-ccall_retval_movs)*2);
158}
159
160void VG_(print_UInstr_histogram)(void)
161{
162 Int i, j;
163 UInt total_counts = 0;
164 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000165
njn25e49d8e72002-09-23 09:36:25 +0000166 for (i = 0; i < 100; i++) {
167 total_counts += histogram[i].counts;
168 total_size += histogram[i].size;
169 }
170
171 VG_(printf)("-- UInstr frequencies -----------\n");
172 for (i = 0; i < 100; i++) {
173 if (0 != histogram[i].counts) {
174
175 UInt count_pc =
176 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
177 UInt size_pc =
178 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
179 UInt avg_size =
180 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
181
182 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000183 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000184 histogram[i].counts, count_pc,
185 avg_size, size_pc);
186
sewardj05bcdcb2003-05-18 10:05:38 +0000187 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000188 VG_(printf)("\n");
189
190 } else {
191 vg_assert(0 == histogram[i].size);
192 }
193 }
194
195 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
196}
197
sewardjde4a1d02002-03-22 01:27:54 +0000198static void expandEmittedCode ( void )
199{
200 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000201 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000202 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
203 for (i = 0; i < emitted_code_size; i++)
204 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000206 emitted_code = tmp;
207 emitted_code_size *= 2;
208}
209
njn25e49d8e72002-09-23 09:36:25 +0000210/* Local calls will be inlined, cross-module ones not */
211__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000212{
213 if (dis) {
214 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
215 }
216 if (emitted_code_used == emitted_code_size)
217 expandEmittedCode();
218
219 emitted_code[emitted_code_used] = (UChar)b;
220 emitted_code_used++;
221}
222
njn25e49d8e72002-09-23 09:36:25 +0000223__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000224{
njn25e49d8e72002-09-23 09:36:25 +0000225 VG_(emitB) ( (l) & 0x000000FF );
226 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000227}
228
sewardj56867352003-10-12 10:27:06 +0000229/* __inline__ */
230void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000231{
njn25e49d8e72002-09-23 09:36:25 +0000232 VG_(emitB) ( (l) & 0x000000FF );
233 VG_(emitB) ( (l >> 8) & 0x000000FF );
234 VG_(emitB) ( (l >> 16) & 0x000000FF );
235 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000236}
237
fitzhardinge98abfc72003-12-16 02:05:15 +0000238/* This bit is ORd onto the size to indicate that it's a client
239 pointer which needs bounds checking. */
240#define DO_BOUNDSCHECK (1<<8)
241
242/* If the user asks for it, generate bounds checks on application
243 pointer dereferences, in the form of a segment override. */
244static __inline__ void boundscheck()
245{
246 if (VG_(clo_pointercheck))
247 VG_(emitB)(0x64); /* %fs prefix - see vg_dispatch.S */
248}
249
250
sewardjfa492d42002-12-08 18:20:01 +0000251static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000252{
sewardjfa492d42002-12-08 18:20:01 +0000253 Int off = 4 * VGOFF_(m_eflags);
254 vg_assert(off >= 0 && off < 128);
255
256 if (dis)
257 VG_(printf)("\t %4d: ", emitted_code_used );
258
259 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
260 VG_(emitB) ( 0x75 );
261 VG_(emitB) ( off );
262 VG_(emitB) ( 0x9D ); /* POPFL */
263 if (dis)
264 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
265}
266
267static void emit_put_eflags ( void )
268{
269 Int off = 4 * VGOFF_(m_eflags);
270 vg_assert(off >= 0 && off < 128);
271
272 if (dis)
273 VG_(printf)("\t %4d: ", emitted_code_used );
274
275 VG_(emitB) ( 0x9C ); /* PUSHFL */
276 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
277 VG_(emitB) ( 0x45 );
278 VG_(emitB) ( off );
279 if (dis)
280 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
281}
282
283static void maybe_emit_put_eflags( void )
284{
285 if (eflags_state == UPD_Real) {
286 eflags_state = UPD_Both;
287 emit_put_eflags();
288 }
289}
290
sewardja2c5a732002-12-15 03:10:42 +0000291
292/* evidently unused */
293#if 0
sewardjfa492d42002-12-08 18:20:01 +0000294static void maybe_emit_get_eflags( void )
295{
296 if (eflags_state == UPD_Simd) {
297 eflags_state = UPD_Both;
298 emit_get_eflags();
299 }
300}
sewardja2c5a732002-12-15 03:10:42 +0000301#endif
sewardjfa492d42002-12-08 18:20:01 +0000302
sewardjf0f12aa2002-12-28 00:04:08 +0000303
304#if 0
305/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
306/* An alternative implementation of new_emit in which the
307 state space is explicitly enumerated. */
308__inline__
309void VG_(new_emit) ( Bool upds_simd_flags,
310 FlagSet use_flags, FlagSet set_flags )
311{
312 Bool simd = upds_simd_flags;
313 enum _eflags_state where = eflags_state;
314
315 enum { WNone, WSome, WAll } ww;
316 Bool rr;
317
318#define DIS_HEADER \
319 if (dis) \
320 VG_(printf)("\t %4d: ", emitted_code_used );
321
322 if (use_flags == FlagsEmpty) {
323 rr = False;
324 } else {
325 rr = True;
326 }
327
328 if (set_flags == FlagsEmpty) {
329 ww = WNone;
330 } else
331 if (set_flags == FlagsOSZACP) {
332 ww = WAll;
333 } else {
334 ww = WSome;
335 }
336
337 /* If we're not wanting to interact with simd flags, and the simd
338 flags are not in the real flags, then do nothing. */
339 if (simd == False && where == UPD_Simd)
340 goto noaction;
341
342 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
343 /* We're going to generate a complete new simd flag state without
344 consulting the old one first, so just deem this insn to create
345 the state in the real flags. */
346 eflags_state = UPD_Real;
347 DIS_HEADER;
348 return;
349 }
350
351 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
352 /* Want to partially update the flags state, but is in simd. So
353 fetch it first, then declare that the real state is the most
354 recent. */
355 emit_get_eflags();
356 eflags_state = UPD_Real;
357 DIS_HEADER;
358 return;
359 }
360
361 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
362 /* want to read simd flags, but not in real -> copy to real. */
363 emit_get_eflags();
364 eflags_state = UPD_Both;
365 DIS_HEADER;
366 return;
367 }
368
369 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
370 /* want to read and write simd flags, but not in real -> copy to
371 real. State is then Real since they get updated. */
372 emit_get_eflags();
373 eflags_state = UPD_Real;
374 DIS_HEADER;
375 return;
376 }
377
378 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
379 /* Doesn't really make sense. Want to interact with simd flags,
380 but insn doesn't modify them. So don't do anything. ??? */
381 goto noaction;
382 }
383
384 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
385 /* Doesn't really make sense. Want to interact with simd flags,
386 but insn doesn't modify them. So don't do anything. ??? */
387 goto noaction;
388 }
389
390 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
391 /* simd is in real. Insn reads real but does not change. --> do
392 nothing. */
393 goto noaction;
394 }
395
396 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
397 /* simd is in real. we want to capture changes made by it. -->
398 do nothing */
399 goto noaction;
400 }
401
402 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
403 /* simd is in real. Insn creates new simd state. --> leave in
404 real */
405 goto noaction;
406 }
407
408 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
409 /* simd is in both. Insn creates new simd state. --> change
410 state to Real. */
411 narrow_Both_to_Real:
412 eflags_state = UPD_Real;
413 DIS_HEADER;
414 return;
415 }
416
417 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
418 /* simd is in both. Insn creates partial new simd state. -->
419 change state to Real. No need to get, since Both holds. */
420 goto narrow_Both_to_Real;
421 }
422
423 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
424 /* simd is in real. Insn creates new simd state. --> leave in
425 real */
426 goto noaction;
427 }
428
429 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
430 /* want to read the simd flags, but already have a copy in real,
431 and not planning to modify it --> do nothing. */
432 goto noaction;
433
434 ////////////////
435
436 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
437 /* simd state is in real, but insn doesn't touch it --> do nothing */
438 goto noaction;
439
440 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
441 /* simd state is in both, insn doesn't touch it --> do nothing */
442 goto noaction;
443
444 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
445 /* simd state is in both. insn trashes real, therefore declare
446 simd state only in simd. */
447 narrow_Both_to_Simd:
448 eflags_state = UPD_Simd;
449 DIS_HEADER;
450 return;
451 }
452
453 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
454 /* simd state is in both. insn trashes real, therefore declare
455 simd state only in simd. */
456 goto narrow_Both_to_Simd;
457 }
458
459 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
460 /* simd state is in real; we don't want simd state changed, but
461 insn writes the flags. Therefore have to copy back first. */
462 put_flags_and_continue:
463 emit_put_eflags();
464 eflags_state = UPD_Simd;
465 DIS_HEADER;
466 return;
467 }
468
469 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
470 /* simd state is in real; we don't want simd state changed, but
471 insn writes the flags. Therefore have to copy back first. */
472 goto put_flags_and_continue;
473 }
474
475 goto unhandled;
476
477 noaction:
478 DIS_HEADER;
479 return;
480
481 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
482 // return;
483 //}
484
485 unhandled:
486 VG_(printf)("simd %s, where %s, read %s, write %s\n",
487 simd ? "True " : "False",
488 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
489 ? "Real" : "Both")),
490 rr ? "True " : "False",
491 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
492 );
493
494 VG_(core_panic)("new_emit");
495}
496/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
497#endif
498
499
sewardjfa492d42002-12-08 18:20:01 +0000500/* Call this before emitting each instruction.
501
502 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000503 interacts_with_simd_flags:
504 if true, this instruction wants to interact (read and/or write)
505 the simulated %EFLAGS state,
506 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000507 use_flags: set of (real) flags the instruction uses
508 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000509*/
sewardjf0f12aa2002-12-28 00:04:08 +0000510void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000511 FlagSet use_flags, FlagSet set_flags )
512{
513 Bool use, set;
514
515 use = use_flags != FlagsEmpty
516 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
517 set = set_flags != FlagsEmpty;
518
519 if (0)
520 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000521 "new_emit: state=%d interacts_with_simd_flags=%d "
522 "use_flags=%x set_flags=%x\n",
523 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000524
sewardjf0f12aa2002-12-28 00:04:08 +0000525 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000526 if (use && eflags_state == UPD_Simd) {
527 /* we need the CPU flags set, but they're not already */
528 eflags_state = UPD_Both;
529 emit_get_eflags();
530 }
531 if (set) {
532 /* if we're setting the flags, then the CPU will have the
533 only good copy */
534 eflags_state = UPD_Real;
535 }
536 } else {
537 /* presume that if non-simd code is using flags, it knows what
538 it's doing (ie, it just set up the flags). */
539 if (set) {
540 /* This instruction is going to trash the flags, so we'd
541 better save them away and say that they're only in the
542 simulated state. */
543 maybe_emit_put_eflags();
544 eflags_state = UPD_Simd;
545 }
546 }
547
sewardjde4a1d02002-03-22 01:27:54 +0000548 if (dis)
549 VG_(printf)("\t %4d: ", emitted_code_used );
550}
551
sewardjde4a1d02002-03-22 01:27:54 +0000552
553/*----------------------------------------------------*/
554/*--- Addressing modes ---*/
555/*----------------------------------------------------*/
556
557static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
558{
559 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
560}
561
562static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
563{
564 Int shift;
565 switch (scale) {
566 case 1: shift = 0; break;
567 case 2: shift = 1; break;
568 case 4: shift = 2; break;
569 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000570 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000571 }
572 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
573}
574
575static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
576{
577 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000578 VG_(emitB) ( mkModRegRM(0, reg, 5) );
579 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000580}
581
582static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
583{
584 /* (regmem), reg */
585 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000586 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000587 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000588 VG_(emitB) ( mkModRegRM(1, reg, 5) );
589 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000590 } else {
njn25e49d8e72002-09-23 09:36:25 +0000591 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000592 }
593}
594
njn25e49d8e72002-09-23 09:36:25 +0000595void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000596{
597 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000598 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000599 if (off < -128 || off > 127) {
600 /* Use a large offset */
601 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000602 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
603 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000604 } else {
605 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000606 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
607 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000608 }
609}
610
611static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
612 Int regindex, Int reg )
613{
614 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000615 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000616 if (off < -128 || off > 127) {
617 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000618 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
619 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
620 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000621 } else {
622 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000623 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
624 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
625 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000626 }
627}
628
njn25e49d8e72002-09-23 09:36:25 +0000629void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000630{
631 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000632 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000633}
634
635static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
636{
637 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000638 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000639}
640
641
642/*----------------------------------------------------*/
643/*--- Opcode translation ---*/
644/*----------------------------------------------------*/
645
646static __inline__ Int mkGrp1opcode ( Opcode opc )
647{
648 switch (opc) {
649 case ADD: return 0;
650 case OR: return 1;
651 case ADC: return 2;
652 case SBB: return 3;
653 case AND: return 4;
654 case SUB: return 5;
655 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000656 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000657 }
658}
659
sewardjfa492d42002-12-08 18:20:01 +0000660static __inline__ FlagSet nonshiftop_use(Opcode opc)
661{
662 switch(opc) {
663 case ADC:
664 case SBB:
665 return FlagC;
666
667 case ADD:
668 case OR:
669 case AND:
670 case SUB:
671 case XOR:
672 return FlagsEmpty;
673
674 default:
675 VG_(core_panic)("nonshiftop_use");
676 }
677}
678
679static __inline__ FlagSet nonshiftop_set(Opcode opc)
680{
681 switch(opc) {
682 case ADC:
683 case SBB:
684 case ADD:
685 case OR:
686 case AND:
687 case SUB:
688 case XOR:
689 return FlagsOSZACP;
690
691 default:
692 VG_(core_panic)("nonshiftop_set");
693 }
694}
695
sewardjde4a1d02002-03-22 01:27:54 +0000696static __inline__ Int mkGrp2opcode ( Opcode opc )
697{
698 switch (opc) {
699 case ROL: return 0;
700 case ROR: return 1;
701 case RCL: return 2;
702 case RCR: return 3;
703 case SHL: return 4;
704 case SHR: return 5;
705 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000706 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000707 }
708}
709
sewardjfa492d42002-12-08 18:20:01 +0000710static __inline__ FlagSet shiftop_use(Opcode opc)
711{
712 switch(opc) {
713 case ROR:
714 case ROL:
715 case SHL:
716 case SHR:
717 case SAR:
718 return FlagsEmpty;
719
720 case RCL:
721 case RCR:
722 return FlagC;
723
724 default:
725 VG_(core_panic)("shiftop_use");
726 }
727}
728
729static __inline__ FlagSet shiftop_set(Opcode opc)
730{
731 switch(opc) {
732 case ROR:
733 case ROL:
734 case RCL:
735 case RCR:
736 return FlagsOC;
737
738 case SHL:
739 case SHR:
740 case SAR:
741 return FlagsOSZACP;
742
743 default:
744 VG_(core_panic)("shiftop_set");
745 }
746}
747
sewardjde4a1d02002-03-22 01:27:54 +0000748static __inline__ Int mkGrp3opcode ( Opcode opc )
749{
750 switch (opc) {
751 case NOT: return 2;
752 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000753 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000754 }
755}
756
757static __inline__ Int mkGrp4opcode ( Opcode opc )
758{
759 switch (opc) {
760 case INC: return 0;
761 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000762 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000763 }
764}
765
766static __inline__ Int mkGrp5opcode ( Opcode opc )
767{
768 switch (opc) {
769 case CALLM: return 2;
770 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000771 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000772 }
773}
774
775static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
776{
777 switch (opc) {
778 case ADD: return 0x00;
779 case ADC: return 0x10;
780 case AND: return 0x20;
781 case XOR: return 0x30;
782 case OR: return 0x08;
783 case SBB: return 0x18;
784 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000785 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000786 }
787}
788
789/*----------------------------------------------------*/
790/*--- v-size (4, or 2 with OSO) insn emitters ---*/
791/*----------------------------------------------------*/
792
njn25e49d8e72002-09-23 09:36:25 +0000793void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
798 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
801 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000807
808 if (sz & DO_BOUNDSCHECK) {
809 boundscheck();
810 sz &= ~DO_BOUNDSCHECK;
811 }
812
njn25e49d8e72002-09-23 09:36:25 +0000813 if (sz == 2) VG_(emitB) ( 0x66 );
814 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
815 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000816 if (dis)
817 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
818 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
819}
820
821static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
822{
sewardjf0f12aa2002-12-28 00:04:08 +0000823 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000824
825 if (sz & DO_BOUNDSCHECK) {
826 boundscheck();
827 sz &= ~DO_BOUNDSCHECK;
828 }
829
njn25e49d8e72002-09-23 09:36:25 +0000830 if (sz == 2) VG_(emitB) ( 0x66 );
831 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000832 emit_amode_regmem_reg ( reg1, reg2 );
833 if (dis)
834 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
835 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
836}
837
838static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
839{
sewardjf0f12aa2002-12-28 00:04:08 +0000840 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000841
842 if (sz & DO_BOUNDSCHECK) {
843 boundscheck();
844 sz &= ~DO_BOUNDSCHECK;
845 }
846
njn25e49d8e72002-09-23 09:36:25 +0000847 if (sz == 2) VG_(emitB) ( 0x66 );
848 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000849 emit_amode_regmem_reg ( reg2, reg1 );
850 if (dis)
851 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
852 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
853}
854
njn25e49d8e72002-09-23 09:36:25 +0000855void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000856{
sewardjf0f12aa2002-12-28 00:04:08 +0000857 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000858 if (sz == 2) VG_(emitB) ( 0x66 );
859 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
860 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000861 if (dis)
862 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
863 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
864}
865
sewardjf0f12aa2002-12-28 00:04:08 +0000866void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
867 Int sz, Opcode opc,
868 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000869{
sewardjf0f12aa2002-12-28 00:04:08 +0000870 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000871
njn25e49d8e72002-09-23 09:36:25 +0000872 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000873 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
874 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000875 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
876 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
877 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000878 } else {
njn25e49d8e72002-09-23 09:36:25 +0000879 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
880 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
881 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000882 }
883 if (dis)
884 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000885 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000886 lit, nameIReg(sz,reg));
887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
890 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000891 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000892{
sewardjf0f12aa2002-12-28 00:04:08 +0000893 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000894 if (sz == 2) VG_(emitB) ( 0x66 );
895 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
896 /* short form OK */
897 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
898 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
899 VG_(emitB) ( lit & 0x000000FF );
900 } else {
901 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
902 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
903 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
904 }
905 if (dis)
906 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
907 VG_(name_UOpcode)(False,opc), nameISize(sz),
908 lit, off, nameIReg(sz,regmem));
909}
910
sewardjf0f12aa2002-12-28 00:04:08 +0000911void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
912 Int sz, Opcode opc,
913 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000914{
sewardjf0f12aa2002-12-28 00:04:08 +0000915 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000916
njn25e49d8e72002-09-23 09:36:25 +0000917 if (sz == 2) VG_(emitB) ( 0x66 );
918 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
919 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
920 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000921 if (dis)
922 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000923 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000924 lit, nameIReg(sz,reg));
925}
926
sewardjf0f12aa2002-12-28 00:04:08 +0000927static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000928{
sewardjf0f12aa2002-12-28 00:04:08 +0000929 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000930 if (sz == 2) VG_(emitB) ( 0x66 );
931 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
932 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
933 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
934 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000935 if (dis)
936 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000937 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000938}
939
sewardjf0f12aa2002-12-28 00:04:08 +0000940static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000941{
sewardjf0f12aa2002-12-28 00:04:08 +0000942 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000943 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
944 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
945 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
946 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000947 if (dis)
948 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000949 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000950}
951
sewardjf0f12aa2002-12-28 00:04:08 +0000952static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
953 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000954 Int off, Int areg, Int reg )
955{
sewardjf0f12aa2002-12-28 00:04:08 +0000956 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000957 if (sz == 2) VG_(emitB) ( 0x66 );
958 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
959 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000960 if (dis)
961 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000962 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000963 off, nameIReg(4,areg), nameIReg(sz,reg));
964}
965
sewardja2c5a732002-12-15 03:10:42 +0000966#if 0
967/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000968static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000969 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjf0f12aa2002-12-28 00:04:08 +0000971 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000972 if (sz == 2) VG_(emitB) ( 0x66 );
973 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
974 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
975 if (dis)
976 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
977 VG_(name_UOpcode)(False,opc), nameISize(sz),
978 nameIReg(sz,reg), off, nameIReg(4,areg));
979}
sewardja2c5a732002-12-15 03:10:42 +0000980#endif
sewardjfa492d42002-12-08 18:20:01 +0000981
sewardjf0f12aa2002-12-28 00:04:08 +0000982void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000983 Int reg1, Int reg2 )
984{
sewardjf0f12aa2002-12-28 00:04:08 +0000985 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000986 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000987# if 0
988 /* Perfectly correct, but the GNU assembler uses the other form.
989 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000990 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
991 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000992# else
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000994 emit_amode_greg_ereg ( reg1, reg2 );
995# endif
996 if (dis)
997 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000998 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000999 nameIReg(sz,reg1), nameIReg(sz,reg2));
1000}
1001
njn25e49d8e72002-09-23 09:36:25 +00001002void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001003{
sewardjf0f12aa2002-12-28 00:04:08 +00001004#if 0
sewardjfa492d42002-12-08 18:20:01 +00001005 if (lit == 0 && eflags_state != UPD_Real) {
1006 /* Only emit this for zeroing if it won't stomp flags */
1007 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001008 return;
1009 }
sewardjf0f12aa2002-12-28 00:04:08 +00001010#endif
1011 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001012 if (sz == 2) VG_(emitB) ( 0x66 );
1013 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
1014 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001015 if (dis)
1016 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
1017 nameISize(sz), lit, nameIReg(sz,reg));
1018}
1019
sewardjf0f12aa2002-12-28 00:04:08 +00001020void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001021{
sewardjde4a1d02002-03-22 01:27:54 +00001022 switch (opc) {
1023 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001024 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +00001025 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001026 VG_(emitB) ( 0xF7 );
1027 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001028 if (dis)
1029 VG_(printf)( "\n\t\tneg%c\t%s\n",
1030 nameISize(sz), nameIReg(sz,reg));
1031 break;
1032 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001033 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +00001034 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001035 VG_(emitB) ( 0xF7 );
1036 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001037 if (dis)
1038 VG_(printf)( "\n\t\tnot%c\t%s\n",
1039 nameISize(sz), nameIReg(sz,reg));
1040 break;
1041 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001042 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001043 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001044 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001045 if (dis)
1046 VG_(printf)( "\n\t\tdec%c\t%s\n",
1047 nameISize(sz), nameIReg(sz,reg));
1048 break;
1049 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001050 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001051 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001052 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001053 if (dis)
1054 VG_(printf)( "\n\t\tinc%c\t%s\n",
1055 nameISize(sz), nameIReg(sz,reg));
1056 break;
1057 default:
njne427a662002-10-02 11:08:25 +00001058 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001059 }
1060}
1061
njn25e49d8e72002-09-23 09:36:25 +00001062void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001063{
sewardjf0f12aa2002-12-28 00:04:08 +00001064 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001065 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001066 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001067 } else {
1068 vg_assert(sz == 4);
1069 }
njn25e49d8e72002-09-23 09:36:25 +00001070 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001078 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001079 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001080 } else {
1081 vg_assert(sz == 4);
1082 }
njn25e49d8e72002-09-23 09:36:25 +00001083 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001084 if (dis)
1085 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1086}
1087
njn25e49d8e72002-09-23 09:36:25 +00001088void VG_(emit_pushl_lit32) ( UInt int32 )
1089{
sewardjf0f12aa2002-12-28 00:04:08 +00001090 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001091 VG_(emitB) ( 0x68 );
1092 VG_(emitL) ( int32 );
1093 if (dis)
1094 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1095}
1096
1097void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001098{
1099 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001100 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001101 VG_(emitB) ( 0x6A );
1102 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001103 if (dis)
1104 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1105}
1106
sewardjf0f12aa2002-12-28 00:04:08 +00001107void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001108{
sewardjf0f12aa2002-12-28 00:04:08 +00001109 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001110 VG_(emitB) ( 0x83 );
1111 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1112 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001113 if (dis)
1114 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1115}
1116
1117static void emit_swapl_reg_ECX ( Int reg )
1118{
sewardjf0f12aa2002-12-28 00:04:08 +00001119 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001120 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1121 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1124}
1125
njn25e49d8e72002-09-23 09:36:25 +00001126void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001127{
sewardjf0f12aa2002-12-28 00:04:08 +00001128 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001129 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001130 if (dis)
1131 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1132}
1133
1134static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1138 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001139 if (dis)
1140 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1141 nameIReg(4,reg2));
1142}
1143
1144static void emit_bswapl_reg ( Int reg )
1145{
sewardjf0f12aa2002-12-28 00:04:08 +00001146 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001147 VG_(emitB) ( 0x0F );
1148 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001149 if (dis)
1150 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1151}
1152
1153static void emit_movl_reg_reg ( Int regs, Int regd )
1154{
sewardjf0f12aa2002-12-28 00:04:08 +00001155 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001156 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1157 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001158 if (dis)
1159 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1160}
1161
njn25e49d8e72002-09-23 09:36:25 +00001162void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001163{
sewardjf0f12aa2002-12-28 00:04:08 +00001164 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001165 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001166 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001167 } else {
1168 vg_assert(sz == 4);
1169 }
njn25e49d8e72002-09-23 09:36:25 +00001170 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1171 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1172 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001173 if (dis)
1174 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1175 nameISize(sz), lit, off, nameIReg(4,memreg) );
1176}
1177
1178
1179/*----------------------------------------------------*/
1180/*--- b-size (1 byte) instruction emitters ---*/
1181/*----------------------------------------------------*/
1182
1183/* There is some doubt as to whether C6 (Grp 11) is in the
1184 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1186{
sewardjf0f12aa2002-12-28 00:04:08 +00001187 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001188 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1189 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1190 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1193 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001197 Int off, Int areg, Int reg )
1198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg));
1206}
1207
sewardjf0f12aa2002-12-28 00:04:08 +00001208static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001209 UInt lit, Int off, Int areg )
1210{
sewardjf0f12aa2002-12-28 00:04:08 +00001211 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001212 VG_(emitB) ( 0x80 );
1213 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1214 VG_(emitB) ( lit );
1215 if (dis)
1216 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1217 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1218}
1219
sewardja2c5a732002-12-15 03:10:42 +00001220#if 0
1221/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001222static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001223 Int off, Int areg, Int reg )
1224{
sewardjf0f12aa2002-12-28 00:04:08 +00001225 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001226 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1227 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1228 if (dis)
1229 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1230 VG_(name_UOpcode)(False,opc),
1231 nameIReg(1,reg),
1232 off, nameIReg(4,areg));
1233}
sewardja2c5a732002-12-15 03:10:42 +00001234#endif
sewardjfa492d42002-12-08 18:20:01 +00001235
njn25e49d8e72002-09-23 09:36:25 +00001236void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001237{
1238 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001239 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001240 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1241 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001242 if (dis)
1243 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1244 nameIReg(1,reg), off, nameIReg(4,areg));
1245}
1246
sewardjf0f12aa2002-12-28 00:04:08 +00001247static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1248 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001249{
sewardjf0f12aa2002-12-28 00:04:08 +00001250 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001251 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1252 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001253 if (dis)
1254 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001255 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001256 nameIReg(1,reg1), nameIReg(1,reg2));
1257}
1258
fitzhardinge98abfc72003-12-16 02:05:15 +00001259static void emit_movb_reg_regmem ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001260{
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001262
1263 if (bounds)
1264 boundscheck();
1265
njn25e49d8e72002-09-23 09:36:25 +00001266 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001267 emit_amode_regmem_reg ( reg2, reg1 );
1268 if (dis)
1269 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1270 nameIReg(4,reg2));
1271}
1272
sewardjf0f12aa2002-12-28 00:04:08 +00001273static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1274 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001275{
sewardjf0f12aa2002-12-28 00:04:08 +00001276 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001277 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1278 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1279 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001280 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001281 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001282 lit, nameIReg(1,reg));
1283}
1284
sewardjf0f12aa2002-12-28 00:04:08 +00001285static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1286 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001287{
sewardjf0f12aa2002-12-28 00:04:08 +00001288 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001289 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1290 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1291 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001292 if (dis)
1293 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001294 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001295 lit, nameIReg(1,reg));
1296}
1297
sewardjf0f12aa2002-12-28 00:04:08 +00001298void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001299{
sewardjde4a1d02002-03-22 01:27:54 +00001300 switch (opc) {
1301 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001302 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001303 VG_(emitB) ( 0xFE );
1304 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001305 if (dis)
1306 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1307 break;
1308 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001309 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001310 VG_(emitB) ( 0xFE );
1311 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001312 if (dis)
1313 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1314 break;
1315 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001316 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001317 VG_(emitB) ( 0xF6 );
1318 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001319 if (dis)
1320 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1321 break;
1322 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001323 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001324 VG_(emitB) ( 0xF6 );
1325 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001326 if (dis)
1327 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1328 break;
1329 default:
njne427a662002-10-02 11:08:25 +00001330 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001331 }
1332}
1333
sewardjf0f12aa2002-12-28 00:04:08 +00001334void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001335{
sewardjf0f12aa2002-12-28 00:04:08 +00001336 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001337 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1338 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1339 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001340 if (dis)
1341 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1342}
1343
sewardjde4a1d02002-03-22 01:27:54 +00001344/*----------------------------------------------------*/
1345/*--- zero-extended load emitters ---*/
1346/*----------------------------------------------------*/
1347
fitzhardinge98abfc72003-12-16 02:05:15 +00001348void VG_(emit_movzbl_offregmem_reg) ( Bool bounds, Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001349{
sewardjf0f12aa2002-12-28 00:04:08 +00001350 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001351 if (bounds)
1352 boundscheck();
njn25e49d8e72002-09-23 09:36:25 +00001353 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1354 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001355 if (dis)
1356 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1357 off, nameIReg(4,regmem), nameIReg(4,reg));
1358}
1359
fitzhardinge98abfc72003-12-16 02:05:15 +00001360static void emit_movzbl_regmem_reg ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001361{
sewardjf0f12aa2002-12-28 00:04:08 +00001362 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001363
1364 if (bounds)
1365 boundscheck();
1366
njn25e49d8e72002-09-23 09:36:25 +00001367 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001368 emit_amode_regmem_reg ( reg1, reg2 );
1369 if (dis)
1370 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1371 nameIReg(4,reg2));
1372}
1373
fitzhardinge98abfc72003-12-16 02:05:15 +00001374void VG_(emit_movzwl_offregmem_reg) ( Bool bounds, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001375{
sewardjf0f12aa2002-12-28 00:04:08 +00001376 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001377
1378 if (bounds)
1379 boundscheck();
1380
njn25e49d8e72002-09-23 09:36:25 +00001381 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1382 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001383 if (dis)
1384 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1385 off, nameIReg(4,areg), nameIReg(4,reg));
1386}
1387
fitzhardinge98abfc72003-12-16 02:05:15 +00001388void VG_( emit_movzwl_regmem_reg ) ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001389{
sewardjf0f12aa2002-12-28 00:04:08 +00001390 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001391
1392 if (bounds)
1393 boundscheck();
1394
njn25e49d8e72002-09-23 09:36:25 +00001395 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001396 emit_amode_regmem_reg ( reg1, reg2 );
1397 if (dis)
1398 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1399 nameIReg(4,reg2));
1400}
1401
1402/*----------------------------------------------------*/
1403/*--- FPU instruction emitters ---*/
1404/*----------------------------------------------------*/
1405
sewardjb91ae7f2003-04-29 23:50:00 +00001406static void emit_get_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) ( 0x8D ); /* fxrstor d32(%ebp) */
1413 VG_(emitL) ( off );
1414 if (dis)
1415 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1416 } else {
1417 /* Not a SSE-capable CPU. Just do frstor. */
1418 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1419 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1420 VG_(emitL) ( off );
1421 if (dis)
1422 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1423 }
sewardjde4a1d02002-03-22 01:27:54 +00001424}
1425
sewardjb91ae7f2003-04-29 23:50:00 +00001426static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001427{
sewardjb91ae7f2003-04-29 23:50:00 +00001428 Int off = 4 * VGOFF_(m_ssestate);
1429 if (VG_(have_ssestate)) {
1430 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1431 VG_(emitB) ( 0x0F );
1432 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1433 VG_(emitL) ( off );
1434 if (dis)
1435 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1436 } else {
1437 /* Not a SSE-capable CPU. Just do fnsave. */
1438 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1439 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1440 VG_(emitL) ( off );
1441 if (dis)
1442 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1443 }
sewardjde4a1d02002-03-22 01:27:54 +00001444}
1445
sewardjf0f12aa2002-12-28 00:04:08 +00001446static void emit_fpu_no_mem ( FlagSet uses_sflags,
1447 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001448 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001449 UChar second_byte )
1450{
sewardjf0f12aa2002-12-28 00:04:08 +00001451 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001452 VG_(emitB) ( first_byte );
1453 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001454 if (dis)
1455 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1456 (UInt)first_byte, (UInt)second_byte );
1457}
1458
sewardjf0f12aa2002-12-28 00:04:08 +00001459static void emit_fpu_regmem ( FlagSet uses_sflags,
1460 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001461 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001462 UChar second_byte_masked,
1463 Int reg )
1464{
sewardjf0f12aa2002-12-28 00:04:08 +00001465 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001466
1467 boundscheck(); /* assume all FPU ops are the client's */
1468
njn25e49d8e72002-09-23 09:36:25 +00001469 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001470 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1471 if (dis)
1472 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1473 (UInt)first_byte, (UInt)second_byte_masked,
1474 nameIReg(4,reg) );
1475}
1476
sewardj3d7c9c82003-03-26 21:08:13 +00001477static void emit_MMX2_regmem ( FlagSet uses_sflags,
1478 FlagSet sets_sflags,
1479 UChar first_byte,
1480 UChar second_byte,
1481 Int ireg )
1482{
1483 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001484
1485 boundscheck();
1486
sewardj3d7c9c82003-03-26 21:08:13 +00001487 VG_(emitB) ( 0x0F );
1488 VG_(emitB) ( first_byte );
1489 second_byte &= 0x38; /* mask out mod and rm fields */
1490 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1491 if (dis)
1492 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1493 (UInt)first_byte, (UInt)second_byte,
1494 nameIReg(4,ireg) );
1495}
1496
sewardjfebaa3b2003-05-25 01:07:34 +00001497static void emit_SSE2a ( FlagSet uses_sflags,
1498 FlagSet sets_sflags,
1499 UChar first_byte,
1500 UChar second_byte,
1501 UChar third_byte,
1502 Int ireg )
1503{
1504 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001505
1506 boundscheck();
1507
sewardjfebaa3b2003-05-25 01:07:34 +00001508 VG_(emitB) ( first_byte );
1509 VG_(emitB) ( second_byte );
1510 third_byte &= 0x38; /* mask out mod and rm fields */
1511 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1512 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001513 VG_(printf)("\n\t\tsse2a-0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001514 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1515 nameIReg(4,ireg) );
1516}
1517
sewardj9dd209f2003-06-18 23:30:52 +00001518static void emit_SSE2a1 ( FlagSet uses_sflags,
1519 FlagSet sets_sflags,
1520 UChar first_byte,
1521 UChar second_byte,
1522 UChar third_byte,
1523 UChar fourth_byte,
1524 Int ireg )
1525{
1526 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001527
1528 boundscheck();
1529
sewardj9dd209f2003-06-18 23:30:52 +00001530 VG_(emitB) ( first_byte );
1531 VG_(emitB) ( second_byte );
1532 third_byte &= 0x38; /* mask out mod and rm fields */
1533 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1534 VG_(emitB) ( fourth_byte );
1535 if (dis)
1536 VG_(printf)("\n\t\tsse2a1-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1537 (UInt)first_byte, (UInt)second_byte,
1538 (UInt)third_byte, (UInt)fourth_byte,
1539 nameIReg(4,ireg) );
1540}
1541
sewardjfebaa3b2003-05-25 01:07:34 +00001542static void emit_SSE3a ( FlagSet uses_sflags,
1543 FlagSet sets_sflags,
1544 UChar first_byte,
1545 UChar second_byte,
1546 UChar third_byte,
1547 UChar fourth_byte,
1548 Int ireg )
1549{
1550 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001551
1552 boundscheck();
1553
sewardjfebaa3b2003-05-25 01:07:34 +00001554 VG_(emitB) ( first_byte );
1555 VG_(emitB) ( second_byte );
1556 VG_(emitB) ( third_byte );
1557 fourth_byte &= 0x38; /* mask out mod and rm fields */
1558 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1559 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001560 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001561 (UInt)first_byte, (UInt)second_byte,
1562 (UInt)third_byte, (UInt)fourth_byte,
1563 nameIReg(4,ireg) );
1564}
1565
sewardjabf8bf82003-06-15 22:28:05 +00001566static void emit_SSE3e ( FlagSet uses_sflags,
1567 FlagSet sets_sflags,
1568 UChar first_byte,
1569 UChar second_byte,
1570 UChar third_byte,
1571 UChar fourth_byte,
1572 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001573{
1574 VG_(new_emit)(True, uses_sflags, sets_sflags);
1575 VG_(emitB) ( first_byte );
1576 VG_(emitB) ( second_byte );
1577 VG_(emitB) ( third_byte );
1578 fourth_byte &= 0x38; /* mask out mod and rm fields */
1579 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1580 fourth_byte |= (ireg & 7); /* patch in our ireg */
1581 VG_(emitB) ( fourth_byte );
1582 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001583 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001584 "\n\t\tsse3e--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001585 (UInt)first_byte, (UInt)second_byte,
1586 (UInt)third_byte, (UInt)fourth_byte,
1587 nameIReg(4,ireg)
1588 );
sewardjfebaa3b2003-05-25 01:07:34 +00001589}
1590
sewardjabf8bf82003-06-15 22:28:05 +00001591static void emit_SSE3e1 ( FlagSet uses_sflags,
1592 FlagSet sets_sflags,
1593 UChar first_byte,
1594 UChar second_byte,
1595 UChar third_byte,
1596 UChar fourth_byte,
1597 UChar fifth_byte,
1598 Int ireg )
sewardj8f33ba62003-06-14 12:00:45 +00001599{
1600 VG_(new_emit)(True, uses_sflags, sets_sflags);
1601 VG_(emitB) ( first_byte );
1602 VG_(emitB) ( second_byte );
1603 VG_(emitB) ( third_byte );
1604 fourth_byte &= 0x38; /* mask out mod and rm fields */
1605 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1606 fourth_byte |= (ireg & 7); /* patch in our ireg */
1607 VG_(emitB) ( fourth_byte );
1608 VG_(emitB) ( fifth_byte );
1609 if (dis)
1610 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001611 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001612 (UInt)first_byte, (UInt)second_byte,
1613 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1614 nameIReg(4,ireg)
1615 );
1616}
1617
sewardjabf8bf82003-06-15 22:28:05 +00001618static void emit_SSE3g1 ( FlagSet uses_sflags,
1619 FlagSet sets_sflags,
1620 UChar first_byte,
1621 UChar second_byte,
1622 UChar third_byte,
1623 UChar fourth_byte,
1624 UChar fifth_byte,
1625 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001626{
1627 VG_(new_emit)(True, uses_sflags, sets_sflags);
1628 VG_(emitB) ( first_byte );
1629 VG_(emitB) ( second_byte );
1630 VG_(emitB) ( third_byte );
1631 fourth_byte &= 0xC7; /* mask out reg field */
1632 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1633 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1634 VG_(emitB) ( fourth_byte );
1635 VG_(emitB) ( fifth_byte );
1636 if (dis)
1637 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001638 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001639 (UInt)first_byte, (UInt)second_byte,
1640 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1641 nameIReg(4,ireg)
1642 );
1643}
1644
sewardjabf8bf82003-06-15 22:28:05 +00001645static void emit_SSE3g ( FlagSet uses_sflags,
1646 FlagSet sets_sflags,
1647 UChar first_byte,
1648 UChar second_byte,
1649 UChar third_byte,
1650 UChar fourth_byte,
1651 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001652{
1653 VG_(new_emit)(True, uses_sflags, sets_sflags);
1654 VG_(emitB) ( first_byte );
1655 VG_(emitB) ( second_byte );
1656 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001657 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001658 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001659 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001660 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001661 if (dis)
1662 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001663 "\n\t\tsse3g--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001664 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001665 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001666 nameIReg(4,ireg)
1667 );
1668}
1669
sewardj77d30a22003-10-19 08:18:52 +00001670static void emit_SSE3a1 ( FlagSet uses_sflags,
1671 FlagSet sets_sflags,
1672 UChar first_byte,
1673 UChar second_byte,
1674 UChar third_byte,
1675 UChar fourth_byte,
1676 UChar fifth_byte,
1677 Int ireg )
1678{
1679 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001680
1681 boundscheck();
1682
sewardj77d30a22003-10-19 08:18:52 +00001683 VG_(emitB) ( first_byte );
1684 VG_(emitB) ( second_byte );
1685 VG_(emitB) ( third_byte );
1686 fourth_byte &= 0x38; /* mask out mod and rm fields */
1687 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1688 VG_(emitB) ( fifth_byte );
1689 if (dis)
1690 VG_(printf)("\n\t\tsse3a1-0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1691 (UInt)first_byte, (UInt)second_byte,
1692 (UInt)third_byte, (UInt)fourth_byte,
1693 (UInt)fifth_byte,
1694 nameIReg(4,ireg) );
1695}
1696
sewardjfebaa3b2003-05-25 01:07:34 +00001697static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001698 FlagSet sets_sflags,
1699 UChar first_byte,
1700 UChar second_byte,
1701 UChar third_byte,
1702 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001703{
1704 VG_(new_emit)(True, uses_sflags, sets_sflags);
1705 VG_(emitB) ( first_byte );
1706 VG_(emitB) ( second_byte );
1707 VG_(emitB) ( third_byte );
1708 VG_(emitB) ( fourth_byte );
1709 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001710 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001711 (UInt)first_byte, (UInt)second_byte,
1712 (UInt)third_byte, (UInt)fourth_byte );
1713}
1714
sewardja453fb02003-06-14 13:22:36 +00001715static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001716 FlagSet sets_sflags,
1717 UChar first_byte,
1718 UChar second_byte,
1719 UChar third_byte,
1720 UChar fourth_byte,
1721 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001722{
1723 VG_(new_emit)(True, uses_sflags, sets_sflags);
1724 VG_(emitB) ( first_byte );
1725 VG_(emitB) ( second_byte );
1726 VG_(emitB) ( third_byte );
1727 VG_(emitB) ( fourth_byte );
1728 VG_(emitB) ( fifth_byte );
1729 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001730 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001731 (UInt)first_byte, (UInt)second_byte,
1732 (UInt)third_byte, (UInt)fourth_byte,
1733 (UInt)fifth_byte );
1734}
1735
sewardja60be0e2003-05-26 08:47:27 +00001736static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001737 FlagSet sets_sflags,
1738 UChar first_byte,
1739 UChar second_byte,
1740 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001741{
1742 VG_(new_emit)(True, uses_sflags, sets_sflags);
1743 VG_(emitB) ( first_byte );
1744 VG_(emitB) ( second_byte );
1745 VG_(emitB) ( third_byte );
1746 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001747 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001748 (UInt)first_byte, (UInt)second_byte,
1749 (UInt)third_byte );
1750}
1751
sewardje3891fa2003-06-15 03:13:48 +00001752static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1753 FlagSet sets_sflags,
1754 UChar first_byte,
1755 UChar second_byte,
1756 UChar third_byte,
1757 Int addr_reg,
1758 Int dest_reg )
1759{
1760 VG_(new_emit)(True, uses_sflags, sets_sflags);
1761 VG_(emitB) ( first_byte );
1762 VG_(emitB) ( second_byte );
1763 VG_(emitB) ( third_byte );
1764 /* 4th byte can be completely synthesised from addr_reg and
1765 dest_reg. */
1766 emit_amode_regmem_reg ( addr_reg, dest_reg );
1767 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001768 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 +00001769 (UInt)first_byte, (UInt)second_byte,
1770 (UInt)third_byte, nameIReg(4, addr_reg),
1771 nameIReg(4, dest_reg));
1772}
1773
sewardjca860012003-03-27 23:52:58 +00001774static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1775 FlagSet sets_sflags,
1776 UChar first_byte,
1777 UChar second_byte,
1778 Int ireg )
1779{
1780 VG_(new_emit)(True, uses_sflags, sets_sflags);
1781 VG_(emitB) ( 0x0F );
1782 VG_(emitB) ( first_byte );
1783 second_byte &= 0x38; /* mask out mod and rm fields */
1784 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1785 second_byte |= (ireg & 7); /* patch in our ireg */
1786 VG_(emitB) ( second_byte );
1787 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001788 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1789 (UInt)first_byte, (UInt)second_byte,
1790 nameIReg(4,ireg) );
1791}
1792
1793static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1794 FlagSet sets_sflags,
1795 UChar first_byte,
1796 UChar second_byte,
1797 Int ireg )
1798{
1799 VG_(new_emit)(True, uses_sflags, sets_sflags);
1800 VG_(emitB) ( 0x0F );
1801 VG_(emitB) ( first_byte );
1802 second_byte &= 0x38; /* mask out mod and rm fields */
1803 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1804 second_byte |= (ireg & 7); /* patch in our ireg */
1805 VG_(emitB) ( second_byte );
1806 if (dis)
1807 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001808 (UInt)first_byte, (UInt)second_byte,
1809 nameIReg(4,ireg) );
1810}
1811
1812static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1813 FlagSet sets_sflags,
1814 UChar first_byte,
1815 UChar second_byte,
1816 UChar third_byte )
1817{
1818 VG_(new_emit)(True, uses_sflags, sets_sflags);
1819 VG_(emitB) ( 0x0F );
1820 VG_(emitB) ( first_byte );
1821 VG_(emitB) ( second_byte );
1822 VG_(emitB) ( third_byte );
1823 if (dis)
1824 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1825 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1826}
1827
sewardj3d7c9c82003-03-26 21:08:13 +00001828static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1829 FlagSet sets_sflags,
1830 UChar first_byte,
1831 UChar second_byte )
1832{
1833 VG_(new_emit)(True, uses_sflags, sets_sflags);
1834 VG_(emitB) ( 0x0F );
1835 VG_(emitB) ( first_byte );
1836 VG_(emitB) ( second_byte );
1837 if (dis)
1838 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1839 (UInt)first_byte, (UInt)second_byte );
1840}
1841
1842static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1843 FlagSet sets_sflags,
1844 UChar first_byte )
1845{
1846 VG_(new_emit)(True, uses_sflags, sets_sflags);
1847 VG_(emitB) ( 0x0F );
1848 VG_(emitB) ( first_byte );
1849 if (dis)
1850 VG_(printf)("\n\t\tmmx1-0x%x\n",
1851 (UInt)first_byte );
1852}
1853
sewardjde4a1d02002-03-22 01:27:54 +00001854
1855/*----------------------------------------------------*/
1856/*--- misc instruction emitters ---*/
1857/*----------------------------------------------------*/
1858
njn25e49d8e72002-09-23 09:36:25 +00001859void VG_(emit_call_reg) ( Int reg )
1860{
sewardjfa492d42002-12-08 18:20:01 +00001861 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001862 VG_(emitB) ( 0xFF ); /* Grp5 */
1863 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1864 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001865 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001866}
1867
sewardjf0f12aa2002-12-28 00:04:08 +00001868static
1869void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1870 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001871{
sewardjfa492d42002-12-08 18:20:01 +00001872 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001873 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001874
1875 if (byte_off < -128 || byte_off > 127) {
1876 VG_(emitB) ( 0xFF );
1877 VG_(emitB) ( 0x95 );
1878 VG_(emitL) ( byte_off );
1879 } else {
1880 VG_(emitB) ( 0xFF );
1881 VG_(emitB) ( 0x55 );
1882 VG_(emitB) ( byte_off );
1883 }
1884 if (dis)
1885 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001886}
1887
sewardja2c5a732002-12-15 03:10:42 +00001888#if 0
1889/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001890static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1891{
1892 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001893 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001894 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1895 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001896 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001897 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001898 if (dis)
1899 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1900 nameIReg(4,regmem));
1901}
sewardja2c5a732002-12-15 03:10:42 +00001902#endif
sewardjde4a1d02002-03-22 01:27:54 +00001903
njn25e49d8e72002-09-23 09:36:25 +00001904void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001905{
njne427a662002-10-02 11:08:25 +00001906 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001907 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1908 VG_(emitB) ( 0x8D );
1909 VG_(emitB) ( 0x64 );
1910 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001911 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001912 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001913 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001914}
1915
1916
1917static void emit_movb_AL_zeroESPmem ( void )
1918{
1919 /* movb %al, 0(%esp) */
1920 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001921 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001922 VG_(emitB) ( 0x88 );
1923 VG_(emitB) ( 0x44 );
1924 VG_(emitB) ( 0x24 );
1925 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001926 if (dis)
1927 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1928}
1929
1930static void emit_movb_zeroESPmem_AL ( void )
1931{
1932 /* movb 0(%esp), %al */
1933 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001934 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001935 VG_(emitB) ( 0x8A );
1936 VG_(emitB) ( 0x44 );
1937 VG_(emitB) ( 0x24 );
1938 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001939 if (dis)
1940 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1941}
1942
sewardja2113f92002-12-12 23:42:48 +00001943/* Jump target states */
1944#define TGT_UNDEF (1 << 16)
1945#define TGT_FORWARD (2 << 16)
1946#define TGT_BACKWARD (3 << 16)
1947
1948static inline Int tgt_state(Int tgt)
1949{
1950 return tgt & 0xffff0000;
1951}
1952
1953static inline Int tgt_addr(Int tgt)
1954{
1955 return tgt & 0x0000ffff;
1956}
1957
1958static inline Int mk_tgt(Int state, Int addr)
1959{
fitzhardinge462f4f92003-12-18 02:10:54 +00001960 vg_assert(state == TGT_UNDEF ||
1961 state == TGT_FORWARD ||
1962 state == TGT_BACKWARD);
sewardja2113f92002-12-12 23:42:48 +00001963 vg_assert((addr & 0xffff0000) == 0);
1964
1965 return state | addr;
1966}
1967
1968void VG_(init_target) ( Int *tgt )
1969{
1970 *tgt = TGT_UNDEF;
1971}
1972
1973void VG_(target_back) ( Int *tgt )
1974{
1975 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1976
1977 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1978}
1979
1980void VG_(target_forward) ( Int *tgt )
1981{
1982 Int delta;
1983
1984 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1985 tgt_state(*tgt) == TGT_UNDEF);
1986
1987 if (tgt_state(*tgt) == TGT_UNDEF)
1988 return; /* target not used */
1989
1990 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1991 vg_assert(delta >= -128 && delta <= 127);
1992 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001993 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001994 emitted_code[tgt_addr(*tgt)] = delta;
1995 if (dis)
1996 VG_(printf)("(target to jump site %d; delta: %d)\n",
1997 tgt_addr(*tgt), delta);
1998}
1999
2000void VG_(emit_target_delta) ( Int *tgt )
2001{
2002 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
2003 tgt_state(*tgt) == TGT_BACKWARD);
2004
2005 if (tgt_state(*tgt) == TGT_UNDEF) {
2006 /* forward jump */
2007 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
2008 VG_(emitB) (0x00);
2009 } else {
2010 /* backward jump */
2011 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
2012 vg_assert(delta >= -128 && delta <= 127);
2013 VG_(emitB) (delta);
2014 }
2015}
2016
sewardjde4a1d02002-03-22 01:27:54 +00002017
2018/* Emit a jump short with an 8-bit signed offset. Note that the
2019 offset is that which should be added to %eip once %eip has been
2020 advanced over this insn. */
fitzhardinge462f4f92003-12-18 02:10:54 +00002021void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta, JumpPred pred )
sewardjde4a1d02002-03-22 01:27:54 +00002022{
2023 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00002024 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002025
2026 if (VG_(clo_branchpred) &&
2027 pred != JP_NONE &&
2028 pred != static_pred(cond, delta > 0))
2029 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2030
njn25e49d8e72002-09-23 09:36:25 +00002031 VG_(emitB) ( 0x70 + (UInt)cond );
2032 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00002033 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002034 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+%d\n",
2035 VG_(name_UCondcode)(cond), predstr(pred), delta );
sewardjde4a1d02002-03-22 01:27:54 +00002036}
2037
sewardja2113f92002-12-12 23:42:48 +00002038/* Same as above, but defers emitting the delta */
fitzhardinge462f4f92003-12-18 02:10:54 +00002039void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt, JumpPred pred )
sewardja2113f92002-12-12 23:42:48 +00002040{
sewardj706240d2002-12-26 17:10:12 +00002041 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002042
2043 if (VG_(clo_branchpred) &&
2044 pred != JP_NONE &&
2045 pred != static_pred(cond, tgt_state(*tgt) != TGT_BACKWARD))
2046 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2047
sewardja2113f92002-12-12 23:42:48 +00002048 VG_(emitB) ( 0x70 + (UInt)cond );
2049 VG_(emit_target_delta) (tgt);
2050 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002051 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+(%d)\n",
2052 VG_(name_UCondcode)(cond), predstr(pred), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00002053}
2054
2055
2056
sewardjf0f12aa2002-12-28 00:04:08 +00002057static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002058{
sewardjf0f12aa2002-12-28 00:04:08 +00002059 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002060 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
2061 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00002062 if (dis)
2063 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00002064 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00002065}
2066
2067static void emit_ret ( void )
2068{
sewardjfa492d42002-12-08 18:20:01 +00002069 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00002070 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002071 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00002072 if (dis)
2073 VG_(printf)("\n\t\tret\n");
2074}
2075
sewardj22854b92002-11-30 14:00:47 +00002076/* Predicate used in sanity checks elsewhere - returns true if any
2077 jump-site is an actual chained jump */
2078Bool VG_(is_chained_jumpsite)(Addr a)
2079{
2080 UChar *cp = (UChar *)a;
2081
2082 return (*cp == 0xE9); /* 0xE9 -- jmp */
2083}
2084
sewardj83f11862002-12-01 02:07:08 +00002085static
2086Bool is_fresh_jumpsite(UChar *cp)
2087{
2088 return
2089 cp[0] == 0x0F && /* UD2 */
2090 cp[1] == 0x0B &&
2091 cp[2] == 0x0F && /* UD2 */
2092 cp[3] == 0x0B &&
2093 cp[4] == 0x90; /* NOP */
2094}
2095
sewardj22854b92002-11-30 14:00:47 +00002096/* Predicate used in sanity checks elsewhere - returns true if all
2097 jump-sites are calls to VG_(patch_me) */
2098Bool VG_(is_unchained_jumpsite)(Addr a)
2099{
2100 UChar *cp = (UChar *)a;
2101 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2102 Int idelta;
2103
2104 if (*cp++ != 0xE8) /* 0xE8 == call */
2105 return False;
2106
2107 idelta = (*cp++) << 0;
2108 idelta |= (*cp++) << 8;
2109 idelta |= (*cp++) << 16;
2110 idelta |= (*cp++) << 24;
2111
2112 return idelta == delta;
2113}
2114
2115/* Return target address for a direct jmp */
2116Addr VG_(get_jmp_dest)(Addr a)
2117{
2118 Int delta;
2119 UChar *cp = (UChar *)a;
2120
2121 if (*cp++ != 0xE9) /* 0xE9 == jmp */
2122 return 0;
2123
2124 delta = (*cp++) << 0;
2125 delta |= (*cp++) << 8;
2126 delta |= (*cp++) << 16;
2127 delta |= (*cp++) << 24;
2128
2129 return a + VG_PATCHME_JMPSZ + delta;
2130}
2131
2132/* unchain a BB by generating a call to VG_(patch_me) */
2133void VG_(unchain_jumpsite)(Addr a)
2134{
2135 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2136 UChar *cp = (UChar *)a;
2137
2138 if (VG_(is_unchained_jumpsite)(a))
2139 return; /* don't write unnecessarily */
2140
sewardj83f11862002-12-01 02:07:08 +00002141 if (!is_fresh_jumpsite(cp))
2142 VG_(bb_dechain_count)++; /* update stats */
2143
sewardj22854b92002-11-30 14:00:47 +00002144 *cp++ = 0xE8; /* call */
2145 *cp++ = (delta >> 0) & 0xff;
2146 *cp++ = (delta >> 8) & 0xff;
2147 *cp++ = (delta >> 16) & 0xff;
2148 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002149}
2150
2151/* This doesn't actually generate a call to VG_(patch_me), but
2152 reserves enough space in the instruction stream for it to happen
2153 and records the offset into the jump table. This is because call
2154 is a relative jump, and so will be affected when this code gets
2155 moved about. The translation table will "unchain" this basic block
2156 on insertion (with VG_(unchain_BB)()), and thereby generate a
2157 proper call instruction. */
2158static void emit_call_patchme( void )
2159{
2160 vg_assert(VG_PATCHME_CALLSZ == 5);
2161
sewardjfa492d42002-12-08 18:20:01 +00002162 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002163 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002164
2165 if (jumpidx >= VG_MAX_JUMPS) {
2166 /* If there too many jumps in this basic block, fall back to
2167 dispatch loop. We still need to keep it the same size as the
2168 call sequence. */
2169 VG_(emitB) ( 0xC3 ); /* ret */
fitzhardinge98abfc72003-12-16 02:05:15 +00002170 VG_(emitB) ( 0x8d ); /* 4 byte nop (lea 0x0(%esi,1),%esi) */
2171 VG_(emitB) ( 0x74 );
2172 VG_(emitB) ( 0x26 );
2173 VG_(emitB) ( 0x00 );
sewardj22854b92002-11-30 14:00:47 +00002174
2175 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002176 VG_(printf)("\n\t\tret; nop4\n");
sewardj22854b92002-11-30 14:00:47 +00002177
2178 if (0 && VG_(clo_verbosity))
2179 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2180 } else {
2181 jumps[jumpidx++] = emitted_code_used;
2182
2183 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2184 VG_(emitB) ( 0x0B );
2185 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2186 VG_(emitB) ( 0x0B );
2187 VG_(emitB) ( 0x90 ); /* NOP */
2188
2189 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002190 VG_(printf)("\n\t\tud2; ud2; nop /* call VG_(patchme) */\n");
sewardj22854b92002-11-30 14:00:47 +00002191 }
2192}
2193
njn25e49d8e72002-09-23 09:36:25 +00002194void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002195{
sewardjf0f12aa2002-12-28 00:04:08 +00002196 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002197 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002198 if (dis)
2199 VG_(printf)("\n\t\tpushal\n");
2200}
2201
njn25e49d8e72002-09-23 09:36:25 +00002202void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002203{
sewardjf0f12aa2002-12-28 00:04:08 +00002204 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002205 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002206 if (dis)
2207 VG_(printf)("\n\t\tpopal\n");
2208}
2209
2210static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2211{
sewardjf0f12aa2002-12-28 00:04:08 +00002212 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002213 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2214 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002215 if (dis)
2216 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2217 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2218}
2219
2220static void emit_lea_sib_reg ( UInt lit, Int scale,
2221 Int regbase, Int regindex, Int reg )
2222{
sewardjf0f12aa2002-12-28 00:04:08 +00002223 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002224 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002225 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2226 if (dis)
2227 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2228 lit, nameIReg(4,regbase),
2229 nameIReg(4,regindex), scale,
2230 nameIReg(4,reg) );
2231}
2232
njn25e49d8e72002-09-23 09:36:25 +00002233void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002234{
sewardjf0f12aa2002-12-28 00:04:08 +00002235 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002236 VG_(emitB) ( 0x0F );
2237 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002238 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2239 if (dis)
2240 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2241}
2242
2243/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002244/*--- Helper offset -> addr translation ---*/
2245/*----------------------------------------------------*/
2246
2247/* Finds the baseBlock offset of a skin-specified helper.
2248 * Searches through compacts first, then non-compacts. */
2249Int VG_(helper_offset)(Addr a)
2250{
sewardj05bcdcb2003-05-18 10:05:38 +00002251 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002252 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002253
2254 for (i = 0; i < VG_(n_compact_helpers); i++)
2255 if (VG_(compact_helper_addrs)[i] == a)
2256 return VG_(compact_helper_offsets)[i];
2257 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2258 if (VG_(noncompact_helper_addrs)[i] == a)
2259 return VG_(noncompact_helper_offsets)[i];
2260
2261 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002262 VG_(get_fnname) ( a, buf, 100 );
2263
njn25e49d8e72002-09-23 09:36:25 +00002264 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002265 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2266 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002267
2268 VG_(printf)(" compact helpers: ");
2269 for (i = 0; i < VG_(n_compact_helpers); i++)
2270 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2271
2272 VG_(printf)("\n non-compact helpers: ");
2273 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2274 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2275
2276 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002277 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002278}
2279
2280/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002281/*--- Instruction synthesisers ---*/
2282/*----------------------------------------------------*/
2283
2284static Condcode invertCondition ( Condcode cond )
2285{
2286 return (Condcode)(1 ^ (UInt)cond);
2287}
2288
2289
2290/* Synthesise a call to *baseBlock[offset], ie,
2291 call * (4 x offset)(%ebp).
2292*/
sewardjfa492d42002-12-08 18:20:01 +00002293void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002294 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002295{
2296 vg_assert(word_offset >= 0);
2297 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002298 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002299 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002300 }
sewardjf0f12aa2002-12-28 00:04:08 +00002301 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002302}
2303
njn25e49d8e72002-09-23 09:36:25 +00002304static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002305{
njn25e49d8e72002-09-23 09:36:25 +00002306 if (src != dst) {
2307 VG_(emit_movv_reg_reg) ( 4, src, dst );
2308 ccall_arg_setup_instrs++;
2309 }
njn6431be72002-07-28 09:53:34 +00002310}
njn25e49d8e72002-09-23 09:36:25 +00002311
2312/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2313static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2314{
2315 if (RealReg == tag) {
2316 maybe_emit_movl_reg_reg ( litOrReg, reg );
2317 } else if (Literal == tag) {
2318 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2319 ccall_arg_setup_instrs++;
2320 }
2321 else
njne427a662002-10-02 11:08:25 +00002322 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002323}
2324
2325static
2326void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2327{
2328 if (R_EAX == reg1) {
2329 VG_(emit_swapl_reg_EAX) ( reg2 );
2330 } else if (R_EAX == reg2) {
2331 VG_(emit_swapl_reg_EAX) ( reg1 );
2332 } else {
2333 emit_swapl_reg_reg ( reg1, reg2 );
2334 }
2335 ccall_arg_setup_instrs++;
2336}
2337
2338static
2339void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2340{
2341 if (dst1 != src2) {
2342 maybe_emit_movl_reg_reg ( src1, dst1 );
2343 maybe_emit_movl_reg_reg ( src2, dst2 );
2344
2345 } else if (dst2 != src1) {
2346 maybe_emit_movl_reg_reg ( src2, dst2 );
2347 maybe_emit_movl_reg_reg ( src1, dst1 );
2348
2349 } else {
2350 /* swap to break cycle */
2351 emit_swapl_arg_regs ( dst1, dst2 );
2352 }
2353}
2354
2355static
2356void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2357 UInt dst1, UInt dst2, UInt dst3)
2358{
2359 if (dst1 != src2 && dst1 != src3) {
2360 maybe_emit_movl_reg_reg ( src1, dst1 );
2361 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2362
2363 } else if (dst2 != src1 && dst2 != src3) {
2364 maybe_emit_movl_reg_reg ( src2, dst2 );
2365 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2366
2367 } else if (dst3 != src1 && dst3 != src2) {
2368 maybe_emit_movl_reg_reg ( src3, dst3 );
2369 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2370
2371 } else {
2372 /* break cycle */
2373 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2374 emit_swapl_arg_regs ( dst1, dst2 );
2375 emit_swapl_arg_regs ( dst1, dst3 );
2376
2377 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2378 emit_swapl_arg_regs ( dst1, dst3 );
2379 emit_swapl_arg_regs ( dst1, dst2 );
2380
2381 } else {
njne427a662002-10-02 11:08:25 +00002382 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002383 }
2384 }
2385}
2386
2387static
2388void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2389 UInt src1, UInt src2,
2390 UInt dst1, UInt dst2)
2391{
2392 /* If either are lits, order doesn't matter */
2393 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2394 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2395 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2396
2397 } else {
2398 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2399 }
2400}
2401
2402static
2403void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2404 UInt src1, UInt src2, UInt src3,
2405 UInt dst1, UInt dst2, UInt dst3)
2406{
2407 // SSS: fix this eventually -- make STOREV use two RealRegs?
2408 /* Not supporting literals for 3-arg C functions -- they're only used
2409 by STOREV which has 2 args */
2410 vg_assert(RealReg == tagv[src1] &&
2411 RealReg == tagv[src2] &&
2412 RealReg == tagv[src3]);
2413 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2414 dst1, dst2, dst3 );
2415}
2416
2417/* Synthesise a call to a C function `fn' (which must be registered in
2418 baseBlock) doing all the reg saving and arg handling work.
2419
2420 WARNING: a UInstr should *not* be translated with synth_ccall followed
2421 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2422 such behaviour and everything will fall over.
2423 */
2424void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2425 Tag tagv[], Int ret_reg,
2426 RRegSet regs_live_before, RRegSet regs_live_after )
2427{
2428 Int i;
2429 Int stack_used = 0;
2430 Bool preserve_eax, preserve_ecx, preserve_edx;
2431
2432 vg_assert(0 <= regparms_n && regparms_n <= 3);
2433
2434 ccalls++;
2435
2436 /* If %e[acd]x is live before and after the C call, save/restore it.
2437 Unless the return values clobbers the reg; in this case we must not
2438 save/restore the reg, because the restore would clobber the return
2439 value. (Before and after the UInstr really constitute separate live
2440 ranges, but you miss this if you don't consider what happens during
2441 the UInstr.) */
2442# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002443 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2444 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002445 ret_reg != realReg)
2446
2447 preserve_eax = PRESERVE_REG(R_EAX);
2448 preserve_ecx = PRESERVE_REG(R_ECX);
2449 preserve_edx = PRESERVE_REG(R_EDX);
2450
2451# undef PRESERVE_REG
2452
2453 /* Save caller-save regs as required */
2454 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2455 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2456 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2457
2458 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2459 is the number of args passed in regs (maximum 3 for GCC on x86). */
2460
2461 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002462
njn25e49d8e72002-09-23 09:36:25 +00002463 /* First push stack args (RealRegs or Literals) in reverse order. */
2464 for (i = argc-1; i >= regparms_n; i--) {
2465 switch (tagv[i]) {
2466 case RealReg:
2467 VG_(emit_pushv_reg) ( 4, argv[i] );
2468 break;
2469 case Literal:
2470 /* Use short form of pushl if possible. */
2471 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2472 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2473 else
2474 VG_(emit_pushl_lit32)( argv[i] );
2475 break;
2476 default:
2477 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002478 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002479 }
2480 stack_used += 4;
2481 ccall_arg_setup_instrs++;
2482 }
njn6431be72002-07-28 09:53:34 +00002483
njn25e49d8e72002-09-23 09:36:25 +00002484 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2485 If moving values between registers, be careful not to clobber any on
2486 the way. Happily we can use xchgl to swap registers.
2487 */
2488 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002489
njn25e49d8e72002-09-23 09:36:25 +00002490 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2491 case 3:
2492 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2493 R_EAX, R_EDX, R_ECX );
2494 break;
njn6431be72002-07-28 09:53:34 +00002495
njn25e49d8e72002-09-23 09:36:25 +00002496 /* Less-tricky. Args passed in %eax and %edx. */
2497 case 2:
2498 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2499 break;
2500
2501 /* Easy. Just move arg1 into %eax (if not already in there). */
2502 case 1:
2503 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2504 break;
2505
2506 case 0:
2507 break;
2508
2509 default:
njne427a662002-10-02 11:08:25 +00002510 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002511 }
2512
sewardjfa492d42002-12-08 18:20:01 +00002513 /* Call the function - may trash all flags */
2514 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002515
2516 /* Clear any args from stack */
2517 if (0 != stack_used) {
2518 VG_(emit_add_lit_to_esp) ( stack_used );
2519 ccall_stack_clears++;
2520 }
2521
2522 /* Move return value into ret_reg if necessary and not already there */
2523 if (INVALID_REALREG != ret_reg) {
2524 ccall_retvals++;
2525 if (R_EAX != ret_reg) {
2526 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2527 ccall_retval_movs++;
2528 }
2529 }
2530
2531 /* Restore live caller-save regs as required */
2532 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2533 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2534 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002535}
sewardjde4a1d02002-03-22 01:27:54 +00002536
sewardj2e93c502002-04-12 11:12:52 +00002537static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002538{
sewardj2e93c502002-04-12 11:12:52 +00002539 switch (jmpkind) {
2540 case JmpBoring:
2541 break;
sewardj2e93c502002-04-12 11:12:52 +00002542 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002543 break;
2544 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002545 break;
2546 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002547 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002548 break;
2549 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002550 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002551 break;
2552 default:
njne427a662002-10-02 11:08:25 +00002553 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002554 }
2555}
2556
2557/* Jump to the next translation, by loading its original addr into
2558 %eax and returning to the scheduler. Signal special requirements
2559 by loading a special value into %ebp first.
2560*/
2561static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2562{
sewardjfa492d42002-12-08 18:20:01 +00002563 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002564 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002565 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002566 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002567 emit_ret();
2568}
2569
sewardj22854b92002-11-30 14:00:47 +00002570static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002571
2572/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002573static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002574{
sewardjfa492d42002-12-08 18:20:01 +00002575 maybe_emit_put_eflags(); /* save flags here */
2576
njn25e49d8e72002-09-23 09:36:25 +00002577 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002578
2579 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2580 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2581 emit_call_patchme();
2582 } else {
2583 load_ebp_from_JmpKind ( jmpkind );
2584 emit_ret();
2585 }
sewardjde4a1d02002-03-22 01:27:54 +00002586}
2587
2588
sewardj2370f3b2002-11-30 15:01:01 +00002589static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002590static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002591 Opcode opcode, Int size,
2592 UInt lit, Int reg );
2593
sewardjfa492d42002-12-08 18:20:01 +00002594static void synth_jcond_lit ( Condcode cond,
2595 Addr addr,
2596 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002597{
sewardj2370f3b2002-11-30 15:01:01 +00002598 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002599 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002600 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002601
sewardja2113f92002-12-12 23:42:48 +00002602 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002603 VG_(init_target)(&tgt2);
2604 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002605
sewardjfa492d42002-12-08 18:20:01 +00002606 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2607 if need be */
2608 maybe_emit_put_eflags();
2609 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2610
2611 if (eflags_state == UPD_Both) {
2612 /* The flags are already set up, so we just use them as is. */
2613 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002614 cond = invertCondition(cond);
2615 } else {
sewardj75f04932002-12-12 23:13:21 +00002616 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002617
2618 /* The simd state contains the most recent version, so we emit a
2619 sequence to calculate the relevant condition directly out of
2620 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2621 copying them back to the real flags via popf. Notice that
2622 some of these sequences trash %eax, but that should be free
2623 now since this is the end of a bb and therefore all regs are
2624 dead. */
2625 simd = False;
2626
2627 switch (cond) {
2628
sewardjbb6c1182002-12-12 23:54:47 +00002629 case CondLE: /* Z || S != O -> S || !P */
2630 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002631 vg_assert(eax_trashable);
2632
2633 VG_(emit_movv_offregmem_reg)
2634 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2635 /* eax == %EFLAGS */
2636
sewardjbb6c1182002-12-12 23:54:47 +00002637 VG_(emit_nonshiftopv_lit_reg)
2638 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2639 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002640
sewardjbb6c1182002-12-12 23:54:47 +00002641 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2642 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002643
sewardj09736622002-12-28 00:19:00 +00002644 /* actually set the real cpu flags, since ROR changes
2645 neither P nor Z */
2646 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2647
sewardjbb6c1182002-12-12 23:54:47 +00002648 if (cond == CondLE) {
2649 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002650 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002651 /* test OF != SF */
2652 cond = CondP;
2653 } else {
2654 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002655 VG_(emit_jcondshort_target)(False, CondS, &tgt2, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002656 /* test OF == SF */
2657 cond = CondNP;
2658 }
sewardj2370f3b2002-11-30 15:01:01 +00002659 break;
2660
sewardjfa492d42002-12-08 18:20:01 +00002661 case CondL:
2662 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002663 vg_assert(eax_trashable);
2664
2665 VG_(emit_movv_offregmem_reg)
2666 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2667 /* eax == %EFLAGS */
2668
sewardj75f04932002-12-12 23:13:21 +00002669 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2670 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002671
sewardj75f04932002-12-12 23:13:21 +00002672 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2673 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002674
sewardj09736622002-12-28 00:19:00 +00002675 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002676 if (cond == CondL) cond = CondP; else cond = CondNP;
2677 break;
sewardjfa492d42002-12-08 18:20:01 +00002678
2679 case CondB:
2680 case CondNB:
2681 mask = EFlagC; goto simple; /* C=1 */
2682
2683 case CondZ:
2684 case CondNZ:
2685 mask = EFlagZ; goto simple; /* Z=1 */
2686
2687 case CondBE:
2688 case CondNBE:
2689 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2690
2691 case CondS:
2692 case CondNS:
2693 mask = EFlagS; goto simple; /* S=1 */
2694
2695 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002696 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002697 mask = EFlagP; goto simple; /* P=1 */
2698
sewardj39542072002-12-09 22:44:00 +00002699 case CondO:
2700 case CondNO:
2701 mask = EFlagO; goto simple; /* O=1 */
2702
sewardjfa492d42002-12-08 18:20:01 +00002703 default:
2704 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002705 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002706 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2707
2708 simple:
2709 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002710 if ((mask & 0xff) == mask) {
2711 VG_(emitB) ( 0xF6 ); /* Grp3 */
2712 VG_(emit_amode_offregmem_reg)(
2713 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2714 VG_(emitB) (mask);
2715 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002716 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002717 mask, VGOFF_(m_eflags) * 4);
2718 } else {
sewardjfa492d42002-12-08 18:20:01 +00002719 /* all cond codes are in lower 16 bits */
2720 vg_assert((mask & 0xffff) == mask);
2721
2722 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002723 VG_(emitB) ( 0xF7 );
2724 VG_(emit_amode_offregmem_reg)(
2725 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002726 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002727 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002728 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002729 mask, VGOFF_(m_eflags) * 4);
2730 }
2731
sewardj75f04932002-12-12 23:13:21 +00002732 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002733 break;
2734 }
2735 }
2736
fitzhardinge462f4f92003-12-18 02:10:54 +00002737 VG_(emit_jcondshort_target) ( simd, cond, &tgt, JP_NONE );
sewardjbb6c1182002-12-12 23:54:47 +00002738
2739 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002740 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002741
2742 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002743 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002744}
2745
2746
sewardj2370f3b2002-11-30 15:01:01 +00002747
sewardjde4a1d02002-03-22 01:27:54 +00002748static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2749{
sewardja2113f92002-12-12 23:42:48 +00002750 Int tgt;
2751
2752 VG_(init_target)(&tgt);
2753
sewardjfa492d42002-12-08 18:20:01 +00002754 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002755
fitzhardinge462f4f92003-12-18 02:10:54 +00002756 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt, JP_NONE );
sewardj2e93c502002-04-12 11:12:52 +00002757 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002758
2759 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002760}
2761
2762
2763static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2764{
2765 /* Load the zero-extended literal into reg, at size l,
2766 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002767 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002768}
2769
2770
2771static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2772{
fitzhardinge98abfc72003-12-16 02:05:15 +00002773 switch (size & ~DO_BOUNDSCHECK) {
2774 case 4: emit_movv_regmem_reg ( size, reg1, reg2 ); break;
2775 case 2: VG_(emit_movzwl_regmem_reg) ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
2776 case 1: emit_movzbl_regmem_reg ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002777 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002778 }
2779}
2780
2781
2782static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2783{
fitzhardinge98abfc72003-12-16 02:05:15 +00002784 switch (size & ~DO_BOUNDSCHECK) {
njn25e49d8e72002-09-23 09:36:25 +00002785 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
fitzhardinge98abfc72003-12-16 02:05:15 +00002786 case 2: VG_(emit_movzwl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
2787 case 1: VG_(emit_movzbl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002788 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002789 }
2790}
2791
2792
2793static void synth_mov_reg_offregmem ( Int size, Int reg,
2794 Int off, Int areg )
2795{
2796 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002797 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2798 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002799 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002800 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002801 }
2802 else {
njn25e49d8e72002-09-23 09:36:25 +00002803 VG_(emit_swapl_reg_EAX) ( reg );
2804 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2805 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002806 }
2807 break;
njne427a662002-10-02 11:08:25 +00002808 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002809 }
2810}
2811
2812
2813static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2814{
2815 Int s1;
fitzhardinge98abfc72003-12-16 02:05:15 +00002816 switch (size & ~DO_BOUNDSCHECK) {
2817 case 4:
2818 case 2: emit_movv_reg_regmem ( size, reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002819 case 1: if (reg1 < 4) {
fitzhardinge98abfc72003-12-16 02:05:15 +00002820 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002821 }
2822 else {
2823 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2824 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2825 emit_swapl_reg_reg ( s1, reg1 );
fitzhardinge98abfc72003-12-16 02:05:15 +00002826 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, s1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002827 emit_swapl_reg_reg ( s1, reg1 );
2828 }
2829 break;
njne427a662002-10-02 11:08:25 +00002830 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002831 }
2832}
2833
2834
sewardjf0f12aa2002-12-28 00:04:08 +00002835static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002836 Opcode opcode, Int size,
2837 Int reg )
2838{
2839 /* NB! opcode is a uinstr opcode, not an x86 one! */
2840 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002841 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002842 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002843 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002844 break;
2845 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002846 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002847 } else {
njn25e49d8e72002-09-23 09:36:25 +00002848 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002849 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002850 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002851 }
2852 break;
njne427a662002-10-02 11:08:25 +00002853 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002854 }
2855}
2856
2857
2858
sewardjf0f12aa2002-12-28 00:04:08 +00002859static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002860 Opcode opcode, Int size,
2861 Int reg1, Int reg2 )
2862{
2863 /* NB! opcode is a uinstr opcode, not an x86 one! */
2864 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002865 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002866 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002867 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002868 break;
2869 case 1: { /* Horrible ... */
2870 Int s1, s2;
2871 /* Choose s1 and s2 to be x86 regs which we can talk about the
2872 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2873 sure s1 != s2 and that neither of them equal either reg1 or
2874 reg2. Then use them as temporaries to make things work. */
2875 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002876 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002877 break;
2878 }
2879 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2880 if (reg1 >= 4 && reg2 < 4) {
2881 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002882 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002883 emit_swapl_reg_reg ( reg1, s1 );
2884 break;
2885 }
2886 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2887 if (reg1 < 4 && reg2 >= 4) {
2888 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002889 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002890 emit_swapl_reg_reg ( reg2, s2 );
2891 break;
2892 }
2893 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2894 emit_swapl_reg_reg ( reg1, s1 );
2895 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002896 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002897 emit_swapl_reg_reg ( reg1, s1 );
2898 emit_swapl_reg_reg ( reg2, s2 );
2899 break;
2900 }
2901 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2902 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002903 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002904 emit_swapl_reg_reg ( reg1, s1 );
2905 break;
2906 }
njne427a662002-10-02 11:08:25 +00002907 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002908 }
njne427a662002-10-02 11:08:25 +00002909 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002910 }
2911}
2912
sewardja2c5a732002-12-15 03:10:42 +00002913#if 0
2914/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002915static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002916 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002917 Opcode opcode, Int size,
2918 Int off, Int areg, Int reg )
2919{
2920 switch (size) {
2921 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002922 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002923 break;
2924 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002925 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002926 break;
2927 case 1:
2928 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002929 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002930 } else {
2931 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002932 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002933 VG_(emit_swapl_reg_EAX) ( reg );
2934 }
2935 break;
2936 default:
2937 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2938 }
2939}
sewardja2c5a732002-12-15 03:10:42 +00002940#endif
sewardjfa492d42002-12-08 18:20:01 +00002941
sewardjde4a1d02002-03-22 01:27:54 +00002942static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002943 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002944 Opcode opcode, Int size,
2945 Int off, Int areg, Int reg )
2946{
2947 switch (size) {
2948 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002949 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002950 break;
2951 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002952 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002953 break;
2954 case 1:
2955 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002956 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002957 } else {
njn25e49d8e72002-09-23 09:36:25 +00002958 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002959 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002960 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002961 }
2962 break;
2963 default:
njne427a662002-10-02 11:08:25 +00002964 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002965 }
2966}
2967
2968
sewardjf0f12aa2002-12-28 00:04:08 +00002969static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002970 Opcode opcode, Int size,
2971 UInt lit, Int reg )
2972{
2973 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002974 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002975 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002976 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002977 break;
2978 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002979 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002980 } else {
njn25e49d8e72002-09-23 09:36:25 +00002981 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002982 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002983 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002984 }
2985 break;
njne427a662002-10-02 11:08:25 +00002986 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002987 }
2988}
2989
sewardjf0f12aa2002-12-28 00:04:08 +00002990static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002991 Opcode opcode, Int size,
2992 UInt lit, Int off, Int regmem )
2993{
2994 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002995 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002996 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002997 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002998 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002999 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003000 break;
3001 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
3002 }
3003}
3004
sewardjde4a1d02002-03-22 01:27:54 +00003005
jsgf5efa4fd2003-10-14 21:49:11 +00003006static void synth_mul_reg_reg ( Bool upd_cc,
3007 Opcode opcode, Int size,
3008 Int reg1, Int reg2 )
3009{
3010 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3011
3012 switch (size) {
3013 case 2:
3014 VG_(emitB)(0x66);
3015 /* FALLTHROUGH */
3016 case 4:
3017 VG_(emitB)(0x0F);
3018 VG_(emitB)(0xAF);
3019 VG_(emit_amode_ereg_greg)(reg1, reg2);
3020 break;
3021
3022 case 1:
3023 VG_(core_panic)("can't do byte mul");
3024 break;
3025 }
3026 if (dis)
3027 VG_(printf)("\n\t\timul%c\t%s, %s\n",
3028 nameISize(size),
3029 nameIReg(size, reg1),
3030 nameIReg(size, reg2));
3031}
3032
3033static void synth_mul_lit_reg ( Bool upd_cc,
3034 Opcode opcode, Int size,
3035 UInt lit, Int reg )
3036{
3037 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3038
3039 switch (size) {
3040 case 2:
3041 VG_(emitB)(0x66);
3042 /* FALLTHROUGH */
3043 case 4:
3044 VG_(emitB)(0x69);
3045 VG_(emit_amode_ereg_greg)(reg, 0);
3046 if (size == 2)
3047 VG_(emitW)(lit);
3048 else
3049 VG_(emitL)(lit);
3050 break;
3051
3052 case 1:
3053 VG_(core_panic)("can't do byte mul");
3054 break;
3055 }
3056 if (dis)
3057 VG_(printf)("\n\t\timul%c\t%d, %s\n",
3058 nameISize(size),
3059 lit,
3060 nameIReg(size, reg));
3061}
3062
3063static void synth_mul_offregmem_reg (
3064 Bool upd_cc,
3065 Opcode opcode, Int size,
3066 Int off, Int areg, Int reg )
3067{
3068 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3069
3070 switch(size) {
3071 case 2:
3072 VG_(emitB)(0x66);
3073 /* FALLTHROUGH */
3074 case 4:
3075 VG_(emitB)(0x0F);
3076 VG_(emitB)(0xAF);
3077 VG_(emit_amode_offregmem_reg)(off, areg, reg);
3078 break;
3079
3080 case 1:
3081 VG_(core_panic)("can't do byte mul");
3082 }
3083
3084 if (dis)
3085 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
3086 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
3087
3088}
3089
3090
sewardjde4a1d02002-03-22 01:27:54 +00003091static void synth_push_reg ( Int size, Int reg )
3092{
3093 switch (size) {
3094 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003095 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003096 break;
3097 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003098 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003099 break;
3100 /* Pray that we don't have to generate this really cruddy bit of
3101 code very often. Could do better, but can I be bothered? */
3102 case 1:
3103 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003104 VG_(emit_add_lit_to_esp)(-1);
3105 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003106 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00003107 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003108 break;
3109 default:
njne427a662002-10-02 11:08:25 +00003110 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003111 }
3112}
3113
3114
3115static void synth_pop_reg ( Int size, Int reg )
3116{
3117 switch (size) {
3118 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003119 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003120 break;
3121 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003122 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003123 break;
3124 case 1:
3125 /* Same comment as above applies. */
3126 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003127 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003128 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003129 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3130 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003131 break;
njne427a662002-10-02 11:08:25 +00003132 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003133 }
3134}
3135
3136
sewardjf0f12aa2002-12-28 00:04:08 +00003137static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003138 Opcode opcode, Int size,
3139 Int regs, Int regd )
3140{
3141 synth_push_reg ( size, regd );
3142 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003143 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003144 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3145 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3146 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003147 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003148 }
sewardjde4a1d02002-03-22 01:27:54 +00003149 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3150 synth_pop_reg ( size, regd );
3151}
3152
3153
sewardjf0f12aa2002-12-28 00:04:08 +00003154static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003155 Opcode opcode, Int size,
3156 UInt lit, Int reg )
3157{
3158 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003159 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003160 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003161 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003162 break;
3163 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003164 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003165 } else {
njn25e49d8e72002-09-23 09:36:25 +00003166 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003167 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003168 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003169 }
3170 break;
njne427a662002-10-02 11:08:25 +00003171 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003172 }
3173}
3174
3175
sewardjf0f12aa2002-12-28 00:04:08 +00003176static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003177{
sewardjde4a1d02002-03-22 01:27:54 +00003178 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003179 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003180 } else {
njn25e49d8e72002-09-23 09:36:25 +00003181 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003182 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003183 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003184 }
3185}
3186
3187
sewardj3d7c9c82003-03-26 21:08:13 +00003188static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3189 UChar first_byte,
3190 UChar second_byte,
3191 Int ireg )
3192{
3193 emit_MMX2_regmem ( uses_flags, sets_flags,
3194 first_byte, second_byte, ireg );
3195}
3196
3197
sewardjca860012003-03-27 23:52:58 +00003198static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3199 UChar first_byte,
3200 UChar second_byte,
3201 Int ireg )
3202{
3203 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3204 first_byte, second_byte, ireg );
3205}
3206
sewardjd1c9e432003-04-04 20:40:34 +00003207static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3208 UChar first_byte,
3209 UChar second_byte,
3210 Int ireg )
3211{
3212 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3213 first_byte, second_byte, ireg );
3214}
3215
sewardj3d7c9c82003-03-26 21:08:13 +00003216static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3217 UChar first_byte,
3218 UChar second_byte )
3219{
3220 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3221}
3222
3223
sewardjca860012003-03-27 23:52:58 +00003224static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3225 UChar first_byte,
3226 UChar second_byte,
3227 UChar third_byte )
3228{
3229 emit_MMX3_no_mem ( uses_flags, sets_flags,
3230 first_byte, second_byte, third_byte );
3231}
3232
3233
sewardj3d7c9c82003-03-26 21:08:13 +00003234static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3235 UChar first_byte )
3236{
3237 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3238}
3239
3240
sewardjfa492d42002-12-08 18:20:01 +00003241static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3242 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003243 UChar second_byte_masked,
3244 Int reg )
3245{
sewardj3d7c9c82003-03-26 21:08:13 +00003246 emit_fpu_regmem ( uses_flags, sets_flags,
3247 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003248}
3249
3250
sewardjfa492d42002-12-08 18:20:01 +00003251static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3252 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003253 UChar second_byte )
3254{
sewardjfa492d42002-12-08 18:20:01 +00003255 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003256}
3257
3258
3259static void synth_movl_reg_reg ( Int src, Int dst )
3260{
3261 emit_movl_reg_reg ( src, dst );
3262}
3263
3264static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3265{
sewardja2113f92002-12-12 23:42:48 +00003266 Int tgt;
3267
3268 VG_(init_target)(&tgt);
3269
fitzhardinge462f4f92003-12-18 02:10:54 +00003270 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt, JP_NONE);
sewardjde4a1d02002-03-22 01:27:54 +00003271 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003272
3273 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003274}
3275
3276
sewardjde4a1d02002-03-22 01:27:54 +00003277/*----------------------------------------------------*/
3278/*--- Top level of the uinstr -> x86 translation. ---*/
3279/*----------------------------------------------------*/
3280
3281/* Return the byte offset from %ebp (ie, into baseBlock)
3282 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003283static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3284{
3285 if (tag == SpillNo) {
3286 vg_assert(size == 4);
3287 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3288 return 4 * (value + VGOFF_(spillslots));
3289 }
3290 if (tag == ArchReg) {
3291 switch (value) {
3292 case R_EAX: return 4 * VGOFF_(m_eax);
3293 case R_ECX: return 4 * VGOFF_(m_ecx);
3294 case R_EDX: return 4 * VGOFF_(m_edx);
3295 case R_EBX: return 4 * VGOFF_(m_ebx);
3296 case R_ESP:
3297 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3298 else return 4 * VGOFF_(m_esp);
3299 case R_EBP:
3300 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3301 else return 4 * VGOFF_(m_ebp);
3302 case R_ESI:
3303 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3304 else return 4 * VGOFF_(m_esi);
3305 case R_EDI:
3306 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3307 else return 4 * VGOFF_(m_edi);
3308 }
3309 }
njne427a662002-10-02 11:08:25 +00003310 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003311}
3312
sewardjde4a1d02002-03-22 01:27:54 +00003313static Int eflagsOffset ( void )
3314{
3315 return 4 * VGOFF_(m_eflags);
3316}
3317
sewardje1042472002-09-30 12:33:11 +00003318static Int segRegOffset ( UInt archregs )
3319{
3320 switch (archregs) {
3321 case R_CS: return 4 * VGOFF_(m_cs);
3322 case R_SS: return 4 * VGOFF_(m_ss);
3323 case R_DS: return 4 * VGOFF_(m_ds);
3324 case R_ES: return 4 * VGOFF_(m_es);
3325 case R_FS: return 4 * VGOFF_(m_fs);
3326 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003327 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003328 }
3329}
3330
njnf4ce3d32003-02-10 10:17:26 +00003331UInt VG_(get_archreg) ( UInt arch )
3332{
3333 switch (arch) {
3334 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3335 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3336 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3337 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3338 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3339 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3340 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3341 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003342 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003343 }
3344}
3345
3346UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3347{
3348 ThreadState* tst;
3349
3350 vg_assert(VG_(is_valid_tid)(tid));
3351 tst = & VG_(threads)[tid];
3352
3353 switch (arch) {
3354 case R_EAX: return tst->m_eax;
3355 case R_ECX: return tst->m_ecx;
3356 case R_EDX: return tst->m_edx;
3357 case R_EBX: return tst->m_ebx;
3358 case R_ESP: return tst->m_esp;
3359 case R_EBP: return tst->m_ebp;
3360 case R_ESI: return tst->m_esi;
3361 case R_EDI: return tst->m_edi;
3362 default: VG_(core_panic)( "get_thread_archreg");
3363 }
3364}
3365
njnb93d1782003-02-03 12:03:22 +00003366/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003367static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003368{
3369 switch (arch) {
3370 case R_EAX: return VGOFF_(sh_eax);
3371 case R_ECX: return VGOFF_(sh_ecx);
3372 case R_EDX: return VGOFF_(sh_edx);
3373 case R_EBX: return VGOFF_(sh_ebx);
3374 case R_ESP: return VGOFF_(sh_esp);
3375 case R_EBP: return VGOFF_(sh_ebp);
3376 case R_ESI: return VGOFF_(sh_esi);
3377 case R_EDI: return VGOFF_(sh_edi);
3378 default: VG_(core_panic)( "shadow_reg_index");
3379 }
3380}
sewardjde4a1d02002-03-22 01:27:54 +00003381
njn25e49d8e72002-09-23 09:36:25 +00003382/* Return the byte offset from %ebp (ie, into baseBlock)
3383 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003384Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003385{
njnb93d1782003-02-03 12:03:22 +00003386 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003387}
3388
njn4ba5a792002-09-30 10:23:54 +00003389Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003390{
3391 return 4 * VGOFF_(sh_eflags);
3392}
3393
njnb93d1782003-02-03 12:03:22 +00003394/* Accessing shadow arch. registers */
3395UInt VG_(get_shadow_archreg) ( UInt archreg )
3396{
3397 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3398}
3399
3400void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3401{
3402 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3403}
3404
njnd3040452003-05-19 15:04:06 +00003405void VG_(set_shadow_eflags) ( UInt val )
3406{
3407 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3408}
3409
njnf4ce3d32003-02-10 10:17:26 +00003410UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3411{
3412 ThreadState* tst;
3413
3414 vg_assert(VG_(is_valid_tid)(tid));
3415 tst = & VG_(threads)[tid];
3416
3417 switch (archreg) {
3418 case R_EAX: return tst->sh_eax;
3419 case R_ECX: return tst->sh_ecx;
3420 case R_EDX: return tst->sh_edx;
3421 case R_EBX: return tst->sh_ebx;
3422 case R_ESP: return tst->sh_esp;
3423 case R_EBP: return tst->sh_ebp;
3424 case R_ESI: return tst->sh_esi;
3425 case R_EDI: return tst->sh_edi;
3426 default: VG_(core_panic)( "get_thread_shadow_archreg");
3427 }
3428}
3429
3430void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3431{
3432 ThreadState* tst;
3433
3434 vg_assert(VG_(is_valid_tid)(tid));
3435 tst = & VG_(threads)[tid];
3436
3437 switch (archreg) {
3438 case R_EAX: tst->sh_eax = val; break;
3439 case R_ECX: tst->sh_ecx = val; break;
3440 case R_EDX: tst->sh_edx = val; break;
3441 case R_EBX: tst->sh_ebx = val; break;
3442 case R_ESP: tst->sh_esp = val; break;
3443 case R_EBP: tst->sh_ebp = val; break;
3444 case R_ESI: tst->sh_esi = val; break;
3445 case R_EDI: tst->sh_edi = val; break;
3446 default: VG_(core_panic)( "set_thread_shadow_archreg");
3447 }
3448}
3449
njnb93d1782003-02-03 12:03:22 +00003450Addr VG_(shadow_archreg_address) ( UInt archreg )
3451{
3452 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3453}
sewardjde4a1d02002-03-22 01:27:54 +00003454
sewardjde4a1d02002-03-22 01:27:54 +00003455static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3456{
3457 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003458 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3459 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003460 }
3461 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003462 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3463 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003464 }
3465 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003466 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3467 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003468 }
3469 else
njne427a662002-10-02 11:08:25 +00003470 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003471}
3472
3473
sewardjde4a1d02002-03-22 01:27:54 +00003474/*----------------------------------------------------*/
3475/*--- Generate code for a single UInstr. ---*/
3476/*----------------------------------------------------*/
3477
sewardj478335c2002-10-05 02:44:47 +00003478static __inline__
3479Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003480{
3481 return (u->flags_w != FlagsEmpty);
3482}
3483
sewardjfa492d42002-12-08 18:20:01 +00003484static __inline__
3485Bool readFlagUse ( UInstr* u )
3486{
3487 /* If the UInstr writes some flags but not all, then we still need
3488 to consider it as reading flags so that the unchanged values are
3489 passed through properly. (D is special) */
3490 return
3491 (u->flags_r != FlagsEmpty) ||
3492 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3493}
3494
sewardj478335c2002-10-05 02:44:47 +00003495static __inline__
3496Bool anyFlagUse ( UInstr* u )
3497{
sewardjfa492d42002-12-08 18:20:01 +00003498 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003499}
3500
3501
sewardjb91ae7f2003-04-29 23:50:00 +00003502/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3503 the real machine's cpu. If so we need to be very careful not to trash it.
3504 If FPU/SSE state is live and we deem it necessary to copy it back to
3505 the simulated machine's FPU/SSE state, we do so. The final state of
3506 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003507 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003508 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003509*/
sewardjb5ff83e2002-12-01 19:40:49 +00003510static void emitUInstr ( UCodeBlock* cb, Int i,
3511 RRegSet regs_live_before,
3512 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003513 Bool* sselive, /* True<==>FPU/SSE
3514 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003515 Addr* orig_eip, /* previous curr_eip, or zero */
3516 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003517{
njn25e49d8e72002-09-23 09:36:25 +00003518 Int old_emitted_code_used;
3519 UInstr* u = &cb->instrs[i];
3520
sewardjde4a1d02002-03-22 01:27:54 +00003521 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003522 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003523
njn25e49d8e72002-09-23 09:36:25 +00003524 old_emitted_code_used = emitted_code_used;
3525
sewardjde4a1d02002-03-22 01:27:54 +00003526 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003527 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003528
sewardjb5ff83e2002-12-01 19:40:49 +00003529 case INCEIP:
3530 /* Advance %EIP some small amount. */
3531 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003532
sewardjb5ff83e2002-12-01 19:40:49 +00003533 if (*orig_eip == 0 /* we don't know what the old value was */
3534 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3535 /* We have to update all 32 bits of the value. */
3536 VG_(emit_movv_lit_offregmem)(
3537 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3538 } else {
3539 /* Cool! we only need to update lowest 8 bits */
3540 VG_(emit_movb_lit_offregmem)(
3541 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003542 }
njn25e49d8e72002-09-23 09:36:25 +00003543
sewardjb5ff83e2002-12-01 19:40:49 +00003544 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003545 break;
sewardjde4a1d02002-03-22 01:27:54 +00003546
3547 case LEA1: {
3548 vg_assert(u->tag1 == RealReg);
3549 vg_assert(u->tag2 == RealReg);
3550 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3551 break;
3552 }
3553
3554 case LEA2: {
3555 vg_assert(u->tag1 == RealReg);
3556 vg_assert(u->tag2 == RealReg);
3557 vg_assert(u->tag3 == RealReg);
3558 emit_lea_sib_reg ( u->lit32, u->extra4b,
3559 u->val1, u->val2, u->val3 );
3560 break;
3561 }
3562
3563 case WIDEN: {
3564 vg_assert(u->tag1 == RealReg);
3565 if (u->signed_widen) {
3566 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3567 } else {
3568 /* no need to generate any code. */
3569 }
3570 break;
3571 }
3572
sewardjde4a1d02002-03-22 01:27:54 +00003573 case STORE: {
3574 vg_assert(u->tag1 == RealReg);
3575 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003576 synth_mov_reg_memreg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003577 break;
3578 }
3579
3580 case LOAD: {
3581 vg_assert(u->tag1 == RealReg);
3582 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003583 synth_mov_regmem_reg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003584 break;
3585 }
3586
sewardjde4a1d02002-03-22 01:27:54 +00003587 case GET: {
3588 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3589 vg_assert(u->tag2 == RealReg);
3590 synth_mov_offregmem_reg (
3591 u->size,
3592 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3593 R_EBP,
3594 u->val2
3595 );
3596 break;
3597 }
3598
3599 case PUT: {
3600 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3601 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003602 synth_mov_reg_offregmem (
3603 u->size,
3604 u->val1,
3605 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3606 R_EBP
3607 );
sewardjde4a1d02002-03-22 01:27:54 +00003608 break;
3609 }
3610
sewardje1042472002-09-30 12:33:11 +00003611 case GETSEG: {
3612 vg_assert(u->tag1 == ArchRegS);
3613 vg_assert(u->tag2 == RealReg);
3614 vg_assert(u->size == 2);
3615 synth_mov_offregmem_reg (
3616 4,
3617 segRegOffset( u->val1 ),
3618 R_EBP,
3619 u->val2
3620 );
3621 break;
3622 }
3623
3624 case PUTSEG: {
3625 vg_assert(u->tag1 == RealReg);
3626 vg_assert(u->tag2 == ArchRegS);
3627 vg_assert(u->size == 2);
3628 synth_mov_reg_offregmem (
3629 4,
3630 u->val1,
3631 segRegOffset( u->val2 ),
3632 R_EBP
3633 );
3634 break;
3635 }
3636
sewardjde4a1d02002-03-22 01:27:54 +00003637 case GETF: {
3638 vg_assert(u->size == 2 || u->size == 4);
3639 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003640
3641 /* This complexity is because the D(irection) flag is stored
3642 separately from the rest of EFLAGS. */
3643
3644 /* We're only fetching from the Simd state, so make sure it's
3645 up to date. */
3646 maybe_emit_put_eflags();
3647
3648 /* get D in u->val1 (== 1 or -1) */
3649 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3650
3651 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3652 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3653
3654 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3655 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3656 eflagsOffset(), R_EBP);
3657
3658 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3659 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3660 eflagsOffset(), R_EBP);
3661
3662 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3663 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3664 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003665 break;
3666 }
3667
3668 case PUTF: {
3669 vg_assert(u->size == 2 || u->size == 4);
3670 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003671
3672 /* When putting a value into EFLAGS, this generates the
3673 correct value for m_dflag (-1 or 1), and clears the D bit
3674 in EFLAGS. */
3675
3676 /* We're updating the whole flag state, so the old state
3677 doesn't matter; make sure that the new simulated state
3678 will be fetched when needed. */
3679 eflags_state = UPD_Simd;
3680
3681 /* store EFLAGS (with D) */
3682 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3683
3684 /* u->val1 &= EFlagD */
3685 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3686
3687 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3688 synth_unaryop_reg(False, NEG, u->size, u->val1);
3689 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3690 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3691
3692 /* save D */
3693 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3694
3695 /* EFLAGS &= ~EFlagD */
3696 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3697 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003698 break;
3699 }
3700
3701 case MOV: {
3702 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3703 vg_assert(u->tag2 == RealReg);
3704 switch (u->tag1) {
3705 case RealReg: vg_assert(u->size == 4);
3706 if (u->val1 != u->val2)
3707 synth_movl_reg_reg ( u->val1, u->val2 );
3708 break;
3709 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3710 break;
njne427a662002-10-02 11:08:25 +00003711 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003712 }
3713 break;
3714 }
3715
sewardje1042472002-09-30 12:33:11 +00003716 case USESEG: {
3717 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3718 ones. */
sewardjd077f532002-09-30 21:52:50 +00003719 UInt argv[] = { u->val1, u->val2 };
3720 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003721 UInt ret_reg = u->val2;
3722
3723 vg_assert(u->tag1 == RealReg);
3724 vg_assert(u->tag2 == RealReg);
3725 vg_assert(u->size == 0);
3726
sewardjb91ae7f2003-04-29 23:50:00 +00003727 if (*sselive) {
3728 emit_put_sse_state();
3729 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003730 }
3731
sewardje1042472002-09-30 12:33:11 +00003732 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3733 2, /* args */
3734 0, /* regparms_n */
3735 argv, tagv,
3736 ret_reg, regs_live_before, u->regs_live_after );
3737 break;
3738 }
3739
jsgf5efa4fd2003-10-14 21:49:11 +00003740 case MUL: {
3741 vg_assert(u->tag2 == RealReg);
3742
3743 switch(u->tag1) {
3744 case Literal:
3745 synth_mul_lit_reg(anyFlagUse(u),
3746 u->opcode, u->size, u->lit32, u->val2);
3747 break;
3748 case RealReg:
3749 synth_mul_reg_reg(anyFlagUse(u),
3750 u->opcode, u->size, u->val1, u->val2);
3751 break;
3752 case ArchReg:
3753 synth_mul_offregmem_reg(anyFlagUse(u),
3754 u->opcode, u->size,
3755 spillOrArchOffset(u->size, u->tag1, u->val1),
3756 R_EBP, u->val2);
3757 break;
3758
3759 default: VG_(core_panic)("emitUInstr:MUL");
3760 }
3761 break;
3762 }
3763
sewardj478335c2002-10-05 02:44:47 +00003764 case SBB:
3765 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003766 case XOR:
3767 case OR:
3768 case AND:
3769 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003770 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003771 vg_assert(u->tag2 == RealReg);
3772 switch (u->tag1) {
3773 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003774 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003775 u->opcode, u->size, u->lit32, u->val2 );
3776 break;
3777 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003778 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003779 u->opcode, u->size, u->val1, u->val2 );
3780 break;
3781 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003782 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003783 u->opcode, u->size,
3784 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3785 R_EBP,
3786 u->val2 );
3787 break;
njne427a662002-10-02 11:08:25 +00003788 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003789 }
3790 break;
3791 }
3792
sewardj478335c2002-10-05 02:44:47 +00003793 case RCR:
3794 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003795 case ROR:
3796 case ROL:
3797 case SAR:
3798 case SHR:
3799 case SHL: {
3800 vg_assert(u->tag2 == RealReg);
3801 switch (u->tag1) {
3802 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003803 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003804 u->opcode, u->size, u->lit32, u->val2 );
3805 break;
3806 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003807 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003808 u->opcode, u->size, u->val1, u->val2 );
3809 break;
njne427a662002-10-02 11:08:25 +00003810 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003811 }
3812 break;
3813 }
3814
3815 case INC:
3816 case DEC:
3817 case NEG:
3818 case NOT:
3819 vg_assert(u->tag1 == RealReg);
3820 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003821 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003822 break;
3823
3824 case BSWAP:
3825 vg_assert(u->tag1 == RealReg);
3826 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003827 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003828 emit_bswapl_reg ( u->val1 );
3829 break;
3830
3831 case CMOV:
3832 vg_assert(u->tag1 == RealReg);
3833 vg_assert(u->tag2 == RealReg);
3834 vg_assert(u->cond != CondAlways);
3835 vg_assert(u->size == 4);
3836 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3837 break;
3838
3839 case JMP: {
3840 vg_assert(u->tag2 == NoValue);
3841 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003842 if (*sselive) {
3843 emit_put_sse_state();
3844 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003845 }
sewardjde4a1d02002-03-22 01:27:54 +00003846 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003847 switch (u->tag1) {
3848 case RealReg:
3849 synth_jmp_reg ( u->val1, u->jmpkind );
3850 break;
3851 case Literal:
3852 synth_jmp_lit ( u->lit32, u->jmpkind );
3853 break;
3854 default:
njne427a662002-10-02 11:08:25 +00003855 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003856 break;
sewardjde4a1d02002-03-22 01:27:54 +00003857 }
3858 } else {
sewardj2e93c502002-04-12 11:12:52 +00003859 switch (u->tag1) {
3860 case RealReg:
njne427a662002-10-02 11:08:25 +00003861 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003862 break;
3863 case Literal:
3864 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003865 /* %eax had better not be live since synth_jcond_lit
3866 trashes it in some circumstances. If that turns
3867 out to be a problem we can get synth_jcond_lit to
3868 push/pop it when it is live. */
3869 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3870 u->regs_live_after));
3871 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003872 break;
3873 default:
njne427a662002-10-02 11:08:25 +00003874 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003875 break;
sewardjde4a1d02002-03-22 01:27:54 +00003876 }
3877 }
3878 break;
3879 }
3880
3881 case JIFZ:
3882 vg_assert(u->tag1 == RealReg);
3883 vg_assert(u->tag2 == Literal);
3884 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003885 if (*sselive) {
3886 emit_put_sse_state();
3887 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003888 }
sewardjde4a1d02002-03-22 01:27:54 +00003889 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3890 break;
3891
sewardjde4a1d02002-03-22 01:27:54 +00003892 case PUSH:
3893 vg_assert(u->tag1 == RealReg);
3894 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003895 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003896 break;
3897
3898 case POP:
3899 vg_assert(u->tag1 == RealReg);
3900 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003901 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003902 break;
3903
3904 case CALLM:
3905 vg_assert(u->tag1 == Lit16);
3906 vg_assert(u->tag2 == NoValue);
3907 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003908 if (*sselive) {
3909 emit_put_sse_state();
3910 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003911 }
sewardjfa492d42002-12-08 18:20:01 +00003912 /* Call to a helper which is pretending to be a real CPU
3913 instruction (and therefore operates on Real flags and
3914 registers) */
3915 VG_(synth_call) ( False, u->val1,
3916 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003917 break;
3918
njn25e49d8e72002-09-23 09:36:25 +00003919 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003920 /* If you change this, remember to change USESEG above, since
3921 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003922 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3923 ones. */
3924 UInt argv[] = { u->val1, u->val2, u->val3 };
3925 UInt tagv[] = { RealReg, RealReg, RealReg };
3926 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3927
3928 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3929 else vg_assert(u->tag1 == NoValue);
3930 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3931 else vg_assert(u->tag2 == NoValue);
3932 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3933 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003934 vg_assert(u->size == 0);
3935
sewardjb91ae7f2003-04-29 23:50:00 +00003936 if (*sselive) {
3937 emit_put_sse_state();
3938 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003939 }
njn25e49d8e72002-09-23 09:36:25 +00003940 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3941 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003942 break;
njn25e49d8e72002-09-23 09:36:25 +00003943 }
sewardje1042472002-09-30 12:33:11 +00003944
sewardjde4a1d02002-03-22 01:27:54 +00003945 case CLEAR:
3946 vg_assert(u->tag1 == Lit16);
3947 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003948 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003949 break;
3950
3951 case CC2VAL:
3952 vg_assert(u->tag1 == RealReg);
3953 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003954 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003955 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003956 break;
3957
sewardjde4a1d02002-03-22 01:27:54 +00003958 case FPU_R:
3959 case FPU_W:
3960 vg_assert(u->tag1 == Lit16);
3961 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003962 if (!(*sselive)) {
3963 emit_get_sse_state();
3964 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003965 }
sewardjfa492d42002-12-08 18:20:01 +00003966 synth_fpu_regmem ( u->flags_r, u->flags_w,
3967 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003968 u->val1 & 0xFF,
3969 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003970 break;
3971
3972 case FPU:
3973 vg_assert(u->tag1 == Lit16);
3974 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003975 if (!(*sselive)) {
3976 emit_get_sse_state();
3977 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003978 }
sewardjfa492d42002-12-08 18:20:01 +00003979 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3980 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003981 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003982 break;
3983
sewardj3d7c9c82003-03-26 21:08:13 +00003984 case MMX2_MemWr:
3985 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003986 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003987 vg_assert(u->tag1 == Lit16);
3988 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003989 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003990 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003991 if (!(*sselive)) {
3992 emit_get_sse_state();
3993 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003994 }
3995 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3996 (u->val1 >> 8) & 0xFF,
3997 u->val1 & 0xFF,
3998 u->val2 );
3999 break;
4000
sewardj4fbe6e92003-06-15 21:54:34 +00004001 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00004002 vg_assert(u->tag1 == Lit16);
4003 vg_assert(u->tag2 == RealReg);
4004 vg_assert(u->tag3 == NoValue);
4005 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004006 if (!(*sselive)) {
4007 emit_get_sse_state();
4008 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004009 }
4010 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
4011 (u->val1 >> 8) & 0xFF,
4012 u->val1 & 0xFF,
4013 u->val2 );
4014 break;
4015
sewardj4fbe6e92003-06-15 21:54:34 +00004016 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00004017 vg_assert(u->tag1 == Lit16);
4018 vg_assert(u->tag2 == RealReg);
4019 vg_assert(u->tag3 == NoValue);
4020 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004021 if (!(*sselive)) {
4022 emit_get_sse_state();
4023 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00004024 }
4025 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
4026 (u->val1 >> 8) & 0xFF,
4027 u->val1 & 0xFF,
4028 u->val2 );
4029 break;
4030
sewardj3d7c9c82003-03-26 21:08:13 +00004031 case MMX1:
4032 vg_assert(u->tag1 == Lit16);
4033 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004034 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004035 if (!(*sselive)) {
4036 emit_get_sse_state();
4037 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004038 }
4039 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
4040 u->val1 & 0xFF );
4041 break;
4042
4043 case MMX2:
4044 vg_assert(u->tag1 == Lit16);
4045 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004046 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004047 if (!(*sselive)) {
4048 emit_get_sse_state();
4049 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004050 }
4051 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
4052 (u->val1 >> 8) & 0xFF,
4053 u->val1 & 0xFF );
4054 break;
4055
sewardjca860012003-03-27 23:52:58 +00004056 case MMX3:
4057 vg_assert(u->tag1 == Lit16);
4058 vg_assert(u->tag2 == Lit16);
4059 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004060 if (!(*sselive)) {
4061 emit_get_sse_state();
4062 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004063 }
4064 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
4065 (u->val1 >> 8) & 0xFF,
4066 u->val1 & 0xFF,
4067 u->val2 & 0xFF );
4068 break;
4069
sewardjfebaa3b2003-05-25 01:07:34 +00004070 case SSE2a_MemWr:
4071 case SSE2a_MemRd:
4072 vg_assert(u->size == 4 || u->size == 16);
4073 vg_assert(u->tag1 == Lit16);
4074 vg_assert(u->tag2 == Lit16);
4075 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004076 if (!(*sselive)) {
4077 emit_get_sse_state();
4078 *sselive = True;
4079 }
4080 emit_SSE2a ( u->flags_r, u->flags_w,
4081 (u->val1 >> 8) & 0xFF,
4082 u->val1 & 0xFF,
4083 u->val2 & 0xFF,
4084 u->val3 );
4085 break;
4086
sewardj9dd209f2003-06-18 23:30:52 +00004087 case SSE2a1_MemRd:
4088 vg_assert(u->size == 4 || u->size == 16);
4089 vg_assert(u->tag1 == Lit16);
4090 vg_assert(u->tag2 == Lit16);
4091 vg_assert(u->tag3 == RealReg);
4092 vg_assert(!anyFlagUse(u));
4093 if (!(*sselive)) {
4094 emit_get_sse_state();
4095 *sselive = True;
4096 }
4097 emit_SSE2a1 ( u->flags_r, u->flags_w,
4098 (u->val1 >> 8) & 0xFF,
4099 u->val1 & 0xFF,
4100 (u->val2 >> 8) & 0xFF,
4101 u->val2 & 0xFF,
4102 u->val3 );
4103 break;
4104
sewardjfebaa3b2003-05-25 01:07:34 +00004105 case SSE3a_MemWr:
4106 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00004107 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00004108 vg_assert(u->tag1 == Lit16);
4109 vg_assert(u->tag2 == Lit16);
4110 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004111 if (!(*sselive)) {
4112 emit_get_sse_state();
4113 *sselive = True;
4114 }
4115 emit_SSE3a ( u->flags_r, u->flags_w,
4116 (u->val1 >> 8) & 0xFF,
4117 u->val1 & 0xFF,
4118 (u->val2 >> 8) & 0xFF,
4119 u->val2 & 0xFF,
4120 u->val3 );
4121 break;
4122
sewardjabf8bf82003-06-15 22:28:05 +00004123 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004124 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004125 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004126 vg_assert(u->size == 4);
4127 vg_assert(u->tag1 == Lit16);
4128 vg_assert(u->tag2 == Lit16);
4129 vg_assert(u->tag3 == RealReg);
4130 vg_assert(!anyFlagUse(u));
4131 if (!(*sselive)) {
4132 emit_get_sse_state();
4133 *sselive = True;
4134 }
sewardjabf8bf82003-06-15 22:28:05 +00004135 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4136 emit_SSE3e ( u->flags_r, u->flags_w,
4137 (u->val1 >> 8) & 0xFF,
4138 u->val1 & 0xFF,
4139 (u->val2 >> 8) & 0xFF,
4140 u->val2 & 0xFF,
4141 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004142 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004143 emit_SSE3g ( u->flags_r, u->flags_w,
4144 (u->val1 >> 8) & 0xFF,
4145 u->val1 & 0xFF,
4146 (u->val2 >> 8) & 0xFF,
4147 u->val2 & 0xFF,
4148 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004149 }
sewardjfebaa3b2003-05-25 01:07:34 +00004150 break;
4151
sewardjb31b06d2003-06-13 00:26:02 +00004152 case SSE3g1_RegWr:
4153 vg_assert(u->size == 4);
4154 vg_assert(u->tag1 == Lit16);
4155 vg_assert(u->tag2 == Lit16);
4156 vg_assert(u->tag3 == RealReg);
4157 vg_assert(!anyFlagUse(u));
4158 if (!(*sselive)) {
4159 emit_get_sse_state();
4160 *sselive = True;
4161 }
sewardjabf8bf82003-06-15 22:28:05 +00004162 emit_SSE3g1 ( u->flags_r, u->flags_w,
4163 (u->val1 >> 8) & 0xFF,
4164 u->val1 & 0xFF,
4165 (u->val2 >> 8) & 0xFF,
4166 u->val2 & 0xFF,
4167 u->lit32 & 0xFF,
4168 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004169 break;
4170
sewardj4fbe6e92003-06-15 21:54:34 +00004171 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004172 vg_assert(u->size == 2);
4173 vg_assert(u->tag1 == Lit16);
4174 vg_assert(u->tag2 == Lit16);
4175 vg_assert(u->tag3 == RealReg);
4176 vg_assert(!anyFlagUse(u));
4177 if (!(*sselive)) {
4178 emit_get_sse_state();
4179 *sselive = True;
4180 }
sewardjabf8bf82003-06-15 22:28:05 +00004181 emit_SSE3e1 ( u->flags_r, u->flags_w,
4182 (u->val1 >> 8) & 0xFF,
4183 u->val1 & 0xFF,
4184 (u->val2 >> 8) & 0xFF,
4185 u->val2 & 0xFF,
4186 u->lit32 & 0xFF,
4187 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004188 break;
4189
sewardj77d30a22003-10-19 08:18:52 +00004190 case SSE3a1_MemRd:
4191 vg_assert(u->size == 16);
4192 vg_assert(u->tag1 == Lit16);
4193 vg_assert(u->tag2 == Lit16);
4194 vg_assert(u->tag3 == RealReg);
4195 vg_assert(!anyFlagUse(u));
4196 if (!(*sselive)) {
4197 emit_get_sse_state();
4198 *sselive = True;
4199 }
4200 emit_SSE3a1 ( u->flags_r, u->flags_w,
4201 (u->val1 >> 8) & 0xFF,
4202 u->val1 & 0xFF,
4203 (u->val2 >> 8) & 0xFF,
4204 u->val2 & 0xFF,
4205 (u->lit32 >> 8) & 0xFF,
4206 u->val3 );
4207 break;
4208
sewardja453fb02003-06-14 13:22:36 +00004209 case SSE5:
4210 vg_assert(u->size == 0);
4211 vg_assert(u->tag1 == Lit16);
4212 vg_assert(u->tag2 == Lit16);
4213 vg_assert(u->tag3 == Lit16);
4214 vg_assert(!anyFlagUse(u));
4215 if (!(*sselive)) {
4216 emit_get_sse_state();
4217 *sselive = True;
4218 }
4219 emit_SSE5 ( u->flags_r, u->flags_w,
4220 (u->val1 >> 8) & 0xFF,
4221 u->val1 & 0xFF,
4222 (u->val2 >> 8) & 0xFF,
4223 u->val2 & 0xFF,
4224 u->val3 & 0xFF );
4225 break;
4226
sewardjfebaa3b2003-05-25 01:07:34 +00004227 case SSE4:
4228 vg_assert(u->size == 0);
4229 vg_assert(u->tag1 == Lit16);
4230 vg_assert(u->tag2 == Lit16);
4231 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004232 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004233 if (!(*sselive)) {
4234 emit_get_sse_state();
4235 *sselive = True;
4236 }
4237 emit_SSE4 ( u->flags_r, u->flags_w,
4238 (u->val1 >> 8) & 0xFF,
4239 u->val1 & 0xFF,
4240 (u->val2 >> 8) & 0xFF,
4241 u->val2 & 0xFF );
4242 break;
4243
sewardja60be0e2003-05-26 08:47:27 +00004244 case SSE3:
4245 vg_assert(u->size == 0);
4246 vg_assert(u->tag1 == Lit16);
4247 vg_assert(u->tag2 == Lit16);
4248 vg_assert(u->tag3 == NoValue);
sewardj77d30a22003-10-19 08:18:52 +00004249 vg_assert(!readFlagUse(u));
sewardja60be0e2003-05-26 08:47:27 +00004250 if (!(*sselive)) {
4251 emit_get_sse_state();
4252 *sselive = True;
4253 }
4254 emit_SSE3 ( u->flags_r, u->flags_w,
4255 (u->val1 >> 8) & 0xFF,
4256 u->val1 & 0xFF,
4257 u->val2 & 0xFF );
4258 break;
4259
sewardje3891fa2003-06-15 03:13:48 +00004260 case SSE3ag_MemRd_RegWr:
4261 vg_assert(u->size == 4 || u->size == 8);
4262 vg_assert(u->tag1 == RealReg);
4263 vg_assert(u->tag2 == RealReg);
4264 vg_assert(u->tag3 == NoValue);
4265 vg_assert(!anyFlagUse(u));
4266 if (!(*sselive)) {
4267 emit_get_sse_state();
4268 *sselive = True;
4269 }
4270 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4271 (u->lit32 >> 24) & 0xFF,
4272 (u->lit32 >> 16) & 0xFF,
4273 (u->lit32 >> 8) & 0xFF,
4274 u->val1, u->val2 );
4275 break;
4276
sewardjde4a1d02002-03-22 01:27:54 +00004277 default:
sewardj1b7d8022002-11-30 12:35:42 +00004278 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004279 if (*sselive) {
4280 emit_put_sse_state();
4281 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004282 }
njn4ba5a792002-09-30 10:23:54 +00004283 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004284 } else {
njn25e49d8e72002-09-23 09:36:25 +00004285 VG_(printf)("\nError:\n"
4286 " unhandled opcode: %u. Perhaps "
4287 " VG_(needs).extended_UCode should be set?\n",
4288 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004289 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004290 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004291 }
sewardjde4a1d02002-03-22 01:27:54 +00004292 }
4293
sewardjb91ae7f2003-04-29 23:50:00 +00004294 if (0 && (*sselive)) {
4295 emit_put_sse_state();
4296 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004297 }
4298
njn25e49d8e72002-09-23 09:36:25 +00004299 /* Update UInstr histogram */
4300 vg_assert(u->opcode < 100);
4301 histogram[u->opcode].counts++;
4302 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004303}
4304
4305
4306/* Emit x86 for the ucode in cb, returning the address of the
4307 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004308UChar* VG_(emit_code) ( UCodeBlock* cb,
4309 Int* nbytes,
4310 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004311{
4312 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004313 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004314 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004315 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004316 Int tgt;
4317
sewardjfa492d42002-12-08 18:20:01 +00004318 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004319
njn25e49d8e72002-09-23 09:36:25 +00004320 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004321
fitzhardinge462f4f92003-12-18 02:10:54 +00004322 /* Generate subl $1, VG_(dispatch_ctr) and drop into dispatch if we hit
sewardj22854b92002-11-30 14:00:47 +00004323 zero. We have to do this regardless of whether we're t-chaining
fitzhardinge462f4f92003-12-18 02:10:54 +00004324 or not. (The ia32 optimisation guide recommends sub over dec.) */
sewardja2113f92002-12-12 23:42:48 +00004325 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004326 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
fitzhardinge462f4f92003-12-18 02:10:54 +00004327 VG_(emitB) (0x83); /* subl */
4328 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 5);
4329 VG_(emitB) (0x01);
4330
sewardj22854b92002-11-30 14:00:47 +00004331 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00004332 VG_(printf)("\n\t\tsubl $1, (%p)\n", &VG_(dispatch_ctr));
4333
4334 VG_(emit_jcondshort_target)(False, CondNZ, &tgt, JP_TAKEN);
sewardj22854b92002-11-30 14:00:47 +00004335 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4336 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004337 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004338
sewardjb5ff83e2002-12-01 19:40:49 +00004339 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004340 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004341 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004342 curr_eip = cb->orig_eip;
4343 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4344 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004345 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004346 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004347 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004348 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004349
sewardjde4a1d02002-03-22 01:27:54 +00004350 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004351 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004352 if (!sane) {
4353 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004354 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004355 }
4356 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004357 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004358 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004359 }
njn25e49d8e72002-09-23 09:36:25 +00004360 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004361 }
njn25e49d8e72002-09-23 09:36:25 +00004362 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004363 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004364 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004365
sewardj22854b92002-11-30 14:00:47 +00004366 if (j != NULL) {
4367 vg_assert(jumpidx <= VG_MAX_JUMPS);
4368 for(i = 0; i < jumpidx; i++)
4369 j[i] = jumps[i];
4370 }
4371
sewardjde4a1d02002-03-22 01:27:54 +00004372 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004373 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004374 *nbytes = emitted_code_used;
4375 return emitted_code;
4376}
4377
njn25e49d8e72002-09-23 09:36:25 +00004378#undef dis
4379
sewardjde4a1d02002-03-22 01:27:54 +00004380/*--------------------------------------------------------------------*/
4381/*--- end vg_from_ucode.c ---*/
4382/*--------------------------------------------------------------------*/