blob: 2c60eb74b08958a3bc2fc9cf1f7292dbff148d2c [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00006
sewardjde4a1d02002-03-22 01:27:54 +00007/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
41/*------------------------------------------------------------*/
42/*--- Instruction emission -- turning final uinstrs back ---*/
43/*--- into x86 code. ---*/
44/*------------------------------------------------------------*/
45
46/* [2001-07-08 This comment is now somewhat out of date.]
47
48 This is straightforward but for one thing: to facilitate generating
49 code in a single pass, we generate position-independent code. To
50 do this, calls and jmps to fixed addresses must specify the address
51 by first loading it into a register, and jump to/call that
52 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000053 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000054 call insns may only have a register as target anyway, so there's no
55 need to do anything fancy for them.
56
57 The emit_* routines constitute the lowest level of instruction
58 emission. They simply emit the sequence of bytes corresponding to
59 the relevant instruction, with no further ado. In particular there
60 is no checking about whether uses of byte registers makes sense,
61 nor whether shift insns have their first operand in %cl, etc.
62
63 These issues are taken care of by the level above, the synth_*
64 routines. These detect impossible operand combinations and turn
65 them into sequences of legal instructions. Finally, emitUInstr is
66 phrased in terms of the synth_* abstraction layer. */
67
sewardjfa492d42002-12-08 18:20:01 +000068/* Static state for the current basic block */
sewardjde4a1d02002-03-22 01:27:54 +000069static UChar* emitted_code;
70static Int emitted_code_used;
71static Int emitted_code_size;
72
sewardj22854b92002-11-30 14:00:47 +000073/* offset (in bytes into the basic block) */
74static UShort jumps[VG_MAX_JUMPS];
75static Int jumpidx;
76
sewardjf0f12aa2002-12-28 00:04:08 +000077static enum _eflags_state {
sewardjfa492d42002-12-08 18:20:01 +000078 UPD_Simd, /* baseblock copy is up to date */
79 UPD_Real, /* CPU copy is up to date */
80 UPD_Both, /* both are current */
81} eflags_state;
82
83/* single site for resetting state */
84static void reset_state(void)
85{
86 emitted_code_used = 0;
87 emitted_code_size = 500; /* reasonable initial size */
88 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
89 jumpidx = 0;
90 eflags_state = UPD_Simd;
91}
92
93
njn25e49d8e72002-09-23 09:36:25 +000094/* Statistics about C functions called from generated code. */
95static UInt ccalls = 0;
96static UInt ccall_reg_saves = 0;
97static UInt ccall_args = 0;
98static UInt ccall_arg_setup_instrs = 0;
99static UInt ccall_stack_clears = 0;
100static UInt ccall_retvals = 0;
101static UInt ccall_retval_movs = 0;
102
103/* Statistics about frequency of each UInstr */
104typedef
105 struct {
106 UInt counts;
107 UInt size;
108 } Histogram;
109
110/* Automatically zeroed because it's static. */
111static Histogram histogram[100];
112
113void VG_(print_ccall_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " ccalls: %u C calls, %u%% saves+restores avoided"
117 " (%d bytes)",
118 ccalls,
119 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
120 ((ccalls*3) - ccall_reg_saves)*2);
121 VG_(message)(Vg_DebugMsg,
122 " %u args, avg 0.%d setup instrs each (%d bytes)",
123 ccall_args,
124 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
125 (ccall_args - ccall_arg_setup_instrs)*2);
126 VG_(message)(Vg_DebugMsg,
127 " %d%% clear the stack (%d bytes)",
128 (UInt)(ccall_stack_clears/(double)ccalls*100),
129 (ccalls - ccall_stack_clears)*3);
130 VG_(message)(Vg_DebugMsg,
131 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
132 ccall_retvals,
133 ( ccall_retvals == 0
134 ? 100
135 : 100-(UInt)(ccall_retval_movs /
136 (double)ccall_retvals*100)),
137 (ccall_retvals-ccall_retval_movs)*2);
138}
139
140void VG_(print_UInstr_histogram)(void)
141{
142 Int i, j;
143 UInt total_counts = 0;
144 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000145
njn25e49d8e72002-09-23 09:36:25 +0000146 for (i = 0; i < 100; i++) {
147 total_counts += histogram[i].counts;
148 total_size += histogram[i].size;
149 }
150
151 VG_(printf)("-- UInstr frequencies -----------\n");
152 for (i = 0; i < 100; i++) {
153 if (0 != histogram[i].counts) {
154
155 UInt count_pc =
156 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
157 UInt size_pc =
158 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
159 UInt avg_size =
160 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
161
162 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000163 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000164 histogram[i].counts, count_pc,
165 avg_size, size_pc);
166
sewardj05bcdcb2003-05-18 10:05:38 +0000167 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000168 VG_(printf)("\n");
169
170 } else {
171 vg_assert(0 == histogram[i].size);
172 }
173 }
174
175 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
176}
177
sewardjde4a1d02002-03-22 01:27:54 +0000178static void expandEmittedCode ( void )
179{
180 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000181 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000182 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
183 for (i = 0; i < emitted_code_size; i++)
184 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000186 emitted_code = tmp;
187 emitted_code_size *= 2;
188}
189
njn25e49d8e72002-09-23 09:36:25 +0000190/* Local calls will be inlined, cross-module ones not */
191__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
193 if (dis) {
194 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
195 }
196 if (emitted_code_used == emitted_code_size)
197 expandEmittedCode();
198
199 emitted_code[emitted_code_used] = (UChar)b;
200 emitted_code_used++;
201}
202
njn25e49d8e72002-09-23 09:36:25 +0000203__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(emitB) ( (l) & 0x000000FF );
206 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000207}
208
njn25e49d8e72002-09-23 09:36:25 +0000209__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000210{
njn25e49d8e72002-09-23 09:36:25 +0000211 VG_(emitB) ( (l) & 0x000000FF );
212 VG_(emitB) ( (l >> 8) & 0x000000FF );
213 VG_(emitB) ( (l >> 16) & 0x000000FF );
214 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000215}
216
sewardjfa492d42002-12-08 18:20:01 +0000217static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000218{
sewardjfa492d42002-12-08 18:20:01 +0000219 Int off = 4 * VGOFF_(m_eflags);
220 vg_assert(off >= 0 && off < 128);
221
222 if (dis)
223 VG_(printf)("\t %4d: ", emitted_code_used );
224
225 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
226 VG_(emitB) ( 0x75 );
227 VG_(emitB) ( off );
228 VG_(emitB) ( 0x9D ); /* POPFL */
229 if (dis)
230 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
231}
232
233static void emit_put_eflags ( void )
234{
235 Int off = 4 * VGOFF_(m_eflags);
236 vg_assert(off >= 0 && off < 128);
237
238 if (dis)
239 VG_(printf)("\t %4d: ", emitted_code_used );
240
241 VG_(emitB) ( 0x9C ); /* PUSHFL */
242 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
243 VG_(emitB) ( 0x45 );
244 VG_(emitB) ( off );
245 if (dis)
246 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
247}
248
249static void maybe_emit_put_eflags( void )
250{
251 if (eflags_state == UPD_Real) {
252 eflags_state = UPD_Both;
253 emit_put_eflags();
254 }
255}
256
sewardja2c5a732002-12-15 03:10:42 +0000257
258/* evidently unused */
259#if 0
sewardjfa492d42002-12-08 18:20:01 +0000260static void maybe_emit_get_eflags( void )
261{
262 if (eflags_state == UPD_Simd) {
263 eflags_state = UPD_Both;
264 emit_get_eflags();
265 }
266}
sewardja2c5a732002-12-15 03:10:42 +0000267#endif
sewardjfa492d42002-12-08 18:20:01 +0000268
sewardjf0f12aa2002-12-28 00:04:08 +0000269
270#if 0
271/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
272/* An alternative implementation of new_emit in which the
273 state space is explicitly enumerated. */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool simd = upds_simd_flags;
279 enum _eflags_state where = eflags_state;
280
281 enum { WNone, WSome, WAll } ww;
282 Bool rr;
283
284#define DIS_HEADER \
285 if (dis) \
286 VG_(printf)("\t %4d: ", emitted_code_used );
287
288 if (use_flags == FlagsEmpty) {
289 rr = False;
290 } else {
291 rr = True;
292 }
293
294 if (set_flags == FlagsEmpty) {
295 ww = WNone;
296 } else
297 if (set_flags == FlagsOSZACP) {
298 ww = WAll;
299 } else {
300 ww = WSome;
301 }
302
303 /* If we're not wanting to interact with simd flags, and the simd
304 flags are not in the real flags, then do nothing. */
305 if (simd == False && where == UPD_Simd)
306 goto noaction;
307
308 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
309 /* We're going to generate a complete new simd flag state without
310 consulting the old one first, so just deem this insn to create
311 the state in the real flags. */
312 eflags_state = UPD_Real;
313 DIS_HEADER;
314 return;
315 }
316
317 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
318 /* Want to partially update the flags state, but is in simd. So
319 fetch it first, then declare that the real state is the most
320 recent. */
321 emit_get_eflags();
322 eflags_state = UPD_Real;
323 DIS_HEADER;
324 return;
325 }
326
327 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
328 /* want to read simd flags, but not in real -> copy to real. */
329 emit_get_eflags();
330 eflags_state = UPD_Both;
331 DIS_HEADER;
332 return;
333 }
334
335 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
336 /* want to read and write simd flags, but not in real -> copy to
337 real. State is then Real since they get updated. */
338 emit_get_eflags();
339 eflags_state = UPD_Real;
340 DIS_HEADER;
341 return;
342 }
343
344 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
345 /* Doesn't really make sense. Want to interact with simd flags,
346 but insn doesn't modify them. So don't do anything. ??? */
347 goto noaction;
348 }
349
350 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
351 /* Doesn't really make sense. Want to interact with simd flags,
352 but insn doesn't modify them. So don't do anything. ??? */
353 goto noaction;
354 }
355
356 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
357 /* simd is in real. Insn reads real but does not change. --> do
358 nothing. */
359 goto noaction;
360 }
361
362 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
363 /* simd is in real. we want to capture changes made by it. -->
364 do nothing */
365 goto noaction;
366 }
367
368 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
369 /* simd is in real. Insn creates new simd state. --> leave in
370 real */
371 goto noaction;
372 }
373
374 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
375 /* simd is in both. Insn creates new simd state. --> change
376 state to Real. */
377 narrow_Both_to_Real:
378 eflags_state = UPD_Real;
379 DIS_HEADER;
380 return;
381 }
382
383 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
384 /* simd is in both. Insn creates partial new simd state. -->
385 change state to Real. No need to get, since Both holds. */
386 goto narrow_Both_to_Real;
387 }
388
389 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
390 /* simd is in real. Insn creates new simd state. --> leave in
391 real */
392 goto noaction;
393 }
394
395 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
396 /* want to read the simd flags, but already have a copy in real,
397 and not planning to modify it --> do nothing. */
398 goto noaction;
399
400 ////////////////
401
402 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
403 /* simd state is in real, but insn doesn't touch it --> do nothing */
404 goto noaction;
405
406 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
407 /* simd state is in both, insn doesn't touch it --> do nothing */
408 goto noaction;
409
410 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
411 /* simd state is in both. insn trashes real, therefore declare
412 simd state only in simd. */
413 narrow_Both_to_Simd:
414 eflags_state = UPD_Simd;
415 DIS_HEADER;
416 return;
417 }
418
419 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
420 /* simd state is in both. insn trashes real, therefore declare
421 simd state only in simd. */
422 goto narrow_Both_to_Simd;
423 }
424
425 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
426 /* simd state is in real; we don't want simd state changed, but
427 insn writes the flags. Therefore have to copy back first. */
428 put_flags_and_continue:
429 emit_put_eflags();
430 eflags_state = UPD_Simd;
431 DIS_HEADER;
432 return;
433 }
434
435 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
436 /* simd state is in real; we don't want simd state changed, but
437 insn writes the flags. Therefore have to copy back first. */
438 goto put_flags_and_continue;
439 }
440
441 goto unhandled;
442
443 noaction:
444 DIS_HEADER;
445 return;
446
447 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
448 // return;
449 //}
450
451 unhandled:
452 VG_(printf)("simd %s, where %s, read %s, write %s\n",
453 simd ? "True " : "False",
454 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
455 ? "Real" : "Both")),
456 rr ? "True " : "False",
457 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
458 );
459
460 VG_(core_panic)("new_emit");
461}
462/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
463#endif
464
465
sewardjfa492d42002-12-08 18:20:01 +0000466/* Call this before emitting each instruction.
467
468 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000469 interacts_with_simd_flags:
470 if true, this instruction wants to interact (read and/or write)
471 the simulated %EFLAGS state,
472 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000473 use_flags: set of (real) flags the instruction uses
474 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000475*/
sewardjfa492d42002-12-08 18:20:01 +0000476__inline__
sewardjf0f12aa2002-12-28 00:04:08 +0000477void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000478 FlagSet use_flags, FlagSet set_flags )
479{
480 Bool use, set;
481
482 use = use_flags != FlagsEmpty
483 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
484 set = set_flags != FlagsEmpty;
485
486 if (0)
487 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000488 "new_emit: state=%d interacts_with_simd_flags=%d "
489 "use_flags=%x set_flags=%x\n",
490 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000491
sewardjf0f12aa2002-12-28 00:04:08 +0000492 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000493 if (use && eflags_state == UPD_Simd) {
494 /* we need the CPU flags set, but they're not already */
495 eflags_state = UPD_Both;
496 emit_get_eflags();
497 }
498 if (set) {
499 /* if we're setting the flags, then the CPU will have the
500 only good copy */
501 eflags_state = UPD_Real;
502 }
503 } else {
504 /* presume that if non-simd code is using flags, it knows what
505 it's doing (ie, it just set up the flags). */
506 if (set) {
507 /* This instruction is going to trash the flags, so we'd
508 better save them away and say that they're only in the
509 simulated state. */
510 maybe_emit_put_eflags();
511 eflags_state = UPD_Simd;
512 }
513 }
514
sewardjde4a1d02002-03-22 01:27:54 +0000515 if (dis)
516 VG_(printf)("\t %4d: ", emitted_code_used );
517}
518
sewardjde4a1d02002-03-22 01:27:54 +0000519
520/*----------------------------------------------------*/
521/*--- Addressing modes ---*/
522/*----------------------------------------------------*/
523
524static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
525{
526 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
527}
528
529static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
530{
531 Int shift;
532 switch (scale) {
533 case 1: shift = 0; break;
534 case 2: shift = 1; break;
535 case 4: shift = 2; break;
536 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000537 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
540}
541
542static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
543{
544 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000545 VG_(emitB) ( mkModRegRM(0, reg, 5) );
546 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000547}
548
549static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
550{
551 /* (regmem), reg */
552 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000553 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( mkModRegRM(1, reg, 5) );
556 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000557 } else {
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000559 }
560}
561
njn25e49d8e72002-09-23 09:36:25 +0000562void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000563{
564 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 if (off < -128 || off > 127) {
567 /* Use a large offset */
568 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
570 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000571 } else {
572 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
574 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000575 }
576}
577
578static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
579 Int regindex, Int reg )
580{
581 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000582 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (off < -128 || off > 127) {
584 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000585 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
586 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
587 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000588 } else {
589 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
591 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
592 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000593 }
594}
595
njn25e49d8e72002-09-23 09:36:25 +0000596void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000597{
598 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000599 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000600}
601
602static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
603{
604 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000606}
607
608
609/*----------------------------------------------------*/
610/*--- Opcode translation ---*/
611/*----------------------------------------------------*/
612
613static __inline__ Int mkGrp1opcode ( Opcode opc )
614{
615 switch (opc) {
616 case ADD: return 0;
617 case OR: return 1;
618 case ADC: return 2;
619 case SBB: return 3;
620 case AND: return 4;
621 case SUB: return 5;
622 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000623 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000624 }
625}
626
sewardjfa492d42002-12-08 18:20:01 +0000627static __inline__ FlagSet nonshiftop_use(Opcode opc)
628{
629 switch(opc) {
630 case ADC:
631 case SBB:
632 return FlagC;
633
634 case ADD:
635 case OR:
636 case AND:
637 case SUB:
638 case XOR:
639 return FlagsEmpty;
640
641 default:
642 VG_(core_panic)("nonshiftop_use");
643 }
644}
645
646static __inline__ FlagSet nonshiftop_set(Opcode opc)
647{
648 switch(opc) {
649 case ADC:
650 case SBB:
651 case ADD:
652 case OR:
653 case AND:
654 case SUB:
655 case XOR:
656 return FlagsOSZACP;
657
658 default:
659 VG_(core_panic)("nonshiftop_set");
660 }
661}
662
sewardjde4a1d02002-03-22 01:27:54 +0000663static __inline__ Int mkGrp2opcode ( Opcode opc )
664{
665 switch (opc) {
666 case ROL: return 0;
667 case ROR: return 1;
668 case RCL: return 2;
669 case RCR: return 3;
670 case SHL: return 4;
671 case SHR: return 5;
672 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000673 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000674 }
675}
676
sewardjfa492d42002-12-08 18:20:01 +0000677static __inline__ FlagSet shiftop_use(Opcode opc)
678{
679 switch(opc) {
680 case ROR:
681 case ROL:
682 case SHL:
683 case SHR:
684 case SAR:
685 return FlagsEmpty;
686
687 case RCL:
688 case RCR:
689 return FlagC;
690
691 default:
692 VG_(core_panic)("shiftop_use");
693 }
694}
695
696static __inline__ FlagSet shiftop_set(Opcode opc)
697{
698 switch(opc) {
699 case ROR:
700 case ROL:
701 case RCL:
702 case RCR:
703 return FlagsOC;
704
705 case SHL:
706 case SHR:
707 case SAR:
708 return FlagsOSZACP;
709
710 default:
711 VG_(core_panic)("shiftop_set");
712 }
713}
714
sewardjde4a1d02002-03-22 01:27:54 +0000715static __inline__ Int mkGrp3opcode ( Opcode opc )
716{
717 switch (opc) {
718 case NOT: return 2;
719 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000720 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000721 }
722}
723
724static __inline__ Int mkGrp4opcode ( Opcode opc )
725{
726 switch (opc) {
727 case INC: return 0;
728 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000729 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000730 }
731}
732
733static __inline__ Int mkGrp5opcode ( Opcode opc )
734{
735 switch (opc) {
736 case CALLM: return 2;
737 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000738 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000739 }
740}
741
742static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
743{
744 switch (opc) {
745 case ADD: return 0x00;
746 case ADC: return 0x10;
747 case AND: return 0x20;
748 case XOR: return 0x30;
749 case OR: return 0x08;
750 case SBB: return 0x18;
751 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000752 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000753 }
754}
755
756/*----------------------------------------------------*/
757/*--- v-size (4, or 2 with OSO) insn emitters ---*/
758/*----------------------------------------------------*/
759
njn25e49d8e72002-09-23 09:36:25 +0000760void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000761{
sewardjf0f12aa2002-12-28 00:04:08 +0000762 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000763 if (sz == 2) VG_(emitB) ( 0x66 );
764 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
765 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000766 if (dis)
767 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
768 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
769}
770
njn25e49d8e72002-09-23 09:36:25 +0000771void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000772{
sewardjf0f12aa2002-12-28 00:04:08 +0000773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000774 if (sz == 2) VG_(emitB) ( 0x66 );
775 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
776 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
779 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
780}
781
782static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
783{
sewardjf0f12aa2002-12-28 00:04:08 +0000784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000785 if (sz == 2) VG_(emitB) ( 0x66 );
786 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000787 emit_amode_regmem_reg ( reg1, reg2 );
788 if (dis)
789 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
790 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
791}
792
793static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000798 emit_amode_regmem_reg ( reg2, reg1 );
799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
801 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000807 if (sz == 2) VG_(emitB) ( 0x66 );
808 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
809 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000810 if (dis)
811 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
812 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
813}
814
sewardjf0f12aa2002-12-28 00:04:08 +0000815void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
816 Int sz, Opcode opc,
817 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjf0f12aa2002-12-28 00:04:08 +0000819 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000820
njn25e49d8e72002-09-23 09:36:25 +0000821 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
823 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000824 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
825 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
826 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000827 } else {
njn25e49d8e72002-09-23 09:36:25 +0000828 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
829 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
830 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000831 }
832 if (dis)
833 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000834 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000835 lit, nameIReg(sz,reg));
836}
837
sewardjf0f12aa2002-12-28 00:04:08 +0000838void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
839 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000840 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000841{
sewardjf0f12aa2002-12-28 00:04:08 +0000842 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000843 if (sz == 2) VG_(emitB) ( 0x66 );
844 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
845 /* short form OK */
846 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
847 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
848 VG_(emitB) ( lit & 0x000000FF );
849 } else {
850 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
851 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
852 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
853 }
854 if (dis)
855 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
856 VG_(name_UOpcode)(False,opc), nameISize(sz),
857 lit, off, nameIReg(sz,regmem));
858}
859
sewardjf0f12aa2002-12-28 00:04:08 +0000860void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
861 Int sz, Opcode opc,
862 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000863{
sewardjf0f12aa2002-12-28 00:04:08 +0000864 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000865
njn25e49d8e72002-09-23 09:36:25 +0000866 if (sz == 2) VG_(emitB) ( 0x66 );
867 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
868 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
869 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000870 if (dis)
871 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000872 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000873 lit, nameIReg(sz,reg));
874}
875
sewardjf0f12aa2002-12-28 00:04:08 +0000876static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000877{
sewardjf0f12aa2002-12-28 00:04:08 +0000878 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000879 if (sz == 2) VG_(emitB) ( 0x66 );
880 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
881 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
882 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
883 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000886 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000890{
sewardjf0f12aa2002-12-28 00:04:08 +0000891 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000892 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
893 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
894 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
895 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000896 if (dis)
897 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000898 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000899}
900
sewardjf0f12aa2002-12-28 00:04:08 +0000901static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
902 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000903 Int off, Int areg, Int reg )
904{
sewardjf0f12aa2002-12-28 00:04:08 +0000905 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000906 if (sz == 2) VG_(emitB) ( 0x66 );
907 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
908 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000909 if (dis)
910 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000911 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000912 off, nameIReg(4,areg), nameIReg(sz,reg));
913}
914
sewardja2c5a732002-12-15 03:10:42 +0000915#if 0
916/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000917static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000918 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000919{
sewardjf0f12aa2002-12-28 00:04:08 +0000920 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000921 if (sz == 2) VG_(emitB) ( 0x66 );
922 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
923 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
926 VG_(name_UOpcode)(False,opc), nameISize(sz),
927 nameIReg(sz,reg), off, nameIReg(4,areg));
928}
sewardja2c5a732002-12-15 03:10:42 +0000929#endif
sewardjfa492d42002-12-08 18:20:01 +0000930
sewardjf0f12aa2002-12-28 00:04:08 +0000931void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000932 Int reg1, Int reg2 )
933{
sewardjf0f12aa2002-12-28 00:04:08 +0000934 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000936# if 0
937 /* Perfectly correct, but the GNU assembler uses the other form.
938 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
940 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000941# else
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000943 emit_amode_greg_ereg ( reg1, reg2 );
944# endif
945 if (dis)
946 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000947 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000948 nameIReg(sz,reg1), nameIReg(sz,reg2));
949}
950
njn25e49d8e72002-09-23 09:36:25 +0000951void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000952{
sewardjf0f12aa2002-12-28 00:04:08 +0000953#if 0
sewardjfa492d42002-12-08 18:20:01 +0000954 if (lit == 0 && eflags_state != UPD_Real) {
955 /* Only emit this for zeroing if it won't stomp flags */
956 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000957 return;
958 }
sewardjf0f12aa2002-12-28 00:04:08 +0000959#endif
960 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000961 if (sz == 2) VG_(emitB) ( 0x66 );
962 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
963 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000964 if (dis)
965 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
966 nameISize(sz), lit, nameIReg(sz,reg));
967}
968
sewardjf0f12aa2002-12-28 00:04:08 +0000969void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjde4a1d02002-03-22 01:27:54 +0000971 switch (opc) {
972 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +0000973 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +0000974 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000975 VG_(emitB) ( 0xF7 );
976 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000977 if (dis)
978 VG_(printf)( "\n\t\tneg%c\t%s\n",
979 nameISize(sz), nameIReg(sz,reg));
980 break;
981 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +0000982 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +0000983 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000984 VG_(emitB) ( 0xF7 );
985 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000986 if (dis)
987 VG_(printf)( "\n\t\tnot%c\t%s\n",
988 nameISize(sz), nameIReg(sz,reg));
989 break;
990 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +0000991 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tdec%c\t%s\n",
996 nameISize(sz), nameIReg(sz,reg));
997 break;
998 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +0000999 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001000 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001001 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (dis)
1003 VG_(printf)( "\n\t\tinc%c\t%s\n",
1004 nameISize(sz), nameIReg(sz,reg));
1005 break;
1006 default:
njne427a662002-10-02 11:08:25 +00001007 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001008 }
1009}
1010
njn25e49d8e72002-09-23 09:36:25 +00001011void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001014 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001016 } else {
1017 vg_assert(sz == 4);
1018 }
njn25e49d8e72002-09-23 09:36:25 +00001019 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001020 if (dis)
1021 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1022}
1023
njn25e49d8e72002-09-23 09:36:25 +00001024void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001025{
sewardjf0f12aa2002-12-28 00:04:08 +00001026 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001029 } else {
1030 vg_assert(sz == 4);
1031 }
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1035}
1036
njn25e49d8e72002-09-23 09:36:25 +00001037void VG_(emit_pushl_lit32) ( UInt int32 )
1038{
sewardjf0f12aa2002-12-28 00:04:08 +00001039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001040 VG_(emitB) ( 0x68 );
1041 VG_(emitL) ( int32 );
1042 if (dis)
1043 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1044}
1045
1046void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001047{
1048 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001049 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x6A );
1051 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001052 if (dis)
1053 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1054}
1055
sewardjf0f12aa2002-12-28 00:04:08 +00001056void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001057{
sewardjf0f12aa2002-12-28 00:04:08 +00001058 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x83 );
1060 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1061 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001062 if (dis)
1063 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1064}
1065
1066static void emit_swapl_reg_ECX ( Int reg )
1067{
sewardjf0f12aa2002-12-28 00:04:08 +00001068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1070 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001078 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001079 if (dis)
1080 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1081}
1082
1083static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1084{
sewardjf0f12aa2002-12-28 00:04:08 +00001085 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1087 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
1093static void emit_bswapl_reg ( Int reg )
1094{
sewardjf0f12aa2002-12-28 00:04:08 +00001095 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F );
1097 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1100}
1101
1102static void emit_movl_reg_reg ( Int regs, Int regd )
1103{
sewardjf0f12aa2002-12-28 00:04:08 +00001104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001105 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1106 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001107 if (dis)
1108 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1109}
1110
njn25e49d8e72002-09-23 09:36:25 +00001111void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001112{
sewardjf0f12aa2002-12-28 00:04:08 +00001113 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001114 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001115 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 } else {
1117 vg_assert(sz == 4);
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1120 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1121 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1124 nameISize(sz), lit, off, nameIReg(4,memreg) );
1125}
1126
1127
1128/*----------------------------------------------------*/
1129/*--- b-size (1 byte) instruction emitters ---*/
1130/*----------------------------------------------------*/
1131
1132/* There is some doubt as to whether C6 (Grp 11) is in the
1133 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001134void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1138 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1139 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (dis)
1141 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1142 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001143}
1144
sewardjf0f12aa2002-12-28 00:04:08 +00001145static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001146 Int off, Int areg, Int reg )
1147{
sewardjf0f12aa2002-12-28 00:04:08 +00001148 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001149 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1150 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001151 if (dis)
1152 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001154 nameIReg(1,reg));
1155}
1156
sewardjf0f12aa2002-12-28 00:04:08 +00001157static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001158 UInt lit, Int off, Int areg )
1159{
sewardjf0f12aa2002-12-28 00:04:08 +00001160 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001161 VG_(emitB) ( 0x80 );
1162 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1163 VG_(emitB) ( lit );
1164 if (dis)
1165 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1166 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1167}
1168
sewardja2c5a732002-12-15 03:10:42 +00001169#if 0
1170/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001171static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001172 Int off, Int areg, Int reg )
1173{
sewardjf0f12aa2002-12-28 00:04:08 +00001174 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001175 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1176 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1177 if (dis)
1178 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1179 VG_(name_UOpcode)(False,opc),
1180 nameIReg(1,reg),
1181 off, nameIReg(4,areg));
1182}
sewardja2c5a732002-12-15 03:10:42 +00001183#endif
sewardjfa492d42002-12-08 18:20:01 +00001184
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001186{
1187 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001188 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001189 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1190 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1193 nameIReg(1,reg), off, nameIReg(4,areg));
1194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1197 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg1), nameIReg(1,reg2));
1206}
1207
1208static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1209{
sewardjf0f12aa2002-12-28 00:04:08 +00001210 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001212 emit_amode_regmem_reg ( reg2, reg1 );
1213 if (dis)
1214 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1215 nameIReg(4,reg2));
1216}
1217
sewardjf0f12aa2002-12-28 00:04:08 +00001218static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1219 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001220{
sewardjf0f12aa2002-12-28 00:04:08 +00001221 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001222 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1223 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1224 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001225 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001226 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001227 lit, nameIReg(1,reg));
1228}
1229
sewardjf0f12aa2002-12-28 00:04:08 +00001230static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1231 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001232{
sewardjf0f12aa2002-12-28 00:04:08 +00001233 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001234 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1235 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1236 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001237 if (dis)
1238 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001239 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001240 lit, nameIReg(1,reg));
1241}
1242
sewardjf0f12aa2002-12-28 00:04:08 +00001243void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001244{
sewardjde4a1d02002-03-22 01:27:54 +00001245 switch (opc) {
1246 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001247 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001248 VG_(emitB) ( 0xFE );
1249 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001250 if (dis)
1251 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1252 break;
1253 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001254 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001255 VG_(emitB) ( 0xFE );
1256 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001257 if (dis)
1258 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1259 break;
1260 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001262 VG_(emitB) ( 0xF6 );
1263 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001264 if (dis)
1265 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1266 break;
1267 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xF6 );
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001271 if (dis)
1272 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1273 break;
1274 default:
njne427a662002-10-02 11:08:25 +00001275 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001276 }
1277}
1278
sewardjf0f12aa2002-12-28 00:04:08 +00001279void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001280{
sewardjf0f12aa2002-12-28 00:04:08 +00001281 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001282 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1283 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1284 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1287}
1288
sewardjde4a1d02002-03-22 01:27:54 +00001289/*----------------------------------------------------*/
1290/*--- zero-extended load emitters ---*/
1291/*----------------------------------------------------*/
1292
njn25e49d8e72002-09-23 09:36:25 +00001293void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001294{
sewardjf0f12aa2002-12-28 00:04:08 +00001295 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001296 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1297 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001298 if (dis)
1299 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1300 off, nameIReg(4,regmem), nameIReg(4,reg));
1301}
1302
1303static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1304{
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001307 emit_amode_regmem_reg ( reg1, reg2 );
1308 if (dis)
1309 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1310 nameIReg(4,reg2));
1311}
1312
njn25e49d8e72002-09-23 09:36:25 +00001313void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001314{
sewardjf0f12aa2002-12-28 00:04:08 +00001315 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001316 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1317 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001318 if (dis)
1319 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1320 off, nameIReg(4,areg), nameIReg(4,reg));
1321}
1322
1323static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1324{
sewardjf0f12aa2002-12-28 00:04:08 +00001325 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001327 emit_amode_regmem_reg ( reg1, reg2 );
1328 if (dis)
1329 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1330 nameIReg(4,reg2));
1331}
1332
1333/*----------------------------------------------------*/
1334/*--- FPU instruction emitters ---*/
1335/*----------------------------------------------------*/
1336
sewardjb91ae7f2003-04-29 23:50:00 +00001337static void emit_get_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001338{
sewardjb91ae7f2003-04-29 23:50:00 +00001339 Int off = 4 * VGOFF_(m_ssestate);
1340 if (VG_(have_ssestate)) {
1341 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1342 VG_(emitB) ( 0x0F );
1343 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x8D ); /* fxrstor d32(%ebp) */
1344 VG_(emitL) ( off );
1345 if (dis)
1346 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1347 } else {
1348 /* Not a SSE-capable CPU. Just do frstor. */
1349 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1350 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1351 VG_(emitL) ( off );
1352 if (dis)
1353 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1354 }
sewardjde4a1d02002-03-22 01:27:54 +00001355}
1356
sewardjb91ae7f2003-04-29 23:50:00 +00001357static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001358{
sewardjb91ae7f2003-04-29 23:50:00 +00001359 Int off = 4 * VGOFF_(m_ssestate);
1360 if (VG_(have_ssestate)) {
1361 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1362 VG_(emitB) ( 0x0F );
1363 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1364 VG_(emitL) ( off );
1365 if (dis)
1366 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1367 } else {
1368 /* Not a SSE-capable CPU. Just do fnsave. */
1369 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1370 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1371 VG_(emitL) ( off );
1372 if (dis)
1373 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1374 }
sewardjde4a1d02002-03-22 01:27:54 +00001375}
1376
sewardjf0f12aa2002-12-28 00:04:08 +00001377static void emit_fpu_no_mem ( FlagSet uses_sflags,
1378 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001379 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001380 UChar second_byte )
1381{
sewardjf0f12aa2002-12-28 00:04:08 +00001382 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001383 VG_(emitB) ( first_byte );
1384 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001385 if (dis)
1386 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1387 (UInt)first_byte, (UInt)second_byte );
1388}
1389
sewardjf0f12aa2002-12-28 00:04:08 +00001390static void emit_fpu_regmem ( FlagSet uses_sflags,
1391 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001392 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001393 UChar second_byte_masked,
1394 Int reg )
1395{
sewardjf0f12aa2002-12-28 00:04:08 +00001396 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001397 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001398 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1399 if (dis)
1400 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1401 (UInt)first_byte, (UInt)second_byte_masked,
1402 nameIReg(4,reg) );
1403}
1404
sewardj3d7c9c82003-03-26 21:08:13 +00001405static void emit_MMX2_regmem ( FlagSet uses_sflags,
1406 FlagSet sets_sflags,
1407 UChar first_byte,
1408 UChar second_byte,
1409 Int ireg )
1410{
1411 VG_(new_emit)(True, uses_sflags, sets_sflags);
1412 VG_(emitB) ( 0x0F );
1413 VG_(emitB) ( first_byte );
1414 second_byte &= 0x38; /* mask out mod and rm fields */
1415 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1416 if (dis)
1417 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1418 (UInt)first_byte, (UInt)second_byte,
1419 nameIReg(4,ireg) );
1420}
1421
sewardjfebaa3b2003-05-25 01:07:34 +00001422static void emit_SSE2a ( FlagSet uses_sflags,
1423 FlagSet sets_sflags,
1424 UChar first_byte,
1425 UChar second_byte,
1426 UChar third_byte,
1427 Int ireg )
1428{
1429 VG_(new_emit)(True, uses_sflags, sets_sflags);
1430 VG_(emitB) ( first_byte );
1431 VG_(emitB) ( second_byte );
1432 third_byte &= 0x38; /* mask out mod and rm fields */
1433 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1434 if (dis)
1435 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x-(%s)\n",
1436 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1437 nameIReg(4,ireg) );
1438}
1439
1440static void emit_SSE3a ( FlagSet uses_sflags,
1441 FlagSet sets_sflags,
1442 UChar first_byte,
1443 UChar second_byte,
1444 UChar third_byte,
1445 UChar fourth_byte,
1446 Int ireg )
1447{
1448 VG_(new_emit)(True, uses_sflags, sets_sflags);
1449 VG_(emitB) ( first_byte );
1450 VG_(emitB) ( second_byte );
1451 VG_(emitB) ( third_byte );
1452 fourth_byte &= 0x38; /* mask out mod and rm fields */
1453 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1454 if (dis)
1455 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1456 (UInt)first_byte, (UInt)second_byte,
1457 (UInt)third_byte, (UInt)fourth_byte,
1458 nameIReg(4,ireg) );
1459}
1460
sewardj8f33ba62003-06-14 12:00:45 +00001461static void emit_SSE3g_RegRd ( FlagSet uses_sflags,
1462 FlagSet sets_sflags,
1463 UChar first_byte,
1464 UChar second_byte,
1465 UChar third_byte,
1466 UChar fourth_byte,
1467 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001468{
1469 VG_(new_emit)(True, uses_sflags, sets_sflags);
1470 VG_(emitB) ( first_byte );
1471 VG_(emitB) ( second_byte );
1472 VG_(emitB) ( third_byte );
1473 fourth_byte &= 0x38; /* mask out mod and rm fields */
1474 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1475 fourth_byte |= (ireg & 7); /* patch in our ireg */
1476 VG_(emitB) ( fourth_byte );
1477 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001478 VG_(printf)(
sewardj8f33ba62003-06-14 12:00:45 +00001479 "\n\t\tireg-to-ssereg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001480 (UInt)first_byte, (UInt)second_byte,
1481 (UInt)third_byte, (UInt)fourth_byte,
1482 nameIReg(4,ireg)
1483 );
sewardjfebaa3b2003-05-25 01:07:34 +00001484}
1485
sewardj8f33ba62003-06-14 12:00:45 +00001486static void emit_SSE3g1_RegRd ( FlagSet uses_sflags,
1487 FlagSet sets_sflags,
1488 UChar first_byte,
1489 UChar second_byte,
1490 UChar third_byte,
1491 UChar fourth_byte,
1492 UChar fifth_byte,
1493 Int ireg )
1494{
1495 VG_(new_emit)(True, uses_sflags, sets_sflags);
1496 VG_(emitB) ( first_byte );
1497 VG_(emitB) ( second_byte );
1498 VG_(emitB) ( third_byte );
1499 fourth_byte &= 0x38; /* mask out mod and rm fields */
1500 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1501 fourth_byte |= (ireg & 7); /* patch in our ireg */
1502 VG_(emitB) ( fourth_byte );
1503 VG_(emitB) ( fifth_byte );
1504 if (dis)
1505 VG_(printf)(
1506 "\n\t\tireg-to-ssereg--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1507 (UInt)first_byte, (UInt)second_byte,
1508 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1509 nameIReg(4,ireg)
1510 );
1511}
1512
sewardjb31b06d2003-06-13 00:26:02 +00001513static void emit_SSE3g1_RegWr ( FlagSet uses_sflags,
1514 FlagSet sets_sflags,
1515 UChar first_byte,
1516 UChar second_byte,
1517 UChar third_byte,
1518 UChar fourth_byte,
1519 UChar fifth_byte,
1520 Int ireg )
1521{
1522 VG_(new_emit)(True, uses_sflags, sets_sflags);
1523 VG_(emitB) ( first_byte );
1524 VG_(emitB) ( second_byte );
1525 VG_(emitB) ( third_byte );
1526 fourth_byte &= 0xC7; /* mask out reg field */
1527 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1528 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1529 VG_(emitB) ( fourth_byte );
1530 VG_(emitB) ( fifth_byte );
1531 if (dis)
1532 VG_(printf)(
1533 "\n\t\tssereg-to-ireg--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1534 (UInt)first_byte, (UInt)second_byte,
1535 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1536 nameIReg(4,ireg)
1537 );
1538}
1539
sewardj8f33ba62003-06-14 12:00:45 +00001540static void emit_SSE3g_RegWr ( FlagSet uses_sflags,
1541 FlagSet sets_sflags,
1542 UChar first_byte,
1543 UChar second_byte,
1544 UChar third_byte,
1545 UChar fourth_byte,
1546 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001547{
1548 VG_(new_emit)(True, uses_sflags, sets_sflags);
1549 VG_(emitB) ( first_byte );
1550 VG_(emitB) ( second_byte );
1551 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001552 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001553 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001554 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001555 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001556 if (dis)
1557 VG_(printf)(
sewardj8f33ba62003-06-14 12:00:45 +00001558 "\n\t\tssereg-to-ireg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001559 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001560 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001561 nameIReg(4,ireg)
1562 );
1563}
1564
sewardjfebaa3b2003-05-25 01:07:34 +00001565static void emit_SSE4 ( FlagSet uses_sflags,
1566 FlagSet sets_sflags,
1567 UChar first_byte,
1568 UChar second_byte,
1569 UChar third_byte,
1570 UChar fourth_byte )
1571{
1572 VG_(new_emit)(True, uses_sflags, sets_sflags);
1573 VG_(emitB) ( first_byte );
1574 VG_(emitB) ( second_byte );
1575 VG_(emitB) ( third_byte );
1576 VG_(emitB) ( fourth_byte );
1577 if (dis)
1578 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x\n",
1579 (UInt)first_byte, (UInt)second_byte,
1580 (UInt)third_byte, (UInt)fourth_byte );
1581}
1582
sewardja60be0e2003-05-26 08:47:27 +00001583static void emit_SSE3 ( FlagSet uses_sflags,
1584 FlagSet sets_sflags,
1585 UChar first_byte,
1586 UChar second_byte,
1587 UChar third_byte )
1588{
1589 VG_(new_emit)(True, uses_sflags, sets_sflags);
1590 VG_(emitB) ( first_byte );
1591 VG_(emitB) ( second_byte );
1592 VG_(emitB) ( third_byte );
1593 if (dis)
1594 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x\n",
1595 (UInt)first_byte, (UInt)second_byte,
1596 (UInt)third_byte );
1597}
1598
sewardjca860012003-03-27 23:52:58 +00001599static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1600 FlagSet sets_sflags,
1601 UChar first_byte,
1602 UChar second_byte,
1603 Int ireg )
1604{
1605 VG_(new_emit)(True, uses_sflags, sets_sflags);
1606 VG_(emitB) ( 0x0F );
1607 VG_(emitB) ( first_byte );
1608 second_byte &= 0x38; /* mask out mod and rm fields */
1609 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1610 second_byte |= (ireg & 7); /* patch in our ireg */
1611 VG_(emitB) ( second_byte );
1612 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001613 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1614 (UInt)first_byte, (UInt)second_byte,
1615 nameIReg(4,ireg) );
1616}
1617
1618static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1619 FlagSet sets_sflags,
1620 UChar first_byte,
1621 UChar second_byte,
1622 Int ireg )
1623{
1624 VG_(new_emit)(True, uses_sflags, sets_sflags);
1625 VG_(emitB) ( 0x0F );
1626 VG_(emitB) ( first_byte );
1627 second_byte &= 0x38; /* mask out mod and rm fields */
1628 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1629 second_byte |= (ireg & 7); /* patch in our ireg */
1630 VG_(emitB) ( second_byte );
1631 if (dis)
1632 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001633 (UInt)first_byte, (UInt)second_byte,
1634 nameIReg(4,ireg) );
1635}
1636
1637static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1638 FlagSet sets_sflags,
1639 UChar first_byte,
1640 UChar second_byte,
1641 UChar third_byte )
1642{
1643 VG_(new_emit)(True, uses_sflags, sets_sflags);
1644 VG_(emitB) ( 0x0F );
1645 VG_(emitB) ( first_byte );
1646 VG_(emitB) ( second_byte );
1647 VG_(emitB) ( third_byte );
1648 if (dis)
1649 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1650 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1651}
1652
sewardj3d7c9c82003-03-26 21:08:13 +00001653static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1654 FlagSet sets_sflags,
1655 UChar first_byte,
1656 UChar second_byte )
1657{
1658 VG_(new_emit)(True, uses_sflags, sets_sflags);
1659 VG_(emitB) ( 0x0F );
1660 VG_(emitB) ( first_byte );
1661 VG_(emitB) ( second_byte );
1662 if (dis)
1663 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1664 (UInt)first_byte, (UInt)second_byte );
1665}
1666
1667static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1668 FlagSet sets_sflags,
1669 UChar first_byte )
1670{
1671 VG_(new_emit)(True, uses_sflags, sets_sflags);
1672 VG_(emitB) ( 0x0F );
1673 VG_(emitB) ( first_byte );
1674 if (dis)
1675 VG_(printf)("\n\t\tmmx1-0x%x\n",
1676 (UInt)first_byte );
1677}
1678
sewardjde4a1d02002-03-22 01:27:54 +00001679
1680/*----------------------------------------------------*/
1681/*--- misc instruction emitters ---*/
1682/*----------------------------------------------------*/
1683
njn25e49d8e72002-09-23 09:36:25 +00001684void VG_(emit_call_reg) ( Int reg )
1685{
sewardjfa492d42002-12-08 18:20:01 +00001686 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001687 VG_(emitB) ( 0xFF ); /* Grp5 */
1688 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1689 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001690 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001691}
1692
sewardjf0f12aa2002-12-28 00:04:08 +00001693static
1694void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1695 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001696{
sewardjfa492d42002-12-08 18:20:01 +00001697 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001698 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001699
1700 if (byte_off < -128 || byte_off > 127) {
1701 VG_(emitB) ( 0xFF );
1702 VG_(emitB) ( 0x95 );
1703 VG_(emitL) ( byte_off );
1704 } else {
1705 VG_(emitB) ( 0xFF );
1706 VG_(emitB) ( 0x55 );
1707 VG_(emitB) ( byte_off );
1708 }
1709 if (dis)
1710 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001711}
1712
sewardja2c5a732002-12-15 03:10:42 +00001713#if 0
1714/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001715static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1716{
1717 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001718 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001719 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1720 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001721 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001722 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001723 if (dis)
1724 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1725 nameIReg(4,regmem));
1726}
sewardja2c5a732002-12-15 03:10:42 +00001727#endif
sewardjde4a1d02002-03-22 01:27:54 +00001728
njn25e49d8e72002-09-23 09:36:25 +00001729void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001730{
njne427a662002-10-02 11:08:25 +00001731 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001732 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1733 VG_(emitB) ( 0x8D );
1734 VG_(emitB) ( 0x64 );
1735 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001736 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001737 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001738 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001739}
1740
1741
1742static void emit_movb_AL_zeroESPmem ( void )
1743{
1744 /* movb %al, 0(%esp) */
1745 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001746 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001747 VG_(emitB) ( 0x88 );
1748 VG_(emitB) ( 0x44 );
1749 VG_(emitB) ( 0x24 );
1750 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001751 if (dis)
1752 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1753}
1754
1755static void emit_movb_zeroESPmem_AL ( void )
1756{
1757 /* movb 0(%esp), %al */
1758 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001759 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001760 VG_(emitB) ( 0x8A );
1761 VG_(emitB) ( 0x44 );
1762 VG_(emitB) ( 0x24 );
1763 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001764 if (dis)
1765 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1766}
1767
sewardja2113f92002-12-12 23:42:48 +00001768/* Jump target states */
1769#define TGT_UNDEF (1 << 16)
1770#define TGT_FORWARD (2 << 16)
1771#define TGT_BACKWARD (3 << 16)
1772
1773static inline Int tgt_state(Int tgt)
1774{
1775 return tgt & 0xffff0000;
1776}
1777
1778static inline Int tgt_addr(Int tgt)
1779{
1780 return tgt & 0x0000ffff;
1781}
1782
1783static inline Int mk_tgt(Int state, Int addr)
1784{
1785 vg_assert(state == TGT_UNDEF
1786 || state == TGT_FORWARD || state == TGT_BACKWARD);
1787 vg_assert((addr & 0xffff0000) == 0);
1788
1789 return state | addr;
1790}
1791
1792void VG_(init_target) ( Int *tgt )
1793{
1794 *tgt = TGT_UNDEF;
1795}
1796
1797void VG_(target_back) ( Int *tgt )
1798{
1799 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1800
1801 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1802}
1803
1804void VG_(target_forward) ( Int *tgt )
1805{
1806 Int delta;
1807
1808 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1809 tgt_state(*tgt) == TGT_UNDEF);
1810
1811 if (tgt_state(*tgt) == TGT_UNDEF)
1812 return; /* target not used */
1813
1814 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1815 vg_assert(delta >= -128 && delta <= 127);
1816 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001817 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001818 emitted_code[tgt_addr(*tgt)] = delta;
1819 if (dis)
1820 VG_(printf)("(target to jump site %d; delta: %d)\n",
1821 tgt_addr(*tgt), delta);
1822}
1823
1824void VG_(emit_target_delta) ( Int *tgt )
1825{
1826 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1827 tgt_state(*tgt) == TGT_BACKWARD);
1828
1829 if (tgt_state(*tgt) == TGT_UNDEF) {
1830 /* forward jump */
1831 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1832 VG_(emitB) (0x00);
1833 } else {
1834 /* backward jump */
1835 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1836 vg_assert(delta >= -128 && delta <= 127);
1837 VG_(emitB) (delta);
1838 }
1839}
1840
sewardjde4a1d02002-03-22 01:27:54 +00001841
1842/* Emit a jump short with an 8-bit signed offset. Note that the
1843 offset is that which should be added to %eip once %eip has been
1844 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001845void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001846{
1847 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001848 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001849 VG_(emitB) ( 0x70 + (UInt)cond );
1850 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001851 if (dis)
1852 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001853 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001854}
1855
sewardja2113f92002-12-12 23:42:48 +00001856/* Same as above, but defers emitting the delta */
1857void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1858{
sewardj706240d2002-12-26 17:10:12 +00001859 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001860 VG_(emitB) ( 0x70 + (UInt)cond );
1861 VG_(emit_target_delta) (tgt);
1862 if (dis)
1863 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001864 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001865}
1866
1867
1868
sewardjf0f12aa2002-12-28 00:04:08 +00001869static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001870{
sewardjf0f12aa2002-12-28 00:04:08 +00001871 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001872 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1873 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001874 if (dis)
1875 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001876 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001877}
1878
1879static void emit_ret ( void )
1880{
sewardjfa492d42002-12-08 18:20:01 +00001881 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001882 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001883 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001884 if (dis)
1885 VG_(printf)("\n\t\tret\n");
1886}
1887
sewardj22854b92002-11-30 14:00:47 +00001888/* Predicate used in sanity checks elsewhere - returns true if any
1889 jump-site is an actual chained jump */
1890Bool VG_(is_chained_jumpsite)(Addr a)
1891{
1892 UChar *cp = (UChar *)a;
1893
1894 return (*cp == 0xE9); /* 0xE9 -- jmp */
1895}
1896
sewardj83f11862002-12-01 02:07:08 +00001897static
1898Bool is_fresh_jumpsite(UChar *cp)
1899{
1900 return
1901 cp[0] == 0x0F && /* UD2 */
1902 cp[1] == 0x0B &&
1903 cp[2] == 0x0F && /* UD2 */
1904 cp[3] == 0x0B &&
1905 cp[4] == 0x90; /* NOP */
1906}
1907
sewardj22854b92002-11-30 14:00:47 +00001908/* Predicate used in sanity checks elsewhere - returns true if all
1909 jump-sites are calls to VG_(patch_me) */
1910Bool VG_(is_unchained_jumpsite)(Addr a)
1911{
1912 UChar *cp = (UChar *)a;
1913 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1914 Int idelta;
1915
1916 if (*cp++ != 0xE8) /* 0xE8 == call */
1917 return False;
1918
1919 idelta = (*cp++) << 0;
1920 idelta |= (*cp++) << 8;
1921 idelta |= (*cp++) << 16;
1922 idelta |= (*cp++) << 24;
1923
1924 return idelta == delta;
1925}
1926
1927/* Return target address for a direct jmp */
1928Addr VG_(get_jmp_dest)(Addr a)
1929{
1930 Int delta;
1931 UChar *cp = (UChar *)a;
1932
1933 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1934 return 0;
1935
1936 delta = (*cp++) << 0;
1937 delta |= (*cp++) << 8;
1938 delta |= (*cp++) << 16;
1939 delta |= (*cp++) << 24;
1940
1941 return a + VG_PATCHME_JMPSZ + delta;
1942}
1943
1944/* unchain a BB by generating a call to VG_(patch_me) */
1945void VG_(unchain_jumpsite)(Addr a)
1946{
1947 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1948 UChar *cp = (UChar *)a;
1949
1950 if (VG_(is_unchained_jumpsite)(a))
1951 return; /* don't write unnecessarily */
1952
sewardj83f11862002-12-01 02:07:08 +00001953 if (!is_fresh_jumpsite(cp))
1954 VG_(bb_dechain_count)++; /* update stats */
1955
sewardj22854b92002-11-30 14:00:47 +00001956 *cp++ = 0xE8; /* call */
1957 *cp++ = (delta >> 0) & 0xff;
1958 *cp++ = (delta >> 8) & 0xff;
1959 *cp++ = (delta >> 16) & 0xff;
1960 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001961}
1962
1963/* This doesn't actually generate a call to VG_(patch_me), but
1964 reserves enough space in the instruction stream for it to happen
1965 and records the offset into the jump table. This is because call
1966 is a relative jump, and so will be affected when this code gets
1967 moved about. The translation table will "unchain" this basic block
1968 on insertion (with VG_(unchain_BB)()), and thereby generate a
1969 proper call instruction. */
1970static void emit_call_patchme( void )
1971{
1972 vg_assert(VG_PATCHME_CALLSZ == 5);
1973
sewardjfa492d42002-12-08 18:20:01 +00001974 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001975 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001976
1977 if (jumpidx >= VG_MAX_JUMPS) {
1978 /* If there too many jumps in this basic block, fall back to
1979 dispatch loop. We still need to keep it the same size as the
1980 call sequence. */
1981 VG_(emitB) ( 0xC3 ); /* ret */
1982 VG_(emitB) ( 0x90 ); /* nop */
1983 VG_(emitB) ( 0x90 ); /* nop */
1984 VG_(emitB) ( 0x90 ); /* nop */
1985 VG_(emitB) ( 0x90 ); /* nop */
1986
1987 if (dis)
1988 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1989
1990 if (0 && VG_(clo_verbosity))
1991 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1992 } else {
1993 jumps[jumpidx++] = emitted_code_used;
1994
1995 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1996 VG_(emitB) ( 0x0B );
1997 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1998 VG_(emitB) ( 0x0B );
1999 VG_(emitB) ( 0x90 ); /* NOP */
2000
2001 if (dis)
2002 VG_(printf)("\n\t\tud2; ud2; nop\n");
2003 }
2004}
2005
njn25e49d8e72002-09-23 09:36:25 +00002006void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002007{
sewardjf0f12aa2002-12-28 00:04:08 +00002008 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002009 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002010 if (dis)
2011 VG_(printf)("\n\t\tpushal\n");
2012}
2013
njn25e49d8e72002-09-23 09:36:25 +00002014void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002015{
sewardjf0f12aa2002-12-28 00:04:08 +00002016 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002017 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002018 if (dis)
2019 VG_(printf)("\n\t\tpopal\n");
2020}
2021
2022static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2023{
sewardjf0f12aa2002-12-28 00:04:08 +00002024 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002025 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2026 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002027 if (dis)
2028 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2029 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2030}
2031
2032static void emit_lea_sib_reg ( UInt lit, Int scale,
2033 Int regbase, Int regindex, Int reg )
2034{
sewardjf0f12aa2002-12-28 00:04:08 +00002035 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002036 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002037 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2038 if (dis)
2039 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2040 lit, nameIReg(4,regbase),
2041 nameIReg(4,regindex), scale,
2042 nameIReg(4,reg) );
2043}
2044
njn25e49d8e72002-09-23 09:36:25 +00002045void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002046{
sewardjf0f12aa2002-12-28 00:04:08 +00002047 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002048 VG_(emitB) ( 0x0F );
2049 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002050 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2051 if (dis)
2052 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2053}
2054
2055/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002056/*--- Helper offset -> addr translation ---*/
2057/*----------------------------------------------------*/
2058
2059/* Finds the baseBlock offset of a skin-specified helper.
2060 * Searches through compacts first, then non-compacts. */
2061Int VG_(helper_offset)(Addr a)
2062{
sewardj05bcdcb2003-05-18 10:05:38 +00002063 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002064 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002065
2066 for (i = 0; i < VG_(n_compact_helpers); i++)
2067 if (VG_(compact_helper_addrs)[i] == a)
2068 return VG_(compact_helper_offsets)[i];
2069 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2070 if (VG_(noncompact_helper_addrs)[i] == a)
2071 return VG_(noncompact_helper_offsets)[i];
2072
2073 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002074 VG_(get_fnname) ( a, buf, 100 );
2075
njn25e49d8e72002-09-23 09:36:25 +00002076 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002077 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2078 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002079
2080 VG_(printf)(" compact helpers: ");
2081 for (i = 0; i < VG_(n_compact_helpers); i++)
2082 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2083
2084 VG_(printf)("\n non-compact helpers: ");
2085 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2086 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2087
2088 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002089 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002090}
2091
2092/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002093/*--- Instruction synthesisers ---*/
2094/*----------------------------------------------------*/
2095
2096static Condcode invertCondition ( Condcode cond )
2097{
2098 return (Condcode)(1 ^ (UInt)cond);
2099}
2100
2101
2102/* Synthesise a call to *baseBlock[offset], ie,
2103 call * (4 x offset)(%ebp).
2104*/
sewardjfa492d42002-12-08 18:20:01 +00002105void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002106 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002107{
2108 vg_assert(word_offset >= 0);
2109 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002110 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002111 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002112 }
sewardjf0f12aa2002-12-28 00:04:08 +00002113 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002114}
2115
njn25e49d8e72002-09-23 09:36:25 +00002116static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002117{
njn25e49d8e72002-09-23 09:36:25 +00002118 if (src != dst) {
2119 VG_(emit_movv_reg_reg) ( 4, src, dst );
2120 ccall_arg_setup_instrs++;
2121 }
njn6431be72002-07-28 09:53:34 +00002122}
njn25e49d8e72002-09-23 09:36:25 +00002123
2124/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2125static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2126{
2127 if (RealReg == tag) {
2128 maybe_emit_movl_reg_reg ( litOrReg, reg );
2129 } else if (Literal == tag) {
2130 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2131 ccall_arg_setup_instrs++;
2132 }
2133 else
njne427a662002-10-02 11:08:25 +00002134 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002135}
2136
2137static
2138void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2139{
2140 if (R_EAX == reg1) {
2141 VG_(emit_swapl_reg_EAX) ( reg2 );
2142 } else if (R_EAX == reg2) {
2143 VG_(emit_swapl_reg_EAX) ( reg1 );
2144 } else {
2145 emit_swapl_reg_reg ( reg1, reg2 );
2146 }
2147 ccall_arg_setup_instrs++;
2148}
2149
2150static
2151void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2152{
2153 if (dst1 != src2) {
2154 maybe_emit_movl_reg_reg ( src1, dst1 );
2155 maybe_emit_movl_reg_reg ( src2, dst2 );
2156
2157 } else if (dst2 != src1) {
2158 maybe_emit_movl_reg_reg ( src2, dst2 );
2159 maybe_emit_movl_reg_reg ( src1, dst1 );
2160
2161 } else {
2162 /* swap to break cycle */
2163 emit_swapl_arg_regs ( dst1, dst2 );
2164 }
2165}
2166
2167static
2168void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2169 UInt dst1, UInt dst2, UInt dst3)
2170{
2171 if (dst1 != src2 && dst1 != src3) {
2172 maybe_emit_movl_reg_reg ( src1, dst1 );
2173 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2174
2175 } else if (dst2 != src1 && dst2 != src3) {
2176 maybe_emit_movl_reg_reg ( src2, dst2 );
2177 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2178
2179 } else if (dst3 != src1 && dst3 != src2) {
2180 maybe_emit_movl_reg_reg ( src3, dst3 );
2181 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2182
2183 } else {
2184 /* break cycle */
2185 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2186 emit_swapl_arg_regs ( dst1, dst2 );
2187 emit_swapl_arg_regs ( dst1, dst3 );
2188
2189 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2190 emit_swapl_arg_regs ( dst1, dst3 );
2191 emit_swapl_arg_regs ( dst1, dst2 );
2192
2193 } else {
njne427a662002-10-02 11:08:25 +00002194 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002195 }
2196 }
2197}
2198
2199static
2200void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2201 UInt src1, UInt src2,
2202 UInt dst1, UInt dst2)
2203{
2204 /* If either are lits, order doesn't matter */
2205 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2206 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2207 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2208
2209 } else {
2210 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2211 }
2212}
2213
2214static
2215void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2216 UInt src1, UInt src2, UInt src3,
2217 UInt dst1, UInt dst2, UInt dst3)
2218{
2219 // SSS: fix this eventually -- make STOREV use two RealRegs?
2220 /* Not supporting literals for 3-arg C functions -- they're only used
2221 by STOREV which has 2 args */
2222 vg_assert(RealReg == tagv[src1] &&
2223 RealReg == tagv[src2] &&
2224 RealReg == tagv[src3]);
2225 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2226 dst1, dst2, dst3 );
2227}
2228
2229/* Synthesise a call to a C function `fn' (which must be registered in
2230 baseBlock) doing all the reg saving and arg handling work.
2231
2232 WARNING: a UInstr should *not* be translated with synth_ccall followed
2233 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2234 such behaviour and everything will fall over.
2235 */
2236void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2237 Tag tagv[], Int ret_reg,
2238 RRegSet regs_live_before, RRegSet regs_live_after )
2239{
2240 Int i;
2241 Int stack_used = 0;
2242 Bool preserve_eax, preserve_ecx, preserve_edx;
2243
2244 vg_assert(0 <= regparms_n && regparms_n <= 3);
2245
2246 ccalls++;
2247
2248 /* If %e[acd]x is live before and after the C call, save/restore it.
2249 Unless the return values clobbers the reg; in this case we must not
2250 save/restore the reg, because the restore would clobber the return
2251 value. (Before and after the UInstr really constitute separate live
2252 ranges, but you miss this if you don't consider what happens during
2253 the UInstr.) */
2254# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002255 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2256 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002257 ret_reg != realReg)
2258
2259 preserve_eax = PRESERVE_REG(R_EAX);
2260 preserve_ecx = PRESERVE_REG(R_ECX);
2261 preserve_edx = PRESERVE_REG(R_EDX);
2262
2263# undef PRESERVE_REG
2264
2265 /* Save caller-save regs as required */
2266 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2267 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2268 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2269
2270 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2271 is the number of args passed in regs (maximum 3 for GCC on x86). */
2272
2273 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002274
njn25e49d8e72002-09-23 09:36:25 +00002275 /* First push stack args (RealRegs or Literals) in reverse order. */
2276 for (i = argc-1; i >= regparms_n; i--) {
2277 switch (tagv[i]) {
2278 case RealReg:
2279 VG_(emit_pushv_reg) ( 4, argv[i] );
2280 break;
2281 case Literal:
2282 /* Use short form of pushl if possible. */
2283 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2284 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2285 else
2286 VG_(emit_pushl_lit32)( argv[i] );
2287 break;
2288 default:
2289 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002290 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002291 }
2292 stack_used += 4;
2293 ccall_arg_setup_instrs++;
2294 }
njn6431be72002-07-28 09:53:34 +00002295
njn25e49d8e72002-09-23 09:36:25 +00002296 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2297 If moving values between registers, be careful not to clobber any on
2298 the way. Happily we can use xchgl to swap registers.
2299 */
2300 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002301
njn25e49d8e72002-09-23 09:36:25 +00002302 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2303 case 3:
2304 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2305 R_EAX, R_EDX, R_ECX );
2306 break;
njn6431be72002-07-28 09:53:34 +00002307
njn25e49d8e72002-09-23 09:36:25 +00002308 /* Less-tricky. Args passed in %eax and %edx. */
2309 case 2:
2310 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2311 break;
2312
2313 /* Easy. Just move arg1 into %eax (if not already in there). */
2314 case 1:
2315 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2316 break;
2317
2318 case 0:
2319 break;
2320
2321 default:
njne427a662002-10-02 11:08:25 +00002322 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002323 }
2324
sewardjfa492d42002-12-08 18:20:01 +00002325 /* Call the function - may trash all flags */
2326 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002327
2328 /* Clear any args from stack */
2329 if (0 != stack_used) {
2330 VG_(emit_add_lit_to_esp) ( stack_used );
2331 ccall_stack_clears++;
2332 }
2333
2334 /* Move return value into ret_reg if necessary and not already there */
2335 if (INVALID_REALREG != ret_reg) {
2336 ccall_retvals++;
2337 if (R_EAX != ret_reg) {
2338 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2339 ccall_retval_movs++;
2340 }
2341 }
2342
2343 /* Restore live caller-save regs as required */
2344 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2345 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2346 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002347}
sewardjde4a1d02002-03-22 01:27:54 +00002348
sewardj2e93c502002-04-12 11:12:52 +00002349static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002350{
sewardj2e93c502002-04-12 11:12:52 +00002351 switch (jmpkind) {
2352 case JmpBoring:
2353 break;
sewardj2e93c502002-04-12 11:12:52 +00002354 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002355 break;
2356 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002357 break;
2358 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002359 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002360 break;
2361 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002362 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002363 break;
2364 default:
njne427a662002-10-02 11:08:25 +00002365 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002366 }
2367}
2368
2369/* Jump to the next translation, by loading its original addr into
2370 %eax and returning to the scheduler. Signal special requirements
2371 by loading a special value into %ebp first.
2372*/
2373static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2374{
sewardjfa492d42002-12-08 18:20:01 +00002375 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002376 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002377 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002378 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002379 emit_ret();
2380}
2381
sewardj22854b92002-11-30 14:00:47 +00002382static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002383
2384/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002385static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002386{
sewardjfa492d42002-12-08 18:20:01 +00002387 maybe_emit_put_eflags(); /* save flags here */
2388
njn25e49d8e72002-09-23 09:36:25 +00002389 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002390
2391 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2392 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2393 emit_call_patchme();
2394 } else {
2395 load_ebp_from_JmpKind ( jmpkind );
2396 emit_ret();
2397 }
sewardjde4a1d02002-03-22 01:27:54 +00002398}
2399
2400
sewardj2370f3b2002-11-30 15:01:01 +00002401static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002402static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002403 Opcode opcode, Int size,
2404 UInt lit, Int reg );
2405
sewardjfa492d42002-12-08 18:20:01 +00002406static void synth_jcond_lit ( Condcode cond,
2407 Addr addr,
2408 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002409{
sewardj2370f3b2002-11-30 15:01:01 +00002410 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002411 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002412 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002413
sewardja2113f92002-12-12 23:42:48 +00002414 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002415 VG_(init_target)(&tgt2);
2416 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002417
sewardjfa492d42002-12-08 18:20:01 +00002418 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2419 if need be */
2420 maybe_emit_put_eflags();
2421 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2422
2423 if (eflags_state == UPD_Both) {
2424 /* The flags are already set up, so we just use them as is. */
2425 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002426 cond = invertCondition(cond);
2427 } else {
sewardj75f04932002-12-12 23:13:21 +00002428 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002429
2430 /* The simd state contains the most recent version, so we emit a
2431 sequence to calculate the relevant condition directly out of
2432 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2433 copying them back to the real flags via popf. Notice that
2434 some of these sequences trash %eax, but that should be free
2435 now since this is the end of a bb and therefore all regs are
2436 dead. */
2437 simd = False;
2438
2439 switch (cond) {
2440
sewardjbb6c1182002-12-12 23:54:47 +00002441 case CondLE: /* Z || S != O -> S || !P */
2442 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002443 vg_assert(eax_trashable);
2444
2445 VG_(emit_movv_offregmem_reg)
2446 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2447 /* eax == %EFLAGS */
2448
sewardjbb6c1182002-12-12 23:54:47 +00002449 VG_(emit_nonshiftopv_lit_reg)
2450 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2451 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002452
sewardjbb6c1182002-12-12 23:54:47 +00002453 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2454 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002455
sewardj09736622002-12-28 00:19:00 +00002456 /* actually set the real cpu flags, since ROR changes
2457 neither P nor Z */
2458 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2459
sewardjbb6c1182002-12-12 23:54:47 +00002460 if (cond == CondLE) {
2461 /* test Z */
2462 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2463 /* test OF != SF */
2464 cond = CondP;
2465 } else {
2466 /* test Z */
2467 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2468 /* test OF == SF */
2469 cond = CondNP;
2470 }
sewardj2370f3b2002-11-30 15:01:01 +00002471 break;
2472
sewardjfa492d42002-12-08 18:20:01 +00002473 case CondL:
2474 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002475 vg_assert(eax_trashable);
2476
2477 VG_(emit_movv_offregmem_reg)
2478 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2479 /* eax == %EFLAGS */
2480
sewardj75f04932002-12-12 23:13:21 +00002481 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2482 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002483
sewardj75f04932002-12-12 23:13:21 +00002484 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2485 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002486
sewardj09736622002-12-28 00:19:00 +00002487 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002488 if (cond == CondL) cond = CondP; else cond = CondNP;
2489 break;
sewardjfa492d42002-12-08 18:20:01 +00002490
2491 case CondB:
2492 case CondNB:
2493 mask = EFlagC; goto simple; /* C=1 */
2494
2495 case CondZ:
2496 case CondNZ:
2497 mask = EFlagZ; goto simple; /* Z=1 */
2498
2499 case CondBE:
2500 case CondNBE:
2501 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2502
2503 case CondS:
2504 case CondNS:
2505 mask = EFlagS; goto simple; /* S=1 */
2506
2507 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002508 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002509 mask = EFlagP; goto simple; /* P=1 */
2510
sewardj39542072002-12-09 22:44:00 +00002511 case CondO:
2512 case CondNO:
2513 mask = EFlagO; goto simple; /* O=1 */
2514
sewardjfa492d42002-12-08 18:20:01 +00002515 default:
2516 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002517 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002518 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2519
2520 simple:
2521 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002522 if ((mask & 0xff) == mask) {
2523 VG_(emitB) ( 0xF6 ); /* Grp3 */
2524 VG_(emit_amode_offregmem_reg)(
2525 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2526 VG_(emitB) (mask);
2527 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002528 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002529 mask, VGOFF_(m_eflags) * 4);
2530 } else {
sewardjfa492d42002-12-08 18:20:01 +00002531 /* all cond codes are in lower 16 bits */
2532 vg_assert((mask & 0xffff) == mask);
2533
2534 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002535 VG_(emitB) ( 0xF7 );
2536 VG_(emit_amode_offregmem_reg)(
2537 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002538 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002539 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002540 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002541 mask, VGOFF_(m_eflags) * 4);
2542 }
2543
sewardj75f04932002-12-12 23:13:21 +00002544 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002545 break;
2546 }
2547 }
2548
sewardja2113f92002-12-12 23:42:48 +00002549 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002550
2551 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002552 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002553
2554 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002555 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002556}
2557
2558
sewardj2370f3b2002-11-30 15:01:01 +00002559
sewardjde4a1d02002-03-22 01:27:54 +00002560static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2561{
sewardja2113f92002-12-12 23:42:48 +00002562 Int tgt;
2563
2564 VG_(init_target)(&tgt);
2565
sewardjfa492d42002-12-08 18:20:01 +00002566 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002567
2568 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002569 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002570
2571 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002572}
2573
2574
2575static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2576{
2577 /* Load the zero-extended literal into reg, at size l,
2578 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002579 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002580}
2581
2582
2583static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2584{
2585 switch (size) {
2586 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2587 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2588 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002589 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002590 }
2591}
2592
2593
2594static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2595{
2596 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002597 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2598 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2599 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002600 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002601 }
2602}
2603
2604
2605static void synth_mov_reg_offregmem ( Int size, Int reg,
2606 Int off, Int areg )
2607{
2608 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002609 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2610 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002611 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002612 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002613 }
2614 else {
njn25e49d8e72002-09-23 09:36:25 +00002615 VG_(emit_swapl_reg_EAX) ( reg );
2616 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2617 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002618 }
2619 break;
njne427a662002-10-02 11:08:25 +00002620 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002621 }
2622}
2623
2624
2625static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2626{
2627 Int s1;
2628 switch (size) {
2629 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2630 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2631 case 1: if (reg1 < 4) {
2632 emit_movb_reg_regmem ( reg1, reg2 );
2633 }
2634 else {
2635 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2636 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2637 emit_swapl_reg_reg ( s1, reg1 );
2638 emit_movb_reg_regmem ( s1, reg2 );
2639 emit_swapl_reg_reg ( s1, reg1 );
2640 }
2641 break;
njne427a662002-10-02 11:08:25 +00002642 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002643 }
2644}
2645
2646
sewardjf0f12aa2002-12-28 00:04:08 +00002647static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002648 Opcode opcode, Int size,
2649 Int reg )
2650{
2651 /* NB! opcode is a uinstr opcode, not an x86 one! */
2652 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002653 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002654 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002655 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002656 break;
2657 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002658 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002659 } else {
njn25e49d8e72002-09-23 09:36:25 +00002660 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002661 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002662 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002663 }
2664 break;
njne427a662002-10-02 11:08:25 +00002665 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002666 }
2667}
2668
2669
2670
sewardjf0f12aa2002-12-28 00:04:08 +00002671static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002672 Opcode opcode, Int size,
2673 Int reg1, Int reg2 )
2674{
2675 /* NB! opcode is a uinstr opcode, not an x86 one! */
2676 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002677 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002678 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002679 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002680 break;
2681 case 1: { /* Horrible ... */
2682 Int s1, s2;
2683 /* Choose s1 and s2 to be x86 regs which we can talk about the
2684 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2685 sure s1 != s2 and that neither of them equal either reg1 or
2686 reg2. Then use them as temporaries to make things work. */
2687 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002688 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002689 break;
2690 }
2691 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2692 if (reg1 >= 4 && reg2 < 4) {
2693 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002694 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002695 emit_swapl_reg_reg ( reg1, s1 );
2696 break;
2697 }
2698 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2699 if (reg1 < 4 && reg2 >= 4) {
2700 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002701 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002702 emit_swapl_reg_reg ( reg2, s2 );
2703 break;
2704 }
2705 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2706 emit_swapl_reg_reg ( reg1, s1 );
2707 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002708 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002709 emit_swapl_reg_reg ( reg1, s1 );
2710 emit_swapl_reg_reg ( reg2, s2 );
2711 break;
2712 }
2713 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2714 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002715 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002716 emit_swapl_reg_reg ( reg1, s1 );
2717 break;
2718 }
njne427a662002-10-02 11:08:25 +00002719 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002720 }
njne427a662002-10-02 11:08:25 +00002721 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002722 }
2723}
2724
sewardja2c5a732002-12-15 03:10:42 +00002725#if 0
2726/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002727static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002728 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002729 Opcode opcode, Int size,
2730 Int off, Int areg, Int reg )
2731{
2732 switch (size) {
2733 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002734 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002735 break;
2736 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002737 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002738 break;
2739 case 1:
2740 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002741 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002742 } else {
2743 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002744 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002745 VG_(emit_swapl_reg_EAX) ( reg );
2746 }
2747 break;
2748 default:
2749 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2750 }
2751}
sewardja2c5a732002-12-15 03:10:42 +00002752#endif
sewardjfa492d42002-12-08 18:20:01 +00002753
sewardjde4a1d02002-03-22 01:27:54 +00002754static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002755 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002756 Opcode opcode, Int size,
2757 Int off, Int areg, Int reg )
2758{
2759 switch (size) {
2760 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002761 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002762 break;
2763 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002764 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002765 break;
2766 case 1:
2767 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002768 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002769 } else {
njn25e49d8e72002-09-23 09:36:25 +00002770 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002771 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002772 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002773 }
2774 break;
2775 default:
njne427a662002-10-02 11:08:25 +00002776 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002777 }
2778}
2779
2780
sewardjf0f12aa2002-12-28 00:04:08 +00002781static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002782 Opcode opcode, Int size,
2783 UInt lit, Int reg )
2784{
2785 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002786 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002787 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002788 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002789 break;
2790 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002791 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002792 } else {
njn25e49d8e72002-09-23 09:36:25 +00002793 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002794 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002795 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002796 }
2797 break;
njne427a662002-10-02 11:08:25 +00002798 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002799 }
2800}
2801
sewardjf0f12aa2002-12-28 00:04:08 +00002802static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002803 Opcode opcode, Int size,
2804 UInt lit, Int off, Int regmem )
2805{
2806 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002807 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002808 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002809 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002810 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002811 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002812 break;
2813 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2814 }
2815}
2816
sewardjde4a1d02002-03-22 01:27:54 +00002817
2818static void synth_push_reg ( Int size, Int reg )
2819{
2820 switch (size) {
2821 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002822 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002823 break;
2824 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002825 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002826 break;
2827 /* Pray that we don't have to generate this really cruddy bit of
2828 code very often. Could do better, but can I be bothered? */
2829 case 1:
2830 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002831 VG_(emit_add_lit_to_esp)(-1);
2832 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002833 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002834 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002835 break;
2836 default:
njne427a662002-10-02 11:08:25 +00002837 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002838 }
2839}
2840
2841
2842static void synth_pop_reg ( Int size, Int reg )
2843{
2844 switch (size) {
2845 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002846 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002847 break;
2848 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002849 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002850 break;
2851 case 1:
2852 /* Same comment as above applies. */
2853 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002854 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002855 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002856 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2857 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002858 break;
njne427a662002-10-02 11:08:25 +00002859 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002860 }
2861}
2862
2863
sewardjf0f12aa2002-12-28 00:04:08 +00002864static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002865 Opcode opcode, Int size,
2866 Int regs, Int regd )
2867{
2868 synth_push_reg ( size, regd );
2869 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002870 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002871 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2872 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2873 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002874 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002875 }
sewardjde4a1d02002-03-22 01:27:54 +00002876 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2877 synth_pop_reg ( size, regd );
2878}
2879
2880
sewardjf0f12aa2002-12-28 00:04:08 +00002881static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002882 Opcode opcode, Int size,
2883 UInt lit, Int reg )
2884{
2885 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002886 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002887 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002888 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002889 break;
2890 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002891 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002892 } else {
njn25e49d8e72002-09-23 09:36:25 +00002893 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002894 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002895 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002896 }
2897 break;
njne427a662002-10-02 11:08:25 +00002898 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002899 }
2900}
2901
2902
sewardjf0f12aa2002-12-28 00:04:08 +00002903static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002904{
sewardjde4a1d02002-03-22 01:27:54 +00002905 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002906 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002907 } else {
njn25e49d8e72002-09-23 09:36:25 +00002908 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002909 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002910 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002911 }
2912}
2913
2914
sewardj3d7c9c82003-03-26 21:08:13 +00002915static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2916 UChar first_byte,
2917 UChar second_byte,
2918 Int ireg )
2919{
2920 emit_MMX2_regmem ( uses_flags, sets_flags,
2921 first_byte, second_byte, ireg );
2922}
2923
2924
sewardjca860012003-03-27 23:52:58 +00002925static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2926 UChar first_byte,
2927 UChar second_byte,
2928 Int ireg )
2929{
2930 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2931 first_byte, second_byte, ireg );
2932}
2933
sewardjd1c9e432003-04-04 20:40:34 +00002934static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2935 UChar first_byte,
2936 UChar second_byte,
2937 Int ireg )
2938{
2939 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2940 first_byte, second_byte, ireg );
2941}
2942
sewardj3d7c9c82003-03-26 21:08:13 +00002943static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2944 UChar first_byte,
2945 UChar second_byte )
2946{
2947 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2948}
2949
2950
sewardjca860012003-03-27 23:52:58 +00002951static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2952 UChar first_byte,
2953 UChar second_byte,
2954 UChar third_byte )
2955{
2956 emit_MMX3_no_mem ( uses_flags, sets_flags,
2957 first_byte, second_byte, third_byte );
2958}
2959
2960
sewardj3d7c9c82003-03-26 21:08:13 +00002961static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2962 UChar first_byte )
2963{
2964 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2965}
2966
2967
sewardjfa492d42002-12-08 18:20:01 +00002968static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2969 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002970 UChar second_byte_masked,
2971 Int reg )
2972{
sewardj3d7c9c82003-03-26 21:08:13 +00002973 emit_fpu_regmem ( uses_flags, sets_flags,
2974 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002975}
2976
2977
sewardjfa492d42002-12-08 18:20:01 +00002978static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2979 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002980 UChar second_byte )
2981{
sewardjfa492d42002-12-08 18:20:01 +00002982 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002983}
2984
2985
2986static void synth_movl_reg_reg ( Int src, Int dst )
2987{
2988 emit_movl_reg_reg ( src, dst );
2989}
2990
2991static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2992{
sewardja2113f92002-12-12 23:42:48 +00002993 Int tgt;
2994
2995 VG_(init_target)(&tgt);
2996
2997 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002998 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002999
3000 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003001}
3002
3003
sewardjde4a1d02002-03-22 01:27:54 +00003004/*----------------------------------------------------*/
3005/*--- Top level of the uinstr -> x86 translation. ---*/
3006/*----------------------------------------------------*/
3007
3008/* Return the byte offset from %ebp (ie, into baseBlock)
3009 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003010static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3011{
3012 if (tag == SpillNo) {
3013 vg_assert(size == 4);
3014 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3015 return 4 * (value + VGOFF_(spillslots));
3016 }
3017 if (tag == ArchReg) {
3018 switch (value) {
3019 case R_EAX: return 4 * VGOFF_(m_eax);
3020 case R_ECX: return 4 * VGOFF_(m_ecx);
3021 case R_EDX: return 4 * VGOFF_(m_edx);
3022 case R_EBX: return 4 * VGOFF_(m_ebx);
3023 case R_ESP:
3024 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3025 else return 4 * VGOFF_(m_esp);
3026 case R_EBP:
3027 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3028 else return 4 * VGOFF_(m_ebp);
3029 case R_ESI:
3030 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3031 else return 4 * VGOFF_(m_esi);
3032 case R_EDI:
3033 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3034 else return 4 * VGOFF_(m_edi);
3035 }
3036 }
njne427a662002-10-02 11:08:25 +00003037 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003038}
3039
sewardjde4a1d02002-03-22 01:27:54 +00003040static Int eflagsOffset ( void )
3041{
3042 return 4 * VGOFF_(m_eflags);
3043}
3044
sewardje1042472002-09-30 12:33:11 +00003045static Int segRegOffset ( UInt archregs )
3046{
3047 switch (archregs) {
3048 case R_CS: return 4 * VGOFF_(m_cs);
3049 case R_SS: return 4 * VGOFF_(m_ss);
3050 case R_DS: return 4 * VGOFF_(m_ds);
3051 case R_ES: return 4 * VGOFF_(m_es);
3052 case R_FS: return 4 * VGOFF_(m_fs);
3053 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003054 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003055 }
3056}
3057
njnf4ce3d32003-02-10 10:17:26 +00003058UInt VG_(get_archreg) ( UInt arch )
3059{
3060 switch (arch) {
3061 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3062 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3063 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3064 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3065 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3066 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3067 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3068 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
3069 default: VG_(core_panic)( "get_thread_archreg");
3070 }
3071}
3072
3073UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3074{
3075 ThreadState* tst;
3076
3077 vg_assert(VG_(is_valid_tid)(tid));
3078 tst = & VG_(threads)[tid];
3079
3080 switch (arch) {
3081 case R_EAX: return tst->m_eax;
3082 case R_ECX: return tst->m_ecx;
3083 case R_EDX: return tst->m_edx;
3084 case R_EBX: return tst->m_ebx;
3085 case R_ESP: return tst->m_esp;
3086 case R_EBP: return tst->m_ebp;
3087 case R_ESI: return tst->m_esi;
3088 case R_EDI: return tst->m_edi;
3089 default: VG_(core_panic)( "get_thread_archreg");
3090 }
3091}
3092
njnb93d1782003-02-03 12:03:22 +00003093/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003094static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003095{
3096 switch (arch) {
3097 case R_EAX: return VGOFF_(sh_eax);
3098 case R_ECX: return VGOFF_(sh_ecx);
3099 case R_EDX: return VGOFF_(sh_edx);
3100 case R_EBX: return VGOFF_(sh_ebx);
3101 case R_ESP: return VGOFF_(sh_esp);
3102 case R_EBP: return VGOFF_(sh_ebp);
3103 case R_ESI: return VGOFF_(sh_esi);
3104 case R_EDI: return VGOFF_(sh_edi);
3105 default: VG_(core_panic)( "shadow_reg_index");
3106 }
3107}
sewardjde4a1d02002-03-22 01:27:54 +00003108
njn25e49d8e72002-09-23 09:36:25 +00003109/* Return the byte offset from %ebp (ie, into baseBlock)
3110 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003111Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003112{
njnb93d1782003-02-03 12:03:22 +00003113 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003114}
3115
njn4ba5a792002-09-30 10:23:54 +00003116Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003117{
3118 return 4 * VGOFF_(sh_eflags);
3119}
3120
njnb93d1782003-02-03 12:03:22 +00003121/* Accessing shadow arch. registers */
3122UInt VG_(get_shadow_archreg) ( UInt archreg )
3123{
3124 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3125}
3126
3127void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3128{
3129 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3130}
3131
njnd3040452003-05-19 15:04:06 +00003132void VG_(set_shadow_eflags) ( UInt val )
3133{
3134 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3135}
3136
njnf4ce3d32003-02-10 10:17:26 +00003137UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3138{
3139 ThreadState* tst;
3140
3141 vg_assert(VG_(is_valid_tid)(tid));
3142 tst = & VG_(threads)[tid];
3143
3144 switch (archreg) {
3145 case R_EAX: return tst->sh_eax;
3146 case R_ECX: return tst->sh_ecx;
3147 case R_EDX: return tst->sh_edx;
3148 case R_EBX: return tst->sh_ebx;
3149 case R_ESP: return tst->sh_esp;
3150 case R_EBP: return tst->sh_ebp;
3151 case R_ESI: return tst->sh_esi;
3152 case R_EDI: return tst->sh_edi;
3153 default: VG_(core_panic)( "get_thread_shadow_archreg");
3154 }
3155}
3156
3157void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3158{
3159 ThreadState* tst;
3160
3161 vg_assert(VG_(is_valid_tid)(tid));
3162 tst = & VG_(threads)[tid];
3163
3164 switch (archreg) {
3165 case R_EAX: tst->sh_eax = val; break;
3166 case R_ECX: tst->sh_ecx = val; break;
3167 case R_EDX: tst->sh_edx = val; break;
3168 case R_EBX: tst->sh_ebx = val; break;
3169 case R_ESP: tst->sh_esp = val; break;
3170 case R_EBP: tst->sh_ebp = val; break;
3171 case R_ESI: tst->sh_esi = val; break;
3172 case R_EDI: tst->sh_edi = val; break;
3173 default: VG_(core_panic)( "set_thread_shadow_archreg");
3174 }
3175}
3176
njnb93d1782003-02-03 12:03:22 +00003177Addr VG_(shadow_archreg_address) ( UInt archreg )
3178{
3179 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3180}
sewardjde4a1d02002-03-22 01:27:54 +00003181
sewardjde4a1d02002-03-22 01:27:54 +00003182static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3183{
3184 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003185 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3186 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003187 }
3188 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003189 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3190 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003191 }
3192 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003193 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3194 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003195 }
3196 else
njne427a662002-10-02 11:08:25 +00003197 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003198}
3199
3200
sewardjde4a1d02002-03-22 01:27:54 +00003201/*----------------------------------------------------*/
3202/*--- Generate code for a single UInstr. ---*/
3203/*----------------------------------------------------*/
3204
sewardj478335c2002-10-05 02:44:47 +00003205static __inline__
3206Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003207{
3208 return (u->flags_w != FlagsEmpty);
3209}
3210
sewardjfa492d42002-12-08 18:20:01 +00003211static __inline__
3212Bool readFlagUse ( UInstr* u )
3213{
3214 /* If the UInstr writes some flags but not all, then we still need
3215 to consider it as reading flags so that the unchanged values are
3216 passed through properly. (D is special) */
3217 return
3218 (u->flags_r != FlagsEmpty) ||
3219 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3220}
3221
sewardj478335c2002-10-05 02:44:47 +00003222static __inline__
3223Bool anyFlagUse ( UInstr* u )
3224{
sewardjfa492d42002-12-08 18:20:01 +00003225 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003226}
3227
3228
sewardjb91ae7f2003-04-29 23:50:00 +00003229/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3230 the real machine's cpu. If so we need to be very careful not to trash it.
3231 If FPU/SSE state is live and we deem it necessary to copy it back to
3232 the simulated machine's FPU/SSE state, we do so. The final state of
3233 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003234 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003235 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003236*/
sewardjb5ff83e2002-12-01 19:40:49 +00003237static void emitUInstr ( UCodeBlock* cb, Int i,
3238 RRegSet regs_live_before,
3239 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003240 Bool* sselive, /* True<==>FPU/SSE
3241 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003242 Addr* orig_eip, /* previous curr_eip, or zero */
3243 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003244{
njn25e49d8e72002-09-23 09:36:25 +00003245 Int old_emitted_code_used;
3246 UInstr* u = &cb->instrs[i];
3247
sewardjde4a1d02002-03-22 01:27:54 +00003248 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003249 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003250
njn25e49d8e72002-09-23 09:36:25 +00003251 old_emitted_code_used = emitted_code_used;
3252
sewardjde4a1d02002-03-22 01:27:54 +00003253 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003254 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003255
sewardjb5ff83e2002-12-01 19:40:49 +00003256 case INCEIP:
3257 /* Advance %EIP some small amount. */
3258 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003259
sewardjb5ff83e2002-12-01 19:40:49 +00003260 if (*orig_eip == 0 /* we don't know what the old value was */
3261 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3262 /* We have to update all 32 bits of the value. */
3263 VG_(emit_movv_lit_offregmem)(
3264 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3265 } else {
3266 /* Cool! we only need to update lowest 8 bits */
3267 VG_(emit_movb_lit_offregmem)(
3268 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003269 }
njn25e49d8e72002-09-23 09:36:25 +00003270
sewardjb5ff83e2002-12-01 19:40:49 +00003271 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003272 break;
sewardjde4a1d02002-03-22 01:27:54 +00003273
3274 case LEA1: {
3275 vg_assert(u->tag1 == RealReg);
3276 vg_assert(u->tag2 == RealReg);
3277 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3278 break;
3279 }
3280
3281 case LEA2: {
3282 vg_assert(u->tag1 == RealReg);
3283 vg_assert(u->tag2 == RealReg);
3284 vg_assert(u->tag3 == RealReg);
3285 emit_lea_sib_reg ( u->lit32, u->extra4b,
3286 u->val1, u->val2, u->val3 );
3287 break;
3288 }
3289
3290 case WIDEN: {
3291 vg_assert(u->tag1 == RealReg);
3292 if (u->signed_widen) {
3293 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3294 } else {
3295 /* no need to generate any code. */
3296 }
3297 break;
3298 }
3299
sewardjde4a1d02002-03-22 01:27:54 +00003300 case STORE: {
3301 vg_assert(u->tag1 == RealReg);
3302 vg_assert(u->tag2 == RealReg);
3303 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003304 break;
3305 }
3306
3307 case LOAD: {
3308 vg_assert(u->tag1 == RealReg);
3309 vg_assert(u->tag2 == RealReg);
3310 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3311 break;
3312 }
3313
sewardjde4a1d02002-03-22 01:27:54 +00003314 case GET: {
3315 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3316 vg_assert(u->tag2 == RealReg);
3317 synth_mov_offregmem_reg (
3318 u->size,
3319 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3320 R_EBP,
3321 u->val2
3322 );
3323 break;
3324 }
3325
3326 case PUT: {
3327 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3328 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003329 synth_mov_reg_offregmem (
3330 u->size,
3331 u->val1,
3332 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3333 R_EBP
3334 );
sewardjde4a1d02002-03-22 01:27:54 +00003335 break;
3336 }
3337
sewardje1042472002-09-30 12:33:11 +00003338 case GETSEG: {
3339 vg_assert(u->tag1 == ArchRegS);
3340 vg_assert(u->tag2 == RealReg);
3341 vg_assert(u->size == 2);
3342 synth_mov_offregmem_reg (
3343 4,
3344 segRegOffset( u->val1 ),
3345 R_EBP,
3346 u->val2
3347 );
3348 break;
3349 }
3350
3351 case PUTSEG: {
3352 vg_assert(u->tag1 == RealReg);
3353 vg_assert(u->tag2 == ArchRegS);
3354 vg_assert(u->size == 2);
3355 synth_mov_reg_offregmem (
3356 4,
3357 u->val1,
3358 segRegOffset( u->val2 ),
3359 R_EBP
3360 );
3361 break;
3362 }
3363
sewardjde4a1d02002-03-22 01:27:54 +00003364 case GETF: {
3365 vg_assert(u->size == 2 || u->size == 4);
3366 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003367
3368 /* This complexity is because the D(irection) flag is stored
3369 separately from the rest of EFLAGS. */
3370
3371 /* We're only fetching from the Simd state, so make sure it's
3372 up to date. */
3373 maybe_emit_put_eflags();
3374
3375 /* get D in u->val1 (== 1 or -1) */
3376 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3377
3378 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3379 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3380
3381 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3382 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3383 eflagsOffset(), R_EBP);
3384
3385 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3386 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3387 eflagsOffset(), R_EBP);
3388
3389 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3390 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3391 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003392 break;
3393 }
3394
3395 case PUTF: {
3396 vg_assert(u->size == 2 || u->size == 4);
3397 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003398
3399 /* When putting a value into EFLAGS, this generates the
3400 correct value for m_dflag (-1 or 1), and clears the D bit
3401 in EFLAGS. */
3402
3403 /* We're updating the whole flag state, so the old state
3404 doesn't matter; make sure that the new simulated state
3405 will be fetched when needed. */
3406 eflags_state = UPD_Simd;
3407
3408 /* store EFLAGS (with D) */
3409 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3410
3411 /* u->val1 &= EFlagD */
3412 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3413
3414 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3415 synth_unaryop_reg(False, NEG, u->size, u->val1);
3416 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3417 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3418
3419 /* save D */
3420 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3421
3422 /* EFLAGS &= ~EFlagD */
3423 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3424 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003425 break;
3426 }
3427
3428 case MOV: {
3429 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3430 vg_assert(u->tag2 == RealReg);
3431 switch (u->tag1) {
3432 case RealReg: vg_assert(u->size == 4);
3433 if (u->val1 != u->val2)
3434 synth_movl_reg_reg ( u->val1, u->val2 );
3435 break;
3436 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3437 break;
njne427a662002-10-02 11:08:25 +00003438 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003439 }
3440 break;
3441 }
3442
sewardje1042472002-09-30 12:33:11 +00003443 case USESEG: {
3444 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3445 ones. */
sewardjd077f532002-09-30 21:52:50 +00003446 UInt argv[] = { u->val1, u->val2 };
3447 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003448 UInt ret_reg = u->val2;
3449
3450 vg_assert(u->tag1 == RealReg);
3451 vg_assert(u->tag2 == RealReg);
3452 vg_assert(u->size == 0);
3453
sewardjb91ae7f2003-04-29 23:50:00 +00003454 if (*sselive) {
3455 emit_put_sse_state();
3456 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003457 }
3458
sewardje1042472002-09-30 12:33:11 +00003459 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3460 2, /* args */
3461 0, /* regparms_n */
3462 argv, tagv,
3463 ret_reg, regs_live_before, u->regs_live_after );
3464 break;
3465 }
3466
sewardj478335c2002-10-05 02:44:47 +00003467 case SBB:
3468 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003469 case XOR:
3470 case OR:
3471 case AND:
3472 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003473 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003474 vg_assert(u->tag2 == RealReg);
3475 switch (u->tag1) {
3476 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003477 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003478 u->opcode, u->size, u->lit32, u->val2 );
3479 break;
3480 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003481 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003482 u->opcode, u->size, u->val1, u->val2 );
3483 break;
3484 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003485 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003486 u->opcode, u->size,
3487 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3488 R_EBP,
3489 u->val2 );
3490 break;
njne427a662002-10-02 11:08:25 +00003491 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003492 }
3493 break;
3494 }
3495
sewardj478335c2002-10-05 02:44:47 +00003496 case RCR:
3497 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003498 case ROR:
3499 case ROL:
3500 case SAR:
3501 case SHR:
3502 case SHL: {
3503 vg_assert(u->tag2 == RealReg);
3504 switch (u->tag1) {
3505 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003506 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003507 u->opcode, u->size, u->lit32, u->val2 );
3508 break;
3509 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003510 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003511 u->opcode, u->size, u->val1, u->val2 );
3512 break;
njne427a662002-10-02 11:08:25 +00003513 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003514 }
3515 break;
3516 }
3517
3518 case INC:
3519 case DEC:
3520 case NEG:
3521 case NOT:
3522 vg_assert(u->tag1 == RealReg);
3523 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003524 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003525 break;
3526
3527 case BSWAP:
3528 vg_assert(u->tag1 == RealReg);
3529 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003530 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003531 emit_bswapl_reg ( u->val1 );
3532 break;
3533
3534 case CMOV:
3535 vg_assert(u->tag1 == RealReg);
3536 vg_assert(u->tag2 == RealReg);
3537 vg_assert(u->cond != CondAlways);
3538 vg_assert(u->size == 4);
3539 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3540 break;
3541
3542 case JMP: {
3543 vg_assert(u->tag2 == NoValue);
3544 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003545 if (*sselive) {
3546 emit_put_sse_state();
3547 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003548 }
sewardjde4a1d02002-03-22 01:27:54 +00003549 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003550 switch (u->tag1) {
3551 case RealReg:
3552 synth_jmp_reg ( u->val1, u->jmpkind );
3553 break;
3554 case Literal:
3555 synth_jmp_lit ( u->lit32, u->jmpkind );
3556 break;
3557 default:
njne427a662002-10-02 11:08:25 +00003558 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003559 break;
sewardjde4a1d02002-03-22 01:27:54 +00003560 }
3561 } else {
sewardj2e93c502002-04-12 11:12:52 +00003562 switch (u->tag1) {
3563 case RealReg:
njne427a662002-10-02 11:08:25 +00003564 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003565 break;
3566 case Literal:
3567 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003568 /* %eax had better not be live since synth_jcond_lit
3569 trashes it in some circumstances. If that turns
3570 out to be a problem we can get synth_jcond_lit to
3571 push/pop it when it is live. */
3572 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3573 u->regs_live_after));
3574 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003575 break;
3576 default:
njne427a662002-10-02 11:08:25 +00003577 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003578 break;
sewardjde4a1d02002-03-22 01:27:54 +00003579 }
3580 }
3581 break;
3582 }
3583
3584 case JIFZ:
3585 vg_assert(u->tag1 == RealReg);
3586 vg_assert(u->tag2 == Literal);
3587 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003588 if (*sselive) {
3589 emit_put_sse_state();
3590 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003591 }
sewardjde4a1d02002-03-22 01:27:54 +00003592 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3593 break;
3594
sewardjde4a1d02002-03-22 01:27:54 +00003595 case PUSH:
3596 vg_assert(u->tag1 == RealReg);
3597 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003598 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003599 break;
3600
3601 case POP:
3602 vg_assert(u->tag1 == RealReg);
3603 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003604 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003605 break;
3606
3607 case CALLM:
3608 vg_assert(u->tag1 == Lit16);
3609 vg_assert(u->tag2 == NoValue);
3610 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003611 if (*sselive) {
3612 emit_put_sse_state();
3613 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003614 }
sewardjfa492d42002-12-08 18:20:01 +00003615 /* Call to a helper which is pretending to be a real CPU
3616 instruction (and therefore operates on Real flags and
3617 registers) */
3618 VG_(synth_call) ( False, u->val1,
3619 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003620 break;
3621
njn25e49d8e72002-09-23 09:36:25 +00003622 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003623 /* If you change this, remember to change USESEG above, since
3624 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003625 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3626 ones. */
3627 UInt argv[] = { u->val1, u->val2, u->val3 };
3628 UInt tagv[] = { RealReg, RealReg, RealReg };
3629 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3630
3631 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3632 else vg_assert(u->tag1 == NoValue);
3633 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3634 else vg_assert(u->tag2 == NoValue);
3635 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3636 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003637 vg_assert(u->size == 0);
3638
sewardjb91ae7f2003-04-29 23:50:00 +00003639 if (*sselive) {
3640 emit_put_sse_state();
3641 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003642 }
njn25e49d8e72002-09-23 09:36:25 +00003643 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3644 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003645 break;
njn25e49d8e72002-09-23 09:36:25 +00003646 }
sewardje1042472002-09-30 12:33:11 +00003647
sewardjde4a1d02002-03-22 01:27:54 +00003648 case CLEAR:
3649 vg_assert(u->tag1 == Lit16);
3650 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003651 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003652 break;
3653
3654 case CC2VAL:
3655 vg_assert(u->tag1 == RealReg);
3656 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003657 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003658 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003659 break;
3660
sewardjde4a1d02002-03-22 01:27:54 +00003661 case FPU_R:
3662 case FPU_W:
3663 vg_assert(u->tag1 == Lit16);
3664 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003665 if (!(*sselive)) {
3666 emit_get_sse_state();
3667 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003668 }
sewardjfa492d42002-12-08 18:20:01 +00003669 synth_fpu_regmem ( u->flags_r, u->flags_w,
3670 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003671 u->val1 & 0xFF,
3672 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003673 break;
3674
3675 case FPU:
3676 vg_assert(u->tag1 == Lit16);
3677 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003678 if (!(*sselive)) {
3679 emit_get_sse_state();
3680 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003681 }
sewardjfa492d42002-12-08 18:20:01 +00003682 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3683 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003684 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003685 break;
3686
sewardj3d7c9c82003-03-26 21:08:13 +00003687 case MMX2_MemWr:
3688 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003689 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003690 vg_assert(u->tag1 == Lit16);
3691 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003692 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003693 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003694 if (!(*sselive)) {
3695 emit_get_sse_state();
3696 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003697 }
3698 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3699 (u->val1 >> 8) & 0xFF,
3700 u->val1 & 0xFF,
3701 u->val2 );
3702 break;
3703
sewardjca860012003-03-27 23:52:58 +00003704 case MMX2_RegRd:
3705 vg_assert(u->tag1 == Lit16);
3706 vg_assert(u->tag2 == RealReg);
3707 vg_assert(u->tag3 == NoValue);
3708 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003709 if (!(*sselive)) {
3710 emit_get_sse_state();
3711 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003712 }
3713 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3714 (u->val1 >> 8) & 0xFF,
3715 u->val1 & 0xFF,
3716 u->val2 );
3717 break;
3718
sewardjd1c9e432003-04-04 20:40:34 +00003719 case MMX2_RegWr:
3720 vg_assert(u->tag1 == Lit16);
3721 vg_assert(u->tag2 == RealReg);
3722 vg_assert(u->tag3 == NoValue);
3723 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003724 if (!(*sselive)) {
3725 emit_get_sse_state();
3726 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003727 }
3728 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3729 (u->val1 >> 8) & 0xFF,
3730 u->val1 & 0xFF,
3731 u->val2 );
3732 break;
3733
sewardj3d7c9c82003-03-26 21:08:13 +00003734 case MMX1:
3735 vg_assert(u->tag1 == Lit16);
3736 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003737 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003738 if (!(*sselive)) {
3739 emit_get_sse_state();
3740 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003741 }
3742 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3743 u->val1 & 0xFF );
3744 break;
3745
3746 case MMX2:
3747 vg_assert(u->tag1 == Lit16);
3748 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003749 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003750 if (!(*sselive)) {
3751 emit_get_sse_state();
3752 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003753 }
3754 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3755 (u->val1 >> 8) & 0xFF,
3756 u->val1 & 0xFF );
3757 break;
3758
sewardjca860012003-03-27 23:52:58 +00003759 case MMX3:
3760 vg_assert(u->tag1 == Lit16);
3761 vg_assert(u->tag2 == Lit16);
3762 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003763 if (!(*sselive)) {
3764 emit_get_sse_state();
3765 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003766 }
3767 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3768 (u->val1 >> 8) & 0xFF,
3769 u->val1 & 0xFF,
3770 u->val2 & 0xFF );
3771 break;
3772
sewardjfebaa3b2003-05-25 01:07:34 +00003773 case SSE2a_MemWr:
3774 case SSE2a_MemRd:
3775 vg_assert(u->size == 4 || u->size == 16);
3776 vg_assert(u->tag1 == Lit16);
3777 vg_assert(u->tag2 == Lit16);
3778 vg_assert(u->tag3 == RealReg);
3779 vg_assert(!anyFlagUse(u));
3780 if (!(*sselive)) {
3781 emit_get_sse_state();
3782 *sselive = True;
3783 }
3784 emit_SSE2a ( u->flags_r, u->flags_w,
3785 (u->val1 >> 8) & 0xFF,
3786 u->val1 & 0xFF,
3787 u->val2 & 0xFF,
3788 u->val3 );
3789 break;
3790
3791 case SSE3a_MemWr:
3792 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00003793 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00003794 vg_assert(u->tag1 == Lit16);
3795 vg_assert(u->tag2 == Lit16);
3796 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003797 if (!(*sselive)) {
3798 emit_get_sse_state();
3799 *sselive = True;
3800 }
3801 emit_SSE3a ( u->flags_r, u->flags_w,
3802 (u->val1 >> 8) & 0xFF,
3803 u->val1 & 0xFF,
3804 (u->val2 >> 8) & 0xFF,
3805 u->val2 & 0xFF,
3806 u->val3 );
3807 break;
3808
3809 case SSE3g_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00003810 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00003811 vg_assert(u->size == 4);
3812 vg_assert(u->tag1 == Lit16);
3813 vg_assert(u->tag2 == Lit16);
3814 vg_assert(u->tag3 == RealReg);
3815 vg_assert(!anyFlagUse(u));
3816 if (!(*sselive)) {
3817 emit_get_sse_state();
3818 *sselive = True;
3819 }
sewardj8f33ba62003-06-14 12:00:45 +00003820 if (u->opcode==SSE3g_RegRd) {
3821 emit_SSE3g_RegRd ( u->flags_r, u->flags_w,
3822 (u->val1 >> 8) & 0xFF,
3823 u->val1 & 0xFF,
3824 (u->val2 >> 8) & 0xFF,
3825 u->val2 & 0xFF,
3826 u->val3 );
3827 } else {
3828 emit_SSE3g_RegWr ( u->flags_r, u->flags_w,
3829 (u->val1 >> 8) & 0xFF,
3830 u->val1 & 0xFF,
3831 (u->val2 >> 8) & 0xFF,
3832 u->val2 & 0xFF,
3833 u->val3 );
3834 }
sewardjfebaa3b2003-05-25 01:07:34 +00003835 break;
3836
sewardjb31b06d2003-06-13 00:26:02 +00003837 case SSE3g1_RegWr:
3838 vg_assert(u->size == 4);
3839 vg_assert(u->tag1 == Lit16);
3840 vg_assert(u->tag2 == Lit16);
3841 vg_assert(u->tag3 == RealReg);
3842 vg_assert(!anyFlagUse(u));
3843 if (!(*sselive)) {
3844 emit_get_sse_state();
3845 *sselive = True;
3846 }
3847 emit_SSE3g1_RegWr ( u->flags_r, u->flags_w,
3848 (u->val1 >> 8) & 0xFF,
3849 u->val1 & 0xFF,
3850 (u->val2 >> 8) & 0xFF,
3851 u->val2 & 0xFF,
3852 u->lit32 & 0xFF,
3853 u->val3 );
3854 break;
3855
3856 case SSE3g1_RegRd:
3857 vg_assert(u->size == 2);
3858 vg_assert(u->tag1 == Lit16);
3859 vg_assert(u->tag2 == Lit16);
3860 vg_assert(u->tag3 == RealReg);
3861 vg_assert(!anyFlagUse(u));
3862 if (!(*sselive)) {
3863 emit_get_sse_state();
3864 *sselive = True;
3865 }
3866 emit_SSE3g1_RegRd ( u->flags_r, u->flags_w,
3867 (u->val1 >> 8) & 0xFF,
3868 u->val1 & 0xFF,
3869 (u->val2 >> 8) & 0xFF,
3870 u->val2 & 0xFF,
3871 u->lit32 & 0xFF,
3872 u->val3 );
3873 break;
3874
sewardjfebaa3b2003-05-25 01:07:34 +00003875 case SSE4:
3876 vg_assert(u->size == 0);
3877 vg_assert(u->tag1 == Lit16);
3878 vg_assert(u->tag2 == Lit16);
3879 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00003880 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00003881 if (!(*sselive)) {
3882 emit_get_sse_state();
3883 *sselive = True;
3884 }
3885 emit_SSE4 ( u->flags_r, u->flags_w,
3886 (u->val1 >> 8) & 0xFF,
3887 u->val1 & 0xFF,
3888 (u->val2 >> 8) & 0xFF,
3889 u->val2 & 0xFF );
3890 break;
3891
sewardja60be0e2003-05-26 08:47:27 +00003892 case SSE3:
3893 vg_assert(u->size == 0);
3894 vg_assert(u->tag1 == Lit16);
3895 vg_assert(u->tag2 == Lit16);
3896 vg_assert(u->tag3 == NoValue);
3897 vg_assert(!anyFlagUse(u));
3898 if (!(*sselive)) {
3899 emit_get_sse_state();
3900 *sselive = True;
3901 }
3902 emit_SSE3 ( u->flags_r, u->flags_w,
3903 (u->val1 >> 8) & 0xFF,
3904 u->val1 & 0xFF,
3905 u->val2 & 0xFF );
3906 break;
3907
sewardjde4a1d02002-03-22 01:27:54 +00003908 default:
sewardj1b7d8022002-11-30 12:35:42 +00003909 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003910 if (*sselive) {
3911 emit_put_sse_state();
3912 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003913 }
njn4ba5a792002-09-30 10:23:54 +00003914 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003915 } else {
njn25e49d8e72002-09-23 09:36:25 +00003916 VG_(printf)("\nError:\n"
3917 " unhandled opcode: %u. Perhaps "
3918 " VG_(needs).extended_UCode should be set?\n",
3919 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003920 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003921 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003922 }
sewardjde4a1d02002-03-22 01:27:54 +00003923 }
3924
sewardjb91ae7f2003-04-29 23:50:00 +00003925 if (0 && (*sselive)) {
3926 emit_put_sse_state();
3927 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003928 }
3929
njn25e49d8e72002-09-23 09:36:25 +00003930 /* Update UInstr histogram */
3931 vg_assert(u->opcode < 100);
3932 histogram[u->opcode].counts++;
3933 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003934}
3935
3936
3937/* Emit x86 for the ucode in cb, returning the address of the
3938 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003939UChar* VG_(emit_code) ( UCodeBlock* cb,
3940 Int* nbytes,
3941 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003942{
3943 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003944 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003945 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003946 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003947 Int tgt;
3948
sewardjfa492d42002-12-08 18:20:01 +00003949 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003950
njn25e49d8e72002-09-23 09:36:25 +00003951 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003952
sewardj22854b92002-11-30 14:00:47 +00003953 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3954 zero. We have to do this regardless of whether we're t-chaining
3955 or not. */
sewardja2113f92002-12-12 23:42:48 +00003956 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003957 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003958 VG_(emitB) (0xFF); /* decl */
3959 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3960 if (dis)
3961 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003962 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003963 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3964 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003965 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003966
sewardjb5ff83e2002-12-01 19:40:49 +00003967 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00003968 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00003969 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003970 curr_eip = cb->orig_eip;
3971 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3972 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003973 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003974 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003975 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003976 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003977
sewardjde4a1d02002-03-22 01:27:54 +00003978 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003979 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003980 if (!sane) {
3981 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003982 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003983 }
3984 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003985 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00003986 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003987 }
njn25e49d8e72002-09-23 09:36:25 +00003988 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003989 }
njn25e49d8e72002-09-23 09:36:25 +00003990 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00003991 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00003992 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003993
sewardj22854b92002-11-30 14:00:47 +00003994 if (j != NULL) {
3995 vg_assert(jumpidx <= VG_MAX_JUMPS);
3996 for(i = 0; i < jumpidx; i++)
3997 j[i] = jumps[i];
3998 }
3999
sewardjde4a1d02002-03-22 01:27:54 +00004000 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004001 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004002 *nbytes = emitted_code_used;
4003 return emitted_code;
4004}
4005
njn25e49d8e72002-09-23 09:36:25 +00004006#undef dis
4007
sewardjde4a1d02002-03-22 01:27:54 +00004008/*--------------------------------------------------------------------*/
4009/*--- end vg_from_ucode.c ---*/
4010/*--------------------------------------------------------------------*/