blob: 2c96b2894184864a7a44a532297b13ea82a37b82 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00006
sewardjde4a1d02002-03-22 01:27:54 +00007/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
41/*------------------------------------------------------------*/
42/*--- Instruction emission -- turning final uinstrs back ---*/
43/*--- into x86 code. ---*/
44/*------------------------------------------------------------*/
45
46/* [2001-07-08 This comment is now somewhat out of date.]
47
48 This is straightforward but for one thing: to facilitate generating
49 code in a single pass, we generate position-independent code. To
50 do this, calls and jmps to fixed addresses must specify the address
51 by first loading it into a register, and jump to/call that
52 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000053 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000054 call insns may only have a register as target anyway, so there's no
55 need to do anything fancy for them.
56
57 The emit_* routines constitute the lowest level of instruction
58 emission. They simply emit the sequence of bytes corresponding to
59 the relevant instruction, with no further ado. In particular there
60 is no checking about whether uses of byte registers makes sense,
61 nor whether shift insns have their first operand in %cl, etc.
62
63 These issues are taken care of by the level above, the synth_*
64 routines. These detect impossible operand combinations and turn
65 them into sequences of legal instructions. Finally, emitUInstr is
66 phrased in terms of the synth_* abstraction layer. */
67
sewardjfa492d42002-12-08 18:20:01 +000068/* Static state for the current basic block */
sewardjde4a1d02002-03-22 01:27:54 +000069static UChar* emitted_code;
70static Int emitted_code_used;
71static Int emitted_code_size;
72
sewardj22854b92002-11-30 14:00:47 +000073/* offset (in bytes into the basic block) */
74static UShort jumps[VG_MAX_JUMPS];
75static Int jumpidx;
76
sewardjf0f12aa2002-12-28 00:04:08 +000077static enum _eflags_state {
sewardjfa492d42002-12-08 18:20:01 +000078 UPD_Simd, /* baseblock copy is up to date */
79 UPD_Real, /* CPU copy is up to date */
80 UPD_Both, /* both are current */
81} eflags_state;
82
83/* single site for resetting state */
84static void reset_state(void)
85{
86 emitted_code_used = 0;
87 emitted_code_size = 500; /* reasonable initial size */
88 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
89 jumpidx = 0;
90 eflags_state = UPD_Simd;
91}
92
93
njn25e49d8e72002-09-23 09:36:25 +000094/* Statistics about C functions called from generated code. */
95static UInt ccalls = 0;
96static UInt ccall_reg_saves = 0;
97static UInt ccall_args = 0;
98static UInt ccall_arg_setup_instrs = 0;
99static UInt ccall_stack_clears = 0;
100static UInt ccall_retvals = 0;
101static UInt ccall_retval_movs = 0;
102
103/* Statistics about frequency of each UInstr */
104typedef
105 struct {
106 UInt counts;
107 UInt size;
108 } Histogram;
109
110/* Automatically zeroed because it's static. */
111static Histogram histogram[100];
112
113void VG_(print_ccall_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " ccalls: %u C calls, %u%% saves+restores avoided"
117 " (%d bytes)",
118 ccalls,
119 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
120 ((ccalls*3) - ccall_reg_saves)*2);
121 VG_(message)(Vg_DebugMsg,
122 " %u args, avg 0.%d setup instrs each (%d bytes)",
123 ccall_args,
124 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
125 (ccall_args - ccall_arg_setup_instrs)*2);
126 VG_(message)(Vg_DebugMsg,
127 " %d%% clear the stack (%d bytes)",
128 (UInt)(ccall_stack_clears/(double)ccalls*100),
129 (ccalls - ccall_stack_clears)*3);
130 VG_(message)(Vg_DebugMsg,
131 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
132 ccall_retvals,
133 ( ccall_retvals == 0
134 ? 100
135 : 100-(UInt)(ccall_retval_movs /
136 (double)ccall_retvals*100)),
137 (ccall_retvals-ccall_retval_movs)*2);
138}
139
140void VG_(print_UInstr_histogram)(void)
141{
142 Int i, j;
143 UInt total_counts = 0;
144 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000145
njn25e49d8e72002-09-23 09:36:25 +0000146 for (i = 0; i < 100; i++) {
147 total_counts += histogram[i].counts;
148 total_size += histogram[i].size;
149 }
150
151 VG_(printf)("-- UInstr frequencies -----------\n");
152 for (i = 0; i < 100; i++) {
153 if (0 != histogram[i].counts) {
154
155 UInt count_pc =
156 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
157 UInt size_pc =
158 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
159 UInt avg_size =
160 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
161
162 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000163 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000164 histogram[i].counts, count_pc,
165 avg_size, size_pc);
166
167 for (j = 0; j < size_pc; j++) VG_(printf)("O");
168 VG_(printf)("\n");
169
170 } else {
171 vg_assert(0 == histogram[i].size);
172 }
173 }
174
175 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
176}
177
sewardjde4a1d02002-03-22 01:27:54 +0000178static void expandEmittedCode ( void )
179{
180 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000181 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000182 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
183 for (i = 0; i < emitted_code_size; i++)
184 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000186 emitted_code = tmp;
187 emitted_code_size *= 2;
188}
189
njn25e49d8e72002-09-23 09:36:25 +0000190/* Local calls will be inlined, cross-module ones not */
191__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
193 if (dis) {
194 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
195 }
196 if (emitted_code_used == emitted_code_size)
197 expandEmittedCode();
198
199 emitted_code[emitted_code_used] = (UChar)b;
200 emitted_code_used++;
201}
202
njn25e49d8e72002-09-23 09:36:25 +0000203__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(emitB) ( (l) & 0x000000FF );
206 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000207}
208
njn25e49d8e72002-09-23 09:36:25 +0000209__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000210{
njn25e49d8e72002-09-23 09:36:25 +0000211 VG_(emitB) ( (l) & 0x000000FF );
212 VG_(emitB) ( (l >> 8) & 0x000000FF );
213 VG_(emitB) ( (l >> 16) & 0x000000FF );
214 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000215}
216
sewardjfa492d42002-12-08 18:20:01 +0000217static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000218{
sewardjfa492d42002-12-08 18:20:01 +0000219 Int off = 4 * VGOFF_(m_eflags);
220 vg_assert(off >= 0 && off < 128);
221
222 if (dis)
223 VG_(printf)("\t %4d: ", emitted_code_used );
224
225 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
226 VG_(emitB) ( 0x75 );
227 VG_(emitB) ( off );
228 VG_(emitB) ( 0x9D ); /* POPFL */
229 if (dis)
230 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
231}
232
233static void emit_put_eflags ( void )
234{
235 Int off = 4 * VGOFF_(m_eflags);
236 vg_assert(off >= 0 && off < 128);
237
238 if (dis)
239 VG_(printf)("\t %4d: ", emitted_code_used );
240
241 VG_(emitB) ( 0x9C ); /* PUSHFL */
242 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
243 VG_(emitB) ( 0x45 );
244 VG_(emitB) ( off );
245 if (dis)
246 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
247}
248
249static void maybe_emit_put_eflags( void )
250{
251 if (eflags_state == UPD_Real) {
252 eflags_state = UPD_Both;
253 emit_put_eflags();
254 }
255}
256
sewardja2c5a732002-12-15 03:10:42 +0000257
258/* evidently unused */
259#if 0
sewardjfa492d42002-12-08 18:20:01 +0000260static void maybe_emit_get_eflags( void )
261{
262 if (eflags_state == UPD_Simd) {
263 eflags_state = UPD_Both;
264 emit_get_eflags();
265 }
266}
sewardja2c5a732002-12-15 03:10:42 +0000267#endif
sewardjfa492d42002-12-08 18:20:01 +0000268
sewardjf0f12aa2002-12-28 00:04:08 +0000269
270#if 0
271/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
272/* An alternative implementation of new_emit in which the
273 state space is explicitly enumerated. */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool simd = upds_simd_flags;
279 enum _eflags_state where = eflags_state;
280
281 enum { WNone, WSome, WAll } ww;
282 Bool rr;
283
284#define DIS_HEADER \
285 if (dis) \
286 VG_(printf)("\t %4d: ", emitted_code_used );
287
288 if (use_flags == FlagsEmpty) {
289 rr = False;
290 } else {
291 rr = True;
292 }
293
294 if (set_flags == FlagsEmpty) {
295 ww = WNone;
296 } else
297 if (set_flags == FlagsOSZACP) {
298 ww = WAll;
299 } else {
300 ww = WSome;
301 }
302
303 /* If we're not wanting to interact with simd flags, and the simd
304 flags are not in the real flags, then do nothing. */
305 if (simd == False && where == UPD_Simd)
306 goto noaction;
307
308 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
309 /* We're going to generate a complete new simd flag state without
310 consulting the old one first, so just deem this insn to create
311 the state in the real flags. */
312 eflags_state = UPD_Real;
313 DIS_HEADER;
314 return;
315 }
316
317 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
318 /* Want to partially update the flags state, but is in simd. So
319 fetch it first, then declare that the real state is the most
320 recent. */
321 emit_get_eflags();
322 eflags_state = UPD_Real;
323 DIS_HEADER;
324 return;
325 }
326
327 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
328 /* want to read simd flags, but not in real -> copy to real. */
329 emit_get_eflags();
330 eflags_state = UPD_Both;
331 DIS_HEADER;
332 return;
333 }
334
335 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
336 /* want to read and write simd flags, but not in real -> copy to
337 real. State is then Real since they get updated. */
338 emit_get_eflags();
339 eflags_state = UPD_Real;
340 DIS_HEADER;
341 return;
342 }
343
344 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
345 /* Doesn't really make sense. Want to interact with simd flags,
346 but insn doesn't modify them. So don't do anything. ??? */
347 goto noaction;
348 }
349
350 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
351 /* Doesn't really make sense. Want to interact with simd flags,
352 but insn doesn't modify them. So don't do anything. ??? */
353 goto noaction;
354 }
355
356 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
357 /* simd is in real. Insn reads real but does not change. --> do
358 nothing. */
359 goto noaction;
360 }
361
362 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
363 /* simd is in real. we want to capture changes made by it. -->
364 do nothing */
365 goto noaction;
366 }
367
368 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
369 /* simd is in real. Insn creates new simd state. --> leave in
370 real */
371 goto noaction;
372 }
373
374 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
375 /* simd is in both. Insn creates new simd state. --> change
376 state to Real. */
377 narrow_Both_to_Real:
378 eflags_state = UPD_Real;
379 DIS_HEADER;
380 return;
381 }
382
383 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
384 /* simd is in both. Insn creates partial new simd state. -->
385 change state to Real. No need to get, since Both holds. */
386 goto narrow_Both_to_Real;
387 }
388
389 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
390 /* simd is in real. Insn creates new simd state. --> leave in
391 real */
392 goto noaction;
393 }
394
395 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
396 /* want to read the simd flags, but already have a copy in real,
397 and not planning to modify it --> do nothing. */
398 goto noaction;
399
400 ////////////////
401
402 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
403 /* simd state is in real, but insn doesn't touch it --> do nothing */
404 goto noaction;
405
406 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
407 /* simd state is in both, insn doesn't touch it --> do nothing */
408 goto noaction;
409
410 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
411 /* simd state is in both. insn trashes real, therefore declare
412 simd state only in simd. */
413 narrow_Both_to_Simd:
414 eflags_state = UPD_Simd;
415 DIS_HEADER;
416 return;
417 }
418
419 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
420 /* simd state is in both. insn trashes real, therefore declare
421 simd state only in simd. */
422 goto narrow_Both_to_Simd;
423 }
424
425 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
426 /* simd state is in real; we don't want simd state changed, but
427 insn writes the flags. Therefore have to copy back first. */
428 put_flags_and_continue:
429 emit_put_eflags();
430 eflags_state = UPD_Simd;
431 DIS_HEADER;
432 return;
433 }
434
435 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
436 /* simd state is in real; we don't want simd state changed, but
437 insn writes the flags. Therefore have to copy back first. */
438 goto put_flags_and_continue;
439 }
440
441 goto unhandled;
442
443 noaction:
444 DIS_HEADER;
445 return;
446
447 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
448 // return;
449 //}
450
451 unhandled:
452 VG_(printf)("simd %s, where %s, read %s, write %s\n",
453 simd ? "True " : "False",
454 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
455 ? "Real" : "Both")),
456 rr ? "True " : "False",
457 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
458 );
459
460 VG_(core_panic)("new_emit");
461}
462/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
463#endif
464
465
sewardjfa492d42002-12-08 18:20:01 +0000466/* Call this before emitting each instruction.
467
468 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000469 interacts_with_simd_flags:
470 if true, this instruction wants to interact (read and/or write)
471 the simulated %EFLAGS state,
472 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000473 use_flags: set of (real) flags the instruction uses
474 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000475*/
sewardjfa492d42002-12-08 18:20:01 +0000476__inline__
sewardjf0f12aa2002-12-28 00:04:08 +0000477void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000478 FlagSet use_flags, FlagSet set_flags )
479{
480 Bool use, set;
481
482 use = use_flags != FlagsEmpty
483 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
484 set = set_flags != FlagsEmpty;
485
486 if (0)
487 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000488 "new_emit: state=%d interacts_with_simd_flags=%d "
489 "use_flags=%x set_flags=%x\n",
490 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000491
sewardjf0f12aa2002-12-28 00:04:08 +0000492 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000493 if (use && eflags_state == UPD_Simd) {
494 /* we need the CPU flags set, but they're not already */
495 eflags_state = UPD_Both;
496 emit_get_eflags();
497 }
498 if (set) {
499 /* if we're setting the flags, then the CPU will have the
500 only good copy */
501 eflags_state = UPD_Real;
502 }
503 } else {
504 /* presume that if non-simd code is using flags, it knows what
505 it's doing (ie, it just set up the flags). */
506 if (set) {
507 /* This instruction is going to trash the flags, so we'd
508 better save them away and say that they're only in the
509 simulated state. */
510 maybe_emit_put_eflags();
511 eflags_state = UPD_Simd;
512 }
513 }
514
sewardjde4a1d02002-03-22 01:27:54 +0000515 if (dis)
516 VG_(printf)("\t %4d: ", emitted_code_used );
517}
518
sewardjde4a1d02002-03-22 01:27:54 +0000519
520/*----------------------------------------------------*/
521/*--- Addressing modes ---*/
522/*----------------------------------------------------*/
523
524static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
525{
526 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
527}
528
529static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
530{
531 Int shift;
532 switch (scale) {
533 case 1: shift = 0; break;
534 case 2: shift = 1; break;
535 case 4: shift = 2; break;
536 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000537 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
540}
541
542static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
543{
544 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000545 VG_(emitB) ( mkModRegRM(0, reg, 5) );
546 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000547}
548
549static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
550{
551 /* (regmem), reg */
552 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000553 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( mkModRegRM(1, reg, 5) );
556 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000557 } else {
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000559 }
560}
561
njn25e49d8e72002-09-23 09:36:25 +0000562void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000563{
564 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 if (off < -128 || off > 127) {
567 /* Use a large offset */
568 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
570 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000571 } else {
572 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
574 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000575 }
576}
577
578static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
579 Int regindex, Int reg )
580{
581 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000582 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (off < -128 || off > 127) {
584 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000585 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
586 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
587 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000588 } else {
589 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
591 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
592 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000593 }
594}
595
njn25e49d8e72002-09-23 09:36:25 +0000596void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000597{
598 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000599 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000600}
601
602static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
603{
604 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000606}
607
608
609/*----------------------------------------------------*/
610/*--- Opcode translation ---*/
611/*----------------------------------------------------*/
612
613static __inline__ Int mkGrp1opcode ( Opcode opc )
614{
615 switch (opc) {
616 case ADD: return 0;
617 case OR: return 1;
618 case ADC: return 2;
619 case SBB: return 3;
620 case AND: return 4;
621 case SUB: return 5;
622 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000623 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000624 }
625}
626
sewardjfa492d42002-12-08 18:20:01 +0000627static __inline__ FlagSet nonshiftop_use(Opcode opc)
628{
629 switch(opc) {
630 case ADC:
631 case SBB:
632 return FlagC;
633
634 case ADD:
635 case OR:
636 case AND:
637 case SUB:
638 case XOR:
639 return FlagsEmpty;
640
641 default:
642 VG_(core_panic)("nonshiftop_use");
643 }
644}
645
646static __inline__ FlagSet nonshiftop_set(Opcode opc)
647{
648 switch(opc) {
649 case ADC:
650 case SBB:
651 case ADD:
652 case OR:
653 case AND:
654 case SUB:
655 case XOR:
656 return FlagsOSZACP;
657
658 default:
659 VG_(core_panic)("nonshiftop_set");
660 }
661}
662
sewardjde4a1d02002-03-22 01:27:54 +0000663static __inline__ Int mkGrp2opcode ( Opcode opc )
664{
665 switch (opc) {
666 case ROL: return 0;
667 case ROR: return 1;
668 case RCL: return 2;
669 case RCR: return 3;
670 case SHL: return 4;
671 case SHR: return 5;
672 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000673 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000674 }
675}
676
sewardjfa492d42002-12-08 18:20:01 +0000677static __inline__ FlagSet shiftop_use(Opcode opc)
678{
679 switch(opc) {
680 case ROR:
681 case ROL:
682 case SHL:
683 case SHR:
684 case SAR:
685 return FlagsEmpty;
686
687 case RCL:
688 case RCR:
689 return FlagC;
690
691 default:
692 VG_(core_panic)("shiftop_use");
693 }
694}
695
696static __inline__ FlagSet shiftop_set(Opcode opc)
697{
698 switch(opc) {
699 case ROR:
700 case ROL:
701 case RCL:
702 case RCR:
703 return FlagsOC;
704
705 case SHL:
706 case SHR:
707 case SAR:
708 return FlagsOSZACP;
709
710 default:
711 VG_(core_panic)("shiftop_set");
712 }
713}
714
sewardjde4a1d02002-03-22 01:27:54 +0000715static __inline__ Int mkGrp3opcode ( Opcode opc )
716{
717 switch (opc) {
718 case NOT: return 2;
719 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000720 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000721 }
722}
723
724static __inline__ Int mkGrp4opcode ( Opcode opc )
725{
726 switch (opc) {
727 case INC: return 0;
728 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000729 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000730 }
731}
732
733static __inline__ Int mkGrp5opcode ( Opcode opc )
734{
735 switch (opc) {
736 case CALLM: return 2;
737 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000738 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000739 }
740}
741
742static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
743{
744 switch (opc) {
745 case ADD: return 0x00;
746 case ADC: return 0x10;
747 case AND: return 0x20;
748 case XOR: return 0x30;
749 case OR: return 0x08;
750 case SBB: return 0x18;
751 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000752 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000753 }
754}
755
756/*----------------------------------------------------*/
757/*--- v-size (4, or 2 with OSO) insn emitters ---*/
758/*----------------------------------------------------*/
759
njn25e49d8e72002-09-23 09:36:25 +0000760void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000761{
sewardjf0f12aa2002-12-28 00:04:08 +0000762 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000763 if (sz == 2) VG_(emitB) ( 0x66 );
764 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
765 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000766 if (dis)
767 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
768 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
769}
770
njn25e49d8e72002-09-23 09:36:25 +0000771void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000772{
sewardjf0f12aa2002-12-28 00:04:08 +0000773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000774 if (sz == 2) VG_(emitB) ( 0x66 );
775 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
776 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
779 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
780}
781
782static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
783{
sewardjf0f12aa2002-12-28 00:04:08 +0000784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000785 if (sz == 2) VG_(emitB) ( 0x66 );
786 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000787 emit_amode_regmem_reg ( reg1, reg2 );
788 if (dis)
789 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
790 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
791}
792
793static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000798 emit_amode_regmem_reg ( reg2, reg1 );
799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
801 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000807 if (sz == 2) VG_(emitB) ( 0x66 );
808 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
809 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000810 if (dis)
811 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
812 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
813}
814
sewardjf0f12aa2002-12-28 00:04:08 +0000815void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
816 Int sz, Opcode opc,
817 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjf0f12aa2002-12-28 00:04:08 +0000819 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000820
njn25e49d8e72002-09-23 09:36:25 +0000821 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
823 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000824 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
825 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
826 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000827 } else {
njn25e49d8e72002-09-23 09:36:25 +0000828 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
829 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
830 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000831 }
832 if (dis)
833 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000834 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000835 lit, nameIReg(sz,reg));
836}
837
sewardjf0f12aa2002-12-28 00:04:08 +0000838void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
839 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000840 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000841{
sewardjf0f12aa2002-12-28 00:04:08 +0000842 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000843 if (sz == 2) VG_(emitB) ( 0x66 );
844 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
845 /* short form OK */
846 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
847 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
848 VG_(emitB) ( lit & 0x000000FF );
849 } else {
850 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
851 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
852 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
853 }
854 if (dis)
855 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
856 VG_(name_UOpcode)(False,opc), nameISize(sz),
857 lit, off, nameIReg(sz,regmem));
858}
859
sewardjf0f12aa2002-12-28 00:04:08 +0000860void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
861 Int sz, Opcode opc,
862 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000863{
sewardjf0f12aa2002-12-28 00:04:08 +0000864 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000865
njn25e49d8e72002-09-23 09:36:25 +0000866 if (sz == 2) VG_(emitB) ( 0x66 );
867 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
868 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
869 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000870 if (dis)
871 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000872 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000873 lit, nameIReg(sz,reg));
874}
875
sewardjf0f12aa2002-12-28 00:04:08 +0000876static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000877{
sewardjf0f12aa2002-12-28 00:04:08 +0000878 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000879 if (sz == 2) VG_(emitB) ( 0x66 );
880 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
881 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
882 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
883 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000886 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000890{
sewardjf0f12aa2002-12-28 00:04:08 +0000891 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000892 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
893 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
894 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
895 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000896 if (dis)
897 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000898 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000899}
900
sewardjf0f12aa2002-12-28 00:04:08 +0000901static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
902 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000903 Int off, Int areg, Int reg )
904{
sewardjf0f12aa2002-12-28 00:04:08 +0000905 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000906 if (sz == 2) VG_(emitB) ( 0x66 );
907 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
908 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000909 if (dis)
910 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000911 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000912 off, nameIReg(4,areg), nameIReg(sz,reg));
913}
914
sewardja2c5a732002-12-15 03:10:42 +0000915#if 0
916/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000917static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000918 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000919{
sewardjf0f12aa2002-12-28 00:04:08 +0000920 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000921 if (sz == 2) VG_(emitB) ( 0x66 );
922 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
923 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
926 VG_(name_UOpcode)(False,opc), nameISize(sz),
927 nameIReg(sz,reg), off, nameIReg(4,areg));
928}
sewardja2c5a732002-12-15 03:10:42 +0000929#endif
sewardjfa492d42002-12-08 18:20:01 +0000930
sewardjf0f12aa2002-12-28 00:04:08 +0000931void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000932 Int reg1, Int reg2 )
933{
sewardjf0f12aa2002-12-28 00:04:08 +0000934 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000936# if 0
937 /* Perfectly correct, but the GNU assembler uses the other form.
938 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
940 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000941# else
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000943 emit_amode_greg_ereg ( reg1, reg2 );
944# endif
945 if (dis)
946 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000947 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000948 nameIReg(sz,reg1), nameIReg(sz,reg2));
949}
950
njn25e49d8e72002-09-23 09:36:25 +0000951void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000952{
sewardjf0f12aa2002-12-28 00:04:08 +0000953#if 0
sewardjfa492d42002-12-08 18:20:01 +0000954 if (lit == 0 && eflags_state != UPD_Real) {
955 /* Only emit this for zeroing if it won't stomp flags */
956 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000957 return;
958 }
sewardjf0f12aa2002-12-28 00:04:08 +0000959#endif
960 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000961 if (sz == 2) VG_(emitB) ( 0x66 );
962 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
963 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000964 if (dis)
965 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
966 nameISize(sz), lit, nameIReg(sz,reg));
967}
968
sewardjf0f12aa2002-12-28 00:04:08 +0000969void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjde4a1d02002-03-22 01:27:54 +0000971 switch (opc) {
972 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +0000973 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +0000974 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000975 VG_(emitB) ( 0xF7 );
976 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000977 if (dis)
978 VG_(printf)( "\n\t\tneg%c\t%s\n",
979 nameISize(sz), nameIReg(sz,reg));
980 break;
981 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +0000982 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +0000983 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000984 VG_(emitB) ( 0xF7 );
985 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000986 if (dis)
987 VG_(printf)( "\n\t\tnot%c\t%s\n",
988 nameISize(sz), nameIReg(sz,reg));
989 break;
990 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +0000991 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tdec%c\t%s\n",
996 nameISize(sz), nameIReg(sz,reg));
997 break;
998 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +0000999 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001000 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001001 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (dis)
1003 VG_(printf)( "\n\t\tinc%c\t%s\n",
1004 nameISize(sz), nameIReg(sz,reg));
1005 break;
1006 default:
njne427a662002-10-02 11:08:25 +00001007 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001008 }
1009}
1010
njn25e49d8e72002-09-23 09:36:25 +00001011void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001014 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001016 } else {
1017 vg_assert(sz == 4);
1018 }
njn25e49d8e72002-09-23 09:36:25 +00001019 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001020 if (dis)
1021 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1022}
1023
njn25e49d8e72002-09-23 09:36:25 +00001024void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001025{
sewardjf0f12aa2002-12-28 00:04:08 +00001026 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001029 } else {
1030 vg_assert(sz == 4);
1031 }
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1035}
1036
njn25e49d8e72002-09-23 09:36:25 +00001037void VG_(emit_pushl_lit32) ( UInt int32 )
1038{
sewardjf0f12aa2002-12-28 00:04:08 +00001039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001040 VG_(emitB) ( 0x68 );
1041 VG_(emitL) ( int32 );
1042 if (dis)
1043 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1044}
1045
1046void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001047{
1048 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001049 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x6A );
1051 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001052 if (dis)
1053 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1054}
1055
sewardjf0f12aa2002-12-28 00:04:08 +00001056void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001057{
sewardjf0f12aa2002-12-28 00:04:08 +00001058 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x83 );
1060 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1061 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001062 if (dis)
1063 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1064}
1065
1066static void emit_swapl_reg_ECX ( Int reg )
1067{
sewardjf0f12aa2002-12-28 00:04:08 +00001068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1070 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001078 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001079 if (dis)
1080 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1081}
1082
1083static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1084{
sewardjf0f12aa2002-12-28 00:04:08 +00001085 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1087 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
1093static void emit_bswapl_reg ( Int reg )
1094{
sewardjf0f12aa2002-12-28 00:04:08 +00001095 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F );
1097 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1100}
1101
1102static void emit_movl_reg_reg ( Int regs, Int regd )
1103{
sewardjf0f12aa2002-12-28 00:04:08 +00001104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001105 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1106 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001107 if (dis)
1108 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1109}
1110
njn25e49d8e72002-09-23 09:36:25 +00001111void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001112{
sewardjf0f12aa2002-12-28 00:04:08 +00001113 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001114 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001115 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 } else {
1117 vg_assert(sz == 4);
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1120 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1121 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1124 nameISize(sz), lit, off, nameIReg(4,memreg) );
1125}
1126
1127
1128/*----------------------------------------------------*/
1129/*--- b-size (1 byte) instruction emitters ---*/
1130/*----------------------------------------------------*/
1131
1132/* There is some doubt as to whether C6 (Grp 11) is in the
1133 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001134void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1138 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1139 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (dis)
1141 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1142 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001143}
1144
sewardjf0f12aa2002-12-28 00:04:08 +00001145static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001146 Int off, Int areg, Int reg )
1147{
sewardjf0f12aa2002-12-28 00:04:08 +00001148 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001149 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1150 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001151 if (dis)
1152 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001154 nameIReg(1,reg));
1155}
1156
sewardjf0f12aa2002-12-28 00:04:08 +00001157static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001158 UInt lit, Int off, Int areg )
1159{
sewardjf0f12aa2002-12-28 00:04:08 +00001160 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001161 VG_(emitB) ( 0x80 );
1162 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1163 VG_(emitB) ( lit );
1164 if (dis)
1165 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1166 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1167}
1168
sewardja2c5a732002-12-15 03:10:42 +00001169#if 0
1170/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001171static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001172 Int off, Int areg, Int reg )
1173{
sewardjf0f12aa2002-12-28 00:04:08 +00001174 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001175 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1176 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1177 if (dis)
1178 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1179 VG_(name_UOpcode)(False,opc),
1180 nameIReg(1,reg),
1181 off, nameIReg(4,areg));
1182}
sewardja2c5a732002-12-15 03:10:42 +00001183#endif
sewardjfa492d42002-12-08 18:20:01 +00001184
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001186{
1187 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001188 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001189 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1190 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1193 nameIReg(1,reg), off, nameIReg(4,areg));
1194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1197 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg1), nameIReg(1,reg2));
1206}
1207
1208static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1209{
sewardjf0f12aa2002-12-28 00:04:08 +00001210 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001212 emit_amode_regmem_reg ( reg2, reg1 );
1213 if (dis)
1214 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1215 nameIReg(4,reg2));
1216}
1217
sewardjf0f12aa2002-12-28 00:04:08 +00001218static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1219 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001220{
sewardjf0f12aa2002-12-28 00:04:08 +00001221 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001222 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1223 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1224 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001225 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001226 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001227 lit, nameIReg(1,reg));
1228}
1229
sewardjf0f12aa2002-12-28 00:04:08 +00001230static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1231 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001232{
sewardjf0f12aa2002-12-28 00:04:08 +00001233 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001234 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1235 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1236 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001237 if (dis)
1238 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001239 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001240 lit, nameIReg(1,reg));
1241}
1242
sewardjf0f12aa2002-12-28 00:04:08 +00001243void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001244{
sewardjde4a1d02002-03-22 01:27:54 +00001245 switch (opc) {
1246 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001247 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001248 VG_(emitB) ( 0xFE );
1249 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001250 if (dis)
1251 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1252 break;
1253 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001254 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001255 VG_(emitB) ( 0xFE );
1256 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001257 if (dis)
1258 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1259 break;
1260 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001262 VG_(emitB) ( 0xF6 );
1263 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001264 if (dis)
1265 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1266 break;
1267 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xF6 );
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001271 if (dis)
1272 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1273 break;
1274 default:
njne427a662002-10-02 11:08:25 +00001275 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001276 }
1277}
1278
sewardjf0f12aa2002-12-28 00:04:08 +00001279void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001280{
sewardjf0f12aa2002-12-28 00:04:08 +00001281 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001282 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1283 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1284 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1287}
1288
sewardjde4a1d02002-03-22 01:27:54 +00001289/*----------------------------------------------------*/
1290/*--- zero-extended load emitters ---*/
1291/*----------------------------------------------------*/
1292
njn25e49d8e72002-09-23 09:36:25 +00001293void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001294{
sewardjf0f12aa2002-12-28 00:04:08 +00001295 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001296 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1297 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001298 if (dis)
1299 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1300 off, nameIReg(4,regmem), nameIReg(4,reg));
1301}
1302
1303static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1304{
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001307 emit_amode_regmem_reg ( reg1, reg2 );
1308 if (dis)
1309 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1310 nameIReg(4,reg2));
1311}
1312
njn25e49d8e72002-09-23 09:36:25 +00001313void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001314{
sewardjf0f12aa2002-12-28 00:04:08 +00001315 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001316 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1317 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001318 if (dis)
1319 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1320 off, nameIReg(4,areg), nameIReg(4,reg));
1321}
1322
1323static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1324{
sewardjf0f12aa2002-12-28 00:04:08 +00001325 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001327 emit_amode_regmem_reg ( reg1, reg2 );
1328 if (dis)
1329 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1330 nameIReg(4,reg2));
1331}
1332
1333/*----------------------------------------------------*/
1334/*--- FPU instruction emitters ---*/
1335/*----------------------------------------------------*/
1336
1337static void emit_get_fpu_state ( void )
1338{
1339 Int off = 4 * VGOFF_(m_fpustate);
sewardjf0f12aa2002-12-28 00:04:08 +00001340 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001341 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1342 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001343 if (dis)
1344 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1345}
1346
1347static void emit_put_fpu_state ( void )
1348{
1349 Int off = 4 * VGOFF_(m_fpustate);
sewardjf0f12aa2002-12-28 00:04:08 +00001350 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001351 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1352 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001353 if (dis)
1354 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1355}
1356
sewardjf0f12aa2002-12-28 00:04:08 +00001357static void emit_fpu_no_mem ( FlagSet uses_sflags,
1358 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001359 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001360 UChar second_byte )
1361{
sewardjf0f12aa2002-12-28 00:04:08 +00001362 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001363 VG_(emitB) ( first_byte );
1364 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001365 if (dis)
1366 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1367 (UInt)first_byte, (UInt)second_byte );
1368}
1369
sewardjf0f12aa2002-12-28 00:04:08 +00001370static void emit_fpu_regmem ( FlagSet uses_sflags,
1371 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001372 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001373 UChar second_byte_masked,
1374 Int reg )
1375{
sewardjf0f12aa2002-12-28 00:04:08 +00001376 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001377 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001378 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1379 if (dis)
1380 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1381 (UInt)first_byte, (UInt)second_byte_masked,
1382 nameIReg(4,reg) );
1383}
1384
sewardj3d7c9c82003-03-26 21:08:13 +00001385static void emit_MMX2_regmem ( FlagSet uses_sflags,
1386 FlagSet sets_sflags,
1387 UChar first_byte,
1388 UChar second_byte,
1389 Int ireg )
1390{
1391 VG_(new_emit)(True, uses_sflags, sets_sflags);
1392 VG_(emitB) ( 0x0F );
1393 VG_(emitB) ( first_byte );
1394 second_byte &= 0x38; /* mask out mod and rm fields */
1395 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1396 if (dis)
1397 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1398 (UInt)first_byte, (UInt)second_byte,
1399 nameIReg(4,ireg) );
1400}
1401
sewardjca860012003-03-27 23:52:58 +00001402static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1403 FlagSet sets_sflags,
1404 UChar first_byte,
1405 UChar second_byte,
1406 Int ireg )
1407{
1408 VG_(new_emit)(True, uses_sflags, sets_sflags);
1409 VG_(emitB) ( 0x0F );
1410 VG_(emitB) ( first_byte );
1411 second_byte &= 0x38; /* mask out mod and rm fields */
1412 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1413 second_byte |= (ireg & 7); /* patch in our ireg */
1414 VG_(emitB) ( second_byte );
1415 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001416 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1417 (UInt)first_byte, (UInt)second_byte,
1418 nameIReg(4,ireg) );
1419}
1420
1421static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1422 FlagSet sets_sflags,
1423 UChar first_byte,
1424 UChar second_byte,
1425 Int ireg )
1426{
1427 VG_(new_emit)(True, uses_sflags, sets_sflags);
1428 VG_(emitB) ( 0x0F );
1429 VG_(emitB) ( first_byte );
1430 second_byte &= 0x38; /* mask out mod and rm fields */
1431 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1432 second_byte |= (ireg & 7); /* patch in our ireg */
1433 VG_(emitB) ( second_byte );
1434 if (dis)
1435 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001436 (UInt)first_byte, (UInt)second_byte,
1437 nameIReg(4,ireg) );
1438}
1439
1440static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1441 FlagSet sets_sflags,
1442 UChar first_byte,
1443 UChar second_byte,
1444 UChar third_byte )
1445{
1446 VG_(new_emit)(True, uses_sflags, sets_sflags);
1447 VG_(emitB) ( 0x0F );
1448 VG_(emitB) ( first_byte );
1449 VG_(emitB) ( second_byte );
1450 VG_(emitB) ( third_byte );
1451 if (dis)
1452 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1453 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1454}
1455
sewardj3d7c9c82003-03-26 21:08:13 +00001456static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1457 FlagSet sets_sflags,
1458 UChar first_byte,
1459 UChar second_byte )
1460{
1461 VG_(new_emit)(True, uses_sflags, sets_sflags);
1462 VG_(emitB) ( 0x0F );
1463 VG_(emitB) ( first_byte );
1464 VG_(emitB) ( second_byte );
1465 if (dis)
1466 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1467 (UInt)first_byte, (UInt)second_byte );
1468}
1469
1470static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1471 FlagSet sets_sflags,
1472 UChar first_byte )
1473{
1474 VG_(new_emit)(True, uses_sflags, sets_sflags);
1475 VG_(emitB) ( 0x0F );
1476 VG_(emitB) ( first_byte );
1477 if (dis)
1478 VG_(printf)("\n\t\tmmx1-0x%x\n",
1479 (UInt)first_byte );
1480}
1481
sewardjde4a1d02002-03-22 01:27:54 +00001482
1483/*----------------------------------------------------*/
1484/*--- misc instruction emitters ---*/
1485/*----------------------------------------------------*/
1486
njn25e49d8e72002-09-23 09:36:25 +00001487void VG_(emit_call_reg) ( Int reg )
1488{
sewardjfa492d42002-12-08 18:20:01 +00001489 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001490 VG_(emitB) ( 0xFF ); /* Grp5 */
1491 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1492 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001493 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001494}
1495
sewardjf0f12aa2002-12-28 00:04:08 +00001496static
1497void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1498 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001499{
sewardjfa492d42002-12-08 18:20:01 +00001500 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001501 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001502
1503 if (byte_off < -128 || byte_off > 127) {
1504 VG_(emitB) ( 0xFF );
1505 VG_(emitB) ( 0x95 );
1506 VG_(emitL) ( byte_off );
1507 } else {
1508 VG_(emitB) ( 0xFF );
1509 VG_(emitB) ( 0x55 );
1510 VG_(emitB) ( byte_off );
1511 }
1512 if (dis)
1513 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001514}
1515
sewardja2c5a732002-12-15 03:10:42 +00001516#if 0
1517/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001518static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1519{
1520 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001521 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001522 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1523 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001524 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001525 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001526 if (dis)
1527 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1528 nameIReg(4,regmem));
1529}
sewardja2c5a732002-12-15 03:10:42 +00001530#endif
sewardjde4a1d02002-03-22 01:27:54 +00001531
njn25e49d8e72002-09-23 09:36:25 +00001532void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001533{
njne427a662002-10-02 11:08:25 +00001534 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001535 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1536 VG_(emitB) ( 0x8D );
1537 VG_(emitB) ( 0x64 );
1538 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001539 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001540 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001541 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001542}
1543
1544
1545static void emit_movb_AL_zeroESPmem ( void )
1546{
1547 /* movb %al, 0(%esp) */
1548 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001549 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001550 VG_(emitB) ( 0x88 );
1551 VG_(emitB) ( 0x44 );
1552 VG_(emitB) ( 0x24 );
1553 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001554 if (dis)
1555 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1556}
1557
1558static void emit_movb_zeroESPmem_AL ( void )
1559{
1560 /* movb 0(%esp), %al */
1561 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001562 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001563 VG_(emitB) ( 0x8A );
1564 VG_(emitB) ( 0x44 );
1565 VG_(emitB) ( 0x24 );
1566 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001567 if (dis)
1568 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1569}
1570
sewardja2113f92002-12-12 23:42:48 +00001571/* Jump target states */
1572#define TGT_UNDEF (1 << 16)
1573#define TGT_FORWARD (2 << 16)
1574#define TGT_BACKWARD (3 << 16)
1575
1576static inline Int tgt_state(Int tgt)
1577{
1578 return tgt & 0xffff0000;
1579}
1580
1581static inline Int tgt_addr(Int tgt)
1582{
1583 return tgt & 0x0000ffff;
1584}
1585
1586static inline Int mk_tgt(Int state, Int addr)
1587{
1588 vg_assert(state == TGT_UNDEF
1589 || state == TGT_FORWARD || state == TGT_BACKWARD);
1590 vg_assert((addr & 0xffff0000) == 0);
1591
1592 return state | addr;
1593}
1594
1595void VG_(init_target) ( Int *tgt )
1596{
1597 *tgt = TGT_UNDEF;
1598}
1599
1600void VG_(target_back) ( Int *tgt )
1601{
1602 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1603
1604 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1605}
1606
1607void VG_(target_forward) ( Int *tgt )
1608{
1609 Int delta;
1610
1611 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1612 tgt_state(*tgt) == TGT_UNDEF);
1613
1614 if (tgt_state(*tgt) == TGT_UNDEF)
1615 return; /* target not used */
1616
1617 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1618 vg_assert(delta >= -128 && delta <= 127);
1619 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001620 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001621 emitted_code[tgt_addr(*tgt)] = delta;
1622 if (dis)
1623 VG_(printf)("(target to jump site %d; delta: %d)\n",
1624 tgt_addr(*tgt), delta);
1625}
1626
1627void VG_(emit_target_delta) ( Int *tgt )
1628{
1629 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1630 tgt_state(*tgt) == TGT_BACKWARD);
1631
1632 if (tgt_state(*tgt) == TGT_UNDEF) {
1633 /* forward jump */
1634 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1635 VG_(emitB) (0x00);
1636 } else {
1637 /* backward jump */
1638 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1639 vg_assert(delta >= -128 && delta <= 127);
1640 VG_(emitB) (delta);
1641 }
1642}
1643
sewardjde4a1d02002-03-22 01:27:54 +00001644
1645/* Emit a jump short with an 8-bit signed offset. Note that the
1646 offset is that which should be added to %eip once %eip has been
1647 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001648void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001649{
1650 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001651 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001652 VG_(emitB) ( 0x70 + (UInt)cond );
1653 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001654 if (dis)
1655 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001656 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001657}
1658
sewardja2113f92002-12-12 23:42:48 +00001659/* Same as above, but defers emitting the delta */
1660void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1661{
sewardj706240d2002-12-26 17:10:12 +00001662 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001663 VG_(emitB) ( 0x70 + (UInt)cond );
1664 VG_(emit_target_delta) (tgt);
1665 if (dis)
1666 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001667 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001668}
1669
1670
1671
sewardjf0f12aa2002-12-28 00:04:08 +00001672static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001673{
sewardjf0f12aa2002-12-28 00:04:08 +00001674 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001675 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1676 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001677 if (dis)
1678 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001679 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001680}
1681
1682static void emit_ret ( void )
1683{
sewardjfa492d42002-12-08 18:20:01 +00001684 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001685 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001686 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001687 if (dis)
1688 VG_(printf)("\n\t\tret\n");
1689}
1690
sewardj22854b92002-11-30 14:00:47 +00001691/* Predicate used in sanity checks elsewhere - returns true if any
1692 jump-site is an actual chained jump */
1693Bool VG_(is_chained_jumpsite)(Addr a)
1694{
1695 UChar *cp = (UChar *)a;
1696
1697 return (*cp == 0xE9); /* 0xE9 -- jmp */
1698}
1699
sewardj83f11862002-12-01 02:07:08 +00001700static
1701Bool is_fresh_jumpsite(UChar *cp)
1702{
1703 return
1704 cp[0] == 0x0F && /* UD2 */
1705 cp[1] == 0x0B &&
1706 cp[2] == 0x0F && /* UD2 */
1707 cp[3] == 0x0B &&
1708 cp[4] == 0x90; /* NOP */
1709}
1710
sewardj22854b92002-11-30 14:00:47 +00001711/* Predicate used in sanity checks elsewhere - returns true if all
1712 jump-sites are calls to VG_(patch_me) */
1713Bool VG_(is_unchained_jumpsite)(Addr a)
1714{
1715 UChar *cp = (UChar *)a;
1716 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1717 Int idelta;
1718
1719 if (*cp++ != 0xE8) /* 0xE8 == call */
1720 return False;
1721
1722 idelta = (*cp++) << 0;
1723 idelta |= (*cp++) << 8;
1724 idelta |= (*cp++) << 16;
1725 idelta |= (*cp++) << 24;
1726
1727 return idelta == delta;
1728}
1729
1730/* Return target address for a direct jmp */
1731Addr VG_(get_jmp_dest)(Addr a)
1732{
1733 Int delta;
1734 UChar *cp = (UChar *)a;
1735
1736 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1737 return 0;
1738
1739 delta = (*cp++) << 0;
1740 delta |= (*cp++) << 8;
1741 delta |= (*cp++) << 16;
1742 delta |= (*cp++) << 24;
1743
1744 return a + VG_PATCHME_JMPSZ + delta;
1745}
1746
1747/* unchain a BB by generating a call to VG_(patch_me) */
1748void VG_(unchain_jumpsite)(Addr a)
1749{
1750 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1751 UChar *cp = (UChar *)a;
1752
1753 if (VG_(is_unchained_jumpsite)(a))
1754 return; /* don't write unnecessarily */
1755
sewardj83f11862002-12-01 02:07:08 +00001756 if (!is_fresh_jumpsite(cp))
1757 VG_(bb_dechain_count)++; /* update stats */
1758
sewardj22854b92002-11-30 14:00:47 +00001759 *cp++ = 0xE8; /* call */
1760 *cp++ = (delta >> 0) & 0xff;
1761 *cp++ = (delta >> 8) & 0xff;
1762 *cp++ = (delta >> 16) & 0xff;
1763 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001764}
1765
1766/* This doesn't actually generate a call to VG_(patch_me), but
1767 reserves enough space in the instruction stream for it to happen
1768 and records the offset into the jump table. This is because call
1769 is a relative jump, and so will be affected when this code gets
1770 moved about. The translation table will "unchain" this basic block
1771 on insertion (with VG_(unchain_BB)()), and thereby generate a
1772 proper call instruction. */
1773static void emit_call_patchme( void )
1774{
1775 vg_assert(VG_PATCHME_CALLSZ == 5);
1776
sewardjfa492d42002-12-08 18:20:01 +00001777 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001778 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001779
1780 if (jumpidx >= VG_MAX_JUMPS) {
1781 /* If there too many jumps in this basic block, fall back to
1782 dispatch loop. We still need to keep it the same size as the
1783 call sequence. */
1784 VG_(emitB) ( 0xC3 ); /* ret */
1785 VG_(emitB) ( 0x90 ); /* nop */
1786 VG_(emitB) ( 0x90 ); /* nop */
1787 VG_(emitB) ( 0x90 ); /* nop */
1788 VG_(emitB) ( 0x90 ); /* nop */
1789
1790 if (dis)
1791 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1792
1793 if (0 && VG_(clo_verbosity))
1794 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1795 } else {
1796 jumps[jumpidx++] = emitted_code_used;
1797
1798 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1799 VG_(emitB) ( 0x0B );
1800 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1801 VG_(emitB) ( 0x0B );
1802 VG_(emitB) ( 0x90 ); /* NOP */
1803
1804 if (dis)
1805 VG_(printf)("\n\t\tud2; ud2; nop\n");
1806 }
1807}
1808
njn25e49d8e72002-09-23 09:36:25 +00001809void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001810{
sewardjf0f12aa2002-12-28 00:04:08 +00001811 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001812 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001813 if (dis)
1814 VG_(printf)("\n\t\tpushal\n");
1815}
1816
njn25e49d8e72002-09-23 09:36:25 +00001817void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001818{
sewardjf0f12aa2002-12-28 00:04:08 +00001819 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001820 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001821 if (dis)
1822 VG_(printf)("\n\t\tpopal\n");
1823}
1824
1825static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1826{
sewardjf0f12aa2002-12-28 00:04:08 +00001827 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001828 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1829 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001830 if (dis)
1831 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1832 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1833}
1834
1835static void emit_lea_sib_reg ( UInt lit, Int scale,
1836 Int regbase, Int regindex, Int reg )
1837{
sewardjf0f12aa2002-12-28 00:04:08 +00001838 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001839 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001840 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1841 if (dis)
1842 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1843 lit, nameIReg(4,regbase),
1844 nameIReg(4,regindex), scale,
1845 nameIReg(4,reg) );
1846}
1847
njn25e49d8e72002-09-23 09:36:25 +00001848void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001849{
sewardjf0f12aa2002-12-28 00:04:08 +00001850 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001851 VG_(emitB) ( 0x0F );
1852 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001853 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1854 if (dis)
1855 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1856}
1857
1858/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001859/*--- Helper offset -> addr translation ---*/
1860/*----------------------------------------------------*/
1861
1862/* Finds the baseBlock offset of a skin-specified helper.
1863 * Searches through compacts first, then non-compacts. */
1864Int VG_(helper_offset)(Addr a)
1865{
1866 Int i;
njnf4ce3d32003-02-10 10:17:26 +00001867 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001868
1869 for (i = 0; i < VG_(n_compact_helpers); i++)
1870 if (VG_(compact_helper_addrs)[i] == a)
1871 return VG_(compact_helper_offsets)[i];
1872 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1873 if (VG_(noncompact_helper_addrs)[i] == a)
1874 return VG_(noncompact_helper_offsets)[i];
1875
1876 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001877 VG_(get_fnname) ( a, buf, 100 );
1878
njn25e49d8e72002-09-23 09:36:25 +00001879 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001880 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1881 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001882
1883 VG_(printf)(" compact helpers: ");
1884 for (i = 0; i < VG_(n_compact_helpers); i++)
1885 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1886
1887 VG_(printf)("\n non-compact helpers: ");
1888 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1889 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1890
1891 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001892 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001893}
1894
1895/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001896/*--- Instruction synthesisers ---*/
1897/*----------------------------------------------------*/
1898
1899static Condcode invertCondition ( Condcode cond )
1900{
1901 return (Condcode)(1 ^ (UInt)cond);
1902}
1903
1904
1905/* Synthesise a call to *baseBlock[offset], ie,
1906 call * (4 x offset)(%ebp).
1907*/
sewardjfa492d42002-12-08 18:20:01 +00001908void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00001909 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00001910{
1911 vg_assert(word_offset >= 0);
1912 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00001913 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00001914 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00001915 }
sewardjf0f12aa2002-12-28 00:04:08 +00001916 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00001917}
1918
njn25e49d8e72002-09-23 09:36:25 +00001919static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001920{
njn25e49d8e72002-09-23 09:36:25 +00001921 if (src != dst) {
1922 VG_(emit_movv_reg_reg) ( 4, src, dst );
1923 ccall_arg_setup_instrs++;
1924 }
njn6431be72002-07-28 09:53:34 +00001925}
njn25e49d8e72002-09-23 09:36:25 +00001926
1927/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1928static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1929{
1930 if (RealReg == tag) {
1931 maybe_emit_movl_reg_reg ( litOrReg, reg );
1932 } else if (Literal == tag) {
1933 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1934 ccall_arg_setup_instrs++;
1935 }
1936 else
njne427a662002-10-02 11:08:25 +00001937 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001938}
1939
1940static
1941void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1942{
1943 if (R_EAX == reg1) {
1944 VG_(emit_swapl_reg_EAX) ( reg2 );
1945 } else if (R_EAX == reg2) {
1946 VG_(emit_swapl_reg_EAX) ( reg1 );
1947 } else {
1948 emit_swapl_reg_reg ( reg1, reg2 );
1949 }
1950 ccall_arg_setup_instrs++;
1951}
1952
1953static
1954void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1955{
1956 if (dst1 != src2) {
1957 maybe_emit_movl_reg_reg ( src1, dst1 );
1958 maybe_emit_movl_reg_reg ( src2, dst2 );
1959
1960 } else if (dst2 != src1) {
1961 maybe_emit_movl_reg_reg ( src2, dst2 );
1962 maybe_emit_movl_reg_reg ( src1, dst1 );
1963
1964 } else {
1965 /* swap to break cycle */
1966 emit_swapl_arg_regs ( dst1, dst2 );
1967 }
1968}
1969
1970static
1971void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1972 UInt dst1, UInt dst2, UInt dst3)
1973{
1974 if (dst1 != src2 && dst1 != src3) {
1975 maybe_emit_movl_reg_reg ( src1, dst1 );
1976 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1977
1978 } else if (dst2 != src1 && dst2 != src3) {
1979 maybe_emit_movl_reg_reg ( src2, dst2 );
1980 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1981
1982 } else if (dst3 != src1 && dst3 != src2) {
1983 maybe_emit_movl_reg_reg ( src3, dst3 );
1984 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1985
1986 } else {
1987 /* break cycle */
1988 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1989 emit_swapl_arg_regs ( dst1, dst2 );
1990 emit_swapl_arg_regs ( dst1, dst3 );
1991
1992 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1993 emit_swapl_arg_regs ( dst1, dst3 );
1994 emit_swapl_arg_regs ( dst1, dst2 );
1995
1996 } else {
njne427a662002-10-02 11:08:25 +00001997 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001998 }
1999 }
2000}
2001
2002static
2003void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2004 UInt src1, UInt src2,
2005 UInt dst1, UInt dst2)
2006{
2007 /* If either are lits, order doesn't matter */
2008 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2009 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2010 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2011
2012 } else {
2013 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2014 }
2015}
2016
2017static
2018void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2019 UInt src1, UInt src2, UInt src3,
2020 UInt dst1, UInt dst2, UInt dst3)
2021{
2022 // SSS: fix this eventually -- make STOREV use two RealRegs?
2023 /* Not supporting literals for 3-arg C functions -- they're only used
2024 by STOREV which has 2 args */
2025 vg_assert(RealReg == tagv[src1] &&
2026 RealReg == tagv[src2] &&
2027 RealReg == tagv[src3]);
2028 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2029 dst1, dst2, dst3 );
2030}
2031
2032/* Synthesise a call to a C function `fn' (which must be registered in
2033 baseBlock) doing all the reg saving and arg handling work.
2034
2035 WARNING: a UInstr should *not* be translated with synth_ccall followed
2036 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2037 such behaviour and everything will fall over.
2038 */
2039void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2040 Tag tagv[], Int ret_reg,
2041 RRegSet regs_live_before, RRegSet regs_live_after )
2042{
2043 Int i;
2044 Int stack_used = 0;
2045 Bool preserve_eax, preserve_ecx, preserve_edx;
2046
2047 vg_assert(0 <= regparms_n && regparms_n <= 3);
2048
2049 ccalls++;
2050
2051 /* If %e[acd]x is live before and after the C call, save/restore it.
2052 Unless the return values clobbers the reg; in this case we must not
2053 save/restore the reg, because the restore would clobber the return
2054 value. (Before and after the UInstr really constitute separate live
2055 ranges, but you miss this if you don't consider what happens during
2056 the UInstr.) */
2057# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002058 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2059 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002060 ret_reg != realReg)
2061
2062 preserve_eax = PRESERVE_REG(R_EAX);
2063 preserve_ecx = PRESERVE_REG(R_ECX);
2064 preserve_edx = PRESERVE_REG(R_EDX);
2065
2066# undef PRESERVE_REG
2067
2068 /* Save caller-save regs as required */
2069 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2070 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2071 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2072
2073 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2074 is the number of args passed in regs (maximum 3 for GCC on x86). */
2075
2076 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002077
njn25e49d8e72002-09-23 09:36:25 +00002078 /* First push stack args (RealRegs or Literals) in reverse order. */
2079 for (i = argc-1; i >= regparms_n; i--) {
2080 switch (tagv[i]) {
2081 case RealReg:
2082 VG_(emit_pushv_reg) ( 4, argv[i] );
2083 break;
2084 case Literal:
2085 /* Use short form of pushl if possible. */
2086 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2087 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2088 else
2089 VG_(emit_pushl_lit32)( argv[i] );
2090 break;
2091 default:
2092 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002093 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002094 }
2095 stack_used += 4;
2096 ccall_arg_setup_instrs++;
2097 }
njn6431be72002-07-28 09:53:34 +00002098
njn25e49d8e72002-09-23 09:36:25 +00002099 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2100 If moving values between registers, be careful not to clobber any on
2101 the way. Happily we can use xchgl to swap registers.
2102 */
2103 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002104
njn25e49d8e72002-09-23 09:36:25 +00002105 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2106 case 3:
2107 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2108 R_EAX, R_EDX, R_ECX );
2109 break;
njn6431be72002-07-28 09:53:34 +00002110
njn25e49d8e72002-09-23 09:36:25 +00002111 /* Less-tricky. Args passed in %eax and %edx. */
2112 case 2:
2113 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2114 break;
2115
2116 /* Easy. Just move arg1 into %eax (if not already in there). */
2117 case 1:
2118 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2119 break;
2120
2121 case 0:
2122 break;
2123
2124 default:
njne427a662002-10-02 11:08:25 +00002125 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002126 }
2127
sewardjfa492d42002-12-08 18:20:01 +00002128 /* Call the function - may trash all flags */
2129 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002130
2131 /* Clear any args from stack */
2132 if (0 != stack_used) {
2133 VG_(emit_add_lit_to_esp) ( stack_used );
2134 ccall_stack_clears++;
2135 }
2136
2137 /* Move return value into ret_reg if necessary and not already there */
2138 if (INVALID_REALREG != ret_reg) {
2139 ccall_retvals++;
2140 if (R_EAX != ret_reg) {
2141 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2142 ccall_retval_movs++;
2143 }
2144 }
2145
2146 /* Restore live caller-save regs as required */
2147 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2148 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2149 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002150}
sewardjde4a1d02002-03-22 01:27:54 +00002151
sewardj2e93c502002-04-12 11:12:52 +00002152static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002153{
sewardj2e93c502002-04-12 11:12:52 +00002154 switch (jmpkind) {
2155 case JmpBoring:
2156 break;
sewardj2e93c502002-04-12 11:12:52 +00002157 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002158 break;
2159 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002160 break;
2161 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002162 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002163 break;
2164 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002165 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002166 break;
2167 default:
njne427a662002-10-02 11:08:25 +00002168 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002169 }
2170}
2171
2172/* Jump to the next translation, by loading its original addr into
2173 %eax and returning to the scheduler. Signal special requirements
2174 by loading a special value into %ebp first.
2175*/
2176static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2177{
sewardjfa492d42002-12-08 18:20:01 +00002178 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002179 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002180 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002181 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002182 emit_ret();
2183}
2184
sewardj22854b92002-11-30 14:00:47 +00002185static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002186
2187/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002188static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002189{
sewardjfa492d42002-12-08 18:20:01 +00002190 maybe_emit_put_eflags(); /* save flags here */
2191
njn25e49d8e72002-09-23 09:36:25 +00002192 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002193
2194 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2195 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2196 emit_call_patchme();
2197 } else {
2198 load_ebp_from_JmpKind ( jmpkind );
2199 emit_ret();
2200 }
sewardjde4a1d02002-03-22 01:27:54 +00002201}
2202
2203
sewardj2370f3b2002-11-30 15:01:01 +00002204static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002205static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002206 Opcode opcode, Int size,
2207 UInt lit, Int reg );
2208
sewardjfa492d42002-12-08 18:20:01 +00002209static void synth_jcond_lit ( Condcode cond,
2210 Addr addr,
2211 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002212{
sewardj2370f3b2002-11-30 15:01:01 +00002213 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002214 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002215 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002216
sewardja2113f92002-12-12 23:42:48 +00002217 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002218 VG_(init_target)(&tgt2);
2219 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002220
sewardjfa492d42002-12-08 18:20:01 +00002221 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2222 if need be */
2223 maybe_emit_put_eflags();
2224 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2225
2226 if (eflags_state == UPD_Both) {
2227 /* The flags are already set up, so we just use them as is. */
2228 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002229 cond = invertCondition(cond);
2230 } else {
sewardj75f04932002-12-12 23:13:21 +00002231 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002232
2233 /* The simd state contains the most recent version, so we emit a
2234 sequence to calculate the relevant condition directly out of
2235 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2236 copying them back to the real flags via popf. Notice that
2237 some of these sequences trash %eax, but that should be free
2238 now since this is the end of a bb and therefore all regs are
2239 dead. */
2240 simd = False;
2241
2242 switch (cond) {
2243
sewardjbb6c1182002-12-12 23:54:47 +00002244 case CondLE: /* Z || S != O -> S || !P */
2245 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002246 vg_assert(eax_trashable);
2247
2248 VG_(emit_movv_offregmem_reg)
2249 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2250 /* eax == %EFLAGS */
2251
sewardjbb6c1182002-12-12 23:54:47 +00002252 VG_(emit_nonshiftopv_lit_reg)
2253 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2254 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002255
sewardjbb6c1182002-12-12 23:54:47 +00002256 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2257 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002258
sewardj09736622002-12-28 00:19:00 +00002259 /* actually set the real cpu flags, since ROR changes
2260 neither P nor Z */
2261 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2262
sewardjbb6c1182002-12-12 23:54:47 +00002263 if (cond == CondLE) {
2264 /* test Z */
2265 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2266 /* test OF != SF */
2267 cond = CondP;
2268 } else {
2269 /* test Z */
2270 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2271 /* test OF == SF */
2272 cond = CondNP;
2273 }
sewardj2370f3b2002-11-30 15:01:01 +00002274 break;
2275
sewardjfa492d42002-12-08 18:20:01 +00002276 case CondL:
2277 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002278 vg_assert(eax_trashable);
2279
2280 VG_(emit_movv_offregmem_reg)
2281 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2282 /* eax == %EFLAGS */
2283
sewardj75f04932002-12-12 23:13:21 +00002284 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2285 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002286
sewardj75f04932002-12-12 23:13:21 +00002287 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2288 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002289
sewardj09736622002-12-28 00:19:00 +00002290 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002291 if (cond == CondL) cond = CondP; else cond = CondNP;
2292 break;
sewardjfa492d42002-12-08 18:20:01 +00002293
2294 case CondB:
2295 case CondNB:
2296 mask = EFlagC; goto simple; /* C=1 */
2297
2298 case CondZ:
2299 case CondNZ:
2300 mask = EFlagZ; goto simple; /* Z=1 */
2301
2302 case CondBE:
2303 case CondNBE:
2304 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2305
2306 case CondS:
2307 case CondNS:
2308 mask = EFlagS; goto simple; /* S=1 */
2309
2310 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002311 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002312 mask = EFlagP; goto simple; /* P=1 */
2313
sewardj39542072002-12-09 22:44:00 +00002314 case CondO:
2315 case CondNO:
2316 mask = EFlagO; goto simple; /* O=1 */
2317
sewardjfa492d42002-12-08 18:20:01 +00002318 default:
2319 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002320 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002321 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2322
2323 simple:
2324 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002325 if ((mask & 0xff) == mask) {
2326 VG_(emitB) ( 0xF6 ); /* Grp3 */
2327 VG_(emit_amode_offregmem_reg)(
2328 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2329 VG_(emitB) (mask);
2330 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002331 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002332 mask, VGOFF_(m_eflags) * 4);
2333 } else {
sewardjfa492d42002-12-08 18:20:01 +00002334 /* all cond codes are in lower 16 bits */
2335 vg_assert((mask & 0xffff) == mask);
2336
2337 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002338 VG_(emitB) ( 0xF7 );
2339 VG_(emit_amode_offregmem_reg)(
2340 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002341 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002342 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002343 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002344 mask, VGOFF_(m_eflags) * 4);
2345 }
2346
sewardj75f04932002-12-12 23:13:21 +00002347 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002348 break;
2349 }
2350 }
2351
sewardja2113f92002-12-12 23:42:48 +00002352 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002353
2354 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002355 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002356
2357 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002358 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002359}
2360
2361
sewardj2370f3b2002-11-30 15:01:01 +00002362
sewardjde4a1d02002-03-22 01:27:54 +00002363static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2364{
sewardja2113f92002-12-12 23:42:48 +00002365 Int tgt;
2366
2367 VG_(init_target)(&tgt);
2368
sewardjfa492d42002-12-08 18:20:01 +00002369 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002370
2371 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002372 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002373
2374 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002375}
2376
2377
2378static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2379{
2380 /* Load the zero-extended literal into reg, at size l,
2381 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002382 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002383}
2384
2385
2386static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2387{
2388 switch (size) {
2389 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2390 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2391 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002392 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002393 }
2394}
2395
2396
2397static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2398{
2399 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002400 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2401 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2402 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002403 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002404 }
2405}
2406
2407
2408static void synth_mov_reg_offregmem ( Int size, Int reg,
2409 Int off, Int areg )
2410{
2411 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002412 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2413 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002414 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002415 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002416 }
2417 else {
njn25e49d8e72002-09-23 09:36:25 +00002418 VG_(emit_swapl_reg_EAX) ( reg );
2419 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2420 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002421 }
2422 break;
njne427a662002-10-02 11:08:25 +00002423 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002424 }
2425}
2426
2427
2428static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2429{
2430 Int s1;
2431 switch (size) {
2432 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2433 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2434 case 1: if (reg1 < 4) {
2435 emit_movb_reg_regmem ( reg1, reg2 );
2436 }
2437 else {
2438 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2439 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2440 emit_swapl_reg_reg ( s1, reg1 );
2441 emit_movb_reg_regmem ( s1, reg2 );
2442 emit_swapl_reg_reg ( s1, reg1 );
2443 }
2444 break;
njne427a662002-10-02 11:08:25 +00002445 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002446 }
2447}
2448
2449
sewardjf0f12aa2002-12-28 00:04:08 +00002450static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002451 Opcode opcode, Int size,
2452 Int reg )
2453{
2454 /* NB! opcode is a uinstr opcode, not an x86 one! */
2455 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002456 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002457 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002458 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002459 break;
2460 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002461 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002462 } else {
njn25e49d8e72002-09-23 09:36:25 +00002463 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002464 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002465 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002466 }
2467 break;
njne427a662002-10-02 11:08:25 +00002468 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002469 }
2470}
2471
2472
2473
sewardjf0f12aa2002-12-28 00:04:08 +00002474static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002475 Opcode opcode, Int size,
2476 Int reg1, Int reg2 )
2477{
2478 /* NB! opcode is a uinstr opcode, not an x86 one! */
2479 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002480 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002481 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002482 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002483 break;
2484 case 1: { /* Horrible ... */
2485 Int s1, s2;
2486 /* Choose s1 and s2 to be x86 regs which we can talk about the
2487 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2488 sure s1 != s2 and that neither of them equal either reg1 or
2489 reg2. Then use them as temporaries to make things work. */
2490 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002491 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002492 break;
2493 }
2494 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2495 if (reg1 >= 4 && reg2 < 4) {
2496 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002497 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002498 emit_swapl_reg_reg ( reg1, s1 );
2499 break;
2500 }
2501 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2502 if (reg1 < 4 && reg2 >= 4) {
2503 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002504 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002505 emit_swapl_reg_reg ( reg2, s2 );
2506 break;
2507 }
2508 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2509 emit_swapl_reg_reg ( reg1, s1 );
2510 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002511 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002512 emit_swapl_reg_reg ( reg1, s1 );
2513 emit_swapl_reg_reg ( reg2, s2 );
2514 break;
2515 }
2516 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2517 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002518 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002519 emit_swapl_reg_reg ( reg1, s1 );
2520 break;
2521 }
njne427a662002-10-02 11:08:25 +00002522 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002523 }
njne427a662002-10-02 11:08:25 +00002524 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002525 }
2526}
2527
sewardja2c5a732002-12-15 03:10:42 +00002528#if 0
2529/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002530static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002531 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002532 Opcode opcode, Int size,
2533 Int off, Int areg, Int reg )
2534{
2535 switch (size) {
2536 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002537 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002538 break;
2539 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002540 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002541 break;
2542 case 1:
2543 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002544 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002545 } else {
2546 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002547 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002548 VG_(emit_swapl_reg_EAX) ( reg );
2549 }
2550 break;
2551 default:
2552 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2553 }
2554}
sewardja2c5a732002-12-15 03:10:42 +00002555#endif
sewardjfa492d42002-12-08 18:20:01 +00002556
sewardjde4a1d02002-03-22 01:27:54 +00002557static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002558 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002559 Opcode opcode, Int size,
2560 Int off, Int areg, Int reg )
2561{
2562 switch (size) {
2563 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002564 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002565 break;
2566 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002567 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002568 break;
2569 case 1:
2570 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002571 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002572 } else {
njn25e49d8e72002-09-23 09:36:25 +00002573 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002574 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002575 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002576 }
2577 break;
2578 default:
njne427a662002-10-02 11:08:25 +00002579 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002580 }
2581}
2582
2583
sewardjf0f12aa2002-12-28 00:04:08 +00002584static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002585 Opcode opcode, Int size,
2586 UInt lit, Int reg )
2587{
2588 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002589 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002590 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002591 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002592 break;
2593 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002594 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002595 } else {
njn25e49d8e72002-09-23 09:36:25 +00002596 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002597 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002598 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002599 }
2600 break;
njne427a662002-10-02 11:08:25 +00002601 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002602 }
2603}
2604
sewardjf0f12aa2002-12-28 00:04:08 +00002605static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002606 Opcode opcode, Int size,
2607 UInt lit, Int off, Int regmem )
2608{
2609 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002610 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002611 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002612 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002613 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002614 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002615 break;
2616 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2617 }
2618}
2619
sewardjde4a1d02002-03-22 01:27:54 +00002620
2621static void synth_push_reg ( Int size, Int reg )
2622{
2623 switch (size) {
2624 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002625 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002626 break;
2627 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002628 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002629 break;
2630 /* Pray that we don't have to generate this really cruddy bit of
2631 code very often. Could do better, but can I be bothered? */
2632 case 1:
2633 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002634 VG_(emit_add_lit_to_esp)(-1);
2635 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002636 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002637 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002638 break;
2639 default:
njne427a662002-10-02 11:08:25 +00002640 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002641 }
2642}
2643
2644
2645static void synth_pop_reg ( Int size, Int reg )
2646{
2647 switch (size) {
2648 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002649 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002650 break;
2651 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002652 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002653 break;
2654 case 1:
2655 /* Same comment as above applies. */
2656 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002657 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002658 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002659 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2660 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002661 break;
njne427a662002-10-02 11:08:25 +00002662 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002663 }
2664}
2665
2666
sewardjf0f12aa2002-12-28 00:04:08 +00002667static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002668 Opcode opcode, Int size,
2669 Int regs, Int regd )
2670{
2671 synth_push_reg ( size, regd );
2672 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002673 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002674 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2675 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2676 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002677 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002678 }
sewardjde4a1d02002-03-22 01:27:54 +00002679 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2680 synth_pop_reg ( size, regd );
2681}
2682
2683
sewardjf0f12aa2002-12-28 00:04:08 +00002684static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002685 Opcode opcode, Int size,
2686 UInt lit, Int reg )
2687{
2688 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002689 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002690 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002691 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002692 break;
2693 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002694 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002695 } else {
njn25e49d8e72002-09-23 09:36:25 +00002696 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002697 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002698 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002699 }
2700 break;
njne427a662002-10-02 11:08:25 +00002701 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002702 }
2703}
2704
2705
sewardjf0f12aa2002-12-28 00:04:08 +00002706static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002707{
sewardjde4a1d02002-03-22 01:27:54 +00002708 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002709 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002710 } else {
njn25e49d8e72002-09-23 09:36:25 +00002711 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002712 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002713 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002714 }
2715}
2716
2717
sewardj3d7c9c82003-03-26 21:08:13 +00002718static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2719 UChar first_byte,
2720 UChar second_byte,
2721 Int ireg )
2722{
2723 emit_MMX2_regmem ( uses_flags, sets_flags,
2724 first_byte, second_byte, ireg );
2725}
2726
2727
sewardjca860012003-03-27 23:52:58 +00002728static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2729 UChar first_byte,
2730 UChar second_byte,
2731 Int ireg )
2732{
2733 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2734 first_byte, second_byte, ireg );
2735}
2736
sewardjd1c9e432003-04-04 20:40:34 +00002737static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2738 UChar first_byte,
2739 UChar second_byte,
2740 Int ireg )
2741{
2742 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2743 first_byte, second_byte, ireg );
2744}
2745
sewardj3d7c9c82003-03-26 21:08:13 +00002746static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2747 UChar first_byte,
2748 UChar second_byte )
2749{
2750 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2751}
2752
2753
sewardjca860012003-03-27 23:52:58 +00002754static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2755 UChar first_byte,
2756 UChar second_byte,
2757 UChar third_byte )
2758{
2759 emit_MMX3_no_mem ( uses_flags, sets_flags,
2760 first_byte, second_byte, third_byte );
2761}
2762
2763
sewardj3d7c9c82003-03-26 21:08:13 +00002764static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2765 UChar first_byte )
2766{
2767 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2768}
2769
2770
sewardjfa492d42002-12-08 18:20:01 +00002771static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2772 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002773 UChar second_byte_masked,
2774 Int reg )
2775{
sewardj3d7c9c82003-03-26 21:08:13 +00002776 emit_fpu_regmem ( uses_flags, sets_flags,
2777 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002778}
2779
2780
sewardjfa492d42002-12-08 18:20:01 +00002781static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2782 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002783 UChar second_byte )
2784{
sewardjfa492d42002-12-08 18:20:01 +00002785 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002786}
2787
2788
2789static void synth_movl_reg_reg ( Int src, Int dst )
2790{
2791 emit_movl_reg_reg ( src, dst );
2792}
2793
2794static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2795{
sewardja2113f92002-12-12 23:42:48 +00002796 Int tgt;
2797
2798 VG_(init_target)(&tgt);
2799
2800 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002801 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002802
2803 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002804}
2805
2806
sewardjde4a1d02002-03-22 01:27:54 +00002807/*----------------------------------------------------*/
2808/*--- Top level of the uinstr -> x86 translation. ---*/
2809/*----------------------------------------------------*/
2810
2811/* Return the byte offset from %ebp (ie, into baseBlock)
2812 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002813static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2814{
2815 if (tag == SpillNo) {
2816 vg_assert(size == 4);
2817 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2818 return 4 * (value + VGOFF_(spillslots));
2819 }
2820 if (tag == ArchReg) {
2821 switch (value) {
2822 case R_EAX: return 4 * VGOFF_(m_eax);
2823 case R_ECX: return 4 * VGOFF_(m_ecx);
2824 case R_EDX: return 4 * VGOFF_(m_edx);
2825 case R_EBX: return 4 * VGOFF_(m_ebx);
2826 case R_ESP:
2827 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2828 else return 4 * VGOFF_(m_esp);
2829 case R_EBP:
2830 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2831 else return 4 * VGOFF_(m_ebp);
2832 case R_ESI:
2833 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2834 else return 4 * VGOFF_(m_esi);
2835 case R_EDI:
2836 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2837 else return 4 * VGOFF_(m_edi);
2838 }
2839 }
njne427a662002-10-02 11:08:25 +00002840 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002841}
2842
sewardjde4a1d02002-03-22 01:27:54 +00002843static Int eflagsOffset ( void )
2844{
2845 return 4 * VGOFF_(m_eflags);
2846}
2847
sewardje1042472002-09-30 12:33:11 +00002848static Int segRegOffset ( UInt archregs )
2849{
2850 switch (archregs) {
2851 case R_CS: return 4 * VGOFF_(m_cs);
2852 case R_SS: return 4 * VGOFF_(m_ss);
2853 case R_DS: return 4 * VGOFF_(m_ds);
2854 case R_ES: return 4 * VGOFF_(m_es);
2855 case R_FS: return 4 * VGOFF_(m_fs);
2856 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002857 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002858 }
2859}
2860
njnf4ce3d32003-02-10 10:17:26 +00002861UInt VG_(get_archreg) ( UInt arch )
2862{
2863 switch (arch) {
2864 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2865 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2866 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2867 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2868 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2869 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2870 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2871 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2872 default: VG_(core_panic)( "get_thread_archreg");
2873 }
2874}
2875
2876UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2877{
2878 ThreadState* tst;
2879
2880 vg_assert(VG_(is_valid_tid)(tid));
2881 tst = & VG_(threads)[tid];
2882
2883 switch (arch) {
2884 case R_EAX: return tst->m_eax;
2885 case R_ECX: return tst->m_ecx;
2886 case R_EDX: return tst->m_edx;
2887 case R_EBX: return tst->m_ebx;
2888 case R_ESP: return tst->m_esp;
2889 case R_EBP: return tst->m_ebp;
2890 case R_ESI: return tst->m_esi;
2891 case R_EDI: return tst->m_edi;
2892 default: VG_(core_panic)( "get_thread_archreg");
2893 }
2894}
2895
njnb93d1782003-02-03 12:03:22 +00002896/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00002897static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00002898{
2899 switch (arch) {
2900 case R_EAX: return VGOFF_(sh_eax);
2901 case R_ECX: return VGOFF_(sh_ecx);
2902 case R_EDX: return VGOFF_(sh_edx);
2903 case R_EBX: return VGOFF_(sh_ebx);
2904 case R_ESP: return VGOFF_(sh_esp);
2905 case R_EBP: return VGOFF_(sh_ebp);
2906 case R_ESI: return VGOFF_(sh_esi);
2907 case R_EDI: return VGOFF_(sh_edi);
2908 default: VG_(core_panic)( "shadow_reg_index");
2909 }
2910}
sewardjde4a1d02002-03-22 01:27:54 +00002911
njn25e49d8e72002-09-23 09:36:25 +00002912/* Return the byte offset from %ebp (ie, into baseBlock)
2913 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002914Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002915{
njnb93d1782003-02-03 12:03:22 +00002916 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00002917}
2918
njn4ba5a792002-09-30 10:23:54 +00002919Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002920{
2921 return 4 * VGOFF_(sh_eflags);
2922}
2923
njnb93d1782003-02-03 12:03:22 +00002924/* Accessing shadow arch. registers */
2925UInt VG_(get_shadow_archreg) ( UInt archreg )
2926{
2927 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
2928}
2929
2930void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
2931{
2932 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
2933}
2934
njnf4ce3d32003-02-10 10:17:26 +00002935UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
2936{
2937 ThreadState* tst;
2938
2939 vg_assert(VG_(is_valid_tid)(tid));
2940 tst = & VG_(threads)[tid];
2941
2942 switch (archreg) {
2943 case R_EAX: return tst->sh_eax;
2944 case R_ECX: return tst->sh_ecx;
2945 case R_EDX: return tst->sh_edx;
2946 case R_EBX: return tst->sh_ebx;
2947 case R_ESP: return tst->sh_esp;
2948 case R_EBP: return tst->sh_ebp;
2949 case R_ESI: return tst->sh_esi;
2950 case R_EDI: return tst->sh_edi;
2951 default: VG_(core_panic)( "get_thread_shadow_archreg");
2952 }
2953}
2954
2955void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
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: tst->sh_eax = val; break;
2964 case R_ECX: tst->sh_ecx = val; break;
2965 case R_EDX: tst->sh_edx = val; break;
2966 case R_EBX: tst->sh_ebx = val; break;
2967 case R_ESP: tst->sh_esp = val; break;
2968 case R_EBP: tst->sh_ebp = val; break;
2969 case R_ESI: tst->sh_esi = val; break;
2970 case R_EDI: tst->sh_edi = val; break;
2971 default: VG_(core_panic)( "set_thread_shadow_archreg");
2972 }
2973}
2974
njnb93d1782003-02-03 12:03:22 +00002975Addr VG_(shadow_archreg_address) ( UInt archreg )
2976{
2977 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
2978}
sewardjde4a1d02002-03-22 01:27:54 +00002979
sewardjde4a1d02002-03-22 01:27:54 +00002980static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2981{
2982 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002983 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
2984 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002985 }
2986 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00002987 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
2988 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002989 }
2990 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00002991 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
2992 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002993 }
2994 else
njne427a662002-10-02 11:08:25 +00002995 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002996}
2997
2998
sewardjde4a1d02002-03-22 01:27:54 +00002999/*----------------------------------------------------*/
3000/*--- Generate code for a single UInstr. ---*/
3001/*----------------------------------------------------*/
3002
sewardj478335c2002-10-05 02:44:47 +00003003static __inline__
3004Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003005{
3006 return (u->flags_w != FlagsEmpty);
3007}
3008
sewardjfa492d42002-12-08 18:20:01 +00003009static __inline__
3010Bool readFlagUse ( UInstr* u )
3011{
3012 /* If the UInstr writes some flags but not all, then we still need
3013 to consider it as reading flags so that the unchanged values are
3014 passed through properly. (D is special) */
3015 return
3016 (u->flags_r != FlagsEmpty) ||
3017 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3018}
3019
sewardj478335c2002-10-05 02:44:47 +00003020static __inline__
3021Bool anyFlagUse ( UInstr* u )
3022{
sewardjfa492d42002-12-08 18:20:01 +00003023 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003024}
3025
3026
sewardjb5ff83e2002-12-01 19:40:49 +00003027/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00003028 the real FPU. If so we need to be very careful not to trash it.
3029 If FPU state is live and we deem it necessary to copy it back to
3030 the simulated machine's FPU state, we do so. The final state of
3031 fpliveness is returned. In short we _must_ do put_fpu_state if
3032 there is any chance at all that the code generated for a UInstr
3033 will change the real FPU state.
3034*/
sewardjb5ff83e2002-12-01 19:40:49 +00003035static void emitUInstr ( UCodeBlock* cb, Int i,
3036 RRegSet regs_live_before,
3037 /* Running state, which we update. */
3038 Bool* fplive, /* True<==>FPU state in real FPU */
3039 Addr* orig_eip, /* previous curr_eip, or zero */
3040 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003041{
njn25e49d8e72002-09-23 09:36:25 +00003042 Int old_emitted_code_used;
3043 UInstr* u = &cb->instrs[i];
3044
sewardjde4a1d02002-03-22 01:27:54 +00003045 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003046 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003047
njn25e49d8e72002-09-23 09:36:25 +00003048 old_emitted_code_used = emitted_code_used;
3049
sewardjde4a1d02002-03-22 01:27:54 +00003050 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003051 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003052
sewardjb5ff83e2002-12-01 19:40:49 +00003053 case INCEIP:
3054 /* Advance %EIP some small amount. */
3055 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003056
sewardjb5ff83e2002-12-01 19:40:49 +00003057 if (*orig_eip == 0 /* we don't know what the old value was */
3058 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3059 /* We have to update all 32 bits of the value. */
3060 VG_(emit_movv_lit_offregmem)(
3061 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3062 } else {
3063 /* Cool! we only need to update lowest 8 bits */
3064 VG_(emit_movb_lit_offregmem)(
3065 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003066 }
njn25e49d8e72002-09-23 09:36:25 +00003067
sewardjb5ff83e2002-12-01 19:40:49 +00003068 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003069 break;
sewardjde4a1d02002-03-22 01:27:54 +00003070
3071 case LEA1: {
3072 vg_assert(u->tag1 == RealReg);
3073 vg_assert(u->tag2 == RealReg);
3074 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3075 break;
3076 }
3077
3078 case LEA2: {
3079 vg_assert(u->tag1 == RealReg);
3080 vg_assert(u->tag2 == RealReg);
3081 vg_assert(u->tag3 == RealReg);
3082 emit_lea_sib_reg ( u->lit32, u->extra4b,
3083 u->val1, u->val2, u->val3 );
3084 break;
3085 }
3086
3087 case WIDEN: {
3088 vg_assert(u->tag1 == RealReg);
3089 if (u->signed_widen) {
3090 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3091 } else {
3092 /* no need to generate any code. */
3093 }
3094 break;
3095 }
3096
sewardjde4a1d02002-03-22 01:27:54 +00003097 case STORE: {
3098 vg_assert(u->tag1 == RealReg);
3099 vg_assert(u->tag2 == RealReg);
3100 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003101 break;
3102 }
3103
3104 case LOAD: {
3105 vg_assert(u->tag1 == RealReg);
3106 vg_assert(u->tag2 == RealReg);
3107 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3108 break;
3109 }
3110
sewardjde4a1d02002-03-22 01:27:54 +00003111 case GET: {
3112 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3113 vg_assert(u->tag2 == RealReg);
3114 synth_mov_offregmem_reg (
3115 u->size,
3116 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3117 R_EBP,
3118 u->val2
3119 );
3120 break;
3121 }
3122
3123 case PUT: {
3124 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3125 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003126 synth_mov_reg_offregmem (
3127 u->size,
3128 u->val1,
3129 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3130 R_EBP
3131 );
sewardjde4a1d02002-03-22 01:27:54 +00003132 break;
3133 }
3134
sewardje1042472002-09-30 12:33:11 +00003135 case GETSEG: {
3136 vg_assert(u->tag1 == ArchRegS);
3137 vg_assert(u->tag2 == RealReg);
3138 vg_assert(u->size == 2);
3139 synth_mov_offregmem_reg (
3140 4,
3141 segRegOffset( u->val1 ),
3142 R_EBP,
3143 u->val2
3144 );
3145 break;
3146 }
3147
3148 case PUTSEG: {
3149 vg_assert(u->tag1 == RealReg);
3150 vg_assert(u->tag2 == ArchRegS);
3151 vg_assert(u->size == 2);
3152 synth_mov_reg_offregmem (
3153 4,
3154 u->val1,
3155 segRegOffset( u->val2 ),
3156 R_EBP
3157 );
3158 break;
3159 }
3160
sewardjde4a1d02002-03-22 01:27:54 +00003161 case GETF: {
3162 vg_assert(u->size == 2 || u->size == 4);
3163 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003164
3165 /* This complexity is because the D(irection) flag is stored
3166 separately from the rest of EFLAGS. */
3167
3168 /* We're only fetching from the Simd state, so make sure it's
3169 up to date. */
3170 maybe_emit_put_eflags();
3171
3172 /* get D in u->val1 (== 1 or -1) */
3173 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3174
3175 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3176 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3177
3178 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3179 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3180 eflagsOffset(), R_EBP);
3181
3182 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3183 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3184 eflagsOffset(), R_EBP);
3185
3186 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3187 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3188 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003189 break;
3190 }
3191
3192 case PUTF: {
3193 vg_assert(u->size == 2 || u->size == 4);
3194 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003195
3196 /* When putting a value into EFLAGS, this generates the
3197 correct value for m_dflag (-1 or 1), and clears the D bit
3198 in EFLAGS. */
3199
3200 /* We're updating the whole flag state, so the old state
3201 doesn't matter; make sure that the new simulated state
3202 will be fetched when needed. */
3203 eflags_state = UPD_Simd;
3204
3205 /* store EFLAGS (with D) */
3206 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3207
3208 /* u->val1 &= EFlagD */
3209 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3210
3211 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3212 synth_unaryop_reg(False, NEG, u->size, u->val1);
3213 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3214 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3215
3216 /* save D */
3217 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3218
3219 /* EFLAGS &= ~EFlagD */
3220 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3221 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003222 break;
3223 }
3224
3225 case MOV: {
3226 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3227 vg_assert(u->tag2 == RealReg);
3228 switch (u->tag1) {
3229 case RealReg: vg_assert(u->size == 4);
3230 if (u->val1 != u->val2)
3231 synth_movl_reg_reg ( u->val1, u->val2 );
3232 break;
3233 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3234 break;
njne427a662002-10-02 11:08:25 +00003235 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003236 }
3237 break;
3238 }
3239
sewardje1042472002-09-30 12:33:11 +00003240 case USESEG: {
3241 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3242 ones. */
sewardjd077f532002-09-30 21:52:50 +00003243 UInt argv[] = { u->val1, u->val2 };
3244 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003245 UInt ret_reg = u->val2;
3246
3247 vg_assert(u->tag1 == RealReg);
3248 vg_assert(u->tag2 == RealReg);
3249 vg_assert(u->size == 0);
3250
sewardjb5ff83e2002-12-01 19:40:49 +00003251 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003252 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003253 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003254 }
3255
sewardje1042472002-09-30 12:33:11 +00003256 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3257 2, /* args */
3258 0, /* regparms_n */
3259 argv, tagv,
3260 ret_reg, regs_live_before, u->regs_live_after );
3261 break;
3262 }
3263
sewardj478335c2002-10-05 02:44:47 +00003264 case SBB:
3265 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003266 case XOR:
3267 case OR:
3268 case AND:
3269 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003270 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003271 vg_assert(u->tag2 == RealReg);
3272 switch (u->tag1) {
3273 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003274 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003275 u->opcode, u->size, u->lit32, u->val2 );
3276 break;
3277 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003278 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003279 u->opcode, u->size, u->val1, u->val2 );
3280 break;
3281 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003282 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003283 u->opcode, u->size,
3284 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3285 R_EBP,
3286 u->val2 );
3287 break;
njne427a662002-10-02 11:08:25 +00003288 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003289 }
3290 break;
3291 }
3292
sewardj478335c2002-10-05 02:44:47 +00003293 case RCR:
3294 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003295 case ROR:
3296 case ROL:
3297 case SAR:
3298 case SHR:
3299 case SHL: {
3300 vg_assert(u->tag2 == RealReg);
3301 switch (u->tag1) {
3302 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003303 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003304 u->opcode, u->size, u->lit32, u->val2 );
3305 break;
3306 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003307 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003308 u->opcode, u->size, u->val1, u->val2 );
3309 break;
njne427a662002-10-02 11:08:25 +00003310 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003311 }
3312 break;
3313 }
3314
3315 case INC:
3316 case DEC:
3317 case NEG:
3318 case NOT:
3319 vg_assert(u->tag1 == RealReg);
3320 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003321 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003322 break;
3323
3324 case BSWAP:
3325 vg_assert(u->tag1 == RealReg);
3326 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003327 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003328 emit_bswapl_reg ( u->val1 );
3329 break;
3330
3331 case CMOV:
3332 vg_assert(u->tag1 == RealReg);
3333 vg_assert(u->tag2 == RealReg);
3334 vg_assert(u->cond != CondAlways);
3335 vg_assert(u->size == 4);
3336 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3337 break;
3338
3339 case JMP: {
3340 vg_assert(u->tag2 == NoValue);
3341 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00003342 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003343 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003344 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003345 }
sewardjde4a1d02002-03-22 01:27:54 +00003346 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003347 switch (u->tag1) {
3348 case RealReg:
3349 synth_jmp_reg ( u->val1, u->jmpkind );
3350 break;
3351 case Literal:
3352 synth_jmp_lit ( u->lit32, u->jmpkind );
3353 break;
3354 default:
njne427a662002-10-02 11:08:25 +00003355 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003356 break;
sewardjde4a1d02002-03-22 01:27:54 +00003357 }
3358 } else {
sewardj2e93c502002-04-12 11:12:52 +00003359 switch (u->tag1) {
3360 case RealReg:
njne427a662002-10-02 11:08:25 +00003361 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003362 break;
3363 case Literal:
3364 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003365 /* %eax had better not be live since synth_jcond_lit
3366 trashes it in some circumstances. If that turns
3367 out to be a problem we can get synth_jcond_lit to
3368 push/pop it when it is live. */
3369 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3370 u->regs_live_after));
3371 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003372 break;
3373 default:
njne427a662002-10-02 11:08:25 +00003374 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003375 break;
sewardjde4a1d02002-03-22 01:27:54 +00003376 }
3377 }
3378 break;
3379 }
3380
3381 case JIFZ:
3382 vg_assert(u->tag1 == RealReg);
3383 vg_assert(u->tag2 == Literal);
3384 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00003385 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003386 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003387 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003388 }
sewardjde4a1d02002-03-22 01:27:54 +00003389 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3390 break;
3391
sewardjde4a1d02002-03-22 01:27:54 +00003392 case PUSH:
3393 vg_assert(u->tag1 == RealReg);
3394 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003395 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003396 break;
3397
3398 case POP:
3399 vg_assert(u->tag1 == RealReg);
3400 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003401 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003402 break;
3403
3404 case CALLM:
3405 vg_assert(u->tag1 == Lit16);
3406 vg_assert(u->tag2 == NoValue);
3407 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00003408 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003409 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003410 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003411 }
sewardjfa492d42002-12-08 18:20:01 +00003412 /* Call to a helper which is pretending to be a real CPU
3413 instruction (and therefore operates on Real flags and
3414 registers) */
3415 VG_(synth_call) ( False, u->val1,
3416 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003417 break;
3418
njn25e49d8e72002-09-23 09:36:25 +00003419 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003420 /* If you change this, remember to change USESEG above, since
3421 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003422 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3423 ones. */
3424 UInt argv[] = { u->val1, u->val2, u->val3 };
3425 UInt tagv[] = { RealReg, RealReg, RealReg };
3426 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3427
3428 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3429 else vg_assert(u->tag1 == NoValue);
3430 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3431 else vg_assert(u->tag2 == NoValue);
3432 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3433 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003434 vg_assert(u->size == 0);
3435
sewardjb5ff83e2002-12-01 19:40:49 +00003436 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003437 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003438 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003439 }
njn25e49d8e72002-09-23 09:36:25 +00003440 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3441 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003442 break;
njn25e49d8e72002-09-23 09:36:25 +00003443 }
sewardje1042472002-09-30 12:33:11 +00003444
sewardjde4a1d02002-03-22 01:27:54 +00003445 case CLEAR:
3446 vg_assert(u->tag1 == Lit16);
3447 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003448 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003449 break;
3450
3451 case CC2VAL:
3452 vg_assert(u->tag1 == RealReg);
3453 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003454 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003455 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003456 break;
3457
sewardjde4a1d02002-03-22 01:27:54 +00003458 case FPU_R:
3459 case FPU_W:
3460 vg_assert(u->tag1 == Lit16);
3461 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00003462 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003463 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003464 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003465 }
sewardjfa492d42002-12-08 18:20:01 +00003466 synth_fpu_regmem ( u->flags_r, u->flags_w,
3467 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003468 u->val1 & 0xFF,
3469 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003470 break;
3471
3472 case FPU:
3473 vg_assert(u->tag1 == Lit16);
3474 vg_assert(u->tag2 == NoValue);
sewardjb5ff83e2002-12-01 19:40:49 +00003475 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003476 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003477 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003478 }
sewardjfa492d42002-12-08 18:20:01 +00003479 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3480 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003481 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003482 break;
3483
sewardj3d7c9c82003-03-26 21:08:13 +00003484 case MMX2_MemWr:
3485 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003486 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003487 vg_assert(u->tag1 == Lit16);
3488 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003489 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003490 vg_assert(!anyFlagUse(u));
3491 if (!(*fplive)) {
3492 emit_get_fpu_state();
3493 *fplive = True;
3494 }
3495 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3496 (u->val1 >> 8) & 0xFF,
3497 u->val1 & 0xFF,
3498 u->val2 );
3499 break;
3500
sewardjca860012003-03-27 23:52:58 +00003501 case MMX2_RegRd:
3502 vg_assert(u->tag1 == Lit16);
3503 vg_assert(u->tag2 == RealReg);
3504 vg_assert(u->tag3 == NoValue);
3505 vg_assert(!anyFlagUse(u));
3506 if (!(*fplive)) {
3507 emit_get_fpu_state();
3508 *fplive = True;
3509 }
3510 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3511 (u->val1 >> 8) & 0xFF,
3512 u->val1 & 0xFF,
3513 u->val2 );
3514 break;
3515
sewardjd1c9e432003-04-04 20:40:34 +00003516 case MMX2_RegWr:
3517 vg_assert(u->tag1 == Lit16);
3518 vg_assert(u->tag2 == RealReg);
3519 vg_assert(u->tag3 == NoValue);
3520 vg_assert(!anyFlagUse(u));
3521 if (!(*fplive)) {
3522 emit_get_fpu_state();
3523 *fplive = True;
3524 }
3525 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3526 (u->val1 >> 8) & 0xFF,
3527 u->val1 & 0xFF,
3528 u->val2 );
3529 break;
3530
sewardj3d7c9c82003-03-26 21:08:13 +00003531 case MMX1:
3532 vg_assert(u->tag1 == Lit16);
3533 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003534 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003535 if (!(*fplive)) {
3536 emit_get_fpu_state();
3537 *fplive = True;
3538 }
3539 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3540 u->val1 & 0xFF );
3541 break;
3542
3543 case MMX2:
3544 vg_assert(u->tag1 == Lit16);
3545 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003546 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003547 if (!(*fplive)) {
3548 emit_get_fpu_state();
3549 *fplive = True;
3550 }
3551 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3552 (u->val1 >> 8) & 0xFF,
3553 u->val1 & 0xFF );
3554 break;
3555
sewardjca860012003-03-27 23:52:58 +00003556 case MMX3:
3557 vg_assert(u->tag1 == Lit16);
3558 vg_assert(u->tag2 == Lit16);
3559 vg_assert(u->tag3 == NoValue);
3560 if (!(*fplive)) {
3561 emit_get_fpu_state();
3562 *fplive = True;
3563 }
3564 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3565 (u->val1 >> 8) & 0xFF,
3566 u->val1 & 0xFF,
3567 u->val2 & 0xFF );
3568 break;
3569
sewardjde4a1d02002-03-22 01:27:54 +00003570 default:
sewardj1b7d8022002-11-30 12:35:42 +00003571 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00003572 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00003573 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003574 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003575 }
njn4ba5a792002-09-30 10:23:54 +00003576 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003577 } else {
njn25e49d8e72002-09-23 09:36:25 +00003578 VG_(printf)("\nError:\n"
3579 " unhandled opcode: %u. Perhaps "
3580 " VG_(needs).extended_UCode should be set?\n",
3581 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003582 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003583 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003584 }
sewardjde4a1d02002-03-22 01:27:54 +00003585 }
3586
sewardjb5ff83e2002-12-01 19:40:49 +00003587 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00003588 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00003589 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003590 }
3591
njn25e49d8e72002-09-23 09:36:25 +00003592 /* Update UInstr histogram */
3593 vg_assert(u->opcode < 100);
3594 histogram[u->opcode].counts++;
3595 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003596}
3597
3598
3599/* Emit x86 for the ucode in cb, returning the address of the
3600 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003601UChar* VG_(emit_code) ( UCodeBlock* cb,
3602 Int* nbytes,
3603 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003604{
3605 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003606 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00003607 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00003608 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003609 Int tgt;
3610
sewardjfa492d42002-12-08 18:20:01 +00003611 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003612
njn25e49d8e72002-09-23 09:36:25 +00003613 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003614
sewardj22854b92002-11-30 14:00:47 +00003615 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3616 zero. We have to do this regardless of whether we're t-chaining
3617 or not. */
sewardja2113f92002-12-12 23:42:48 +00003618 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003619 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003620 VG_(emitB) (0xFF); /* decl */
3621 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3622 if (dis)
3623 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003624 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003625 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3626 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003627 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003628
sewardjb5ff83e2002-12-01 19:40:49 +00003629 /* Set up running state. */
3630 fplive = False;
sewardjfa492d42002-12-08 18:20:01 +00003631 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003632 curr_eip = cb->orig_eip;
3633 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3634 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003635 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003636 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003637 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003638 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003639
sewardjde4a1d02002-03-22 01:27:54 +00003640 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003641 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003642 if (!sane) {
3643 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003644 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003645 }
3646 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003647 emitUInstr( cb, i, regs_live_before,
3648 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003649 }
njn25e49d8e72002-09-23 09:36:25 +00003650 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003651 }
njn25e49d8e72002-09-23 09:36:25 +00003652 if (dis) VG_(printf)("\n");
sewardjfa492d42002-12-08 18:20:01 +00003653 vg_assert(!fplive); /* FPU state must be saved by end of BB */
3654 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003655
sewardj22854b92002-11-30 14:00:47 +00003656 if (j != NULL) {
3657 vg_assert(jumpidx <= VG_MAX_JUMPS);
3658 for(i = 0; i < jumpidx; i++)
3659 j[i] = jumps[i];
3660 }
3661
sewardjde4a1d02002-03-22 01:27:54 +00003662 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003663 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003664 *nbytes = emitted_code_used;
3665 return emitted_code;
3666}
3667
njn25e49d8e72002-09-23 09:36:25 +00003668#undef dis
3669
sewardjde4a1d02002-03-22 01:27:54 +00003670/*--------------------------------------------------------------------*/
3671/*--- end vg_from_ucode.c ---*/
3672/*--------------------------------------------------------------------*/