blob: b285e1db0cef5916d1da1ef302e7df257c28390a [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00006
sewardjde4a1d02002-03-22 01:27:54 +00007/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
41/*------------------------------------------------------------*/
42/*--- Instruction emission -- turning final uinstrs back ---*/
43/*--- into x86 code. ---*/
44/*------------------------------------------------------------*/
45
46/* [2001-07-08 This comment is now somewhat out of date.]
47
48 This is straightforward but for one thing: to facilitate generating
49 code in a single pass, we generate position-independent code. To
50 do this, calls and jmps to fixed addresses must specify the address
51 by first loading it into a register, and jump to/call that
52 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000053 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000054 call insns may only have a register as target anyway, so there's no
55 need to do anything fancy for them.
56
57 The emit_* routines constitute the lowest level of instruction
58 emission. They simply emit the sequence of bytes corresponding to
59 the relevant instruction, with no further ado. In particular there
60 is no checking about whether uses of byte registers makes sense,
61 nor whether shift insns have their first operand in %cl, etc.
62
63 These issues are taken care of by the level above, the synth_*
64 routines. These detect impossible operand combinations and turn
65 them into sequences of legal instructions. Finally, emitUInstr is
66 phrased in terms of the synth_* abstraction layer. */
67
sewardjfa492d42002-12-08 18:20:01 +000068/* Static state for the current basic block */
sewardjde4a1d02002-03-22 01:27:54 +000069static UChar* emitted_code;
70static Int emitted_code_used;
71static Int emitted_code_size;
72
sewardj22854b92002-11-30 14:00:47 +000073/* offset (in bytes into the basic block) */
74static UShort jumps[VG_MAX_JUMPS];
75static Int jumpidx;
76
sewardjf0f12aa2002-12-28 00:04:08 +000077static enum _eflags_state {
sewardjfa492d42002-12-08 18:20:01 +000078 UPD_Simd, /* baseblock copy is up to date */
79 UPD_Real, /* CPU copy is up to date */
80 UPD_Both, /* both are current */
81} eflags_state;
82
83/* single site for resetting state */
84static void reset_state(void)
85{
86 emitted_code_used = 0;
87 emitted_code_size = 500; /* reasonable initial size */
88 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
89 jumpidx = 0;
90 eflags_state = UPD_Simd;
91}
92
93
njn25e49d8e72002-09-23 09:36:25 +000094/* Statistics about C functions called from generated code. */
95static UInt ccalls = 0;
96static UInt ccall_reg_saves = 0;
97static UInt ccall_args = 0;
98static UInt ccall_arg_setup_instrs = 0;
99static UInt ccall_stack_clears = 0;
100static UInt ccall_retvals = 0;
101static UInt ccall_retval_movs = 0;
102
103/* Statistics about frequency of each UInstr */
104typedef
105 struct {
106 UInt counts;
107 UInt size;
108 } Histogram;
109
110/* Automatically zeroed because it's static. */
111static Histogram histogram[100];
112
113void VG_(print_ccall_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " ccalls: %u C calls, %u%% saves+restores avoided"
117 " (%d bytes)",
118 ccalls,
119 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
120 ((ccalls*3) - ccall_reg_saves)*2);
121 VG_(message)(Vg_DebugMsg,
122 " %u args, avg 0.%d setup instrs each (%d bytes)",
123 ccall_args,
124 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
125 (ccall_args - ccall_arg_setup_instrs)*2);
126 VG_(message)(Vg_DebugMsg,
127 " %d%% clear the stack (%d bytes)",
128 (UInt)(ccall_stack_clears/(double)ccalls*100),
129 (ccalls - ccall_stack_clears)*3);
130 VG_(message)(Vg_DebugMsg,
131 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
132 ccall_retvals,
133 ( ccall_retvals == 0
134 ? 100
135 : 100-(UInt)(ccall_retval_movs /
136 (double)ccall_retvals*100)),
137 (ccall_retvals-ccall_retval_movs)*2);
138}
139
140void VG_(print_UInstr_histogram)(void)
141{
142 Int i, j;
143 UInt total_counts = 0;
144 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000145
njn25e49d8e72002-09-23 09:36:25 +0000146 for (i = 0; i < 100; i++) {
147 total_counts += histogram[i].counts;
148 total_size += histogram[i].size;
149 }
150
151 VG_(printf)("-- UInstr frequencies -----------\n");
152 for (i = 0; i < 100; i++) {
153 if (0 != histogram[i].counts) {
154
155 UInt count_pc =
156 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
157 UInt size_pc =
158 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
159 UInt avg_size =
160 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
161
162 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000163 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000164 histogram[i].counts, count_pc,
165 avg_size, size_pc);
166
sewardj05bcdcb2003-05-18 10:05:38 +0000167 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000168 VG_(printf)("\n");
169
170 } else {
171 vg_assert(0 == histogram[i].size);
172 }
173 }
174
175 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
176}
177
sewardjde4a1d02002-03-22 01:27:54 +0000178static void expandEmittedCode ( void )
179{
180 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000181 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000182 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
183 for (i = 0; i < emitted_code_size; i++)
184 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000186 emitted_code = tmp;
187 emitted_code_size *= 2;
188}
189
njn25e49d8e72002-09-23 09:36:25 +0000190/* Local calls will be inlined, cross-module ones not */
191__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
193 if (dis) {
194 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
195 }
196 if (emitted_code_used == emitted_code_size)
197 expandEmittedCode();
198
199 emitted_code[emitted_code_used] = (UChar)b;
200 emitted_code_used++;
201}
202
njn25e49d8e72002-09-23 09:36:25 +0000203__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(emitB) ( (l) & 0x000000FF );
206 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000207}
208
njn25e49d8e72002-09-23 09:36:25 +0000209__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000210{
njn25e49d8e72002-09-23 09:36:25 +0000211 VG_(emitB) ( (l) & 0x000000FF );
212 VG_(emitB) ( (l >> 8) & 0x000000FF );
213 VG_(emitB) ( (l >> 16) & 0x000000FF );
214 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000215}
216
sewardjfa492d42002-12-08 18:20:01 +0000217static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000218{
sewardjfa492d42002-12-08 18:20:01 +0000219 Int off = 4 * VGOFF_(m_eflags);
220 vg_assert(off >= 0 && off < 128);
221
222 if (dis)
223 VG_(printf)("\t %4d: ", emitted_code_used );
224
225 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
226 VG_(emitB) ( 0x75 );
227 VG_(emitB) ( off );
228 VG_(emitB) ( 0x9D ); /* POPFL */
229 if (dis)
230 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
231}
232
233static void emit_put_eflags ( void )
234{
235 Int off = 4 * VGOFF_(m_eflags);
236 vg_assert(off >= 0 && off < 128);
237
238 if (dis)
239 VG_(printf)("\t %4d: ", emitted_code_used );
240
241 VG_(emitB) ( 0x9C ); /* PUSHFL */
242 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
243 VG_(emitB) ( 0x45 );
244 VG_(emitB) ( off );
245 if (dis)
246 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
247}
248
249static void maybe_emit_put_eflags( void )
250{
251 if (eflags_state == UPD_Real) {
252 eflags_state = UPD_Both;
253 emit_put_eflags();
254 }
255}
256
sewardja2c5a732002-12-15 03:10:42 +0000257
258/* evidently unused */
259#if 0
sewardjfa492d42002-12-08 18:20:01 +0000260static void maybe_emit_get_eflags( void )
261{
262 if (eflags_state == UPD_Simd) {
263 eflags_state = UPD_Both;
264 emit_get_eflags();
265 }
266}
sewardja2c5a732002-12-15 03:10:42 +0000267#endif
sewardjfa492d42002-12-08 18:20:01 +0000268
sewardjf0f12aa2002-12-28 00:04:08 +0000269
270#if 0
271/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
272/* An alternative implementation of new_emit in which the
273 state space is explicitly enumerated. */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool simd = upds_simd_flags;
279 enum _eflags_state where = eflags_state;
280
281 enum { WNone, WSome, WAll } ww;
282 Bool rr;
283
284#define DIS_HEADER \
285 if (dis) \
286 VG_(printf)("\t %4d: ", emitted_code_used );
287
288 if (use_flags == FlagsEmpty) {
289 rr = False;
290 } else {
291 rr = True;
292 }
293
294 if (set_flags == FlagsEmpty) {
295 ww = WNone;
296 } else
297 if (set_flags == FlagsOSZACP) {
298 ww = WAll;
299 } else {
300 ww = WSome;
301 }
302
303 /* If we're not wanting to interact with simd flags, and the simd
304 flags are not in the real flags, then do nothing. */
305 if (simd == False && where == UPD_Simd)
306 goto noaction;
307
308 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
309 /* We're going to generate a complete new simd flag state without
310 consulting the old one first, so just deem this insn to create
311 the state in the real flags. */
312 eflags_state = UPD_Real;
313 DIS_HEADER;
314 return;
315 }
316
317 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
318 /* Want to partially update the flags state, but is in simd. So
319 fetch it first, then declare that the real state is the most
320 recent. */
321 emit_get_eflags();
322 eflags_state = UPD_Real;
323 DIS_HEADER;
324 return;
325 }
326
327 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
328 /* want to read simd flags, but not in real -> copy to real. */
329 emit_get_eflags();
330 eflags_state = UPD_Both;
331 DIS_HEADER;
332 return;
333 }
334
335 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
336 /* want to read and write simd flags, but not in real -> copy to
337 real. State is then Real since they get updated. */
338 emit_get_eflags();
339 eflags_state = UPD_Real;
340 DIS_HEADER;
341 return;
342 }
343
344 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
345 /* Doesn't really make sense. Want to interact with simd flags,
346 but insn doesn't modify them. So don't do anything. ??? */
347 goto noaction;
348 }
349
350 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
351 /* Doesn't really make sense. Want to interact with simd flags,
352 but insn doesn't modify them. So don't do anything. ??? */
353 goto noaction;
354 }
355
356 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
357 /* simd is in real. Insn reads real but does not change. --> do
358 nothing. */
359 goto noaction;
360 }
361
362 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
363 /* simd is in real. we want to capture changes made by it. -->
364 do nothing */
365 goto noaction;
366 }
367
368 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
369 /* simd is in real. Insn creates new simd state. --> leave in
370 real */
371 goto noaction;
372 }
373
374 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
375 /* simd is in both. Insn creates new simd state. --> change
376 state to Real. */
377 narrow_Both_to_Real:
378 eflags_state = UPD_Real;
379 DIS_HEADER;
380 return;
381 }
382
383 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
384 /* simd is in both. Insn creates partial new simd state. -->
385 change state to Real. No need to get, since Both holds. */
386 goto narrow_Both_to_Real;
387 }
388
389 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
390 /* simd is in real. Insn creates new simd state. --> leave in
391 real */
392 goto noaction;
393 }
394
395 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
396 /* want to read the simd flags, but already have a copy in real,
397 and not planning to modify it --> do nothing. */
398 goto noaction;
399
400 ////////////////
401
402 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
403 /* simd state is in real, but insn doesn't touch it --> do nothing */
404 goto noaction;
405
406 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
407 /* simd state is in both, insn doesn't touch it --> do nothing */
408 goto noaction;
409
410 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
411 /* simd state is in both. insn trashes real, therefore declare
412 simd state only in simd. */
413 narrow_Both_to_Simd:
414 eflags_state = UPD_Simd;
415 DIS_HEADER;
416 return;
417 }
418
419 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
420 /* simd state is in both. insn trashes real, therefore declare
421 simd state only in simd. */
422 goto narrow_Both_to_Simd;
423 }
424
425 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
426 /* simd state is in real; we don't want simd state changed, but
427 insn writes the flags. Therefore have to copy back first. */
428 put_flags_and_continue:
429 emit_put_eflags();
430 eflags_state = UPD_Simd;
431 DIS_HEADER;
432 return;
433 }
434
435 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
436 /* simd state is in real; we don't want simd state changed, but
437 insn writes the flags. Therefore have to copy back first. */
438 goto put_flags_and_continue;
439 }
440
441 goto unhandled;
442
443 noaction:
444 DIS_HEADER;
445 return;
446
447 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
448 // return;
449 //}
450
451 unhandled:
452 VG_(printf)("simd %s, where %s, read %s, write %s\n",
453 simd ? "True " : "False",
454 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
455 ? "Real" : "Both")),
456 rr ? "True " : "False",
457 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
458 );
459
460 VG_(core_panic)("new_emit");
461}
462/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
463#endif
464
465
sewardjfa492d42002-12-08 18:20:01 +0000466/* Call this before emitting each instruction.
467
468 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000469 interacts_with_simd_flags:
470 if true, this instruction wants to interact (read and/or write)
471 the simulated %EFLAGS state,
472 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000473 use_flags: set of (real) flags the instruction uses
474 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000475*/
sewardjfa492d42002-12-08 18:20:01 +0000476__inline__
sewardjf0f12aa2002-12-28 00:04:08 +0000477void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000478 FlagSet use_flags, FlagSet set_flags )
479{
480 Bool use, set;
481
482 use = use_flags != FlagsEmpty
483 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
484 set = set_flags != FlagsEmpty;
485
486 if (0)
487 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000488 "new_emit: state=%d interacts_with_simd_flags=%d "
489 "use_flags=%x set_flags=%x\n",
490 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000491
sewardjf0f12aa2002-12-28 00:04:08 +0000492 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000493 if (use && eflags_state == UPD_Simd) {
494 /* we need the CPU flags set, but they're not already */
495 eflags_state = UPD_Both;
496 emit_get_eflags();
497 }
498 if (set) {
499 /* if we're setting the flags, then the CPU will have the
500 only good copy */
501 eflags_state = UPD_Real;
502 }
503 } else {
504 /* presume that if non-simd code is using flags, it knows what
505 it's doing (ie, it just set up the flags). */
506 if (set) {
507 /* This instruction is going to trash the flags, so we'd
508 better save them away and say that they're only in the
509 simulated state. */
510 maybe_emit_put_eflags();
511 eflags_state = UPD_Simd;
512 }
513 }
514
sewardjde4a1d02002-03-22 01:27:54 +0000515 if (dis)
516 VG_(printf)("\t %4d: ", emitted_code_used );
517}
518
sewardjde4a1d02002-03-22 01:27:54 +0000519
520/*----------------------------------------------------*/
521/*--- Addressing modes ---*/
522/*----------------------------------------------------*/
523
524static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
525{
526 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
527}
528
529static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
530{
531 Int shift;
532 switch (scale) {
533 case 1: shift = 0; break;
534 case 2: shift = 1; break;
535 case 4: shift = 2; break;
536 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000537 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
540}
541
542static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
543{
544 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000545 VG_(emitB) ( mkModRegRM(0, reg, 5) );
546 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000547}
548
549static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
550{
551 /* (regmem), reg */
552 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000553 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( mkModRegRM(1, reg, 5) );
556 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000557 } else {
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000559 }
560}
561
njn25e49d8e72002-09-23 09:36:25 +0000562void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000563{
564 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 if (off < -128 || off > 127) {
567 /* Use a large offset */
568 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
570 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000571 } else {
572 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
574 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000575 }
576}
577
578static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
579 Int regindex, Int reg )
580{
581 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000582 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (off < -128 || off > 127) {
584 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000585 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
586 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
587 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000588 } else {
589 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
591 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
592 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000593 }
594}
595
njn25e49d8e72002-09-23 09:36:25 +0000596void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000597{
598 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000599 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000600}
601
602static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
603{
604 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000606}
607
608
609/*----------------------------------------------------*/
610/*--- Opcode translation ---*/
611/*----------------------------------------------------*/
612
613static __inline__ Int mkGrp1opcode ( Opcode opc )
614{
615 switch (opc) {
616 case ADD: return 0;
617 case OR: return 1;
618 case ADC: return 2;
619 case SBB: return 3;
620 case AND: return 4;
621 case SUB: return 5;
622 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000623 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000624 }
625}
626
sewardjfa492d42002-12-08 18:20:01 +0000627static __inline__ FlagSet nonshiftop_use(Opcode opc)
628{
629 switch(opc) {
630 case ADC:
631 case SBB:
632 return FlagC;
633
634 case ADD:
635 case OR:
636 case AND:
637 case SUB:
638 case XOR:
639 return FlagsEmpty;
640
641 default:
642 VG_(core_panic)("nonshiftop_use");
643 }
644}
645
646static __inline__ FlagSet nonshiftop_set(Opcode opc)
647{
648 switch(opc) {
649 case ADC:
650 case SBB:
651 case ADD:
652 case OR:
653 case AND:
654 case SUB:
655 case XOR:
656 return FlagsOSZACP;
657
658 default:
659 VG_(core_panic)("nonshiftop_set");
660 }
661}
662
sewardjde4a1d02002-03-22 01:27:54 +0000663static __inline__ Int mkGrp2opcode ( Opcode opc )
664{
665 switch (opc) {
666 case ROL: return 0;
667 case ROR: return 1;
668 case RCL: return 2;
669 case RCR: return 3;
670 case SHL: return 4;
671 case SHR: return 5;
672 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000673 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000674 }
675}
676
sewardjfa492d42002-12-08 18:20:01 +0000677static __inline__ FlagSet shiftop_use(Opcode opc)
678{
679 switch(opc) {
680 case ROR:
681 case ROL:
682 case SHL:
683 case SHR:
684 case SAR:
685 return FlagsEmpty;
686
687 case RCL:
688 case RCR:
689 return FlagC;
690
691 default:
692 VG_(core_panic)("shiftop_use");
693 }
694}
695
696static __inline__ FlagSet shiftop_set(Opcode opc)
697{
698 switch(opc) {
699 case ROR:
700 case ROL:
701 case RCL:
702 case RCR:
703 return FlagsOC;
704
705 case SHL:
706 case SHR:
707 case SAR:
708 return FlagsOSZACP;
709
710 default:
711 VG_(core_panic)("shiftop_set");
712 }
713}
714
sewardjde4a1d02002-03-22 01:27:54 +0000715static __inline__ Int mkGrp3opcode ( Opcode opc )
716{
717 switch (opc) {
718 case NOT: return 2;
719 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000720 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000721 }
722}
723
724static __inline__ Int mkGrp4opcode ( Opcode opc )
725{
726 switch (opc) {
727 case INC: return 0;
728 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000729 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000730 }
731}
732
733static __inline__ Int mkGrp5opcode ( Opcode opc )
734{
735 switch (opc) {
736 case CALLM: return 2;
737 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000738 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000739 }
740}
741
742static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
743{
744 switch (opc) {
745 case ADD: return 0x00;
746 case ADC: return 0x10;
747 case AND: return 0x20;
748 case XOR: return 0x30;
749 case OR: return 0x08;
750 case SBB: return 0x18;
751 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000752 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000753 }
754}
755
756/*----------------------------------------------------*/
757/*--- v-size (4, or 2 with OSO) insn emitters ---*/
758/*----------------------------------------------------*/
759
njn25e49d8e72002-09-23 09:36:25 +0000760void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000761{
sewardjf0f12aa2002-12-28 00:04:08 +0000762 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000763 if (sz == 2) VG_(emitB) ( 0x66 );
764 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
765 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000766 if (dis)
767 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
768 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
769}
770
njn25e49d8e72002-09-23 09:36:25 +0000771void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000772{
sewardjf0f12aa2002-12-28 00:04:08 +0000773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000774 if (sz == 2) VG_(emitB) ( 0x66 );
775 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
776 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
779 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
780}
781
782static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
783{
sewardjf0f12aa2002-12-28 00:04:08 +0000784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000785 if (sz == 2) VG_(emitB) ( 0x66 );
786 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000787 emit_amode_regmem_reg ( reg1, reg2 );
788 if (dis)
789 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
790 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
791}
792
793static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000798 emit_amode_regmem_reg ( reg2, reg1 );
799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
801 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000807 if (sz == 2) VG_(emitB) ( 0x66 );
808 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
809 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000810 if (dis)
811 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
812 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
813}
814
sewardjf0f12aa2002-12-28 00:04:08 +0000815void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
816 Int sz, Opcode opc,
817 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjf0f12aa2002-12-28 00:04:08 +0000819 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000820
njn25e49d8e72002-09-23 09:36:25 +0000821 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
823 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000824 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
825 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
826 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000827 } else {
njn25e49d8e72002-09-23 09:36:25 +0000828 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
829 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
830 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000831 }
832 if (dis)
833 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000834 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000835 lit, nameIReg(sz,reg));
836}
837
sewardjf0f12aa2002-12-28 00:04:08 +0000838void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
839 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000840 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000841{
sewardjf0f12aa2002-12-28 00:04:08 +0000842 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000843 if (sz == 2) VG_(emitB) ( 0x66 );
844 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
845 /* short form OK */
846 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
847 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
848 VG_(emitB) ( lit & 0x000000FF );
849 } else {
850 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
851 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
852 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
853 }
854 if (dis)
855 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
856 VG_(name_UOpcode)(False,opc), nameISize(sz),
857 lit, off, nameIReg(sz,regmem));
858}
859
sewardjf0f12aa2002-12-28 00:04:08 +0000860void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
861 Int sz, Opcode opc,
862 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000863{
sewardjf0f12aa2002-12-28 00:04:08 +0000864 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000865
njn25e49d8e72002-09-23 09:36:25 +0000866 if (sz == 2) VG_(emitB) ( 0x66 );
867 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
868 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
869 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000870 if (dis)
871 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000872 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000873 lit, nameIReg(sz,reg));
874}
875
sewardjf0f12aa2002-12-28 00:04:08 +0000876static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000877{
sewardjf0f12aa2002-12-28 00:04:08 +0000878 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000879 if (sz == 2) VG_(emitB) ( 0x66 );
880 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
881 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
882 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
883 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000886 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000890{
sewardjf0f12aa2002-12-28 00:04:08 +0000891 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000892 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
893 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
894 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
895 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000896 if (dis)
897 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000898 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000899}
900
sewardjf0f12aa2002-12-28 00:04:08 +0000901static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
902 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000903 Int off, Int areg, Int reg )
904{
sewardjf0f12aa2002-12-28 00:04:08 +0000905 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000906 if (sz == 2) VG_(emitB) ( 0x66 );
907 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
908 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000909 if (dis)
910 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000911 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000912 off, nameIReg(4,areg), nameIReg(sz,reg));
913}
914
sewardja2c5a732002-12-15 03:10:42 +0000915#if 0
916/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000917static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000918 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000919{
sewardjf0f12aa2002-12-28 00:04:08 +0000920 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000921 if (sz == 2) VG_(emitB) ( 0x66 );
922 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
923 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
926 VG_(name_UOpcode)(False,opc), nameISize(sz),
927 nameIReg(sz,reg), off, nameIReg(4,areg));
928}
sewardja2c5a732002-12-15 03:10:42 +0000929#endif
sewardjfa492d42002-12-08 18:20:01 +0000930
sewardjf0f12aa2002-12-28 00:04:08 +0000931void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000932 Int reg1, Int reg2 )
933{
sewardjf0f12aa2002-12-28 00:04:08 +0000934 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000936# if 0
937 /* Perfectly correct, but the GNU assembler uses the other form.
938 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
940 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000941# else
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000943 emit_amode_greg_ereg ( reg1, reg2 );
944# endif
945 if (dis)
946 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000947 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000948 nameIReg(sz,reg1), nameIReg(sz,reg2));
949}
950
njn25e49d8e72002-09-23 09:36:25 +0000951void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000952{
sewardjf0f12aa2002-12-28 00:04:08 +0000953#if 0
sewardjfa492d42002-12-08 18:20:01 +0000954 if (lit == 0 && eflags_state != UPD_Real) {
955 /* Only emit this for zeroing if it won't stomp flags */
956 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000957 return;
958 }
sewardjf0f12aa2002-12-28 00:04:08 +0000959#endif
960 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000961 if (sz == 2) VG_(emitB) ( 0x66 );
962 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
963 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000964 if (dis)
965 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
966 nameISize(sz), lit, nameIReg(sz,reg));
967}
968
sewardjf0f12aa2002-12-28 00:04:08 +0000969void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjde4a1d02002-03-22 01:27:54 +0000971 switch (opc) {
972 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +0000973 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +0000974 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000975 VG_(emitB) ( 0xF7 );
976 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000977 if (dis)
978 VG_(printf)( "\n\t\tneg%c\t%s\n",
979 nameISize(sz), nameIReg(sz,reg));
980 break;
981 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +0000982 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +0000983 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000984 VG_(emitB) ( 0xF7 );
985 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000986 if (dis)
987 VG_(printf)( "\n\t\tnot%c\t%s\n",
988 nameISize(sz), nameIReg(sz,reg));
989 break;
990 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +0000991 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tdec%c\t%s\n",
996 nameISize(sz), nameIReg(sz,reg));
997 break;
998 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +0000999 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001000 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001001 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (dis)
1003 VG_(printf)( "\n\t\tinc%c\t%s\n",
1004 nameISize(sz), nameIReg(sz,reg));
1005 break;
1006 default:
njne427a662002-10-02 11:08:25 +00001007 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001008 }
1009}
1010
njn25e49d8e72002-09-23 09:36:25 +00001011void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001014 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001016 } else {
1017 vg_assert(sz == 4);
1018 }
njn25e49d8e72002-09-23 09:36:25 +00001019 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001020 if (dis)
1021 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1022}
1023
njn25e49d8e72002-09-23 09:36:25 +00001024void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001025{
sewardjf0f12aa2002-12-28 00:04:08 +00001026 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001029 } else {
1030 vg_assert(sz == 4);
1031 }
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1035}
1036
njn25e49d8e72002-09-23 09:36:25 +00001037void VG_(emit_pushl_lit32) ( UInt int32 )
1038{
sewardjf0f12aa2002-12-28 00:04:08 +00001039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001040 VG_(emitB) ( 0x68 );
1041 VG_(emitL) ( int32 );
1042 if (dis)
1043 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1044}
1045
1046void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001047{
1048 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001049 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x6A );
1051 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001052 if (dis)
1053 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1054}
1055
sewardjf0f12aa2002-12-28 00:04:08 +00001056void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001057{
sewardjf0f12aa2002-12-28 00:04:08 +00001058 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x83 );
1060 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1061 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001062 if (dis)
1063 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1064}
1065
1066static void emit_swapl_reg_ECX ( Int reg )
1067{
sewardjf0f12aa2002-12-28 00:04:08 +00001068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1070 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001078 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001079 if (dis)
1080 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1081}
1082
1083static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1084{
sewardjf0f12aa2002-12-28 00:04:08 +00001085 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1087 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
1093static void emit_bswapl_reg ( Int reg )
1094{
sewardjf0f12aa2002-12-28 00:04:08 +00001095 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F );
1097 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1100}
1101
1102static void emit_movl_reg_reg ( Int regs, Int regd )
1103{
sewardjf0f12aa2002-12-28 00:04:08 +00001104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001105 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1106 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001107 if (dis)
1108 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1109}
1110
njn25e49d8e72002-09-23 09:36:25 +00001111void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001112{
sewardjf0f12aa2002-12-28 00:04:08 +00001113 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001114 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001115 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 } else {
1117 vg_assert(sz == 4);
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1120 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1121 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1124 nameISize(sz), lit, off, nameIReg(4,memreg) );
1125}
1126
1127
1128/*----------------------------------------------------*/
1129/*--- b-size (1 byte) instruction emitters ---*/
1130/*----------------------------------------------------*/
1131
1132/* There is some doubt as to whether C6 (Grp 11) is in the
1133 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001134void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1138 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1139 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (dis)
1141 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1142 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001143}
1144
sewardjf0f12aa2002-12-28 00:04:08 +00001145static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001146 Int off, Int areg, Int reg )
1147{
sewardjf0f12aa2002-12-28 00:04:08 +00001148 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001149 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1150 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001151 if (dis)
1152 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001154 nameIReg(1,reg));
1155}
1156
sewardjf0f12aa2002-12-28 00:04:08 +00001157static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001158 UInt lit, Int off, Int areg )
1159{
sewardjf0f12aa2002-12-28 00:04:08 +00001160 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001161 VG_(emitB) ( 0x80 );
1162 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1163 VG_(emitB) ( lit );
1164 if (dis)
1165 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1166 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1167}
1168
sewardja2c5a732002-12-15 03:10:42 +00001169#if 0
1170/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001171static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001172 Int off, Int areg, Int reg )
1173{
sewardjf0f12aa2002-12-28 00:04:08 +00001174 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001175 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1176 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1177 if (dis)
1178 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1179 VG_(name_UOpcode)(False,opc),
1180 nameIReg(1,reg),
1181 off, nameIReg(4,areg));
1182}
sewardja2c5a732002-12-15 03:10:42 +00001183#endif
sewardjfa492d42002-12-08 18:20:01 +00001184
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001186{
1187 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001188 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001189 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1190 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1193 nameIReg(1,reg), off, nameIReg(4,areg));
1194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1197 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg1), nameIReg(1,reg2));
1206}
1207
1208static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1209{
sewardjf0f12aa2002-12-28 00:04:08 +00001210 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001212 emit_amode_regmem_reg ( reg2, reg1 );
1213 if (dis)
1214 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1215 nameIReg(4,reg2));
1216}
1217
sewardjf0f12aa2002-12-28 00:04:08 +00001218static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1219 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001220{
sewardjf0f12aa2002-12-28 00:04:08 +00001221 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001222 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1223 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1224 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001225 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001226 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001227 lit, nameIReg(1,reg));
1228}
1229
sewardjf0f12aa2002-12-28 00:04:08 +00001230static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1231 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001232{
sewardjf0f12aa2002-12-28 00:04:08 +00001233 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001234 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1235 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1236 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001237 if (dis)
1238 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001239 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001240 lit, nameIReg(1,reg));
1241}
1242
sewardjf0f12aa2002-12-28 00:04:08 +00001243void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001244{
sewardjde4a1d02002-03-22 01:27:54 +00001245 switch (opc) {
1246 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001247 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001248 VG_(emitB) ( 0xFE );
1249 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001250 if (dis)
1251 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1252 break;
1253 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001254 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001255 VG_(emitB) ( 0xFE );
1256 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001257 if (dis)
1258 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1259 break;
1260 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001262 VG_(emitB) ( 0xF6 );
1263 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001264 if (dis)
1265 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1266 break;
1267 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xF6 );
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001271 if (dis)
1272 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1273 break;
1274 default:
njne427a662002-10-02 11:08:25 +00001275 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001276 }
1277}
1278
sewardjf0f12aa2002-12-28 00:04:08 +00001279void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001280{
sewardjf0f12aa2002-12-28 00:04:08 +00001281 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001282 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1283 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1284 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1287}
1288
sewardjde4a1d02002-03-22 01:27:54 +00001289/*----------------------------------------------------*/
1290/*--- zero-extended load emitters ---*/
1291/*----------------------------------------------------*/
1292
njn25e49d8e72002-09-23 09:36:25 +00001293void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001294{
sewardjf0f12aa2002-12-28 00:04:08 +00001295 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001296 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1297 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001298 if (dis)
1299 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1300 off, nameIReg(4,regmem), nameIReg(4,reg));
1301}
1302
1303static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1304{
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001307 emit_amode_regmem_reg ( reg1, reg2 );
1308 if (dis)
1309 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1310 nameIReg(4,reg2));
1311}
1312
njn25e49d8e72002-09-23 09:36:25 +00001313void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001314{
sewardjf0f12aa2002-12-28 00:04:08 +00001315 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001316 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1317 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001318 if (dis)
1319 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1320 off, nameIReg(4,areg), nameIReg(4,reg));
1321}
1322
1323static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1324{
sewardjf0f12aa2002-12-28 00:04:08 +00001325 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001327 emit_amode_regmem_reg ( reg1, reg2 );
1328 if (dis)
1329 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1330 nameIReg(4,reg2));
1331}
1332
1333/*----------------------------------------------------*/
1334/*--- FPU instruction emitters ---*/
1335/*----------------------------------------------------*/
1336
sewardjb91ae7f2003-04-29 23:50:00 +00001337static void emit_get_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001338{
sewardjb91ae7f2003-04-29 23:50:00 +00001339 Int off = 4 * VGOFF_(m_ssestate);
1340 if (VG_(have_ssestate)) {
1341 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1342 VG_(emitB) ( 0x0F );
1343 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x8D ); /* fxrstor d32(%ebp) */
1344 VG_(emitL) ( off );
1345 if (dis)
1346 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1347 } else {
1348 /* Not a SSE-capable CPU. Just do frstor. */
1349 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1350 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1351 VG_(emitL) ( off );
1352 if (dis)
1353 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1354 }
sewardjde4a1d02002-03-22 01:27:54 +00001355}
1356
sewardjb91ae7f2003-04-29 23:50:00 +00001357static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001358{
sewardjb91ae7f2003-04-29 23:50:00 +00001359 Int off = 4 * VGOFF_(m_ssestate);
1360 if (VG_(have_ssestate)) {
1361 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1362 VG_(emitB) ( 0x0F );
1363 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1364 VG_(emitL) ( off );
1365 if (dis)
1366 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1367 } else {
1368 /* Not a SSE-capable CPU. Just do fnsave. */
1369 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1370 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1371 VG_(emitL) ( off );
1372 if (dis)
1373 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1374 }
sewardjde4a1d02002-03-22 01:27:54 +00001375}
1376
sewardjf0f12aa2002-12-28 00:04:08 +00001377static void emit_fpu_no_mem ( FlagSet uses_sflags,
1378 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001379 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001380 UChar second_byte )
1381{
sewardjf0f12aa2002-12-28 00:04:08 +00001382 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001383 VG_(emitB) ( first_byte );
1384 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001385 if (dis)
1386 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1387 (UInt)first_byte, (UInt)second_byte );
1388}
1389
sewardjf0f12aa2002-12-28 00:04:08 +00001390static void emit_fpu_regmem ( FlagSet uses_sflags,
1391 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001392 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001393 UChar second_byte_masked,
1394 Int reg )
1395{
sewardjf0f12aa2002-12-28 00:04:08 +00001396 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001397 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001398 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1399 if (dis)
1400 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1401 (UInt)first_byte, (UInt)second_byte_masked,
1402 nameIReg(4,reg) );
1403}
1404
sewardj3d7c9c82003-03-26 21:08:13 +00001405static void emit_MMX2_regmem ( FlagSet uses_sflags,
1406 FlagSet sets_sflags,
1407 UChar first_byte,
1408 UChar second_byte,
1409 Int ireg )
1410{
1411 VG_(new_emit)(True, uses_sflags, sets_sflags);
1412 VG_(emitB) ( 0x0F );
1413 VG_(emitB) ( first_byte );
1414 second_byte &= 0x38; /* mask out mod and rm fields */
1415 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1416 if (dis)
1417 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1418 (UInt)first_byte, (UInt)second_byte,
1419 nameIReg(4,ireg) );
1420}
1421
sewardjca860012003-03-27 23:52:58 +00001422static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1423 FlagSet sets_sflags,
1424 UChar first_byte,
1425 UChar second_byte,
1426 Int ireg )
1427{
1428 VG_(new_emit)(True, uses_sflags, sets_sflags);
1429 VG_(emitB) ( 0x0F );
1430 VG_(emitB) ( first_byte );
1431 second_byte &= 0x38; /* mask out mod and rm fields */
1432 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1433 second_byte |= (ireg & 7); /* patch in our ireg */
1434 VG_(emitB) ( second_byte );
1435 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001436 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1437 (UInt)first_byte, (UInt)second_byte,
1438 nameIReg(4,ireg) );
1439}
1440
1441static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1442 FlagSet sets_sflags,
1443 UChar first_byte,
1444 UChar second_byte,
1445 Int ireg )
1446{
1447 VG_(new_emit)(True, uses_sflags, sets_sflags);
1448 VG_(emitB) ( 0x0F );
1449 VG_(emitB) ( first_byte );
1450 second_byte &= 0x38; /* mask out mod and rm fields */
1451 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1452 second_byte |= (ireg & 7); /* patch in our ireg */
1453 VG_(emitB) ( second_byte );
1454 if (dis)
1455 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001456 (UInt)first_byte, (UInt)second_byte,
1457 nameIReg(4,ireg) );
1458}
1459
1460static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1461 FlagSet sets_sflags,
1462 UChar first_byte,
1463 UChar second_byte,
1464 UChar third_byte )
1465{
1466 VG_(new_emit)(True, uses_sflags, sets_sflags);
1467 VG_(emitB) ( 0x0F );
1468 VG_(emitB) ( first_byte );
1469 VG_(emitB) ( second_byte );
1470 VG_(emitB) ( third_byte );
1471 if (dis)
1472 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1473 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1474}
1475
sewardj3d7c9c82003-03-26 21:08:13 +00001476static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1477 FlagSet sets_sflags,
1478 UChar first_byte,
1479 UChar second_byte )
1480{
1481 VG_(new_emit)(True, uses_sflags, sets_sflags);
1482 VG_(emitB) ( 0x0F );
1483 VG_(emitB) ( first_byte );
1484 VG_(emitB) ( second_byte );
1485 if (dis)
1486 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1487 (UInt)first_byte, (UInt)second_byte );
1488}
1489
1490static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1491 FlagSet sets_sflags,
1492 UChar first_byte )
1493{
1494 VG_(new_emit)(True, uses_sflags, sets_sflags);
1495 VG_(emitB) ( 0x0F );
1496 VG_(emitB) ( first_byte );
1497 if (dis)
1498 VG_(printf)("\n\t\tmmx1-0x%x\n",
1499 (UInt)first_byte );
1500}
1501
sewardjde4a1d02002-03-22 01:27:54 +00001502
1503/*----------------------------------------------------*/
1504/*--- misc instruction emitters ---*/
1505/*----------------------------------------------------*/
1506
njn25e49d8e72002-09-23 09:36:25 +00001507void VG_(emit_call_reg) ( Int reg )
1508{
sewardjfa492d42002-12-08 18:20:01 +00001509 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001510 VG_(emitB) ( 0xFF ); /* Grp5 */
1511 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1512 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001513 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001514}
1515
sewardjf0f12aa2002-12-28 00:04:08 +00001516static
1517void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1518 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001519{
sewardjfa492d42002-12-08 18:20:01 +00001520 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001521 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001522
1523 if (byte_off < -128 || byte_off > 127) {
1524 VG_(emitB) ( 0xFF );
1525 VG_(emitB) ( 0x95 );
1526 VG_(emitL) ( byte_off );
1527 } else {
1528 VG_(emitB) ( 0xFF );
1529 VG_(emitB) ( 0x55 );
1530 VG_(emitB) ( byte_off );
1531 }
1532 if (dis)
1533 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001534}
1535
sewardja2c5a732002-12-15 03:10:42 +00001536#if 0
1537/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001538static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1539{
1540 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001541 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001542 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1543 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001544 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001545 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001546 if (dis)
1547 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1548 nameIReg(4,regmem));
1549}
sewardja2c5a732002-12-15 03:10:42 +00001550#endif
sewardjde4a1d02002-03-22 01:27:54 +00001551
njn25e49d8e72002-09-23 09:36:25 +00001552void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001553{
njne427a662002-10-02 11:08:25 +00001554 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001555 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1556 VG_(emitB) ( 0x8D );
1557 VG_(emitB) ( 0x64 );
1558 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001559 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001560 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001561 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001562}
1563
1564
1565static void emit_movb_AL_zeroESPmem ( void )
1566{
1567 /* movb %al, 0(%esp) */
1568 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001569 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001570 VG_(emitB) ( 0x88 );
1571 VG_(emitB) ( 0x44 );
1572 VG_(emitB) ( 0x24 );
1573 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001574 if (dis)
1575 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1576}
1577
1578static void emit_movb_zeroESPmem_AL ( void )
1579{
1580 /* movb 0(%esp), %al */
1581 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001582 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001583 VG_(emitB) ( 0x8A );
1584 VG_(emitB) ( 0x44 );
1585 VG_(emitB) ( 0x24 );
1586 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001587 if (dis)
1588 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1589}
1590
sewardja2113f92002-12-12 23:42:48 +00001591/* Jump target states */
1592#define TGT_UNDEF (1 << 16)
1593#define TGT_FORWARD (2 << 16)
1594#define TGT_BACKWARD (3 << 16)
1595
1596static inline Int tgt_state(Int tgt)
1597{
1598 return tgt & 0xffff0000;
1599}
1600
1601static inline Int tgt_addr(Int tgt)
1602{
1603 return tgt & 0x0000ffff;
1604}
1605
1606static inline Int mk_tgt(Int state, Int addr)
1607{
1608 vg_assert(state == TGT_UNDEF
1609 || state == TGT_FORWARD || state == TGT_BACKWARD);
1610 vg_assert((addr & 0xffff0000) == 0);
1611
1612 return state | addr;
1613}
1614
1615void VG_(init_target) ( Int *tgt )
1616{
1617 *tgt = TGT_UNDEF;
1618}
1619
1620void VG_(target_back) ( Int *tgt )
1621{
1622 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1623
1624 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1625}
1626
1627void VG_(target_forward) ( Int *tgt )
1628{
1629 Int delta;
1630
1631 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1632 tgt_state(*tgt) == TGT_UNDEF);
1633
1634 if (tgt_state(*tgt) == TGT_UNDEF)
1635 return; /* target not used */
1636
1637 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1638 vg_assert(delta >= -128 && delta <= 127);
1639 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001640 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001641 emitted_code[tgt_addr(*tgt)] = delta;
1642 if (dis)
1643 VG_(printf)("(target to jump site %d; delta: %d)\n",
1644 tgt_addr(*tgt), delta);
1645}
1646
1647void VG_(emit_target_delta) ( Int *tgt )
1648{
1649 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1650 tgt_state(*tgt) == TGT_BACKWARD);
1651
1652 if (tgt_state(*tgt) == TGT_UNDEF) {
1653 /* forward jump */
1654 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1655 VG_(emitB) (0x00);
1656 } else {
1657 /* backward jump */
1658 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1659 vg_assert(delta >= -128 && delta <= 127);
1660 VG_(emitB) (delta);
1661 }
1662}
1663
sewardjde4a1d02002-03-22 01:27:54 +00001664
1665/* Emit a jump short with an 8-bit signed offset. Note that the
1666 offset is that which should be added to %eip once %eip has been
1667 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001668void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001669{
1670 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001671 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001672 VG_(emitB) ( 0x70 + (UInt)cond );
1673 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001674 if (dis)
1675 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001676 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001677}
1678
sewardja2113f92002-12-12 23:42:48 +00001679/* Same as above, but defers emitting the delta */
1680void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1681{
sewardj706240d2002-12-26 17:10:12 +00001682 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001683 VG_(emitB) ( 0x70 + (UInt)cond );
1684 VG_(emit_target_delta) (tgt);
1685 if (dis)
1686 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001687 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001688}
1689
1690
1691
sewardjf0f12aa2002-12-28 00:04:08 +00001692static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001693{
sewardjf0f12aa2002-12-28 00:04:08 +00001694 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001695 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1696 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001697 if (dis)
1698 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001699 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001700}
1701
1702static void emit_ret ( void )
1703{
sewardjfa492d42002-12-08 18:20:01 +00001704 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001705 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001706 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001707 if (dis)
1708 VG_(printf)("\n\t\tret\n");
1709}
1710
sewardj22854b92002-11-30 14:00:47 +00001711/* Predicate used in sanity checks elsewhere - returns true if any
1712 jump-site is an actual chained jump */
1713Bool VG_(is_chained_jumpsite)(Addr a)
1714{
1715 UChar *cp = (UChar *)a;
1716
1717 return (*cp == 0xE9); /* 0xE9 -- jmp */
1718}
1719
sewardj83f11862002-12-01 02:07:08 +00001720static
1721Bool is_fresh_jumpsite(UChar *cp)
1722{
1723 return
1724 cp[0] == 0x0F && /* UD2 */
1725 cp[1] == 0x0B &&
1726 cp[2] == 0x0F && /* UD2 */
1727 cp[3] == 0x0B &&
1728 cp[4] == 0x90; /* NOP */
1729}
1730
sewardj22854b92002-11-30 14:00:47 +00001731/* Predicate used in sanity checks elsewhere - returns true if all
1732 jump-sites are calls to VG_(patch_me) */
1733Bool VG_(is_unchained_jumpsite)(Addr a)
1734{
1735 UChar *cp = (UChar *)a;
1736 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1737 Int idelta;
1738
1739 if (*cp++ != 0xE8) /* 0xE8 == call */
1740 return False;
1741
1742 idelta = (*cp++) << 0;
1743 idelta |= (*cp++) << 8;
1744 idelta |= (*cp++) << 16;
1745 idelta |= (*cp++) << 24;
1746
1747 return idelta == delta;
1748}
1749
1750/* Return target address for a direct jmp */
1751Addr VG_(get_jmp_dest)(Addr a)
1752{
1753 Int delta;
1754 UChar *cp = (UChar *)a;
1755
1756 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1757 return 0;
1758
1759 delta = (*cp++) << 0;
1760 delta |= (*cp++) << 8;
1761 delta |= (*cp++) << 16;
1762 delta |= (*cp++) << 24;
1763
1764 return a + VG_PATCHME_JMPSZ + delta;
1765}
1766
1767/* unchain a BB by generating a call to VG_(patch_me) */
1768void VG_(unchain_jumpsite)(Addr a)
1769{
1770 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1771 UChar *cp = (UChar *)a;
1772
1773 if (VG_(is_unchained_jumpsite)(a))
1774 return; /* don't write unnecessarily */
1775
sewardj83f11862002-12-01 02:07:08 +00001776 if (!is_fresh_jumpsite(cp))
1777 VG_(bb_dechain_count)++; /* update stats */
1778
sewardj22854b92002-11-30 14:00:47 +00001779 *cp++ = 0xE8; /* call */
1780 *cp++ = (delta >> 0) & 0xff;
1781 *cp++ = (delta >> 8) & 0xff;
1782 *cp++ = (delta >> 16) & 0xff;
1783 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001784}
1785
1786/* This doesn't actually generate a call to VG_(patch_me), but
1787 reserves enough space in the instruction stream for it to happen
1788 and records the offset into the jump table. This is because call
1789 is a relative jump, and so will be affected when this code gets
1790 moved about. The translation table will "unchain" this basic block
1791 on insertion (with VG_(unchain_BB)()), and thereby generate a
1792 proper call instruction. */
1793static void emit_call_patchme( void )
1794{
1795 vg_assert(VG_PATCHME_CALLSZ == 5);
1796
sewardjfa492d42002-12-08 18:20:01 +00001797 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001798 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001799
1800 if (jumpidx >= VG_MAX_JUMPS) {
1801 /* If there too many jumps in this basic block, fall back to
1802 dispatch loop. We still need to keep it the same size as the
1803 call sequence. */
1804 VG_(emitB) ( 0xC3 ); /* ret */
1805 VG_(emitB) ( 0x90 ); /* nop */
1806 VG_(emitB) ( 0x90 ); /* nop */
1807 VG_(emitB) ( 0x90 ); /* nop */
1808 VG_(emitB) ( 0x90 ); /* nop */
1809
1810 if (dis)
1811 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1812
1813 if (0 && VG_(clo_verbosity))
1814 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1815 } else {
1816 jumps[jumpidx++] = emitted_code_used;
1817
1818 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1819 VG_(emitB) ( 0x0B );
1820 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1821 VG_(emitB) ( 0x0B );
1822 VG_(emitB) ( 0x90 ); /* NOP */
1823
1824 if (dis)
1825 VG_(printf)("\n\t\tud2; ud2; nop\n");
1826 }
1827}
1828
njn25e49d8e72002-09-23 09:36:25 +00001829void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001830{
sewardjf0f12aa2002-12-28 00:04:08 +00001831 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001832 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001833 if (dis)
1834 VG_(printf)("\n\t\tpushal\n");
1835}
1836
njn25e49d8e72002-09-23 09:36:25 +00001837void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001838{
sewardjf0f12aa2002-12-28 00:04:08 +00001839 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001840 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001841 if (dis)
1842 VG_(printf)("\n\t\tpopal\n");
1843}
1844
1845static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1846{
sewardjf0f12aa2002-12-28 00:04:08 +00001847 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001848 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1849 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001850 if (dis)
1851 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1852 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1853}
1854
1855static void emit_lea_sib_reg ( UInt lit, Int scale,
1856 Int regbase, Int regindex, Int reg )
1857{
sewardjf0f12aa2002-12-28 00:04:08 +00001858 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001859 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001860 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1861 if (dis)
1862 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1863 lit, nameIReg(4,regbase),
1864 nameIReg(4,regindex), scale,
1865 nameIReg(4,reg) );
1866}
1867
njn25e49d8e72002-09-23 09:36:25 +00001868void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001869{
sewardjf0f12aa2002-12-28 00:04:08 +00001870 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001871 VG_(emitB) ( 0x0F );
1872 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001873 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1874 if (dis)
1875 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1876}
1877
1878/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001879/*--- Helper offset -> addr translation ---*/
1880/*----------------------------------------------------*/
1881
1882/* Finds the baseBlock offset of a skin-specified helper.
1883 * Searches through compacts first, then non-compacts. */
1884Int VG_(helper_offset)(Addr a)
1885{
sewardj05bcdcb2003-05-18 10:05:38 +00001886 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00001887 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001888
1889 for (i = 0; i < VG_(n_compact_helpers); i++)
1890 if (VG_(compact_helper_addrs)[i] == a)
1891 return VG_(compact_helper_offsets)[i];
1892 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1893 if (VG_(noncompact_helper_addrs)[i] == a)
1894 return VG_(noncompact_helper_offsets)[i];
1895
1896 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001897 VG_(get_fnname) ( a, buf, 100 );
1898
njn25e49d8e72002-09-23 09:36:25 +00001899 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001900 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1901 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001902
1903 VG_(printf)(" compact helpers: ");
1904 for (i = 0; i < VG_(n_compact_helpers); i++)
1905 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1906
1907 VG_(printf)("\n non-compact helpers: ");
1908 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1909 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1910
1911 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001912 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001913}
1914
1915/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001916/*--- Instruction synthesisers ---*/
1917/*----------------------------------------------------*/
1918
1919static Condcode invertCondition ( Condcode cond )
1920{
1921 return (Condcode)(1 ^ (UInt)cond);
1922}
1923
1924
1925/* Synthesise a call to *baseBlock[offset], ie,
1926 call * (4 x offset)(%ebp).
1927*/
sewardjfa492d42002-12-08 18:20:01 +00001928void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00001929 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001930{
1931 vg_assert(word_offset >= 0);
1932 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001933 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001934 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001935 }
sewardjf0f12aa2002-12-28 00:04:08 +00001936 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001937}
1938
njn25e49d8e72002-09-23 09:36:25 +00001939static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001940{
njn25e49d8e72002-09-23 09:36:25 +00001941 if (src != dst) {
1942 VG_(emit_movv_reg_reg) ( 4, src, dst );
1943 ccall_arg_setup_instrs++;
1944 }
njn6431be72002-07-28 09:53:34 +00001945}
njn25e49d8e72002-09-23 09:36:25 +00001946
1947/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1948static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1949{
1950 if (RealReg == tag) {
1951 maybe_emit_movl_reg_reg ( litOrReg, reg );
1952 } else if (Literal == tag) {
1953 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1954 ccall_arg_setup_instrs++;
1955 }
1956 else
njne427a662002-10-02 11:08:25 +00001957 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001958}
1959
1960static
1961void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1962{
1963 if (R_EAX == reg1) {
1964 VG_(emit_swapl_reg_EAX) ( reg2 );
1965 } else if (R_EAX == reg2) {
1966 VG_(emit_swapl_reg_EAX) ( reg1 );
1967 } else {
1968 emit_swapl_reg_reg ( reg1, reg2 );
1969 }
1970 ccall_arg_setup_instrs++;
1971}
1972
1973static
1974void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1975{
1976 if (dst1 != src2) {
1977 maybe_emit_movl_reg_reg ( src1, dst1 );
1978 maybe_emit_movl_reg_reg ( src2, dst2 );
1979
1980 } else if (dst2 != src1) {
1981 maybe_emit_movl_reg_reg ( src2, dst2 );
1982 maybe_emit_movl_reg_reg ( src1, dst1 );
1983
1984 } else {
1985 /* swap to break cycle */
1986 emit_swapl_arg_regs ( dst1, dst2 );
1987 }
1988}
1989
1990static
1991void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1992 UInt dst1, UInt dst2, UInt dst3)
1993{
1994 if (dst1 != src2 && dst1 != src3) {
1995 maybe_emit_movl_reg_reg ( src1, dst1 );
1996 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1997
1998 } else if (dst2 != src1 && dst2 != src3) {
1999 maybe_emit_movl_reg_reg ( src2, dst2 );
2000 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2001
2002 } else if (dst3 != src1 && dst3 != src2) {
2003 maybe_emit_movl_reg_reg ( src3, dst3 );
2004 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2005
2006 } else {
2007 /* break cycle */
2008 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2009 emit_swapl_arg_regs ( dst1, dst2 );
2010 emit_swapl_arg_regs ( dst1, dst3 );
2011
2012 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2013 emit_swapl_arg_regs ( dst1, dst3 );
2014 emit_swapl_arg_regs ( dst1, dst2 );
2015
2016 } else {
njne427a662002-10-02 11:08:25 +00002017 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002018 }
2019 }
2020}
2021
2022static
2023void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2024 UInt src1, UInt src2,
2025 UInt dst1, UInt dst2)
2026{
2027 /* If either are lits, order doesn't matter */
2028 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2029 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2030 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2031
2032 } else {
2033 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2034 }
2035}
2036
2037static
2038void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2039 UInt src1, UInt src2, UInt src3,
2040 UInt dst1, UInt dst2, UInt dst3)
2041{
2042 // SSS: fix this eventually -- make STOREV use two RealRegs?
2043 /* Not supporting literals for 3-arg C functions -- they're only used
2044 by STOREV which has 2 args */
2045 vg_assert(RealReg == tagv[src1] &&
2046 RealReg == tagv[src2] &&
2047 RealReg == tagv[src3]);
2048 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2049 dst1, dst2, dst3 );
2050}
2051
2052/* Synthesise a call to a C function `fn' (which must be registered in
2053 baseBlock) doing all the reg saving and arg handling work.
2054
2055 WARNING: a UInstr should *not* be translated with synth_ccall followed
2056 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2057 such behaviour and everything will fall over.
2058 */
2059void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2060 Tag tagv[], Int ret_reg,
2061 RRegSet regs_live_before, RRegSet regs_live_after )
2062{
2063 Int i;
2064 Int stack_used = 0;
2065 Bool preserve_eax, preserve_ecx, preserve_edx;
2066
2067 vg_assert(0 <= regparms_n && regparms_n <= 3);
2068
2069 ccalls++;
2070
2071 /* If %e[acd]x is live before and after the C call, save/restore it.
2072 Unless the return values clobbers the reg; in this case we must not
2073 save/restore the reg, because the restore would clobber the return
2074 value. (Before and after the UInstr really constitute separate live
2075 ranges, but you miss this if you don't consider what happens during
2076 the UInstr.) */
2077# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002078 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2079 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002080 ret_reg != realReg)
2081
2082 preserve_eax = PRESERVE_REG(R_EAX);
2083 preserve_ecx = PRESERVE_REG(R_ECX);
2084 preserve_edx = PRESERVE_REG(R_EDX);
2085
2086# undef PRESERVE_REG
2087
2088 /* Save caller-save regs as required */
2089 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2090 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2091 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2092
2093 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2094 is the number of args passed in regs (maximum 3 for GCC on x86). */
2095
2096 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002097
njn25e49d8e72002-09-23 09:36:25 +00002098 /* First push stack args (RealRegs or Literals) in reverse order. */
2099 for (i = argc-1; i >= regparms_n; i--) {
2100 switch (tagv[i]) {
2101 case RealReg:
2102 VG_(emit_pushv_reg) ( 4, argv[i] );
2103 break;
2104 case Literal:
2105 /* Use short form of pushl if possible. */
2106 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2107 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2108 else
2109 VG_(emit_pushl_lit32)( argv[i] );
2110 break;
2111 default:
2112 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002113 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002114 }
2115 stack_used += 4;
2116 ccall_arg_setup_instrs++;
2117 }
njn6431be72002-07-28 09:53:34 +00002118
njn25e49d8e72002-09-23 09:36:25 +00002119 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2120 If moving values between registers, be careful not to clobber any on
2121 the way. Happily we can use xchgl to swap registers.
2122 */
2123 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002124
njn25e49d8e72002-09-23 09:36:25 +00002125 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2126 case 3:
2127 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2128 R_EAX, R_EDX, R_ECX );
2129 break;
njn6431be72002-07-28 09:53:34 +00002130
njn25e49d8e72002-09-23 09:36:25 +00002131 /* Less-tricky. Args passed in %eax and %edx. */
2132 case 2:
2133 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2134 break;
2135
2136 /* Easy. Just move arg1 into %eax (if not already in there). */
2137 case 1:
2138 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2139 break;
2140
2141 case 0:
2142 break;
2143
2144 default:
njne427a662002-10-02 11:08:25 +00002145 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002146 }
2147
sewardjfa492d42002-12-08 18:20:01 +00002148 /* Call the function - may trash all flags */
2149 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002150
2151 /* Clear any args from stack */
2152 if (0 != stack_used) {
2153 VG_(emit_add_lit_to_esp) ( stack_used );
2154 ccall_stack_clears++;
2155 }
2156
2157 /* Move return value into ret_reg if necessary and not already there */
2158 if (INVALID_REALREG != ret_reg) {
2159 ccall_retvals++;
2160 if (R_EAX != ret_reg) {
2161 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2162 ccall_retval_movs++;
2163 }
2164 }
2165
2166 /* Restore live caller-save regs as required */
2167 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2168 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2169 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002170}
sewardjde4a1d02002-03-22 01:27:54 +00002171
sewardj2e93c502002-04-12 11:12:52 +00002172static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002173{
sewardj2e93c502002-04-12 11:12:52 +00002174 switch (jmpkind) {
2175 case JmpBoring:
2176 break;
sewardj2e93c502002-04-12 11:12:52 +00002177 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002178 break;
2179 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002180 break;
2181 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002182 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002183 break;
2184 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002185 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002186 break;
2187 default:
njne427a662002-10-02 11:08:25 +00002188 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002189 }
2190}
2191
2192/* Jump to the next translation, by loading its original addr into
2193 %eax and returning to the scheduler. Signal special requirements
2194 by loading a special value into %ebp first.
2195*/
2196static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2197{
sewardjfa492d42002-12-08 18:20:01 +00002198 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002199 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002200 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002201 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002202 emit_ret();
2203}
2204
sewardj22854b92002-11-30 14:00:47 +00002205static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002206
2207/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002208static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002209{
sewardjfa492d42002-12-08 18:20:01 +00002210 maybe_emit_put_eflags(); /* save flags here */
2211
njn25e49d8e72002-09-23 09:36:25 +00002212 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002213
2214 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2215 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2216 emit_call_patchme();
2217 } else {
2218 load_ebp_from_JmpKind ( jmpkind );
2219 emit_ret();
2220 }
sewardjde4a1d02002-03-22 01:27:54 +00002221}
2222
2223
sewardj2370f3b2002-11-30 15:01:01 +00002224static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002225static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002226 Opcode opcode, Int size,
2227 UInt lit, Int reg );
2228
sewardjfa492d42002-12-08 18:20:01 +00002229static void synth_jcond_lit ( Condcode cond,
2230 Addr addr,
2231 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002232{
sewardj2370f3b2002-11-30 15:01:01 +00002233 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002234 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002235 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002236
sewardja2113f92002-12-12 23:42:48 +00002237 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002238 VG_(init_target)(&tgt2);
2239 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002240
sewardjfa492d42002-12-08 18:20:01 +00002241 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2242 if need be */
2243 maybe_emit_put_eflags();
2244 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2245
2246 if (eflags_state == UPD_Both) {
2247 /* The flags are already set up, so we just use them as is. */
2248 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002249 cond = invertCondition(cond);
2250 } else {
sewardj75f04932002-12-12 23:13:21 +00002251 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002252
2253 /* The simd state contains the most recent version, so we emit a
2254 sequence to calculate the relevant condition directly out of
2255 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2256 copying them back to the real flags via popf. Notice that
2257 some of these sequences trash %eax, but that should be free
2258 now since this is the end of a bb and therefore all regs are
2259 dead. */
2260 simd = False;
2261
2262 switch (cond) {
2263
sewardjbb6c1182002-12-12 23:54:47 +00002264 case CondLE: /* Z || S != O -> S || !P */
2265 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002266 vg_assert(eax_trashable);
2267
2268 VG_(emit_movv_offregmem_reg)
2269 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2270 /* eax == %EFLAGS */
2271
sewardjbb6c1182002-12-12 23:54:47 +00002272 VG_(emit_nonshiftopv_lit_reg)
2273 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2274 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002275
sewardjbb6c1182002-12-12 23:54:47 +00002276 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2277 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002278
sewardj09736622002-12-28 00:19:00 +00002279 /* actually set the real cpu flags, since ROR changes
2280 neither P nor Z */
2281 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2282
sewardjbb6c1182002-12-12 23:54:47 +00002283 if (cond == CondLE) {
2284 /* test Z */
2285 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2286 /* test OF != SF */
2287 cond = CondP;
2288 } else {
2289 /* test Z */
2290 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2291 /* test OF == SF */
2292 cond = CondNP;
2293 }
sewardj2370f3b2002-11-30 15:01:01 +00002294 break;
2295
sewardjfa492d42002-12-08 18:20:01 +00002296 case CondL:
2297 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002298 vg_assert(eax_trashable);
2299
2300 VG_(emit_movv_offregmem_reg)
2301 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2302 /* eax == %EFLAGS */
2303
sewardj75f04932002-12-12 23:13:21 +00002304 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2305 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002306
sewardj75f04932002-12-12 23:13:21 +00002307 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2308 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002309
sewardj09736622002-12-28 00:19:00 +00002310 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002311 if (cond == CondL) cond = CondP; else cond = CondNP;
2312 break;
sewardjfa492d42002-12-08 18:20:01 +00002313
2314 case CondB:
2315 case CondNB:
2316 mask = EFlagC; goto simple; /* C=1 */
2317
2318 case CondZ:
2319 case CondNZ:
2320 mask = EFlagZ; goto simple; /* Z=1 */
2321
2322 case CondBE:
2323 case CondNBE:
2324 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2325
2326 case CondS:
2327 case CondNS:
2328 mask = EFlagS; goto simple; /* S=1 */
2329
2330 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002331 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002332 mask = EFlagP; goto simple; /* P=1 */
2333
sewardj39542072002-12-09 22:44:00 +00002334 case CondO:
2335 case CondNO:
2336 mask = EFlagO; goto simple; /* O=1 */
2337
sewardjfa492d42002-12-08 18:20:01 +00002338 default:
2339 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002340 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002341 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2342
2343 simple:
2344 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002345 if ((mask & 0xff) == mask) {
2346 VG_(emitB) ( 0xF6 ); /* Grp3 */
2347 VG_(emit_amode_offregmem_reg)(
2348 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2349 VG_(emitB) (mask);
2350 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002351 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002352 mask, VGOFF_(m_eflags) * 4);
2353 } else {
sewardjfa492d42002-12-08 18:20:01 +00002354 /* all cond codes are in lower 16 bits */
2355 vg_assert((mask & 0xffff) == mask);
2356
2357 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002358 VG_(emitB) ( 0xF7 );
2359 VG_(emit_amode_offregmem_reg)(
2360 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002361 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002362 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002363 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002364 mask, VGOFF_(m_eflags) * 4);
2365 }
2366
sewardj75f04932002-12-12 23:13:21 +00002367 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002368 break;
2369 }
2370 }
2371
sewardja2113f92002-12-12 23:42:48 +00002372 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002373
2374 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002375 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002376
2377 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002378 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002379}
2380
2381
sewardj2370f3b2002-11-30 15:01:01 +00002382
sewardjde4a1d02002-03-22 01:27:54 +00002383static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2384{
sewardja2113f92002-12-12 23:42:48 +00002385 Int tgt;
2386
2387 VG_(init_target)(&tgt);
2388
sewardjfa492d42002-12-08 18:20:01 +00002389 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002390
2391 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002392 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002393
2394 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002395}
2396
2397
2398static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2399{
2400 /* Load the zero-extended literal into reg, at size l,
2401 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002402 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002403}
2404
2405
2406static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2407{
2408 switch (size) {
2409 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2410 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2411 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002412 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002413 }
2414}
2415
2416
2417static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2418{
2419 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002420 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2421 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2422 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002423 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002424 }
2425}
2426
2427
2428static void synth_mov_reg_offregmem ( Int size, Int reg,
2429 Int off, Int areg )
2430{
2431 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002432 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2433 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002434 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002435 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002436 }
2437 else {
njn25e49d8e72002-09-23 09:36:25 +00002438 VG_(emit_swapl_reg_EAX) ( reg );
2439 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2440 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002441 }
2442 break;
njne427a662002-10-02 11:08:25 +00002443 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002444 }
2445}
2446
2447
2448static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2449{
2450 Int s1;
2451 switch (size) {
2452 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2453 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2454 case 1: if (reg1 < 4) {
2455 emit_movb_reg_regmem ( reg1, reg2 );
2456 }
2457 else {
2458 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2459 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2460 emit_swapl_reg_reg ( s1, reg1 );
2461 emit_movb_reg_regmem ( s1, reg2 );
2462 emit_swapl_reg_reg ( s1, reg1 );
2463 }
2464 break;
njne427a662002-10-02 11:08:25 +00002465 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002466 }
2467}
2468
2469
sewardjf0f12aa2002-12-28 00:04:08 +00002470static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002471 Opcode opcode, Int size,
2472 Int reg )
2473{
2474 /* NB! opcode is a uinstr opcode, not an x86 one! */
2475 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002476 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002477 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002478 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002479 break;
2480 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002481 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002482 } else {
njn25e49d8e72002-09-23 09:36:25 +00002483 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002484 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002485 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002486 }
2487 break;
njne427a662002-10-02 11:08:25 +00002488 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002489 }
2490}
2491
2492
2493
sewardjf0f12aa2002-12-28 00:04:08 +00002494static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002495 Opcode opcode, Int size,
2496 Int reg1, Int reg2 )
2497{
2498 /* NB! opcode is a uinstr opcode, not an x86 one! */
2499 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002500 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002501 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002502 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002503 break;
2504 case 1: { /* Horrible ... */
2505 Int s1, s2;
2506 /* Choose s1 and s2 to be x86 regs which we can talk about the
2507 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2508 sure s1 != s2 and that neither of them equal either reg1 or
2509 reg2. Then use them as temporaries to make things work. */
2510 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002511 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002512 break;
2513 }
2514 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2515 if (reg1 >= 4 && reg2 < 4) {
2516 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002517 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002518 emit_swapl_reg_reg ( reg1, s1 );
2519 break;
2520 }
2521 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2522 if (reg1 < 4 && reg2 >= 4) {
2523 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002524 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002525 emit_swapl_reg_reg ( reg2, s2 );
2526 break;
2527 }
2528 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2529 emit_swapl_reg_reg ( reg1, s1 );
2530 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002531 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002532 emit_swapl_reg_reg ( reg1, s1 );
2533 emit_swapl_reg_reg ( reg2, s2 );
2534 break;
2535 }
2536 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2537 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002538 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002539 emit_swapl_reg_reg ( reg1, s1 );
2540 break;
2541 }
njne427a662002-10-02 11:08:25 +00002542 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002543 }
njne427a662002-10-02 11:08:25 +00002544 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002545 }
2546}
2547
sewardja2c5a732002-12-15 03:10:42 +00002548#if 0
2549/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002550static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002551 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002552 Opcode opcode, Int size,
2553 Int off, Int areg, Int reg )
2554{
2555 switch (size) {
2556 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002557 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002558 break;
2559 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002560 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002561 break;
2562 case 1:
2563 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002564 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002565 } else {
2566 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002567 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002568 VG_(emit_swapl_reg_EAX) ( reg );
2569 }
2570 break;
2571 default:
2572 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2573 }
2574}
sewardja2c5a732002-12-15 03:10:42 +00002575#endif
sewardjfa492d42002-12-08 18:20:01 +00002576
sewardjde4a1d02002-03-22 01:27:54 +00002577static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002578 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002579 Opcode opcode, Int size,
2580 Int off, Int areg, Int reg )
2581{
2582 switch (size) {
2583 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002584 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002585 break;
2586 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002587 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002588 break;
2589 case 1:
2590 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002591 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002592 } else {
njn25e49d8e72002-09-23 09:36:25 +00002593 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002594 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002595 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002596 }
2597 break;
2598 default:
njne427a662002-10-02 11:08:25 +00002599 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002600 }
2601}
2602
2603
sewardjf0f12aa2002-12-28 00:04:08 +00002604static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002605 Opcode opcode, Int size,
2606 UInt lit, Int reg )
2607{
2608 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002609 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002610 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002611 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002612 break;
2613 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002614 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002615 } else {
njn25e49d8e72002-09-23 09:36:25 +00002616 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002617 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002618 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002619 }
2620 break;
njne427a662002-10-02 11:08:25 +00002621 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002622 }
2623}
2624
sewardjf0f12aa2002-12-28 00:04:08 +00002625static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002626 Opcode opcode, Int size,
2627 UInt lit, Int off, Int regmem )
2628{
2629 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002630 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002631 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002632 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002633 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002634 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002635 break;
2636 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2637 }
2638}
2639
sewardjde4a1d02002-03-22 01:27:54 +00002640
2641static void synth_push_reg ( Int size, Int reg )
2642{
2643 switch (size) {
2644 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002645 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002646 break;
2647 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002648 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002649 break;
2650 /* Pray that we don't have to generate this really cruddy bit of
2651 code very often. Could do better, but can I be bothered? */
2652 case 1:
2653 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002654 VG_(emit_add_lit_to_esp)(-1);
2655 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002656 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002657 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002658 break;
2659 default:
njne427a662002-10-02 11:08:25 +00002660 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002661 }
2662}
2663
2664
2665static void synth_pop_reg ( Int size, Int reg )
2666{
2667 switch (size) {
2668 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002669 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002670 break;
2671 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002672 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002673 break;
2674 case 1:
2675 /* Same comment as above applies. */
2676 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002677 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002678 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002679 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2680 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002681 break;
njne427a662002-10-02 11:08:25 +00002682 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002683 }
2684}
2685
2686
sewardjf0f12aa2002-12-28 00:04:08 +00002687static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002688 Opcode opcode, Int size,
2689 Int regs, Int regd )
2690{
2691 synth_push_reg ( size, regd );
2692 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002693 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002694 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2695 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2696 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002697 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002698 }
sewardjde4a1d02002-03-22 01:27:54 +00002699 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2700 synth_pop_reg ( size, regd );
2701}
2702
2703
sewardjf0f12aa2002-12-28 00:04:08 +00002704static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002705 Opcode opcode, Int size,
2706 UInt lit, Int reg )
2707{
2708 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002709 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002710 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002711 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002712 break;
2713 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002714 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002715 } else {
njn25e49d8e72002-09-23 09:36:25 +00002716 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002717 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002718 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002719 }
2720 break;
njne427a662002-10-02 11:08:25 +00002721 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002722 }
2723}
2724
2725
sewardjf0f12aa2002-12-28 00:04:08 +00002726static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002727{
sewardjde4a1d02002-03-22 01:27:54 +00002728 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002729 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002730 } else {
njn25e49d8e72002-09-23 09:36:25 +00002731 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002732 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002733 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002734 }
2735}
2736
2737
sewardj3d7c9c82003-03-26 21:08:13 +00002738static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2739 UChar first_byte,
2740 UChar second_byte,
2741 Int ireg )
2742{
2743 emit_MMX2_regmem ( uses_flags, sets_flags,
2744 first_byte, second_byte, ireg );
2745}
2746
2747
sewardjca860012003-03-27 23:52:58 +00002748static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2749 UChar first_byte,
2750 UChar second_byte,
2751 Int ireg )
2752{
2753 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2754 first_byte, second_byte, ireg );
2755}
2756
sewardjd1c9e432003-04-04 20:40:34 +00002757static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2758 UChar first_byte,
2759 UChar second_byte,
2760 Int ireg )
2761{
2762 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2763 first_byte, second_byte, ireg );
2764}
2765
sewardj3d7c9c82003-03-26 21:08:13 +00002766static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2767 UChar first_byte,
2768 UChar second_byte )
2769{
2770 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2771}
2772
2773
sewardjca860012003-03-27 23:52:58 +00002774static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2775 UChar first_byte,
2776 UChar second_byte,
2777 UChar third_byte )
2778{
2779 emit_MMX3_no_mem ( uses_flags, sets_flags,
2780 first_byte, second_byte, third_byte );
2781}
2782
2783
sewardj3d7c9c82003-03-26 21:08:13 +00002784static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2785 UChar first_byte )
2786{
2787 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2788}
2789
2790
sewardjfa492d42002-12-08 18:20:01 +00002791static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2792 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002793 UChar second_byte_masked,
2794 Int reg )
2795{
sewardj3d7c9c82003-03-26 21:08:13 +00002796 emit_fpu_regmem ( uses_flags, sets_flags,
2797 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002798}
2799
2800
sewardjfa492d42002-12-08 18:20:01 +00002801static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2802 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002803 UChar second_byte )
2804{
sewardjfa492d42002-12-08 18:20:01 +00002805 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002806}
2807
2808
2809static void synth_movl_reg_reg ( Int src, Int dst )
2810{
2811 emit_movl_reg_reg ( src, dst );
2812}
2813
2814static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2815{
sewardja2113f92002-12-12 23:42:48 +00002816 Int tgt;
2817
2818 VG_(init_target)(&tgt);
2819
2820 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002821 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002822
2823 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002824}
2825
2826
sewardjde4a1d02002-03-22 01:27:54 +00002827/*----------------------------------------------------*/
2828/*--- Top level of the uinstr -> x86 translation. ---*/
2829/*----------------------------------------------------*/
2830
2831/* Return the byte offset from %ebp (ie, into baseBlock)
2832 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002833static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2834{
2835 if (tag == SpillNo) {
2836 vg_assert(size == 4);
2837 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2838 return 4 * (value + VGOFF_(spillslots));
2839 }
2840 if (tag == ArchReg) {
2841 switch (value) {
2842 case R_EAX: return 4 * VGOFF_(m_eax);
2843 case R_ECX: return 4 * VGOFF_(m_ecx);
2844 case R_EDX: return 4 * VGOFF_(m_edx);
2845 case R_EBX: return 4 * VGOFF_(m_ebx);
2846 case R_ESP:
2847 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2848 else return 4 * VGOFF_(m_esp);
2849 case R_EBP:
2850 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2851 else return 4 * VGOFF_(m_ebp);
2852 case R_ESI:
2853 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2854 else return 4 * VGOFF_(m_esi);
2855 case R_EDI:
2856 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2857 else return 4 * VGOFF_(m_edi);
2858 }
2859 }
njne427a662002-10-02 11:08:25 +00002860 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002861}
2862
sewardjde4a1d02002-03-22 01:27:54 +00002863static Int eflagsOffset ( void )
2864{
2865 return 4 * VGOFF_(m_eflags);
2866}
2867
sewardje1042472002-09-30 12:33:11 +00002868static Int segRegOffset ( UInt archregs )
2869{
2870 switch (archregs) {
2871 case R_CS: return 4 * VGOFF_(m_cs);
2872 case R_SS: return 4 * VGOFF_(m_ss);
2873 case R_DS: return 4 * VGOFF_(m_ds);
2874 case R_ES: return 4 * VGOFF_(m_es);
2875 case R_FS: return 4 * VGOFF_(m_fs);
2876 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002877 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002878 }
2879}
2880
njnf4ce3d32003-02-10 10:17:26 +00002881UInt VG_(get_archreg) ( UInt arch )
2882{
2883 switch (arch) {
2884 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2885 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2886 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2887 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2888 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2889 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2890 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2891 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2892 default: VG_(core_panic)( "get_thread_archreg");
2893 }
2894}
2895
2896UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2897{
2898 ThreadState* tst;
2899
2900 vg_assert(VG_(is_valid_tid)(tid));
2901 tst = & VG_(threads)[tid];
2902
2903 switch (arch) {
2904 case R_EAX: return tst->m_eax;
2905 case R_ECX: return tst->m_ecx;
2906 case R_EDX: return tst->m_edx;
2907 case R_EBX: return tst->m_ebx;
2908 case R_ESP: return tst->m_esp;
2909 case R_EBP: return tst->m_ebp;
2910 case R_ESI: return tst->m_esi;
2911 case R_EDI: return tst->m_edi;
2912 default: VG_(core_panic)( "get_thread_archreg");
2913 }
2914}
2915
njnb93d1782003-02-03 12:03:22 +00002916/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00002917static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00002918{
2919 switch (arch) {
2920 case R_EAX: return VGOFF_(sh_eax);
2921 case R_ECX: return VGOFF_(sh_ecx);
2922 case R_EDX: return VGOFF_(sh_edx);
2923 case R_EBX: return VGOFF_(sh_ebx);
2924 case R_ESP: return VGOFF_(sh_esp);
2925 case R_EBP: return VGOFF_(sh_ebp);
2926 case R_ESI: return VGOFF_(sh_esi);
2927 case R_EDI: return VGOFF_(sh_edi);
2928 default: VG_(core_panic)( "shadow_reg_index");
2929 }
2930}
sewardjde4a1d02002-03-22 01:27:54 +00002931
njn25e49d8e72002-09-23 09:36:25 +00002932/* Return the byte offset from %ebp (ie, into baseBlock)
2933 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002934Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002935{
njnb93d1782003-02-03 12:03:22 +00002936 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00002937}
2938
njn4ba5a792002-09-30 10:23:54 +00002939Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002940{
2941 return 4 * VGOFF_(sh_eflags);
2942}
2943
njnb93d1782003-02-03 12:03:22 +00002944/* Accessing shadow arch. registers */
2945UInt VG_(get_shadow_archreg) ( UInt archreg )
2946{
2947 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
2948}
2949
2950void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
2951{
2952 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
2953}
2954
njnf4ce3d32003-02-10 10:17:26 +00002955UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
2956{
2957 ThreadState* tst;
2958
2959 vg_assert(VG_(is_valid_tid)(tid));
2960 tst = & VG_(threads)[tid];
2961
2962 switch (archreg) {
2963 case R_EAX: return tst->sh_eax;
2964 case R_ECX: return tst->sh_ecx;
2965 case R_EDX: return tst->sh_edx;
2966 case R_EBX: return tst->sh_ebx;
2967 case R_ESP: return tst->sh_esp;
2968 case R_EBP: return tst->sh_ebp;
2969 case R_ESI: return tst->sh_esi;
2970 case R_EDI: return tst->sh_edi;
2971 default: VG_(core_panic)( "get_thread_shadow_archreg");
2972 }
2973}
2974
2975void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
2976{
2977 ThreadState* tst;
2978
2979 vg_assert(VG_(is_valid_tid)(tid));
2980 tst = & VG_(threads)[tid];
2981
2982 switch (archreg) {
2983 case R_EAX: tst->sh_eax = val; break;
2984 case R_ECX: tst->sh_ecx = val; break;
2985 case R_EDX: tst->sh_edx = val; break;
2986 case R_EBX: tst->sh_ebx = val; break;
2987 case R_ESP: tst->sh_esp = val; break;
2988 case R_EBP: tst->sh_ebp = val; break;
2989 case R_ESI: tst->sh_esi = val; break;
2990 case R_EDI: tst->sh_edi = val; break;
2991 default: VG_(core_panic)( "set_thread_shadow_archreg");
2992 }
2993}
2994
njnb93d1782003-02-03 12:03:22 +00002995Addr VG_(shadow_archreg_address) ( UInt archreg )
2996{
2997 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
2998}
sewardjde4a1d02002-03-22 01:27:54 +00002999
sewardjde4a1d02002-03-22 01:27:54 +00003000static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3001{
3002 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003003 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3004 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003005 }
3006 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003007 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3008 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003009 }
3010 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003011 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3012 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003013 }
3014 else
njne427a662002-10-02 11:08:25 +00003015 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003016}
3017
3018
sewardjde4a1d02002-03-22 01:27:54 +00003019/*----------------------------------------------------*/
3020/*--- Generate code for a single UInstr. ---*/
3021/*----------------------------------------------------*/
3022
sewardj478335c2002-10-05 02:44:47 +00003023static __inline__
3024Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003025{
3026 return (u->flags_w != FlagsEmpty);
3027}
3028
sewardjfa492d42002-12-08 18:20:01 +00003029static __inline__
3030Bool readFlagUse ( UInstr* u )
3031{
3032 /* If the UInstr writes some flags but not all, then we still need
3033 to consider it as reading flags so that the unchanged values are
3034 passed through properly. (D is special) */
3035 return
3036 (u->flags_r != FlagsEmpty) ||
3037 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3038}
3039
sewardj478335c2002-10-05 02:44:47 +00003040static __inline__
3041Bool anyFlagUse ( UInstr* u )
3042{
sewardjfa492d42002-12-08 18:20:01 +00003043 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003044}
3045
3046
sewardjb91ae7f2003-04-29 23:50:00 +00003047/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3048 the real machine's cpu. If so we need to be very careful not to trash it.
3049 If FPU/SSE state is live and we deem it necessary to copy it back to
3050 the simulated machine's FPU/SSE state, we do so. The final state of
3051 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003052 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003053 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003054*/
sewardjb5ff83e2002-12-01 19:40:49 +00003055static void emitUInstr ( UCodeBlock* cb, Int i,
3056 RRegSet regs_live_before,
3057 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003058 Bool* sselive, /* True<==>FPU/SSE
3059 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003060 Addr* orig_eip, /* previous curr_eip, or zero */
3061 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003062{
njn25e49d8e72002-09-23 09:36:25 +00003063 Int old_emitted_code_used;
3064 UInstr* u = &cb->instrs[i];
3065
sewardjde4a1d02002-03-22 01:27:54 +00003066 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003067 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003068
njn25e49d8e72002-09-23 09:36:25 +00003069 old_emitted_code_used = emitted_code_used;
3070
sewardjde4a1d02002-03-22 01:27:54 +00003071 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003072 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003073
sewardjb5ff83e2002-12-01 19:40:49 +00003074 case INCEIP:
3075 /* Advance %EIP some small amount. */
3076 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003077
sewardjb5ff83e2002-12-01 19:40:49 +00003078 if (*orig_eip == 0 /* we don't know what the old value was */
3079 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3080 /* We have to update all 32 bits of the value. */
3081 VG_(emit_movv_lit_offregmem)(
3082 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3083 } else {
3084 /* Cool! we only need to update lowest 8 bits */
3085 VG_(emit_movb_lit_offregmem)(
3086 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003087 }
njn25e49d8e72002-09-23 09:36:25 +00003088
sewardjb5ff83e2002-12-01 19:40:49 +00003089 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003090 break;
sewardjde4a1d02002-03-22 01:27:54 +00003091
3092 case LEA1: {
3093 vg_assert(u->tag1 == RealReg);
3094 vg_assert(u->tag2 == RealReg);
3095 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3096 break;
3097 }
3098
3099 case LEA2: {
3100 vg_assert(u->tag1 == RealReg);
3101 vg_assert(u->tag2 == RealReg);
3102 vg_assert(u->tag3 == RealReg);
3103 emit_lea_sib_reg ( u->lit32, u->extra4b,
3104 u->val1, u->val2, u->val3 );
3105 break;
3106 }
3107
3108 case WIDEN: {
3109 vg_assert(u->tag1 == RealReg);
3110 if (u->signed_widen) {
3111 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3112 } else {
3113 /* no need to generate any code. */
3114 }
3115 break;
3116 }
3117
sewardjde4a1d02002-03-22 01:27:54 +00003118 case STORE: {
3119 vg_assert(u->tag1 == RealReg);
3120 vg_assert(u->tag2 == RealReg);
3121 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003122 break;
3123 }
3124
3125 case LOAD: {
3126 vg_assert(u->tag1 == RealReg);
3127 vg_assert(u->tag2 == RealReg);
3128 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3129 break;
3130 }
3131
sewardjde4a1d02002-03-22 01:27:54 +00003132 case GET: {
3133 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3134 vg_assert(u->tag2 == RealReg);
3135 synth_mov_offregmem_reg (
3136 u->size,
3137 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3138 R_EBP,
3139 u->val2
3140 );
3141 break;
3142 }
3143
3144 case PUT: {
3145 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3146 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003147 synth_mov_reg_offregmem (
3148 u->size,
3149 u->val1,
3150 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3151 R_EBP
3152 );
sewardjde4a1d02002-03-22 01:27:54 +00003153 break;
3154 }
3155
sewardje1042472002-09-30 12:33:11 +00003156 case GETSEG: {
3157 vg_assert(u->tag1 == ArchRegS);
3158 vg_assert(u->tag2 == RealReg);
3159 vg_assert(u->size == 2);
3160 synth_mov_offregmem_reg (
3161 4,
3162 segRegOffset( u->val1 ),
3163 R_EBP,
3164 u->val2
3165 );
3166 break;
3167 }
3168
3169 case PUTSEG: {
3170 vg_assert(u->tag1 == RealReg);
3171 vg_assert(u->tag2 == ArchRegS);
3172 vg_assert(u->size == 2);
3173 synth_mov_reg_offregmem (
3174 4,
3175 u->val1,
3176 segRegOffset( u->val2 ),
3177 R_EBP
3178 );
3179 break;
3180 }
3181
sewardjde4a1d02002-03-22 01:27:54 +00003182 case GETF: {
3183 vg_assert(u->size == 2 || u->size == 4);
3184 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003185
3186 /* This complexity is because the D(irection) flag is stored
3187 separately from the rest of EFLAGS. */
3188
3189 /* We're only fetching from the Simd state, so make sure it's
3190 up to date. */
3191 maybe_emit_put_eflags();
3192
3193 /* get D in u->val1 (== 1 or -1) */
3194 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3195
3196 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3197 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3198
3199 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3200 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3201 eflagsOffset(), R_EBP);
3202
3203 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3204 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3205 eflagsOffset(), R_EBP);
3206
3207 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3208 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3209 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003210 break;
3211 }
3212
3213 case PUTF: {
3214 vg_assert(u->size == 2 || u->size == 4);
3215 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003216
3217 /* When putting a value into EFLAGS, this generates the
3218 correct value for m_dflag (-1 or 1), and clears the D bit
3219 in EFLAGS. */
3220
3221 /* We're updating the whole flag state, so the old state
3222 doesn't matter; make sure that the new simulated state
3223 will be fetched when needed. */
3224 eflags_state = UPD_Simd;
3225
3226 /* store EFLAGS (with D) */
3227 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3228
3229 /* u->val1 &= EFlagD */
3230 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3231
3232 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3233 synth_unaryop_reg(False, NEG, u->size, u->val1);
3234 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3235 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3236
3237 /* save D */
3238 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3239
3240 /* EFLAGS &= ~EFlagD */
3241 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3242 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003243 break;
3244 }
3245
3246 case MOV: {
3247 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3248 vg_assert(u->tag2 == RealReg);
3249 switch (u->tag1) {
3250 case RealReg: vg_assert(u->size == 4);
3251 if (u->val1 != u->val2)
3252 synth_movl_reg_reg ( u->val1, u->val2 );
3253 break;
3254 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3255 break;
njne427a662002-10-02 11:08:25 +00003256 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003257 }
3258 break;
3259 }
3260
sewardje1042472002-09-30 12:33:11 +00003261 case USESEG: {
3262 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3263 ones. */
sewardjd077f532002-09-30 21:52:50 +00003264 UInt argv[] = { u->val1, u->val2 };
3265 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003266 UInt ret_reg = u->val2;
3267
3268 vg_assert(u->tag1 == RealReg);
3269 vg_assert(u->tag2 == RealReg);
3270 vg_assert(u->size == 0);
3271
sewardjb91ae7f2003-04-29 23:50:00 +00003272 if (*sselive) {
3273 emit_put_sse_state();
3274 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003275 }
3276
sewardje1042472002-09-30 12:33:11 +00003277 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3278 2, /* args */
3279 0, /* regparms_n */
3280 argv, tagv,
3281 ret_reg, regs_live_before, u->regs_live_after );
3282 break;
3283 }
3284
sewardj478335c2002-10-05 02:44:47 +00003285 case SBB:
3286 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003287 case XOR:
3288 case OR:
3289 case AND:
3290 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003291 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003292 vg_assert(u->tag2 == RealReg);
3293 switch (u->tag1) {
3294 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003295 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003296 u->opcode, u->size, u->lit32, u->val2 );
3297 break;
3298 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003299 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003300 u->opcode, u->size, u->val1, u->val2 );
3301 break;
3302 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003303 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003304 u->opcode, u->size,
3305 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3306 R_EBP,
3307 u->val2 );
3308 break;
njne427a662002-10-02 11:08:25 +00003309 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003310 }
3311 break;
3312 }
3313
sewardj478335c2002-10-05 02:44:47 +00003314 case RCR:
3315 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003316 case ROR:
3317 case ROL:
3318 case SAR:
3319 case SHR:
3320 case SHL: {
3321 vg_assert(u->tag2 == RealReg);
3322 switch (u->tag1) {
3323 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003324 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003325 u->opcode, u->size, u->lit32, u->val2 );
3326 break;
3327 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003328 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003329 u->opcode, u->size, u->val1, u->val2 );
3330 break;
njne427a662002-10-02 11:08:25 +00003331 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003332 }
3333 break;
3334 }
3335
3336 case INC:
3337 case DEC:
3338 case NEG:
3339 case NOT:
3340 vg_assert(u->tag1 == RealReg);
3341 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003342 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003343 break;
3344
3345 case BSWAP:
3346 vg_assert(u->tag1 == RealReg);
3347 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003348 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003349 emit_bswapl_reg ( u->val1 );
3350 break;
3351
3352 case CMOV:
3353 vg_assert(u->tag1 == RealReg);
3354 vg_assert(u->tag2 == RealReg);
3355 vg_assert(u->cond != CondAlways);
3356 vg_assert(u->size == 4);
3357 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3358 break;
3359
3360 case JMP: {
3361 vg_assert(u->tag2 == NoValue);
3362 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003363 if (*sselive) {
3364 emit_put_sse_state();
3365 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003366 }
sewardjde4a1d02002-03-22 01:27:54 +00003367 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003368 switch (u->tag1) {
3369 case RealReg:
3370 synth_jmp_reg ( u->val1, u->jmpkind );
3371 break;
3372 case Literal:
3373 synth_jmp_lit ( u->lit32, u->jmpkind );
3374 break;
3375 default:
njne427a662002-10-02 11:08:25 +00003376 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003377 break;
sewardjde4a1d02002-03-22 01:27:54 +00003378 }
3379 } else {
sewardj2e93c502002-04-12 11:12:52 +00003380 switch (u->tag1) {
3381 case RealReg:
njne427a662002-10-02 11:08:25 +00003382 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003383 break;
3384 case Literal:
3385 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003386 /* %eax had better not be live since synth_jcond_lit
3387 trashes it in some circumstances. If that turns
3388 out to be a problem we can get synth_jcond_lit to
3389 push/pop it when it is live. */
3390 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3391 u->regs_live_after));
3392 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003393 break;
3394 default:
njne427a662002-10-02 11:08:25 +00003395 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003396 break;
sewardjde4a1d02002-03-22 01:27:54 +00003397 }
3398 }
3399 break;
3400 }
3401
3402 case JIFZ:
3403 vg_assert(u->tag1 == RealReg);
3404 vg_assert(u->tag2 == Literal);
3405 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003406 if (*sselive) {
3407 emit_put_sse_state();
3408 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003409 }
sewardjde4a1d02002-03-22 01:27:54 +00003410 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3411 break;
3412
sewardjde4a1d02002-03-22 01:27:54 +00003413 case PUSH:
3414 vg_assert(u->tag1 == RealReg);
3415 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003416 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003417 break;
3418
3419 case POP:
3420 vg_assert(u->tag1 == RealReg);
3421 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003422 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003423 break;
3424
3425 case CALLM:
3426 vg_assert(u->tag1 == Lit16);
3427 vg_assert(u->tag2 == NoValue);
3428 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003429 if (*sselive) {
3430 emit_put_sse_state();
3431 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003432 }
sewardjfa492d42002-12-08 18:20:01 +00003433 /* Call to a helper which is pretending to be a real CPU
3434 instruction (and therefore operates on Real flags and
3435 registers) */
3436 VG_(synth_call) ( False, u->val1,
3437 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003438 break;
3439
njn25e49d8e72002-09-23 09:36:25 +00003440 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003441 /* If you change this, remember to change USESEG above, since
3442 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003443 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3444 ones. */
3445 UInt argv[] = { u->val1, u->val2, u->val3 };
3446 UInt tagv[] = { RealReg, RealReg, RealReg };
3447 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3448
3449 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3450 else vg_assert(u->tag1 == NoValue);
3451 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3452 else vg_assert(u->tag2 == NoValue);
3453 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3454 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003455 vg_assert(u->size == 0);
3456
sewardjb91ae7f2003-04-29 23:50:00 +00003457 if (*sselive) {
3458 emit_put_sse_state();
3459 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003460 }
njn25e49d8e72002-09-23 09:36:25 +00003461 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3462 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003463 break;
njn25e49d8e72002-09-23 09:36:25 +00003464 }
sewardje1042472002-09-30 12:33:11 +00003465
sewardjde4a1d02002-03-22 01:27:54 +00003466 case CLEAR:
3467 vg_assert(u->tag1 == Lit16);
3468 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003469 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003470 break;
3471
3472 case CC2VAL:
3473 vg_assert(u->tag1 == RealReg);
3474 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003475 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003476 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003477 break;
3478
sewardjde4a1d02002-03-22 01:27:54 +00003479 case FPU_R:
3480 case FPU_W:
3481 vg_assert(u->tag1 == Lit16);
3482 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003483 if (!(*sselive)) {
3484 emit_get_sse_state();
3485 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003486 }
sewardjfa492d42002-12-08 18:20:01 +00003487 synth_fpu_regmem ( u->flags_r, u->flags_w,
3488 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003489 u->val1 & 0xFF,
3490 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003491 break;
3492
3493 case FPU:
3494 vg_assert(u->tag1 == Lit16);
3495 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003496 if (!(*sselive)) {
3497 emit_get_sse_state();
3498 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003499 }
sewardjfa492d42002-12-08 18:20:01 +00003500 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3501 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003502 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003503 break;
3504
sewardj3d7c9c82003-03-26 21:08:13 +00003505 case MMX2_MemWr:
3506 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003507 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003508 vg_assert(u->tag1 == Lit16);
3509 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003510 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003511 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003512 if (!(*sselive)) {
3513 emit_get_sse_state();
3514 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003515 }
3516 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3517 (u->val1 >> 8) & 0xFF,
3518 u->val1 & 0xFF,
3519 u->val2 );
3520 break;
3521
sewardjca860012003-03-27 23:52:58 +00003522 case MMX2_RegRd:
3523 vg_assert(u->tag1 == Lit16);
3524 vg_assert(u->tag2 == RealReg);
3525 vg_assert(u->tag3 == NoValue);
3526 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003527 if (!(*sselive)) {
3528 emit_get_sse_state();
3529 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003530 }
3531 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3532 (u->val1 >> 8) & 0xFF,
3533 u->val1 & 0xFF,
3534 u->val2 );
3535 break;
3536
sewardjd1c9e432003-04-04 20:40:34 +00003537 case MMX2_RegWr:
3538 vg_assert(u->tag1 == Lit16);
3539 vg_assert(u->tag2 == RealReg);
3540 vg_assert(u->tag3 == NoValue);
3541 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003542 if (!(*sselive)) {
3543 emit_get_sse_state();
3544 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003545 }
3546 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3547 (u->val1 >> 8) & 0xFF,
3548 u->val1 & 0xFF,
3549 u->val2 );
3550 break;
3551
sewardj3d7c9c82003-03-26 21:08:13 +00003552 case MMX1:
3553 vg_assert(u->tag1 == Lit16);
3554 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003555 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003556 if (!(*sselive)) {
3557 emit_get_sse_state();
3558 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003559 }
3560 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3561 u->val1 & 0xFF );
3562 break;
3563
3564 case MMX2:
3565 vg_assert(u->tag1 == Lit16);
3566 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003567 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003568 if (!(*sselive)) {
3569 emit_get_sse_state();
3570 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003571 }
3572 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3573 (u->val1 >> 8) & 0xFF,
3574 u->val1 & 0xFF );
3575 break;
3576
sewardjca860012003-03-27 23:52:58 +00003577 case MMX3:
3578 vg_assert(u->tag1 == Lit16);
3579 vg_assert(u->tag2 == Lit16);
3580 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003581 if (!(*sselive)) {
3582 emit_get_sse_state();
3583 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003584 }
3585 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3586 (u->val1 >> 8) & 0xFF,
3587 u->val1 & 0xFF,
3588 u->val2 & 0xFF );
3589 break;
3590
sewardjde4a1d02002-03-22 01:27:54 +00003591 default:
sewardj1b7d8022002-11-30 12:35:42 +00003592 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003593 if (*sselive) {
3594 emit_put_sse_state();
3595 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003596 }
njn4ba5a792002-09-30 10:23:54 +00003597 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003598 } else {
njn25e49d8e72002-09-23 09:36:25 +00003599 VG_(printf)("\nError:\n"
3600 " unhandled opcode: %u. Perhaps "
3601 " VG_(needs).extended_UCode should be set?\n",
3602 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003603 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003604 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003605 }
sewardjde4a1d02002-03-22 01:27:54 +00003606 }
3607
sewardjb91ae7f2003-04-29 23:50:00 +00003608 if (0 && (*sselive)) {
3609 emit_put_sse_state();
3610 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003611 }
3612
njn25e49d8e72002-09-23 09:36:25 +00003613 /* Update UInstr histogram */
3614 vg_assert(u->opcode < 100);
3615 histogram[u->opcode].counts++;
3616 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003617}
3618
3619
3620/* Emit x86 for the ucode in cb, returning the address of the
3621 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003622UChar* VG_(emit_code) ( UCodeBlock* cb,
3623 Int* nbytes,
3624 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003625{
3626 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003627 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003628 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003629 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003630 Int tgt;
3631
sewardjfa492d42002-12-08 18:20:01 +00003632 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003633
njn25e49d8e72002-09-23 09:36:25 +00003634 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003635
sewardj22854b92002-11-30 14:00:47 +00003636 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3637 zero. We have to do this regardless of whether we're t-chaining
3638 or not. */
sewardja2113f92002-12-12 23:42:48 +00003639 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003640 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003641 VG_(emitB) (0xFF); /* decl */
3642 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3643 if (dis)
3644 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003645 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003646 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3647 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003648 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003649
sewardjb5ff83e2002-12-01 19:40:49 +00003650 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00003651 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00003652 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003653 curr_eip = cb->orig_eip;
3654 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3655 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003656 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003657 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003658 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003659 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003660
sewardjde4a1d02002-03-22 01:27:54 +00003661 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003662 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003663 if (!sane) {
3664 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003665 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003666 }
3667 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003668 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00003669 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003670 }
njn25e49d8e72002-09-23 09:36:25 +00003671 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003672 }
njn25e49d8e72002-09-23 09:36:25 +00003673 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00003674 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00003675 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003676
sewardj22854b92002-11-30 14:00:47 +00003677 if (j != NULL) {
3678 vg_assert(jumpidx <= VG_MAX_JUMPS);
3679 for(i = 0; i < jumpidx; i++)
3680 j[i] = jumps[i];
3681 }
3682
sewardjde4a1d02002-03-22 01:27:54 +00003683 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003684 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003685 *nbytes = emitted_code_used;
3686 return emitted_code;
3687}
3688
njn25e49d8e72002-09-23 09:36:25 +00003689#undef dis
3690
sewardjde4a1d02002-03-22 01:27:54 +00003691/*--------------------------------------------------------------------*/
3692/*--- end vg_from_ucode.c ---*/
3693/*--------------------------------------------------------------------*/