blob: 0b90f11146aa527be28eafdd441bcf5cdf5aec60 [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
1461static void emit_SSE3g ( FlagSet uses_sflags,
1462 FlagSet sets_sflags,
1463 UChar first_byte,
1464 UChar second_byte,
1465 UChar third_byte,
1466 UChar fourth_byte,
sewardj02af6bc2003-06-12 00:56:06 +00001467 Int ireg,
1468 Bool reads_ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001469{
1470 VG_(new_emit)(True, uses_sflags, sets_sflags);
1471 VG_(emitB) ( first_byte );
1472 VG_(emitB) ( second_byte );
1473 VG_(emitB) ( third_byte );
1474 fourth_byte &= 0x38; /* mask out mod and rm fields */
1475 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1476 fourth_byte |= (ireg & 7); /* patch in our ireg */
1477 VG_(emitB) ( fourth_byte );
1478 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001479 VG_(printf)(
1480 reads_ireg
1481 ? "\n\t\tireg-to-ssereg--0x%x:0x%x:0x%x:0x%x-(%s)\n"
1482 : "\n\t\tssereg-to-ireg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
1483 (UInt)first_byte, (UInt)second_byte,
1484 (UInt)third_byte, (UInt)fourth_byte,
1485 nameIReg(4,ireg)
1486 );
sewardjfebaa3b2003-05-25 01:07:34 +00001487}
1488
1489static void emit_SSE4 ( FlagSet uses_sflags,
1490 FlagSet sets_sflags,
1491 UChar first_byte,
1492 UChar second_byte,
1493 UChar third_byte,
1494 UChar fourth_byte )
1495{
1496 VG_(new_emit)(True, uses_sflags, sets_sflags);
1497 VG_(emitB) ( first_byte );
1498 VG_(emitB) ( second_byte );
1499 VG_(emitB) ( third_byte );
1500 VG_(emitB) ( fourth_byte );
1501 if (dis)
1502 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x\n",
1503 (UInt)first_byte, (UInt)second_byte,
1504 (UInt)third_byte, (UInt)fourth_byte );
1505}
1506
sewardja60be0e2003-05-26 08:47:27 +00001507static void emit_SSE3 ( FlagSet uses_sflags,
1508 FlagSet sets_sflags,
1509 UChar first_byte,
1510 UChar second_byte,
1511 UChar third_byte )
1512{
1513 VG_(new_emit)(True, uses_sflags, sets_sflags);
1514 VG_(emitB) ( first_byte );
1515 VG_(emitB) ( second_byte );
1516 VG_(emitB) ( third_byte );
1517 if (dis)
1518 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x\n",
1519 (UInt)first_byte, (UInt)second_byte,
1520 (UInt)third_byte );
1521}
1522
sewardjca860012003-03-27 23:52:58 +00001523static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1524 FlagSet sets_sflags,
1525 UChar first_byte,
1526 UChar second_byte,
1527 Int ireg )
1528{
1529 VG_(new_emit)(True, uses_sflags, sets_sflags);
1530 VG_(emitB) ( 0x0F );
1531 VG_(emitB) ( first_byte );
1532 second_byte &= 0x38; /* mask out mod and rm fields */
1533 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1534 second_byte |= (ireg & 7); /* patch in our ireg */
1535 VG_(emitB) ( second_byte );
1536 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001537 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1538 (UInt)first_byte, (UInt)second_byte,
1539 nameIReg(4,ireg) );
1540}
1541
1542static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1543 FlagSet sets_sflags,
1544 UChar first_byte,
1545 UChar second_byte,
1546 Int ireg )
1547{
1548 VG_(new_emit)(True, uses_sflags, sets_sflags);
1549 VG_(emitB) ( 0x0F );
1550 VG_(emitB) ( first_byte );
1551 second_byte &= 0x38; /* mask out mod and rm fields */
1552 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1553 second_byte |= (ireg & 7); /* patch in our ireg */
1554 VG_(emitB) ( second_byte );
1555 if (dis)
1556 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001557 (UInt)first_byte, (UInt)second_byte,
1558 nameIReg(4,ireg) );
1559}
1560
1561static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1562 FlagSet sets_sflags,
1563 UChar first_byte,
1564 UChar second_byte,
1565 UChar third_byte )
1566{
1567 VG_(new_emit)(True, uses_sflags, sets_sflags);
1568 VG_(emitB) ( 0x0F );
1569 VG_(emitB) ( first_byte );
1570 VG_(emitB) ( second_byte );
1571 VG_(emitB) ( third_byte );
1572 if (dis)
1573 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1574 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1575}
1576
sewardj3d7c9c82003-03-26 21:08:13 +00001577static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1578 FlagSet sets_sflags,
1579 UChar first_byte,
1580 UChar second_byte )
1581{
1582 VG_(new_emit)(True, uses_sflags, sets_sflags);
1583 VG_(emitB) ( 0x0F );
1584 VG_(emitB) ( first_byte );
1585 VG_(emitB) ( second_byte );
1586 if (dis)
1587 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1588 (UInt)first_byte, (UInt)second_byte );
1589}
1590
1591static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1592 FlagSet sets_sflags,
1593 UChar first_byte )
1594{
1595 VG_(new_emit)(True, uses_sflags, sets_sflags);
1596 VG_(emitB) ( 0x0F );
1597 VG_(emitB) ( first_byte );
1598 if (dis)
1599 VG_(printf)("\n\t\tmmx1-0x%x\n",
1600 (UInt)first_byte );
1601}
1602
sewardjde4a1d02002-03-22 01:27:54 +00001603
1604/*----------------------------------------------------*/
1605/*--- misc instruction emitters ---*/
1606/*----------------------------------------------------*/
1607
njn25e49d8e72002-09-23 09:36:25 +00001608void VG_(emit_call_reg) ( Int reg )
1609{
sewardjfa492d42002-12-08 18:20:01 +00001610 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001611 VG_(emitB) ( 0xFF ); /* Grp5 */
1612 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1613 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001614 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001615}
1616
sewardjf0f12aa2002-12-28 00:04:08 +00001617static
1618void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1619 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001620{
sewardjfa492d42002-12-08 18:20:01 +00001621 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001622 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001623
1624 if (byte_off < -128 || byte_off > 127) {
1625 VG_(emitB) ( 0xFF );
1626 VG_(emitB) ( 0x95 );
1627 VG_(emitL) ( byte_off );
1628 } else {
1629 VG_(emitB) ( 0xFF );
1630 VG_(emitB) ( 0x55 );
1631 VG_(emitB) ( byte_off );
1632 }
1633 if (dis)
1634 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001635}
1636
sewardja2c5a732002-12-15 03:10:42 +00001637#if 0
1638/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001639static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1640{
1641 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001642 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001643 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1644 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001645 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001646 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001647 if (dis)
1648 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1649 nameIReg(4,regmem));
1650}
sewardja2c5a732002-12-15 03:10:42 +00001651#endif
sewardjde4a1d02002-03-22 01:27:54 +00001652
njn25e49d8e72002-09-23 09:36:25 +00001653void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001654{
njne427a662002-10-02 11:08:25 +00001655 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001656 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1657 VG_(emitB) ( 0x8D );
1658 VG_(emitB) ( 0x64 );
1659 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001660 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001661 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001662 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001663}
1664
1665
1666static void emit_movb_AL_zeroESPmem ( void )
1667{
1668 /* movb %al, 0(%esp) */
1669 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001670 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001671 VG_(emitB) ( 0x88 );
1672 VG_(emitB) ( 0x44 );
1673 VG_(emitB) ( 0x24 );
1674 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001675 if (dis)
1676 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1677}
1678
1679static void emit_movb_zeroESPmem_AL ( void )
1680{
1681 /* movb 0(%esp), %al */
1682 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001683 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001684 VG_(emitB) ( 0x8A );
1685 VG_(emitB) ( 0x44 );
1686 VG_(emitB) ( 0x24 );
1687 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001688 if (dis)
1689 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1690}
1691
sewardja2113f92002-12-12 23:42:48 +00001692/* Jump target states */
1693#define TGT_UNDEF (1 << 16)
1694#define TGT_FORWARD (2 << 16)
1695#define TGT_BACKWARD (3 << 16)
1696
1697static inline Int tgt_state(Int tgt)
1698{
1699 return tgt & 0xffff0000;
1700}
1701
1702static inline Int tgt_addr(Int tgt)
1703{
1704 return tgt & 0x0000ffff;
1705}
1706
1707static inline Int mk_tgt(Int state, Int addr)
1708{
1709 vg_assert(state == TGT_UNDEF
1710 || state == TGT_FORWARD || state == TGT_BACKWARD);
1711 vg_assert((addr & 0xffff0000) == 0);
1712
1713 return state | addr;
1714}
1715
1716void VG_(init_target) ( Int *tgt )
1717{
1718 *tgt = TGT_UNDEF;
1719}
1720
1721void VG_(target_back) ( Int *tgt )
1722{
1723 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1724
1725 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1726}
1727
1728void VG_(target_forward) ( Int *tgt )
1729{
1730 Int delta;
1731
1732 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1733 tgt_state(*tgt) == TGT_UNDEF);
1734
1735 if (tgt_state(*tgt) == TGT_UNDEF)
1736 return; /* target not used */
1737
1738 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1739 vg_assert(delta >= -128 && delta <= 127);
1740 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001741 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001742 emitted_code[tgt_addr(*tgt)] = delta;
1743 if (dis)
1744 VG_(printf)("(target to jump site %d; delta: %d)\n",
1745 tgt_addr(*tgt), delta);
1746}
1747
1748void VG_(emit_target_delta) ( Int *tgt )
1749{
1750 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1751 tgt_state(*tgt) == TGT_BACKWARD);
1752
1753 if (tgt_state(*tgt) == TGT_UNDEF) {
1754 /* forward jump */
1755 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1756 VG_(emitB) (0x00);
1757 } else {
1758 /* backward jump */
1759 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1760 vg_assert(delta >= -128 && delta <= 127);
1761 VG_(emitB) (delta);
1762 }
1763}
1764
sewardjde4a1d02002-03-22 01:27:54 +00001765
1766/* Emit a jump short with an 8-bit signed offset. Note that the
1767 offset is that which should be added to %eip once %eip has been
1768 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001769void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001770{
1771 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001772 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001773 VG_(emitB) ( 0x70 + (UInt)cond );
1774 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001775 if (dis)
1776 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001777 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001778}
1779
sewardja2113f92002-12-12 23:42:48 +00001780/* Same as above, but defers emitting the delta */
1781void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1782{
sewardj706240d2002-12-26 17:10:12 +00001783 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001784 VG_(emitB) ( 0x70 + (UInt)cond );
1785 VG_(emit_target_delta) (tgt);
1786 if (dis)
1787 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001788 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001789}
1790
1791
1792
sewardjf0f12aa2002-12-28 00:04:08 +00001793static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001794{
sewardjf0f12aa2002-12-28 00:04:08 +00001795 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001796 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1797 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001798 if (dis)
1799 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001800 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001801}
1802
1803static void emit_ret ( void )
1804{
sewardjfa492d42002-12-08 18:20:01 +00001805 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001807 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001808 if (dis)
1809 VG_(printf)("\n\t\tret\n");
1810}
1811
sewardj22854b92002-11-30 14:00:47 +00001812/* Predicate used in sanity checks elsewhere - returns true if any
1813 jump-site is an actual chained jump */
1814Bool VG_(is_chained_jumpsite)(Addr a)
1815{
1816 UChar *cp = (UChar *)a;
1817
1818 return (*cp == 0xE9); /* 0xE9 -- jmp */
1819}
1820
sewardj83f11862002-12-01 02:07:08 +00001821static
1822Bool is_fresh_jumpsite(UChar *cp)
1823{
1824 return
1825 cp[0] == 0x0F && /* UD2 */
1826 cp[1] == 0x0B &&
1827 cp[2] == 0x0F && /* UD2 */
1828 cp[3] == 0x0B &&
1829 cp[4] == 0x90; /* NOP */
1830}
1831
sewardj22854b92002-11-30 14:00:47 +00001832/* Predicate used in sanity checks elsewhere - returns true if all
1833 jump-sites are calls to VG_(patch_me) */
1834Bool VG_(is_unchained_jumpsite)(Addr a)
1835{
1836 UChar *cp = (UChar *)a;
1837 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1838 Int idelta;
1839
1840 if (*cp++ != 0xE8) /* 0xE8 == call */
1841 return False;
1842
1843 idelta = (*cp++) << 0;
1844 idelta |= (*cp++) << 8;
1845 idelta |= (*cp++) << 16;
1846 idelta |= (*cp++) << 24;
1847
1848 return idelta == delta;
1849}
1850
1851/* Return target address for a direct jmp */
1852Addr VG_(get_jmp_dest)(Addr a)
1853{
1854 Int delta;
1855 UChar *cp = (UChar *)a;
1856
1857 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1858 return 0;
1859
1860 delta = (*cp++) << 0;
1861 delta |= (*cp++) << 8;
1862 delta |= (*cp++) << 16;
1863 delta |= (*cp++) << 24;
1864
1865 return a + VG_PATCHME_JMPSZ + delta;
1866}
1867
1868/* unchain a BB by generating a call to VG_(patch_me) */
1869void VG_(unchain_jumpsite)(Addr a)
1870{
1871 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1872 UChar *cp = (UChar *)a;
1873
1874 if (VG_(is_unchained_jumpsite)(a))
1875 return; /* don't write unnecessarily */
1876
sewardj83f11862002-12-01 02:07:08 +00001877 if (!is_fresh_jumpsite(cp))
1878 VG_(bb_dechain_count)++; /* update stats */
1879
sewardj22854b92002-11-30 14:00:47 +00001880 *cp++ = 0xE8; /* call */
1881 *cp++ = (delta >> 0) & 0xff;
1882 *cp++ = (delta >> 8) & 0xff;
1883 *cp++ = (delta >> 16) & 0xff;
1884 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001885}
1886
1887/* This doesn't actually generate a call to VG_(patch_me), but
1888 reserves enough space in the instruction stream for it to happen
1889 and records the offset into the jump table. This is because call
1890 is a relative jump, and so will be affected when this code gets
1891 moved about. The translation table will "unchain" this basic block
1892 on insertion (with VG_(unchain_BB)()), and thereby generate a
1893 proper call instruction. */
1894static void emit_call_patchme( void )
1895{
1896 vg_assert(VG_PATCHME_CALLSZ == 5);
1897
sewardjfa492d42002-12-08 18:20:01 +00001898 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001899 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001900
1901 if (jumpidx >= VG_MAX_JUMPS) {
1902 /* If there too many jumps in this basic block, fall back to
1903 dispatch loop. We still need to keep it the same size as the
1904 call sequence. */
1905 VG_(emitB) ( 0xC3 ); /* ret */
1906 VG_(emitB) ( 0x90 ); /* nop */
1907 VG_(emitB) ( 0x90 ); /* nop */
1908 VG_(emitB) ( 0x90 ); /* nop */
1909 VG_(emitB) ( 0x90 ); /* nop */
1910
1911 if (dis)
1912 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1913
1914 if (0 && VG_(clo_verbosity))
1915 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1916 } else {
1917 jumps[jumpidx++] = emitted_code_used;
1918
1919 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1920 VG_(emitB) ( 0x0B );
1921 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1922 VG_(emitB) ( 0x0B );
1923 VG_(emitB) ( 0x90 ); /* NOP */
1924
1925 if (dis)
1926 VG_(printf)("\n\t\tud2; ud2; nop\n");
1927 }
1928}
1929
njn25e49d8e72002-09-23 09:36:25 +00001930void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001931{
sewardjf0f12aa2002-12-28 00:04:08 +00001932 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001933 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001934 if (dis)
1935 VG_(printf)("\n\t\tpushal\n");
1936}
1937
njn25e49d8e72002-09-23 09:36:25 +00001938void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001939{
sewardjf0f12aa2002-12-28 00:04:08 +00001940 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001941 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001942 if (dis)
1943 VG_(printf)("\n\t\tpopal\n");
1944}
1945
1946static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1947{
sewardjf0f12aa2002-12-28 00:04:08 +00001948 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001949 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1950 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001951 if (dis)
1952 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1953 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1954}
1955
1956static void emit_lea_sib_reg ( UInt lit, Int scale,
1957 Int regbase, Int regindex, Int reg )
1958{
sewardjf0f12aa2002-12-28 00:04:08 +00001959 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001960 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001961 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1962 if (dis)
1963 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1964 lit, nameIReg(4,regbase),
1965 nameIReg(4,regindex), scale,
1966 nameIReg(4,reg) );
1967}
1968
njn25e49d8e72002-09-23 09:36:25 +00001969void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001970{
sewardjf0f12aa2002-12-28 00:04:08 +00001971 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001972 VG_(emitB) ( 0x0F );
1973 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001974 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1975 if (dis)
1976 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1977}
1978
1979/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001980/*--- Helper offset -> addr translation ---*/
1981/*----------------------------------------------------*/
1982
1983/* Finds the baseBlock offset of a skin-specified helper.
1984 * Searches through compacts first, then non-compacts. */
1985Int VG_(helper_offset)(Addr a)
1986{
sewardj05bcdcb2003-05-18 10:05:38 +00001987 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00001988 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001989
1990 for (i = 0; i < VG_(n_compact_helpers); i++)
1991 if (VG_(compact_helper_addrs)[i] == a)
1992 return VG_(compact_helper_offsets)[i];
1993 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1994 if (VG_(noncompact_helper_addrs)[i] == a)
1995 return VG_(noncompact_helper_offsets)[i];
1996
1997 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001998 VG_(get_fnname) ( a, buf, 100 );
1999
njn25e49d8e72002-09-23 09:36:25 +00002000 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002001 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2002 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002003
2004 VG_(printf)(" compact helpers: ");
2005 for (i = 0; i < VG_(n_compact_helpers); i++)
2006 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2007
2008 VG_(printf)("\n non-compact helpers: ");
2009 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2010 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2011
2012 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002013 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002014}
2015
2016/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002017/*--- Instruction synthesisers ---*/
2018/*----------------------------------------------------*/
2019
2020static Condcode invertCondition ( Condcode cond )
2021{
2022 return (Condcode)(1 ^ (UInt)cond);
2023}
2024
2025
2026/* Synthesise a call to *baseBlock[offset], ie,
2027 call * (4 x offset)(%ebp).
2028*/
sewardjfa492d42002-12-08 18:20:01 +00002029void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002030 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002031{
2032 vg_assert(word_offset >= 0);
2033 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002034 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002035 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002036 }
sewardjf0f12aa2002-12-28 00:04:08 +00002037 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002038}
2039
njn25e49d8e72002-09-23 09:36:25 +00002040static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002041{
njn25e49d8e72002-09-23 09:36:25 +00002042 if (src != dst) {
2043 VG_(emit_movv_reg_reg) ( 4, src, dst );
2044 ccall_arg_setup_instrs++;
2045 }
njn6431be72002-07-28 09:53:34 +00002046}
njn25e49d8e72002-09-23 09:36:25 +00002047
2048/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2049static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2050{
2051 if (RealReg == tag) {
2052 maybe_emit_movl_reg_reg ( litOrReg, reg );
2053 } else if (Literal == tag) {
2054 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2055 ccall_arg_setup_instrs++;
2056 }
2057 else
njne427a662002-10-02 11:08:25 +00002058 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002059}
2060
2061static
2062void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2063{
2064 if (R_EAX == reg1) {
2065 VG_(emit_swapl_reg_EAX) ( reg2 );
2066 } else if (R_EAX == reg2) {
2067 VG_(emit_swapl_reg_EAX) ( reg1 );
2068 } else {
2069 emit_swapl_reg_reg ( reg1, reg2 );
2070 }
2071 ccall_arg_setup_instrs++;
2072}
2073
2074static
2075void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2076{
2077 if (dst1 != src2) {
2078 maybe_emit_movl_reg_reg ( src1, dst1 );
2079 maybe_emit_movl_reg_reg ( src2, dst2 );
2080
2081 } else if (dst2 != src1) {
2082 maybe_emit_movl_reg_reg ( src2, dst2 );
2083 maybe_emit_movl_reg_reg ( src1, dst1 );
2084
2085 } else {
2086 /* swap to break cycle */
2087 emit_swapl_arg_regs ( dst1, dst2 );
2088 }
2089}
2090
2091static
2092void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2093 UInt dst1, UInt dst2, UInt dst3)
2094{
2095 if (dst1 != src2 && dst1 != src3) {
2096 maybe_emit_movl_reg_reg ( src1, dst1 );
2097 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2098
2099 } else if (dst2 != src1 && dst2 != src3) {
2100 maybe_emit_movl_reg_reg ( src2, dst2 );
2101 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2102
2103 } else if (dst3 != src1 && dst3 != src2) {
2104 maybe_emit_movl_reg_reg ( src3, dst3 );
2105 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2106
2107 } else {
2108 /* break cycle */
2109 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2110 emit_swapl_arg_regs ( dst1, dst2 );
2111 emit_swapl_arg_regs ( dst1, dst3 );
2112
2113 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2114 emit_swapl_arg_regs ( dst1, dst3 );
2115 emit_swapl_arg_regs ( dst1, dst2 );
2116
2117 } else {
njne427a662002-10-02 11:08:25 +00002118 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002119 }
2120 }
2121}
2122
2123static
2124void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2125 UInt src1, UInt src2,
2126 UInt dst1, UInt dst2)
2127{
2128 /* If either are lits, order doesn't matter */
2129 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2130 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2131 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2132
2133 } else {
2134 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2135 }
2136}
2137
2138static
2139void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2140 UInt src1, UInt src2, UInt src3,
2141 UInt dst1, UInt dst2, UInt dst3)
2142{
2143 // SSS: fix this eventually -- make STOREV use two RealRegs?
2144 /* Not supporting literals for 3-arg C functions -- they're only used
2145 by STOREV which has 2 args */
2146 vg_assert(RealReg == tagv[src1] &&
2147 RealReg == tagv[src2] &&
2148 RealReg == tagv[src3]);
2149 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2150 dst1, dst2, dst3 );
2151}
2152
2153/* Synthesise a call to a C function `fn' (which must be registered in
2154 baseBlock) doing all the reg saving and arg handling work.
2155
2156 WARNING: a UInstr should *not* be translated with synth_ccall followed
2157 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2158 such behaviour and everything will fall over.
2159 */
2160void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2161 Tag tagv[], Int ret_reg,
2162 RRegSet regs_live_before, RRegSet regs_live_after )
2163{
2164 Int i;
2165 Int stack_used = 0;
2166 Bool preserve_eax, preserve_ecx, preserve_edx;
2167
2168 vg_assert(0 <= regparms_n && regparms_n <= 3);
2169
2170 ccalls++;
2171
2172 /* If %e[acd]x is live before and after the C call, save/restore it.
2173 Unless the return values clobbers the reg; in this case we must not
2174 save/restore the reg, because the restore would clobber the return
2175 value. (Before and after the UInstr really constitute separate live
2176 ranges, but you miss this if you don't consider what happens during
2177 the UInstr.) */
2178# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002179 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2180 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002181 ret_reg != realReg)
2182
2183 preserve_eax = PRESERVE_REG(R_EAX);
2184 preserve_ecx = PRESERVE_REG(R_ECX);
2185 preserve_edx = PRESERVE_REG(R_EDX);
2186
2187# undef PRESERVE_REG
2188
2189 /* Save caller-save regs as required */
2190 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2191 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2192 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2193
2194 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2195 is the number of args passed in regs (maximum 3 for GCC on x86). */
2196
2197 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002198
njn25e49d8e72002-09-23 09:36:25 +00002199 /* First push stack args (RealRegs or Literals) in reverse order. */
2200 for (i = argc-1; i >= regparms_n; i--) {
2201 switch (tagv[i]) {
2202 case RealReg:
2203 VG_(emit_pushv_reg) ( 4, argv[i] );
2204 break;
2205 case Literal:
2206 /* Use short form of pushl if possible. */
2207 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2208 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2209 else
2210 VG_(emit_pushl_lit32)( argv[i] );
2211 break;
2212 default:
2213 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002214 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002215 }
2216 stack_used += 4;
2217 ccall_arg_setup_instrs++;
2218 }
njn6431be72002-07-28 09:53:34 +00002219
njn25e49d8e72002-09-23 09:36:25 +00002220 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2221 If moving values between registers, be careful not to clobber any on
2222 the way. Happily we can use xchgl to swap registers.
2223 */
2224 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002225
njn25e49d8e72002-09-23 09:36:25 +00002226 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2227 case 3:
2228 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2229 R_EAX, R_EDX, R_ECX );
2230 break;
njn6431be72002-07-28 09:53:34 +00002231
njn25e49d8e72002-09-23 09:36:25 +00002232 /* Less-tricky. Args passed in %eax and %edx. */
2233 case 2:
2234 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2235 break;
2236
2237 /* Easy. Just move arg1 into %eax (if not already in there). */
2238 case 1:
2239 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2240 break;
2241
2242 case 0:
2243 break;
2244
2245 default:
njne427a662002-10-02 11:08:25 +00002246 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002247 }
2248
sewardjfa492d42002-12-08 18:20:01 +00002249 /* Call the function - may trash all flags */
2250 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002251
2252 /* Clear any args from stack */
2253 if (0 != stack_used) {
2254 VG_(emit_add_lit_to_esp) ( stack_used );
2255 ccall_stack_clears++;
2256 }
2257
2258 /* Move return value into ret_reg if necessary and not already there */
2259 if (INVALID_REALREG != ret_reg) {
2260 ccall_retvals++;
2261 if (R_EAX != ret_reg) {
2262 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2263 ccall_retval_movs++;
2264 }
2265 }
2266
2267 /* Restore live caller-save regs as required */
2268 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2269 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2270 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002271}
sewardjde4a1d02002-03-22 01:27:54 +00002272
sewardj2e93c502002-04-12 11:12:52 +00002273static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002274{
sewardj2e93c502002-04-12 11:12:52 +00002275 switch (jmpkind) {
2276 case JmpBoring:
2277 break;
sewardj2e93c502002-04-12 11:12:52 +00002278 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002279 break;
2280 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002281 break;
2282 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002283 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002284 break;
2285 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002286 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002287 break;
2288 default:
njne427a662002-10-02 11:08:25 +00002289 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002290 }
2291}
2292
2293/* Jump to the next translation, by loading its original addr into
2294 %eax and returning to the scheduler. Signal special requirements
2295 by loading a special value into %ebp first.
2296*/
2297static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2298{
sewardjfa492d42002-12-08 18:20:01 +00002299 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002300 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002301 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002302 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002303 emit_ret();
2304}
2305
sewardj22854b92002-11-30 14:00:47 +00002306static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002307
2308/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002309static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002310{
sewardjfa492d42002-12-08 18:20:01 +00002311 maybe_emit_put_eflags(); /* save flags here */
2312
njn25e49d8e72002-09-23 09:36:25 +00002313 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002314
2315 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2316 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2317 emit_call_patchme();
2318 } else {
2319 load_ebp_from_JmpKind ( jmpkind );
2320 emit_ret();
2321 }
sewardjde4a1d02002-03-22 01:27:54 +00002322}
2323
2324
sewardj2370f3b2002-11-30 15:01:01 +00002325static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002326static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002327 Opcode opcode, Int size,
2328 UInt lit, Int reg );
2329
sewardjfa492d42002-12-08 18:20:01 +00002330static void synth_jcond_lit ( Condcode cond,
2331 Addr addr,
2332 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002333{
sewardj2370f3b2002-11-30 15:01:01 +00002334 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002335 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002336 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002337
sewardja2113f92002-12-12 23:42:48 +00002338 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002339 VG_(init_target)(&tgt2);
2340 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002341
sewardjfa492d42002-12-08 18:20:01 +00002342 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2343 if need be */
2344 maybe_emit_put_eflags();
2345 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2346
2347 if (eflags_state == UPD_Both) {
2348 /* The flags are already set up, so we just use them as is. */
2349 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002350 cond = invertCondition(cond);
2351 } else {
sewardj75f04932002-12-12 23:13:21 +00002352 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002353
2354 /* The simd state contains the most recent version, so we emit a
2355 sequence to calculate the relevant condition directly out of
2356 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2357 copying them back to the real flags via popf. Notice that
2358 some of these sequences trash %eax, but that should be free
2359 now since this is the end of a bb and therefore all regs are
2360 dead. */
2361 simd = False;
2362
2363 switch (cond) {
2364
sewardjbb6c1182002-12-12 23:54:47 +00002365 case CondLE: /* Z || S != O -> S || !P */
2366 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002367 vg_assert(eax_trashable);
2368
2369 VG_(emit_movv_offregmem_reg)
2370 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2371 /* eax == %EFLAGS */
2372
sewardjbb6c1182002-12-12 23:54:47 +00002373 VG_(emit_nonshiftopv_lit_reg)
2374 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2375 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002376
sewardjbb6c1182002-12-12 23:54:47 +00002377 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2378 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002379
sewardj09736622002-12-28 00:19:00 +00002380 /* actually set the real cpu flags, since ROR changes
2381 neither P nor Z */
2382 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2383
sewardjbb6c1182002-12-12 23:54:47 +00002384 if (cond == CondLE) {
2385 /* test Z */
2386 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2387 /* test OF != SF */
2388 cond = CondP;
2389 } else {
2390 /* test Z */
2391 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2392 /* test OF == SF */
2393 cond = CondNP;
2394 }
sewardj2370f3b2002-11-30 15:01:01 +00002395 break;
2396
sewardjfa492d42002-12-08 18:20:01 +00002397 case CondL:
2398 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002399 vg_assert(eax_trashable);
2400
2401 VG_(emit_movv_offregmem_reg)
2402 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2403 /* eax == %EFLAGS */
2404
sewardj75f04932002-12-12 23:13:21 +00002405 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2406 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002407
sewardj75f04932002-12-12 23:13:21 +00002408 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2409 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002410
sewardj09736622002-12-28 00:19:00 +00002411 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002412 if (cond == CondL) cond = CondP; else cond = CondNP;
2413 break;
sewardjfa492d42002-12-08 18:20:01 +00002414
2415 case CondB:
2416 case CondNB:
2417 mask = EFlagC; goto simple; /* C=1 */
2418
2419 case CondZ:
2420 case CondNZ:
2421 mask = EFlagZ; goto simple; /* Z=1 */
2422
2423 case CondBE:
2424 case CondNBE:
2425 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2426
2427 case CondS:
2428 case CondNS:
2429 mask = EFlagS; goto simple; /* S=1 */
2430
2431 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002432 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002433 mask = EFlagP; goto simple; /* P=1 */
2434
sewardj39542072002-12-09 22:44:00 +00002435 case CondO:
2436 case CondNO:
2437 mask = EFlagO; goto simple; /* O=1 */
2438
sewardjfa492d42002-12-08 18:20:01 +00002439 default:
2440 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002441 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002442 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2443
2444 simple:
2445 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002446 if ((mask & 0xff) == mask) {
2447 VG_(emitB) ( 0xF6 ); /* Grp3 */
2448 VG_(emit_amode_offregmem_reg)(
2449 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2450 VG_(emitB) (mask);
2451 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002452 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002453 mask, VGOFF_(m_eflags) * 4);
2454 } else {
sewardjfa492d42002-12-08 18:20:01 +00002455 /* all cond codes are in lower 16 bits */
2456 vg_assert((mask & 0xffff) == mask);
2457
2458 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002459 VG_(emitB) ( 0xF7 );
2460 VG_(emit_amode_offregmem_reg)(
2461 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002462 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002463 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002464 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002465 mask, VGOFF_(m_eflags) * 4);
2466 }
2467
sewardj75f04932002-12-12 23:13:21 +00002468 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002469 break;
2470 }
2471 }
2472
sewardja2113f92002-12-12 23:42:48 +00002473 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002474
2475 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002476 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002477
2478 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002479 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002480}
2481
2482
sewardj2370f3b2002-11-30 15:01:01 +00002483
sewardjde4a1d02002-03-22 01:27:54 +00002484static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2485{
sewardja2113f92002-12-12 23:42:48 +00002486 Int tgt;
2487
2488 VG_(init_target)(&tgt);
2489
sewardjfa492d42002-12-08 18:20:01 +00002490 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002491
2492 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002493 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002494
2495 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002496}
2497
2498
2499static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2500{
2501 /* Load the zero-extended literal into reg, at size l,
2502 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002503 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002504}
2505
2506
2507static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2508{
2509 switch (size) {
2510 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2511 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2512 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002513 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002514 }
2515}
2516
2517
2518static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2519{
2520 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002521 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2522 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2523 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002524 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002525 }
2526}
2527
2528
2529static void synth_mov_reg_offregmem ( Int size, Int reg,
2530 Int off, Int areg )
2531{
2532 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002533 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2534 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002535 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002536 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002537 }
2538 else {
njn25e49d8e72002-09-23 09:36:25 +00002539 VG_(emit_swapl_reg_EAX) ( reg );
2540 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2541 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002542 }
2543 break;
njne427a662002-10-02 11:08:25 +00002544 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002545 }
2546}
2547
2548
2549static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2550{
2551 Int s1;
2552 switch (size) {
2553 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2554 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2555 case 1: if (reg1 < 4) {
2556 emit_movb_reg_regmem ( reg1, reg2 );
2557 }
2558 else {
2559 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2560 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2561 emit_swapl_reg_reg ( s1, reg1 );
2562 emit_movb_reg_regmem ( s1, reg2 );
2563 emit_swapl_reg_reg ( s1, reg1 );
2564 }
2565 break;
njne427a662002-10-02 11:08:25 +00002566 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002567 }
2568}
2569
2570
sewardjf0f12aa2002-12-28 00:04:08 +00002571static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002572 Opcode opcode, Int size,
2573 Int reg )
2574{
2575 /* NB! opcode is a uinstr opcode, not an x86 one! */
2576 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002577 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002578 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002579 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002580 break;
2581 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002582 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002583 } else {
njn25e49d8e72002-09-23 09:36:25 +00002584 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002585 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002586 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002587 }
2588 break;
njne427a662002-10-02 11:08:25 +00002589 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002590 }
2591}
2592
2593
2594
sewardjf0f12aa2002-12-28 00:04:08 +00002595static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002596 Opcode opcode, Int size,
2597 Int reg1, Int reg2 )
2598{
2599 /* NB! opcode is a uinstr opcode, not an x86 one! */
2600 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002601 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002602 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002603 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002604 break;
2605 case 1: { /* Horrible ... */
2606 Int s1, s2;
2607 /* Choose s1 and s2 to be x86 regs which we can talk about the
2608 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2609 sure s1 != s2 and that neither of them equal either reg1 or
2610 reg2. Then use them as temporaries to make things work. */
2611 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002612 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002613 break;
2614 }
2615 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2616 if (reg1 >= 4 && reg2 < 4) {
2617 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002618 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002619 emit_swapl_reg_reg ( reg1, s1 );
2620 break;
2621 }
2622 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2623 if (reg1 < 4 && reg2 >= 4) {
2624 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002625 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002626 emit_swapl_reg_reg ( reg2, s2 );
2627 break;
2628 }
2629 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2630 emit_swapl_reg_reg ( reg1, s1 );
2631 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002632 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002633 emit_swapl_reg_reg ( reg1, s1 );
2634 emit_swapl_reg_reg ( reg2, s2 );
2635 break;
2636 }
2637 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2638 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002639 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002640 emit_swapl_reg_reg ( reg1, s1 );
2641 break;
2642 }
njne427a662002-10-02 11:08:25 +00002643 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002644 }
njne427a662002-10-02 11:08:25 +00002645 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002646 }
2647}
2648
sewardja2c5a732002-12-15 03:10:42 +00002649#if 0
2650/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002651static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002652 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002653 Opcode opcode, Int size,
2654 Int off, Int areg, Int reg )
2655{
2656 switch (size) {
2657 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002658 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002659 break;
2660 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002661 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002662 break;
2663 case 1:
2664 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002665 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002666 } else {
2667 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002668 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002669 VG_(emit_swapl_reg_EAX) ( reg );
2670 }
2671 break;
2672 default:
2673 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2674 }
2675}
sewardja2c5a732002-12-15 03:10:42 +00002676#endif
sewardjfa492d42002-12-08 18:20:01 +00002677
sewardjde4a1d02002-03-22 01:27:54 +00002678static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002679 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002680 Opcode opcode, Int size,
2681 Int off, Int areg, Int reg )
2682{
2683 switch (size) {
2684 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002685 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002686 break;
2687 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002688 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002689 break;
2690 case 1:
2691 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002692 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002693 } else {
njn25e49d8e72002-09-23 09:36:25 +00002694 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002695 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002696 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002697 }
2698 break;
2699 default:
njne427a662002-10-02 11:08:25 +00002700 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002701 }
2702}
2703
2704
sewardjf0f12aa2002-12-28 00:04:08 +00002705static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002706 Opcode opcode, Int size,
2707 UInt lit, Int reg )
2708{
2709 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002710 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002711 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002712 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002713 break;
2714 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002715 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002716 } else {
njn25e49d8e72002-09-23 09:36:25 +00002717 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002718 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002719 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002720 }
2721 break;
njne427a662002-10-02 11:08:25 +00002722 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002723 }
2724}
2725
sewardjf0f12aa2002-12-28 00:04:08 +00002726static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002727 Opcode opcode, Int size,
2728 UInt lit, Int off, Int regmem )
2729{
2730 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002731 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002732 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002733 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002734 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002735 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002736 break;
2737 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2738 }
2739}
2740
sewardjde4a1d02002-03-22 01:27:54 +00002741
2742static void synth_push_reg ( Int size, Int reg )
2743{
2744 switch (size) {
2745 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002746 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002747 break;
2748 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002749 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002750 break;
2751 /* Pray that we don't have to generate this really cruddy bit of
2752 code very often. Could do better, but can I be bothered? */
2753 case 1:
2754 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002755 VG_(emit_add_lit_to_esp)(-1);
2756 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002757 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002758 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002759 break;
2760 default:
njne427a662002-10-02 11:08:25 +00002761 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002762 }
2763}
2764
2765
2766static void synth_pop_reg ( Int size, Int reg )
2767{
2768 switch (size) {
2769 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002770 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002771 break;
2772 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002773 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002774 break;
2775 case 1:
2776 /* Same comment as above applies. */
2777 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002778 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002779 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002780 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2781 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002782 break;
njne427a662002-10-02 11:08:25 +00002783 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002784 }
2785}
2786
2787
sewardjf0f12aa2002-12-28 00:04:08 +00002788static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002789 Opcode opcode, Int size,
2790 Int regs, Int regd )
2791{
2792 synth_push_reg ( size, regd );
2793 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002794 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002795 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2796 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2797 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002798 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002799 }
sewardjde4a1d02002-03-22 01:27:54 +00002800 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2801 synth_pop_reg ( size, regd );
2802}
2803
2804
sewardjf0f12aa2002-12-28 00:04:08 +00002805static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002806 Opcode opcode, Int size,
2807 UInt lit, Int reg )
2808{
2809 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002810 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002811 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002812 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002813 break;
2814 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002815 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002816 } else {
njn25e49d8e72002-09-23 09:36:25 +00002817 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002818 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002819 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002820 }
2821 break;
njne427a662002-10-02 11:08:25 +00002822 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002823 }
2824}
2825
2826
sewardjf0f12aa2002-12-28 00:04:08 +00002827static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002828{
sewardjde4a1d02002-03-22 01:27:54 +00002829 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002830 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002831 } else {
njn25e49d8e72002-09-23 09:36:25 +00002832 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002833 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002834 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002835 }
2836}
2837
2838
sewardj3d7c9c82003-03-26 21:08:13 +00002839static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2840 UChar first_byte,
2841 UChar second_byte,
2842 Int ireg )
2843{
2844 emit_MMX2_regmem ( uses_flags, sets_flags,
2845 first_byte, second_byte, ireg );
2846}
2847
2848
sewardjca860012003-03-27 23:52:58 +00002849static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2850 UChar first_byte,
2851 UChar second_byte,
2852 Int ireg )
2853{
2854 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2855 first_byte, second_byte, ireg );
2856}
2857
sewardjd1c9e432003-04-04 20:40:34 +00002858static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2859 UChar first_byte,
2860 UChar second_byte,
2861 Int ireg )
2862{
2863 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2864 first_byte, second_byte, ireg );
2865}
2866
sewardj3d7c9c82003-03-26 21:08:13 +00002867static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2868 UChar first_byte,
2869 UChar second_byte )
2870{
2871 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2872}
2873
2874
sewardjca860012003-03-27 23:52:58 +00002875static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2876 UChar first_byte,
2877 UChar second_byte,
2878 UChar third_byte )
2879{
2880 emit_MMX3_no_mem ( uses_flags, sets_flags,
2881 first_byte, second_byte, third_byte );
2882}
2883
2884
sewardj3d7c9c82003-03-26 21:08:13 +00002885static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2886 UChar first_byte )
2887{
2888 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2889}
2890
2891
sewardjfa492d42002-12-08 18:20:01 +00002892static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2893 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002894 UChar second_byte_masked,
2895 Int reg )
2896{
sewardj3d7c9c82003-03-26 21:08:13 +00002897 emit_fpu_regmem ( uses_flags, sets_flags,
2898 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002899}
2900
2901
sewardjfa492d42002-12-08 18:20:01 +00002902static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2903 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002904 UChar second_byte )
2905{
sewardjfa492d42002-12-08 18:20:01 +00002906 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002907}
2908
2909
2910static void synth_movl_reg_reg ( Int src, Int dst )
2911{
2912 emit_movl_reg_reg ( src, dst );
2913}
2914
2915static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2916{
sewardja2113f92002-12-12 23:42:48 +00002917 Int tgt;
2918
2919 VG_(init_target)(&tgt);
2920
2921 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002922 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002923
2924 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002925}
2926
2927
sewardjde4a1d02002-03-22 01:27:54 +00002928/*----------------------------------------------------*/
2929/*--- Top level of the uinstr -> x86 translation. ---*/
2930/*----------------------------------------------------*/
2931
2932/* Return the byte offset from %ebp (ie, into baseBlock)
2933 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002934static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2935{
2936 if (tag == SpillNo) {
2937 vg_assert(size == 4);
2938 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2939 return 4 * (value + VGOFF_(spillslots));
2940 }
2941 if (tag == ArchReg) {
2942 switch (value) {
2943 case R_EAX: return 4 * VGOFF_(m_eax);
2944 case R_ECX: return 4 * VGOFF_(m_ecx);
2945 case R_EDX: return 4 * VGOFF_(m_edx);
2946 case R_EBX: return 4 * VGOFF_(m_ebx);
2947 case R_ESP:
2948 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2949 else return 4 * VGOFF_(m_esp);
2950 case R_EBP:
2951 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2952 else return 4 * VGOFF_(m_ebp);
2953 case R_ESI:
2954 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2955 else return 4 * VGOFF_(m_esi);
2956 case R_EDI:
2957 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2958 else return 4 * VGOFF_(m_edi);
2959 }
2960 }
njne427a662002-10-02 11:08:25 +00002961 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002962}
2963
sewardjde4a1d02002-03-22 01:27:54 +00002964static Int eflagsOffset ( void )
2965{
2966 return 4 * VGOFF_(m_eflags);
2967}
2968
sewardje1042472002-09-30 12:33:11 +00002969static Int segRegOffset ( UInt archregs )
2970{
2971 switch (archregs) {
2972 case R_CS: return 4 * VGOFF_(m_cs);
2973 case R_SS: return 4 * VGOFF_(m_ss);
2974 case R_DS: return 4 * VGOFF_(m_ds);
2975 case R_ES: return 4 * VGOFF_(m_es);
2976 case R_FS: return 4 * VGOFF_(m_fs);
2977 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002978 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002979 }
2980}
2981
njnf4ce3d32003-02-10 10:17:26 +00002982UInt VG_(get_archreg) ( UInt arch )
2983{
2984 switch (arch) {
2985 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2986 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2987 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2988 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2989 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2990 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2991 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2992 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2993 default: VG_(core_panic)( "get_thread_archreg");
2994 }
2995}
2996
2997UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2998{
2999 ThreadState* tst;
3000
3001 vg_assert(VG_(is_valid_tid)(tid));
3002 tst = & VG_(threads)[tid];
3003
3004 switch (arch) {
3005 case R_EAX: return tst->m_eax;
3006 case R_ECX: return tst->m_ecx;
3007 case R_EDX: return tst->m_edx;
3008 case R_EBX: return tst->m_ebx;
3009 case R_ESP: return tst->m_esp;
3010 case R_EBP: return tst->m_ebp;
3011 case R_ESI: return tst->m_esi;
3012 case R_EDI: return tst->m_edi;
3013 default: VG_(core_panic)( "get_thread_archreg");
3014 }
3015}
3016
njnb93d1782003-02-03 12:03:22 +00003017/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003018static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003019{
3020 switch (arch) {
3021 case R_EAX: return VGOFF_(sh_eax);
3022 case R_ECX: return VGOFF_(sh_ecx);
3023 case R_EDX: return VGOFF_(sh_edx);
3024 case R_EBX: return VGOFF_(sh_ebx);
3025 case R_ESP: return VGOFF_(sh_esp);
3026 case R_EBP: return VGOFF_(sh_ebp);
3027 case R_ESI: return VGOFF_(sh_esi);
3028 case R_EDI: return VGOFF_(sh_edi);
3029 default: VG_(core_panic)( "shadow_reg_index");
3030 }
3031}
sewardjde4a1d02002-03-22 01:27:54 +00003032
njn25e49d8e72002-09-23 09:36:25 +00003033/* Return the byte offset from %ebp (ie, into baseBlock)
3034 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003035Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003036{
njnb93d1782003-02-03 12:03:22 +00003037 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003038}
3039
njn4ba5a792002-09-30 10:23:54 +00003040Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003041{
3042 return 4 * VGOFF_(sh_eflags);
3043}
3044
njnb93d1782003-02-03 12:03:22 +00003045/* Accessing shadow arch. registers */
3046UInt VG_(get_shadow_archreg) ( UInt archreg )
3047{
3048 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3049}
3050
3051void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3052{
3053 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3054}
3055
njnd3040452003-05-19 15:04:06 +00003056void VG_(set_shadow_eflags) ( UInt val )
3057{
3058 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3059}
3060
njnf4ce3d32003-02-10 10:17:26 +00003061UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3062{
3063 ThreadState* tst;
3064
3065 vg_assert(VG_(is_valid_tid)(tid));
3066 tst = & VG_(threads)[tid];
3067
3068 switch (archreg) {
3069 case R_EAX: return tst->sh_eax;
3070 case R_ECX: return tst->sh_ecx;
3071 case R_EDX: return tst->sh_edx;
3072 case R_EBX: return tst->sh_ebx;
3073 case R_ESP: return tst->sh_esp;
3074 case R_EBP: return tst->sh_ebp;
3075 case R_ESI: return tst->sh_esi;
3076 case R_EDI: return tst->sh_edi;
3077 default: VG_(core_panic)( "get_thread_shadow_archreg");
3078 }
3079}
3080
3081void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3082{
3083 ThreadState* tst;
3084
3085 vg_assert(VG_(is_valid_tid)(tid));
3086 tst = & VG_(threads)[tid];
3087
3088 switch (archreg) {
3089 case R_EAX: tst->sh_eax = val; break;
3090 case R_ECX: tst->sh_ecx = val; break;
3091 case R_EDX: tst->sh_edx = val; break;
3092 case R_EBX: tst->sh_ebx = val; break;
3093 case R_ESP: tst->sh_esp = val; break;
3094 case R_EBP: tst->sh_ebp = val; break;
3095 case R_ESI: tst->sh_esi = val; break;
3096 case R_EDI: tst->sh_edi = val; break;
3097 default: VG_(core_panic)( "set_thread_shadow_archreg");
3098 }
3099}
3100
njnb93d1782003-02-03 12:03:22 +00003101Addr VG_(shadow_archreg_address) ( UInt archreg )
3102{
3103 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3104}
sewardjde4a1d02002-03-22 01:27:54 +00003105
sewardjde4a1d02002-03-22 01:27:54 +00003106static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3107{
3108 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003109 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3110 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003111 }
3112 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003113 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3114 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003115 }
3116 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003117 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3118 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003119 }
3120 else
njne427a662002-10-02 11:08:25 +00003121 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003122}
3123
3124
sewardjde4a1d02002-03-22 01:27:54 +00003125/*----------------------------------------------------*/
3126/*--- Generate code for a single UInstr. ---*/
3127/*----------------------------------------------------*/
3128
sewardj478335c2002-10-05 02:44:47 +00003129static __inline__
3130Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003131{
3132 return (u->flags_w != FlagsEmpty);
3133}
3134
sewardjfa492d42002-12-08 18:20:01 +00003135static __inline__
3136Bool readFlagUse ( UInstr* u )
3137{
3138 /* If the UInstr writes some flags but not all, then we still need
3139 to consider it as reading flags so that the unchanged values are
3140 passed through properly. (D is special) */
3141 return
3142 (u->flags_r != FlagsEmpty) ||
3143 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3144}
3145
sewardj478335c2002-10-05 02:44:47 +00003146static __inline__
3147Bool anyFlagUse ( UInstr* u )
3148{
sewardjfa492d42002-12-08 18:20:01 +00003149 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003150}
3151
3152
sewardjb91ae7f2003-04-29 23:50:00 +00003153/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3154 the real machine's cpu. If so we need to be very careful not to trash it.
3155 If FPU/SSE state is live and we deem it necessary to copy it back to
3156 the simulated machine's FPU/SSE state, we do so. The final state of
3157 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003158 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003159 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003160*/
sewardjb5ff83e2002-12-01 19:40:49 +00003161static void emitUInstr ( UCodeBlock* cb, Int i,
3162 RRegSet regs_live_before,
3163 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003164 Bool* sselive, /* True<==>FPU/SSE
3165 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003166 Addr* orig_eip, /* previous curr_eip, or zero */
3167 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003168{
njn25e49d8e72002-09-23 09:36:25 +00003169 Int old_emitted_code_used;
3170 UInstr* u = &cb->instrs[i];
3171
sewardjde4a1d02002-03-22 01:27:54 +00003172 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003173 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003174
njn25e49d8e72002-09-23 09:36:25 +00003175 old_emitted_code_used = emitted_code_used;
3176
sewardjde4a1d02002-03-22 01:27:54 +00003177 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003178 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003179
sewardjb5ff83e2002-12-01 19:40:49 +00003180 case INCEIP:
3181 /* Advance %EIP some small amount. */
3182 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003183
sewardjb5ff83e2002-12-01 19:40:49 +00003184 if (*orig_eip == 0 /* we don't know what the old value was */
3185 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3186 /* We have to update all 32 bits of the value. */
3187 VG_(emit_movv_lit_offregmem)(
3188 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3189 } else {
3190 /* Cool! we only need to update lowest 8 bits */
3191 VG_(emit_movb_lit_offregmem)(
3192 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003193 }
njn25e49d8e72002-09-23 09:36:25 +00003194
sewardjb5ff83e2002-12-01 19:40:49 +00003195 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003196 break;
sewardjde4a1d02002-03-22 01:27:54 +00003197
3198 case LEA1: {
3199 vg_assert(u->tag1 == RealReg);
3200 vg_assert(u->tag2 == RealReg);
3201 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3202 break;
3203 }
3204
3205 case LEA2: {
3206 vg_assert(u->tag1 == RealReg);
3207 vg_assert(u->tag2 == RealReg);
3208 vg_assert(u->tag3 == RealReg);
3209 emit_lea_sib_reg ( u->lit32, u->extra4b,
3210 u->val1, u->val2, u->val3 );
3211 break;
3212 }
3213
3214 case WIDEN: {
3215 vg_assert(u->tag1 == RealReg);
3216 if (u->signed_widen) {
3217 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3218 } else {
3219 /* no need to generate any code. */
3220 }
3221 break;
3222 }
3223
sewardjde4a1d02002-03-22 01:27:54 +00003224 case STORE: {
3225 vg_assert(u->tag1 == RealReg);
3226 vg_assert(u->tag2 == RealReg);
3227 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003228 break;
3229 }
3230
3231 case LOAD: {
3232 vg_assert(u->tag1 == RealReg);
3233 vg_assert(u->tag2 == RealReg);
3234 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3235 break;
3236 }
3237
sewardjde4a1d02002-03-22 01:27:54 +00003238 case GET: {
3239 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3240 vg_assert(u->tag2 == RealReg);
3241 synth_mov_offregmem_reg (
3242 u->size,
3243 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3244 R_EBP,
3245 u->val2
3246 );
3247 break;
3248 }
3249
3250 case PUT: {
3251 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3252 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003253 synth_mov_reg_offregmem (
3254 u->size,
3255 u->val1,
3256 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3257 R_EBP
3258 );
sewardjde4a1d02002-03-22 01:27:54 +00003259 break;
3260 }
3261
sewardje1042472002-09-30 12:33:11 +00003262 case GETSEG: {
3263 vg_assert(u->tag1 == ArchRegS);
3264 vg_assert(u->tag2 == RealReg);
3265 vg_assert(u->size == 2);
3266 synth_mov_offregmem_reg (
3267 4,
3268 segRegOffset( u->val1 ),
3269 R_EBP,
3270 u->val2
3271 );
3272 break;
3273 }
3274
3275 case PUTSEG: {
3276 vg_assert(u->tag1 == RealReg);
3277 vg_assert(u->tag2 == ArchRegS);
3278 vg_assert(u->size == 2);
3279 synth_mov_reg_offregmem (
3280 4,
3281 u->val1,
3282 segRegOffset( u->val2 ),
3283 R_EBP
3284 );
3285 break;
3286 }
3287
sewardjde4a1d02002-03-22 01:27:54 +00003288 case GETF: {
3289 vg_assert(u->size == 2 || u->size == 4);
3290 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003291
3292 /* This complexity is because the D(irection) flag is stored
3293 separately from the rest of EFLAGS. */
3294
3295 /* We're only fetching from the Simd state, so make sure it's
3296 up to date. */
3297 maybe_emit_put_eflags();
3298
3299 /* get D in u->val1 (== 1 or -1) */
3300 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3301
3302 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3303 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3304
3305 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3306 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3307 eflagsOffset(), R_EBP);
3308
3309 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3310 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3311 eflagsOffset(), R_EBP);
3312
3313 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3314 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3315 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003316 break;
3317 }
3318
3319 case PUTF: {
3320 vg_assert(u->size == 2 || u->size == 4);
3321 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003322
3323 /* When putting a value into EFLAGS, this generates the
3324 correct value for m_dflag (-1 or 1), and clears the D bit
3325 in EFLAGS. */
3326
3327 /* We're updating the whole flag state, so the old state
3328 doesn't matter; make sure that the new simulated state
3329 will be fetched when needed. */
3330 eflags_state = UPD_Simd;
3331
3332 /* store EFLAGS (with D) */
3333 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3334
3335 /* u->val1 &= EFlagD */
3336 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3337
3338 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3339 synth_unaryop_reg(False, NEG, u->size, u->val1);
3340 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3341 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3342
3343 /* save D */
3344 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3345
3346 /* EFLAGS &= ~EFlagD */
3347 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3348 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003349 break;
3350 }
3351
3352 case MOV: {
3353 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3354 vg_assert(u->tag2 == RealReg);
3355 switch (u->tag1) {
3356 case RealReg: vg_assert(u->size == 4);
3357 if (u->val1 != u->val2)
3358 synth_movl_reg_reg ( u->val1, u->val2 );
3359 break;
3360 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3361 break;
njne427a662002-10-02 11:08:25 +00003362 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003363 }
3364 break;
3365 }
3366
sewardje1042472002-09-30 12:33:11 +00003367 case USESEG: {
3368 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3369 ones. */
sewardjd077f532002-09-30 21:52:50 +00003370 UInt argv[] = { u->val1, u->val2 };
3371 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003372 UInt ret_reg = u->val2;
3373
3374 vg_assert(u->tag1 == RealReg);
3375 vg_assert(u->tag2 == RealReg);
3376 vg_assert(u->size == 0);
3377
sewardjb91ae7f2003-04-29 23:50:00 +00003378 if (*sselive) {
3379 emit_put_sse_state();
3380 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003381 }
3382
sewardje1042472002-09-30 12:33:11 +00003383 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3384 2, /* args */
3385 0, /* regparms_n */
3386 argv, tagv,
3387 ret_reg, regs_live_before, u->regs_live_after );
3388 break;
3389 }
3390
sewardj478335c2002-10-05 02:44:47 +00003391 case SBB:
3392 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003393 case XOR:
3394 case OR:
3395 case AND:
3396 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003397 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003398 vg_assert(u->tag2 == RealReg);
3399 switch (u->tag1) {
3400 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003401 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003402 u->opcode, u->size, u->lit32, u->val2 );
3403 break;
3404 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003405 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003406 u->opcode, u->size, u->val1, u->val2 );
3407 break;
3408 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003409 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003410 u->opcode, u->size,
3411 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3412 R_EBP,
3413 u->val2 );
3414 break;
njne427a662002-10-02 11:08:25 +00003415 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003416 }
3417 break;
3418 }
3419
sewardj478335c2002-10-05 02:44:47 +00003420 case RCR:
3421 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003422 case ROR:
3423 case ROL:
3424 case SAR:
3425 case SHR:
3426 case SHL: {
3427 vg_assert(u->tag2 == RealReg);
3428 switch (u->tag1) {
3429 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003430 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003431 u->opcode, u->size, u->lit32, u->val2 );
3432 break;
3433 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003434 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003435 u->opcode, u->size, u->val1, u->val2 );
3436 break;
njne427a662002-10-02 11:08:25 +00003437 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003438 }
3439 break;
3440 }
3441
3442 case INC:
3443 case DEC:
3444 case NEG:
3445 case NOT:
3446 vg_assert(u->tag1 == RealReg);
3447 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003448 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003449 break;
3450
3451 case BSWAP:
3452 vg_assert(u->tag1 == RealReg);
3453 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003454 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003455 emit_bswapl_reg ( u->val1 );
3456 break;
3457
3458 case CMOV:
3459 vg_assert(u->tag1 == RealReg);
3460 vg_assert(u->tag2 == RealReg);
3461 vg_assert(u->cond != CondAlways);
3462 vg_assert(u->size == 4);
3463 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3464 break;
3465
3466 case JMP: {
3467 vg_assert(u->tag2 == NoValue);
3468 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003469 if (*sselive) {
3470 emit_put_sse_state();
3471 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003472 }
sewardjde4a1d02002-03-22 01:27:54 +00003473 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003474 switch (u->tag1) {
3475 case RealReg:
3476 synth_jmp_reg ( u->val1, u->jmpkind );
3477 break;
3478 case Literal:
3479 synth_jmp_lit ( u->lit32, u->jmpkind );
3480 break;
3481 default:
njne427a662002-10-02 11:08:25 +00003482 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003483 break;
sewardjde4a1d02002-03-22 01:27:54 +00003484 }
3485 } else {
sewardj2e93c502002-04-12 11:12:52 +00003486 switch (u->tag1) {
3487 case RealReg:
njne427a662002-10-02 11:08:25 +00003488 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003489 break;
3490 case Literal:
3491 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003492 /* %eax had better not be live since synth_jcond_lit
3493 trashes it in some circumstances. If that turns
3494 out to be a problem we can get synth_jcond_lit to
3495 push/pop it when it is live. */
3496 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3497 u->regs_live_after));
3498 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003499 break;
3500 default:
njne427a662002-10-02 11:08:25 +00003501 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003502 break;
sewardjde4a1d02002-03-22 01:27:54 +00003503 }
3504 }
3505 break;
3506 }
3507
3508 case JIFZ:
3509 vg_assert(u->tag1 == RealReg);
3510 vg_assert(u->tag2 == Literal);
3511 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003512 if (*sselive) {
3513 emit_put_sse_state();
3514 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003515 }
sewardjde4a1d02002-03-22 01:27:54 +00003516 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3517 break;
3518
sewardjde4a1d02002-03-22 01:27:54 +00003519 case PUSH:
3520 vg_assert(u->tag1 == RealReg);
3521 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003522 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003523 break;
3524
3525 case POP:
3526 vg_assert(u->tag1 == RealReg);
3527 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003528 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003529 break;
3530
3531 case CALLM:
3532 vg_assert(u->tag1 == Lit16);
3533 vg_assert(u->tag2 == NoValue);
3534 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003535 if (*sselive) {
3536 emit_put_sse_state();
3537 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003538 }
sewardjfa492d42002-12-08 18:20:01 +00003539 /* Call to a helper which is pretending to be a real CPU
3540 instruction (and therefore operates on Real flags and
3541 registers) */
3542 VG_(synth_call) ( False, u->val1,
3543 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003544 break;
3545
njn25e49d8e72002-09-23 09:36:25 +00003546 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003547 /* If you change this, remember to change USESEG above, since
3548 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003549 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3550 ones. */
3551 UInt argv[] = { u->val1, u->val2, u->val3 };
3552 UInt tagv[] = { RealReg, RealReg, RealReg };
3553 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3554
3555 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3556 else vg_assert(u->tag1 == NoValue);
3557 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3558 else vg_assert(u->tag2 == NoValue);
3559 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3560 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003561 vg_assert(u->size == 0);
3562
sewardjb91ae7f2003-04-29 23:50:00 +00003563 if (*sselive) {
3564 emit_put_sse_state();
3565 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003566 }
njn25e49d8e72002-09-23 09:36:25 +00003567 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3568 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003569 break;
njn25e49d8e72002-09-23 09:36:25 +00003570 }
sewardje1042472002-09-30 12:33:11 +00003571
sewardjde4a1d02002-03-22 01:27:54 +00003572 case CLEAR:
3573 vg_assert(u->tag1 == Lit16);
3574 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003575 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003576 break;
3577
3578 case CC2VAL:
3579 vg_assert(u->tag1 == RealReg);
3580 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003581 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003582 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003583 break;
3584
sewardjde4a1d02002-03-22 01:27:54 +00003585 case FPU_R:
3586 case FPU_W:
3587 vg_assert(u->tag1 == Lit16);
3588 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003589 if (!(*sselive)) {
3590 emit_get_sse_state();
3591 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003592 }
sewardjfa492d42002-12-08 18:20:01 +00003593 synth_fpu_regmem ( u->flags_r, u->flags_w,
3594 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003595 u->val1 & 0xFF,
3596 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003597 break;
3598
3599 case FPU:
3600 vg_assert(u->tag1 == Lit16);
3601 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003602 if (!(*sselive)) {
3603 emit_get_sse_state();
3604 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003605 }
sewardjfa492d42002-12-08 18:20:01 +00003606 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3607 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003608 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003609 break;
3610
sewardj3d7c9c82003-03-26 21:08:13 +00003611 case MMX2_MemWr:
3612 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003613 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003614 vg_assert(u->tag1 == Lit16);
3615 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003616 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003617 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003618 if (!(*sselive)) {
3619 emit_get_sse_state();
3620 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003621 }
3622 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3623 (u->val1 >> 8) & 0xFF,
3624 u->val1 & 0xFF,
3625 u->val2 );
3626 break;
3627
sewardjca860012003-03-27 23:52:58 +00003628 case MMX2_RegRd:
3629 vg_assert(u->tag1 == Lit16);
3630 vg_assert(u->tag2 == RealReg);
3631 vg_assert(u->tag3 == NoValue);
3632 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003633 if (!(*sselive)) {
3634 emit_get_sse_state();
3635 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003636 }
3637 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3638 (u->val1 >> 8) & 0xFF,
3639 u->val1 & 0xFF,
3640 u->val2 );
3641 break;
3642
sewardjd1c9e432003-04-04 20:40:34 +00003643 case MMX2_RegWr:
3644 vg_assert(u->tag1 == Lit16);
3645 vg_assert(u->tag2 == RealReg);
3646 vg_assert(u->tag3 == NoValue);
3647 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003648 if (!(*sselive)) {
3649 emit_get_sse_state();
3650 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003651 }
3652 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3653 (u->val1 >> 8) & 0xFF,
3654 u->val1 & 0xFF,
3655 u->val2 );
3656 break;
3657
sewardj3d7c9c82003-03-26 21:08:13 +00003658 case MMX1:
3659 vg_assert(u->tag1 == Lit16);
3660 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003661 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003662 if (!(*sselive)) {
3663 emit_get_sse_state();
3664 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003665 }
3666 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3667 u->val1 & 0xFF );
3668 break;
3669
3670 case MMX2:
3671 vg_assert(u->tag1 == Lit16);
3672 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003673 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003674 if (!(*sselive)) {
3675 emit_get_sse_state();
3676 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003677 }
3678 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3679 (u->val1 >> 8) & 0xFF,
3680 u->val1 & 0xFF );
3681 break;
3682
sewardjca860012003-03-27 23:52:58 +00003683 case MMX3:
3684 vg_assert(u->tag1 == Lit16);
3685 vg_assert(u->tag2 == Lit16);
3686 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003687 if (!(*sselive)) {
3688 emit_get_sse_state();
3689 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003690 }
3691 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3692 (u->val1 >> 8) & 0xFF,
3693 u->val1 & 0xFF,
3694 u->val2 & 0xFF );
3695 break;
3696
sewardjfebaa3b2003-05-25 01:07:34 +00003697 case SSE2a_MemWr:
3698 case SSE2a_MemRd:
3699 vg_assert(u->size == 4 || u->size == 16);
3700 vg_assert(u->tag1 == Lit16);
3701 vg_assert(u->tag2 == Lit16);
3702 vg_assert(u->tag3 == RealReg);
3703 vg_assert(!anyFlagUse(u));
3704 if (!(*sselive)) {
3705 emit_get_sse_state();
3706 *sselive = True;
3707 }
3708 emit_SSE2a ( u->flags_r, u->flags_w,
3709 (u->val1 >> 8) & 0xFF,
3710 u->val1 & 0xFF,
3711 u->val2 & 0xFF,
3712 u->val3 );
3713 break;
3714
3715 case SSE3a_MemWr:
3716 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00003717 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00003718 vg_assert(u->tag1 == Lit16);
3719 vg_assert(u->tag2 == Lit16);
3720 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003721 if (!(*sselive)) {
3722 emit_get_sse_state();
3723 *sselive = True;
3724 }
3725 emit_SSE3a ( u->flags_r, u->flags_w,
3726 (u->val1 >> 8) & 0xFF,
3727 u->val1 & 0xFF,
3728 (u->val2 >> 8) & 0xFF,
3729 u->val2 & 0xFF,
3730 u->val3 );
3731 break;
3732
3733 case SSE3g_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00003734 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00003735 vg_assert(u->size == 4);
3736 vg_assert(u->tag1 == Lit16);
3737 vg_assert(u->tag2 == Lit16);
3738 vg_assert(u->tag3 == RealReg);
3739 vg_assert(!anyFlagUse(u));
3740 if (!(*sselive)) {
3741 emit_get_sse_state();
3742 *sselive = True;
3743 }
3744 emit_SSE3g ( u->flags_r, u->flags_w,
3745 (u->val1 >> 8) & 0xFF,
3746 u->val1 & 0xFF,
3747 (u->val2 >> 8) & 0xFF,
3748 u->val2 & 0xFF,
sewardj02af6bc2003-06-12 00:56:06 +00003749 u->val3,
3750 u->opcode==SSE3g_RegRd ? True : False );
sewardjfebaa3b2003-05-25 01:07:34 +00003751 break;
3752
3753 case SSE4:
3754 vg_assert(u->size == 0);
3755 vg_assert(u->tag1 == Lit16);
3756 vg_assert(u->tag2 == Lit16);
3757 vg_assert(u->tag3 == NoValue);
3758 vg_assert(!anyFlagUse(u));
3759 if (!(*sselive)) {
3760 emit_get_sse_state();
3761 *sselive = True;
3762 }
3763 emit_SSE4 ( u->flags_r, u->flags_w,
3764 (u->val1 >> 8) & 0xFF,
3765 u->val1 & 0xFF,
3766 (u->val2 >> 8) & 0xFF,
3767 u->val2 & 0xFF );
3768 break;
3769
sewardja60be0e2003-05-26 08:47:27 +00003770 case SSE3:
3771 vg_assert(u->size == 0);
3772 vg_assert(u->tag1 == Lit16);
3773 vg_assert(u->tag2 == Lit16);
3774 vg_assert(u->tag3 == NoValue);
3775 vg_assert(!anyFlagUse(u));
3776 if (!(*sselive)) {
3777 emit_get_sse_state();
3778 *sselive = True;
3779 }
3780 emit_SSE3 ( u->flags_r, u->flags_w,
3781 (u->val1 >> 8) & 0xFF,
3782 u->val1 & 0xFF,
3783 u->val2 & 0xFF );
3784 break;
3785
sewardjde4a1d02002-03-22 01:27:54 +00003786 default:
sewardj1b7d8022002-11-30 12:35:42 +00003787 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003788 if (*sselive) {
3789 emit_put_sse_state();
3790 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003791 }
njn4ba5a792002-09-30 10:23:54 +00003792 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003793 } else {
njn25e49d8e72002-09-23 09:36:25 +00003794 VG_(printf)("\nError:\n"
3795 " unhandled opcode: %u. Perhaps "
3796 " VG_(needs).extended_UCode should be set?\n",
3797 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003798 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003799 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003800 }
sewardjde4a1d02002-03-22 01:27:54 +00003801 }
3802
sewardjb91ae7f2003-04-29 23:50:00 +00003803 if (0 && (*sselive)) {
3804 emit_put_sse_state();
3805 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003806 }
3807
njn25e49d8e72002-09-23 09:36:25 +00003808 /* Update UInstr histogram */
3809 vg_assert(u->opcode < 100);
3810 histogram[u->opcode].counts++;
3811 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003812}
3813
3814
3815/* Emit x86 for the ucode in cb, returning the address of the
3816 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003817UChar* VG_(emit_code) ( UCodeBlock* cb,
3818 Int* nbytes,
3819 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003820{
3821 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003822 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003823 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003824 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003825 Int tgt;
3826
sewardjfa492d42002-12-08 18:20:01 +00003827 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003828
njn25e49d8e72002-09-23 09:36:25 +00003829 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003830
sewardj22854b92002-11-30 14:00:47 +00003831 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3832 zero. We have to do this regardless of whether we're t-chaining
3833 or not. */
sewardja2113f92002-12-12 23:42:48 +00003834 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003835 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003836 VG_(emitB) (0xFF); /* decl */
3837 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3838 if (dis)
3839 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003840 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003841 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3842 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003843 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003844
sewardjb5ff83e2002-12-01 19:40:49 +00003845 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00003846 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00003847 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003848 curr_eip = cb->orig_eip;
3849 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3850 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003851 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003852 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003853 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003854 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003855
sewardjde4a1d02002-03-22 01:27:54 +00003856 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003857 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003858 if (!sane) {
3859 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003860 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003861 }
3862 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003863 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00003864 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003865 }
njn25e49d8e72002-09-23 09:36:25 +00003866 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003867 }
njn25e49d8e72002-09-23 09:36:25 +00003868 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00003869 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00003870 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003871
sewardj22854b92002-11-30 14:00:47 +00003872 if (j != NULL) {
3873 vg_assert(jumpidx <= VG_MAX_JUMPS);
3874 for(i = 0; i < jumpidx; i++)
3875 j[i] = jumps[i];
3876 }
3877
sewardjde4a1d02002-03-22 01:27:54 +00003878 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003879 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003880 *nbytes = emitted_code_used;
3881 return emitted_code;
3882}
3883
njn25e49d8e72002-09-23 09:36:25 +00003884#undef dis
3885
sewardjde4a1d02002-03-22 01:27:54 +00003886/*--------------------------------------------------------------------*/
3887/*--- end vg_from_ucode.c ---*/
3888/*--------------------------------------------------------------------*/