blob: 9b8fb84d02cb23c2ac40329fefba591e3e948c2f [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,
1467 Int ireg )
1468{
1469 VG_(new_emit)(True, uses_sflags, sets_sflags);
1470 VG_(emitB) ( first_byte );
1471 VG_(emitB) ( second_byte );
1472 VG_(emitB) ( third_byte );
1473 fourth_byte &= 0x38; /* mask out mod and rm fields */
1474 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1475 fourth_byte |= (ireg & 7); /* patch in our ireg */
1476 VG_(emitB) ( fourth_byte );
1477 if (dis)
1478 VG_(printf)("\n\t\tsse-reg-to-xmmreg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
1479 (UInt)first_byte, (UInt)second_byte,
1480 (UInt)third_byte, (UInt)fourth_byte,
1481 nameIReg(4,ireg) );
1482}
1483
1484static void emit_SSE4 ( FlagSet uses_sflags,
1485 FlagSet sets_sflags,
1486 UChar first_byte,
1487 UChar second_byte,
1488 UChar third_byte,
1489 UChar fourth_byte )
1490{
1491 VG_(new_emit)(True, uses_sflags, sets_sflags);
1492 VG_(emitB) ( first_byte );
1493 VG_(emitB) ( second_byte );
1494 VG_(emitB) ( third_byte );
1495 VG_(emitB) ( fourth_byte );
1496 if (dis)
1497 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x\n",
1498 (UInt)first_byte, (UInt)second_byte,
1499 (UInt)third_byte, (UInt)fourth_byte );
1500}
1501
sewardjca860012003-03-27 23:52:58 +00001502static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1503 FlagSet sets_sflags,
1504 UChar first_byte,
1505 UChar second_byte,
1506 Int ireg )
1507{
1508 VG_(new_emit)(True, uses_sflags, sets_sflags);
1509 VG_(emitB) ( 0x0F );
1510 VG_(emitB) ( first_byte );
1511 second_byte &= 0x38; /* mask out mod and rm fields */
1512 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1513 second_byte |= (ireg & 7); /* patch in our ireg */
1514 VG_(emitB) ( second_byte );
1515 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001516 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1517 (UInt)first_byte, (UInt)second_byte,
1518 nameIReg(4,ireg) );
1519}
1520
1521static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1522 FlagSet sets_sflags,
1523 UChar first_byte,
1524 UChar second_byte,
1525 Int ireg )
1526{
1527 VG_(new_emit)(True, uses_sflags, sets_sflags);
1528 VG_(emitB) ( 0x0F );
1529 VG_(emitB) ( first_byte );
1530 second_byte &= 0x38; /* mask out mod and rm fields */
1531 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1532 second_byte |= (ireg & 7); /* patch in our ireg */
1533 VG_(emitB) ( second_byte );
1534 if (dis)
1535 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001536 (UInt)first_byte, (UInt)second_byte,
1537 nameIReg(4,ireg) );
1538}
1539
1540static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1541 FlagSet sets_sflags,
1542 UChar first_byte,
1543 UChar second_byte,
1544 UChar third_byte )
1545{
1546 VG_(new_emit)(True, uses_sflags, sets_sflags);
1547 VG_(emitB) ( 0x0F );
1548 VG_(emitB) ( first_byte );
1549 VG_(emitB) ( second_byte );
1550 VG_(emitB) ( third_byte );
1551 if (dis)
1552 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1553 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1554}
1555
sewardj3d7c9c82003-03-26 21:08:13 +00001556static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1557 FlagSet sets_sflags,
1558 UChar first_byte,
1559 UChar second_byte )
1560{
1561 VG_(new_emit)(True, uses_sflags, sets_sflags);
1562 VG_(emitB) ( 0x0F );
1563 VG_(emitB) ( first_byte );
1564 VG_(emitB) ( second_byte );
1565 if (dis)
1566 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1567 (UInt)first_byte, (UInt)second_byte );
1568}
1569
1570static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1571 FlagSet sets_sflags,
1572 UChar first_byte )
1573{
1574 VG_(new_emit)(True, uses_sflags, sets_sflags);
1575 VG_(emitB) ( 0x0F );
1576 VG_(emitB) ( first_byte );
1577 if (dis)
1578 VG_(printf)("\n\t\tmmx1-0x%x\n",
1579 (UInt)first_byte );
1580}
1581
sewardjde4a1d02002-03-22 01:27:54 +00001582
1583/*----------------------------------------------------*/
1584/*--- misc instruction emitters ---*/
1585/*----------------------------------------------------*/
1586
njn25e49d8e72002-09-23 09:36:25 +00001587void VG_(emit_call_reg) ( Int reg )
1588{
sewardjfa492d42002-12-08 18:20:01 +00001589 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001590 VG_(emitB) ( 0xFF ); /* Grp5 */
1591 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1592 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001593 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001594}
1595
sewardjf0f12aa2002-12-28 00:04:08 +00001596static
1597void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1598 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001599{
sewardjfa492d42002-12-08 18:20:01 +00001600 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001601 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001602
1603 if (byte_off < -128 || byte_off > 127) {
1604 VG_(emitB) ( 0xFF );
1605 VG_(emitB) ( 0x95 );
1606 VG_(emitL) ( byte_off );
1607 } else {
1608 VG_(emitB) ( 0xFF );
1609 VG_(emitB) ( 0x55 );
1610 VG_(emitB) ( byte_off );
1611 }
1612 if (dis)
1613 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001614}
1615
sewardja2c5a732002-12-15 03:10:42 +00001616#if 0
1617/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001618static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1619{
1620 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001621 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001622 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1623 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001624 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001625 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001626 if (dis)
1627 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1628 nameIReg(4,regmem));
1629}
sewardja2c5a732002-12-15 03:10:42 +00001630#endif
sewardjde4a1d02002-03-22 01:27:54 +00001631
njn25e49d8e72002-09-23 09:36:25 +00001632void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001633{
njne427a662002-10-02 11:08:25 +00001634 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001635 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1636 VG_(emitB) ( 0x8D );
1637 VG_(emitB) ( 0x64 );
1638 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001639 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001640 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001641 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001642}
1643
1644
1645static void emit_movb_AL_zeroESPmem ( void )
1646{
1647 /* movb %al, 0(%esp) */
1648 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001649 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001650 VG_(emitB) ( 0x88 );
1651 VG_(emitB) ( 0x44 );
1652 VG_(emitB) ( 0x24 );
1653 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001654 if (dis)
1655 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1656}
1657
1658static void emit_movb_zeroESPmem_AL ( void )
1659{
1660 /* movb 0(%esp), %al */
1661 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001662 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001663 VG_(emitB) ( 0x8A );
1664 VG_(emitB) ( 0x44 );
1665 VG_(emitB) ( 0x24 );
1666 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001667 if (dis)
1668 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1669}
1670
sewardja2113f92002-12-12 23:42:48 +00001671/* Jump target states */
1672#define TGT_UNDEF (1 << 16)
1673#define TGT_FORWARD (2 << 16)
1674#define TGT_BACKWARD (3 << 16)
1675
1676static inline Int tgt_state(Int tgt)
1677{
1678 return tgt & 0xffff0000;
1679}
1680
1681static inline Int tgt_addr(Int tgt)
1682{
1683 return tgt & 0x0000ffff;
1684}
1685
1686static inline Int mk_tgt(Int state, Int addr)
1687{
1688 vg_assert(state == TGT_UNDEF
1689 || state == TGT_FORWARD || state == TGT_BACKWARD);
1690 vg_assert((addr & 0xffff0000) == 0);
1691
1692 return state | addr;
1693}
1694
1695void VG_(init_target) ( Int *tgt )
1696{
1697 *tgt = TGT_UNDEF;
1698}
1699
1700void VG_(target_back) ( Int *tgt )
1701{
1702 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1703
1704 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1705}
1706
1707void VG_(target_forward) ( Int *tgt )
1708{
1709 Int delta;
1710
1711 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1712 tgt_state(*tgt) == TGT_UNDEF);
1713
1714 if (tgt_state(*tgt) == TGT_UNDEF)
1715 return; /* target not used */
1716
1717 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1718 vg_assert(delta >= -128 && delta <= 127);
1719 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001720 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001721 emitted_code[tgt_addr(*tgt)] = delta;
1722 if (dis)
1723 VG_(printf)("(target to jump site %d; delta: %d)\n",
1724 tgt_addr(*tgt), delta);
1725}
1726
1727void VG_(emit_target_delta) ( Int *tgt )
1728{
1729 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1730 tgt_state(*tgt) == TGT_BACKWARD);
1731
1732 if (tgt_state(*tgt) == TGT_UNDEF) {
1733 /* forward jump */
1734 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1735 VG_(emitB) (0x00);
1736 } else {
1737 /* backward jump */
1738 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1739 vg_assert(delta >= -128 && delta <= 127);
1740 VG_(emitB) (delta);
1741 }
1742}
1743
sewardjde4a1d02002-03-22 01:27:54 +00001744
1745/* Emit a jump short with an 8-bit signed offset. Note that the
1746 offset is that which should be added to %eip once %eip has been
1747 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001748void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001749{
1750 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001751 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001752 VG_(emitB) ( 0x70 + (UInt)cond );
1753 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001754 if (dis)
1755 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001756 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001757}
1758
sewardja2113f92002-12-12 23:42:48 +00001759/* Same as above, but defers emitting the delta */
1760void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1761{
sewardj706240d2002-12-26 17:10:12 +00001762 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001763 VG_(emitB) ( 0x70 + (UInt)cond );
1764 VG_(emit_target_delta) (tgt);
1765 if (dis)
1766 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001767 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001768}
1769
1770
1771
sewardjf0f12aa2002-12-28 00:04:08 +00001772static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001773{
sewardjf0f12aa2002-12-28 00:04:08 +00001774 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001775 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1776 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001777 if (dis)
1778 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001779 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001780}
1781
1782static void emit_ret ( void )
1783{
sewardjfa492d42002-12-08 18:20:01 +00001784 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001785 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001786 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001787 if (dis)
1788 VG_(printf)("\n\t\tret\n");
1789}
1790
sewardj22854b92002-11-30 14:00:47 +00001791/* Predicate used in sanity checks elsewhere - returns true if any
1792 jump-site is an actual chained jump */
1793Bool VG_(is_chained_jumpsite)(Addr a)
1794{
1795 UChar *cp = (UChar *)a;
1796
1797 return (*cp == 0xE9); /* 0xE9 -- jmp */
1798}
1799
sewardj83f11862002-12-01 02:07:08 +00001800static
1801Bool is_fresh_jumpsite(UChar *cp)
1802{
1803 return
1804 cp[0] == 0x0F && /* UD2 */
1805 cp[1] == 0x0B &&
1806 cp[2] == 0x0F && /* UD2 */
1807 cp[3] == 0x0B &&
1808 cp[4] == 0x90; /* NOP */
1809}
1810
sewardj22854b92002-11-30 14:00:47 +00001811/* Predicate used in sanity checks elsewhere - returns true if all
1812 jump-sites are calls to VG_(patch_me) */
1813Bool VG_(is_unchained_jumpsite)(Addr a)
1814{
1815 UChar *cp = (UChar *)a;
1816 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1817 Int idelta;
1818
1819 if (*cp++ != 0xE8) /* 0xE8 == call */
1820 return False;
1821
1822 idelta = (*cp++) << 0;
1823 idelta |= (*cp++) << 8;
1824 idelta |= (*cp++) << 16;
1825 idelta |= (*cp++) << 24;
1826
1827 return idelta == delta;
1828}
1829
1830/* Return target address for a direct jmp */
1831Addr VG_(get_jmp_dest)(Addr a)
1832{
1833 Int delta;
1834 UChar *cp = (UChar *)a;
1835
1836 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1837 return 0;
1838
1839 delta = (*cp++) << 0;
1840 delta |= (*cp++) << 8;
1841 delta |= (*cp++) << 16;
1842 delta |= (*cp++) << 24;
1843
1844 return a + VG_PATCHME_JMPSZ + delta;
1845}
1846
1847/* unchain a BB by generating a call to VG_(patch_me) */
1848void VG_(unchain_jumpsite)(Addr a)
1849{
1850 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1851 UChar *cp = (UChar *)a;
1852
1853 if (VG_(is_unchained_jumpsite)(a))
1854 return; /* don't write unnecessarily */
1855
sewardj83f11862002-12-01 02:07:08 +00001856 if (!is_fresh_jumpsite(cp))
1857 VG_(bb_dechain_count)++; /* update stats */
1858
sewardj22854b92002-11-30 14:00:47 +00001859 *cp++ = 0xE8; /* call */
1860 *cp++ = (delta >> 0) & 0xff;
1861 *cp++ = (delta >> 8) & 0xff;
1862 *cp++ = (delta >> 16) & 0xff;
1863 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001864}
1865
1866/* This doesn't actually generate a call to VG_(patch_me), but
1867 reserves enough space in the instruction stream for it to happen
1868 and records the offset into the jump table. This is because call
1869 is a relative jump, and so will be affected when this code gets
1870 moved about. The translation table will "unchain" this basic block
1871 on insertion (with VG_(unchain_BB)()), and thereby generate a
1872 proper call instruction. */
1873static void emit_call_patchme( void )
1874{
1875 vg_assert(VG_PATCHME_CALLSZ == 5);
1876
sewardjfa492d42002-12-08 18:20:01 +00001877 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001878 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001879
1880 if (jumpidx >= VG_MAX_JUMPS) {
1881 /* If there too many jumps in this basic block, fall back to
1882 dispatch loop. We still need to keep it the same size as the
1883 call sequence. */
1884 VG_(emitB) ( 0xC3 ); /* ret */
1885 VG_(emitB) ( 0x90 ); /* nop */
1886 VG_(emitB) ( 0x90 ); /* nop */
1887 VG_(emitB) ( 0x90 ); /* nop */
1888 VG_(emitB) ( 0x90 ); /* nop */
1889
1890 if (dis)
1891 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1892
1893 if (0 && VG_(clo_verbosity))
1894 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1895 } else {
1896 jumps[jumpidx++] = emitted_code_used;
1897
1898 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1899 VG_(emitB) ( 0x0B );
1900 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1901 VG_(emitB) ( 0x0B );
1902 VG_(emitB) ( 0x90 ); /* NOP */
1903
1904 if (dis)
1905 VG_(printf)("\n\t\tud2; ud2; nop\n");
1906 }
1907}
1908
njn25e49d8e72002-09-23 09:36:25 +00001909void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001910{
sewardjf0f12aa2002-12-28 00:04:08 +00001911 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001912 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001913 if (dis)
1914 VG_(printf)("\n\t\tpushal\n");
1915}
1916
njn25e49d8e72002-09-23 09:36:25 +00001917void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001918{
sewardjf0f12aa2002-12-28 00:04:08 +00001919 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001920 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001921 if (dis)
1922 VG_(printf)("\n\t\tpopal\n");
1923}
1924
1925static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1926{
sewardjf0f12aa2002-12-28 00:04:08 +00001927 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001928 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1929 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001930 if (dis)
1931 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1932 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1933}
1934
1935static void emit_lea_sib_reg ( UInt lit, Int scale,
1936 Int regbase, Int regindex, Int reg )
1937{
sewardjf0f12aa2002-12-28 00:04:08 +00001938 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001939 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001940 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1941 if (dis)
1942 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1943 lit, nameIReg(4,regbase),
1944 nameIReg(4,regindex), scale,
1945 nameIReg(4,reg) );
1946}
1947
njn25e49d8e72002-09-23 09:36:25 +00001948void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001949{
sewardjf0f12aa2002-12-28 00:04:08 +00001950 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001951 VG_(emitB) ( 0x0F );
1952 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001953 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1954 if (dis)
1955 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1956}
1957
1958/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001959/*--- Helper offset -> addr translation ---*/
1960/*----------------------------------------------------*/
1961
1962/* Finds the baseBlock offset of a skin-specified helper.
1963 * Searches through compacts first, then non-compacts. */
1964Int VG_(helper_offset)(Addr a)
1965{
sewardj05bcdcb2003-05-18 10:05:38 +00001966 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00001967 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001968
1969 for (i = 0; i < VG_(n_compact_helpers); i++)
1970 if (VG_(compact_helper_addrs)[i] == a)
1971 return VG_(compact_helper_offsets)[i];
1972 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1973 if (VG_(noncompact_helper_addrs)[i] == a)
1974 return VG_(noncompact_helper_offsets)[i];
1975
1976 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001977 VG_(get_fnname) ( a, buf, 100 );
1978
njn25e49d8e72002-09-23 09:36:25 +00001979 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001980 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1981 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001982
1983 VG_(printf)(" compact helpers: ");
1984 for (i = 0; i < VG_(n_compact_helpers); i++)
1985 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1986
1987 VG_(printf)("\n non-compact helpers: ");
1988 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1989 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1990
1991 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001992 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001993}
1994
1995/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001996/*--- Instruction synthesisers ---*/
1997/*----------------------------------------------------*/
1998
1999static Condcode invertCondition ( Condcode cond )
2000{
2001 return (Condcode)(1 ^ (UInt)cond);
2002}
2003
2004
2005/* Synthesise a call to *baseBlock[offset], ie,
2006 call * (4 x offset)(%ebp).
2007*/
sewardjfa492d42002-12-08 18:20:01 +00002008void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002009 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002010{
2011 vg_assert(word_offset >= 0);
2012 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002013 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002014 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002015 }
sewardjf0f12aa2002-12-28 00:04:08 +00002016 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002017}
2018
njn25e49d8e72002-09-23 09:36:25 +00002019static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002020{
njn25e49d8e72002-09-23 09:36:25 +00002021 if (src != dst) {
2022 VG_(emit_movv_reg_reg) ( 4, src, dst );
2023 ccall_arg_setup_instrs++;
2024 }
njn6431be72002-07-28 09:53:34 +00002025}
njn25e49d8e72002-09-23 09:36:25 +00002026
2027/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2028static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2029{
2030 if (RealReg == tag) {
2031 maybe_emit_movl_reg_reg ( litOrReg, reg );
2032 } else if (Literal == tag) {
2033 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2034 ccall_arg_setup_instrs++;
2035 }
2036 else
njne427a662002-10-02 11:08:25 +00002037 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002038}
2039
2040static
2041void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2042{
2043 if (R_EAX == reg1) {
2044 VG_(emit_swapl_reg_EAX) ( reg2 );
2045 } else if (R_EAX == reg2) {
2046 VG_(emit_swapl_reg_EAX) ( reg1 );
2047 } else {
2048 emit_swapl_reg_reg ( reg1, reg2 );
2049 }
2050 ccall_arg_setup_instrs++;
2051}
2052
2053static
2054void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2055{
2056 if (dst1 != src2) {
2057 maybe_emit_movl_reg_reg ( src1, dst1 );
2058 maybe_emit_movl_reg_reg ( src2, dst2 );
2059
2060 } else if (dst2 != src1) {
2061 maybe_emit_movl_reg_reg ( src2, dst2 );
2062 maybe_emit_movl_reg_reg ( src1, dst1 );
2063
2064 } else {
2065 /* swap to break cycle */
2066 emit_swapl_arg_regs ( dst1, dst2 );
2067 }
2068}
2069
2070static
2071void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2072 UInt dst1, UInt dst2, UInt dst3)
2073{
2074 if (dst1 != src2 && dst1 != src3) {
2075 maybe_emit_movl_reg_reg ( src1, dst1 );
2076 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2077
2078 } else if (dst2 != src1 && dst2 != src3) {
2079 maybe_emit_movl_reg_reg ( src2, dst2 );
2080 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2081
2082 } else if (dst3 != src1 && dst3 != src2) {
2083 maybe_emit_movl_reg_reg ( src3, dst3 );
2084 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2085
2086 } else {
2087 /* break cycle */
2088 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2089 emit_swapl_arg_regs ( dst1, dst2 );
2090 emit_swapl_arg_regs ( dst1, dst3 );
2091
2092 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2093 emit_swapl_arg_regs ( dst1, dst3 );
2094 emit_swapl_arg_regs ( dst1, dst2 );
2095
2096 } else {
njne427a662002-10-02 11:08:25 +00002097 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002098 }
2099 }
2100}
2101
2102static
2103void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2104 UInt src1, UInt src2,
2105 UInt dst1, UInt dst2)
2106{
2107 /* If either are lits, order doesn't matter */
2108 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2109 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2110 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2111
2112 } else {
2113 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2114 }
2115}
2116
2117static
2118void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2119 UInt src1, UInt src2, UInt src3,
2120 UInt dst1, UInt dst2, UInt dst3)
2121{
2122 // SSS: fix this eventually -- make STOREV use two RealRegs?
2123 /* Not supporting literals for 3-arg C functions -- they're only used
2124 by STOREV which has 2 args */
2125 vg_assert(RealReg == tagv[src1] &&
2126 RealReg == tagv[src2] &&
2127 RealReg == tagv[src3]);
2128 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2129 dst1, dst2, dst3 );
2130}
2131
2132/* Synthesise a call to a C function `fn' (which must be registered in
2133 baseBlock) doing all the reg saving and arg handling work.
2134
2135 WARNING: a UInstr should *not* be translated with synth_ccall followed
2136 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2137 such behaviour and everything will fall over.
2138 */
2139void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2140 Tag tagv[], Int ret_reg,
2141 RRegSet regs_live_before, RRegSet regs_live_after )
2142{
2143 Int i;
2144 Int stack_used = 0;
2145 Bool preserve_eax, preserve_ecx, preserve_edx;
2146
2147 vg_assert(0 <= regparms_n && regparms_n <= 3);
2148
2149 ccalls++;
2150
2151 /* If %e[acd]x is live before and after the C call, save/restore it.
2152 Unless the return values clobbers the reg; in this case we must not
2153 save/restore the reg, because the restore would clobber the return
2154 value. (Before and after the UInstr really constitute separate live
2155 ranges, but you miss this if you don't consider what happens during
2156 the UInstr.) */
2157# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002158 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2159 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002160 ret_reg != realReg)
2161
2162 preserve_eax = PRESERVE_REG(R_EAX);
2163 preserve_ecx = PRESERVE_REG(R_ECX);
2164 preserve_edx = PRESERVE_REG(R_EDX);
2165
2166# undef PRESERVE_REG
2167
2168 /* Save caller-save regs as required */
2169 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2170 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2171 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2172
2173 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2174 is the number of args passed in regs (maximum 3 for GCC on x86). */
2175
2176 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002177
njn25e49d8e72002-09-23 09:36:25 +00002178 /* First push stack args (RealRegs or Literals) in reverse order. */
2179 for (i = argc-1; i >= regparms_n; i--) {
2180 switch (tagv[i]) {
2181 case RealReg:
2182 VG_(emit_pushv_reg) ( 4, argv[i] );
2183 break;
2184 case Literal:
2185 /* Use short form of pushl if possible. */
2186 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2187 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2188 else
2189 VG_(emit_pushl_lit32)( argv[i] );
2190 break;
2191 default:
2192 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002193 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002194 }
2195 stack_used += 4;
2196 ccall_arg_setup_instrs++;
2197 }
njn6431be72002-07-28 09:53:34 +00002198
njn25e49d8e72002-09-23 09:36:25 +00002199 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2200 If moving values between registers, be careful not to clobber any on
2201 the way. Happily we can use xchgl to swap registers.
2202 */
2203 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002204
njn25e49d8e72002-09-23 09:36:25 +00002205 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2206 case 3:
2207 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2208 R_EAX, R_EDX, R_ECX );
2209 break;
njn6431be72002-07-28 09:53:34 +00002210
njn25e49d8e72002-09-23 09:36:25 +00002211 /* Less-tricky. Args passed in %eax and %edx. */
2212 case 2:
2213 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2214 break;
2215
2216 /* Easy. Just move arg1 into %eax (if not already in there). */
2217 case 1:
2218 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2219 break;
2220
2221 case 0:
2222 break;
2223
2224 default:
njne427a662002-10-02 11:08:25 +00002225 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002226 }
2227
sewardjfa492d42002-12-08 18:20:01 +00002228 /* Call the function - may trash all flags */
2229 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002230
2231 /* Clear any args from stack */
2232 if (0 != stack_used) {
2233 VG_(emit_add_lit_to_esp) ( stack_used );
2234 ccall_stack_clears++;
2235 }
2236
2237 /* Move return value into ret_reg if necessary and not already there */
2238 if (INVALID_REALREG != ret_reg) {
2239 ccall_retvals++;
2240 if (R_EAX != ret_reg) {
2241 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2242 ccall_retval_movs++;
2243 }
2244 }
2245
2246 /* Restore live caller-save regs as required */
2247 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2248 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2249 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002250}
sewardjde4a1d02002-03-22 01:27:54 +00002251
sewardj2e93c502002-04-12 11:12:52 +00002252static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002253{
sewardj2e93c502002-04-12 11:12:52 +00002254 switch (jmpkind) {
2255 case JmpBoring:
2256 break;
sewardj2e93c502002-04-12 11:12:52 +00002257 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002258 break;
2259 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002260 break;
2261 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002262 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002263 break;
2264 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002265 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002266 break;
2267 default:
njne427a662002-10-02 11:08:25 +00002268 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002269 }
2270}
2271
2272/* Jump to the next translation, by loading its original addr into
2273 %eax and returning to the scheduler. Signal special requirements
2274 by loading a special value into %ebp first.
2275*/
2276static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2277{
sewardjfa492d42002-12-08 18:20:01 +00002278 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002279 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002280 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002281 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002282 emit_ret();
2283}
2284
sewardj22854b92002-11-30 14:00:47 +00002285static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002286
2287/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002288static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002289{
sewardjfa492d42002-12-08 18:20:01 +00002290 maybe_emit_put_eflags(); /* save flags here */
2291
njn25e49d8e72002-09-23 09:36:25 +00002292 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002293
2294 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2295 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2296 emit_call_patchme();
2297 } else {
2298 load_ebp_from_JmpKind ( jmpkind );
2299 emit_ret();
2300 }
sewardjde4a1d02002-03-22 01:27:54 +00002301}
2302
2303
sewardj2370f3b2002-11-30 15:01:01 +00002304static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002305static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002306 Opcode opcode, Int size,
2307 UInt lit, Int reg );
2308
sewardjfa492d42002-12-08 18:20:01 +00002309static void synth_jcond_lit ( Condcode cond,
2310 Addr addr,
2311 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002312{
sewardj2370f3b2002-11-30 15:01:01 +00002313 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002314 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002315 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002316
sewardja2113f92002-12-12 23:42:48 +00002317 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002318 VG_(init_target)(&tgt2);
2319 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002320
sewardjfa492d42002-12-08 18:20:01 +00002321 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2322 if need be */
2323 maybe_emit_put_eflags();
2324 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2325
2326 if (eflags_state == UPD_Both) {
2327 /* The flags are already set up, so we just use them as is. */
2328 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002329 cond = invertCondition(cond);
2330 } else {
sewardj75f04932002-12-12 23:13:21 +00002331 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002332
2333 /* The simd state contains the most recent version, so we emit a
2334 sequence to calculate the relevant condition directly out of
2335 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2336 copying them back to the real flags via popf. Notice that
2337 some of these sequences trash %eax, but that should be free
2338 now since this is the end of a bb and therefore all regs are
2339 dead. */
2340 simd = False;
2341
2342 switch (cond) {
2343
sewardjbb6c1182002-12-12 23:54:47 +00002344 case CondLE: /* Z || S != O -> S || !P */
2345 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002346 vg_assert(eax_trashable);
2347
2348 VG_(emit_movv_offregmem_reg)
2349 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2350 /* eax == %EFLAGS */
2351
sewardjbb6c1182002-12-12 23:54:47 +00002352 VG_(emit_nonshiftopv_lit_reg)
2353 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2354 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002355
sewardjbb6c1182002-12-12 23:54:47 +00002356 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2357 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002358
sewardj09736622002-12-28 00:19:00 +00002359 /* actually set the real cpu flags, since ROR changes
2360 neither P nor Z */
2361 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2362
sewardjbb6c1182002-12-12 23:54:47 +00002363 if (cond == CondLE) {
2364 /* test Z */
2365 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2366 /* test OF != SF */
2367 cond = CondP;
2368 } else {
2369 /* test Z */
2370 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2371 /* test OF == SF */
2372 cond = CondNP;
2373 }
sewardj2370f3b2002-11-30 15:01:01 +00002374 break;
2375
sewardjfa492d42002-12-08 18:20:01 +00002376 case CondL:
2377 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002378 vg_assert(eax_trashable);
2379
2380 VG_(emit_movv_offregmem_reg)
2381 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2382 /* eax == %EFLAGS */
2383
sewardj75f04932002-12-12 23:13:21 +00002384 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2385 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002386
sewardj75f04932002-12-12 23:13:21 +00002387 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2388 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002389
sewardj09736622002-12-28 00:19:00 +00002390 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002391 if (cond == CondL) cond = CondP; else cond = CondNP;
2392 break;
sewardjfa492d42002-12-08 18:20:01 +00002393
2394 case CondB:
2395 case CondNB:
2396 mask = EFlagC; goto simple; /* C=1 */
2397
2398 case CondZ:
2399 case CondNZ:
2400 mask = EFlagZ; goto simple; /* Z=1 */
2401
2402 case CondBE:
2403 case CondNBE:
2404 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2405
2406 case CondS:
2407 case CondNS:
2408 mask = EFlagS; goto simple; /* S=1 */
2409
2410 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002411 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002412 mask = EFlagP; goto simple; /* P=1 */
2413
sewardj39542072002-12-09 22:44:00 +00002414 case CondO:
2415 case CondNO:
2416 mask = EFlagO; goto simple; /* O=1 */
2417
sewardjfa492d42002-12-08 18:20:01 +00002418 default:
2419 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002420 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002421 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2422
2423 simple:
2424 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002425 if ((mask & 0xff) == mask) {
2426 VG_(emitB) ( 0xF6 ); /* Grp3 */
2427 VG_(emit_amode_offregmem_reg)(
2428 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2429 VG_(emitB) (mask);
2430 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002431 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002432 mask, VGOFF_(m_eflags) * 4);
2433 } else {
sewardjfa492d42002-12-08 18:20:01 +00002434 /* all cond codes are in lower 16 bits */
2435 vg_assert((mask & 0xffff) == mask);
2436
2437 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002438 VG_(emitB) ( 0xF7 );
2439 VG_(emit_amode_offregmem_reg)(
2440 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002441 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002442 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002443 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002444 mask, VGOFF_(m_eflags) * 4);
2445 }
2446
sewardj75f04932002-12-12 23:13:21 +00002447 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002448 break;
2449 }
2450 }
2451
sewardja2113f92002-12-12 23:42:48 +00002452 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002453
2454 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002455 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002456
2457 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002458 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002459}
2460
2461
sewardj2370f3b2002-11-30 15:01:01 +00002462
sewardjde4a1d02002-03-22 01:27:54 +00002463static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2464{
sewardja2113f92002-12-12 23:42:48 +00002465 Int tgt;
2466
2467 VG_(init_target)(&tgt);
2468
sewardjfa492d42002-12-08 18:20:01 +00002469 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002470
2471 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002472 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002473
2474 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002475}
2476
2477
2478static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2479{
2480 /* Load the zero-extended literal into reg, at size l,
2481 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002482 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002483}
2484
2485
2486static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2487{
2488 switch (size) {
2489 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2490 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2491 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002492 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002493 }
2494}
2495
2496
2497static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2498{
2499 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002500 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2501 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2502 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002503 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002504 }
2505}
2506
2507
2508static void synth_mov_reg_offregmem ( Int size, Int reg,
2509 Int off, Int areg )
2510{
2511 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002512 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2513 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002514 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002515 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002516 }
2517 else {
njn25e49d8e72002-09-23 09:36:25 +00002518 VG_(emit_swapl_reg_EAX) ( reg );
2519 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2520 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002521 }
2522 break;
njne427a662002-10-02 11:08:25 +00002523 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002524 }
2525}
2526
2527
2528static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2529{
2530 Int s1;
2531 switch (size) {
2532 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2533 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2534 case 1: if (reg1 < 4) {
2535 emit_movb_reg_regmem ( reg1, reg2 );
2536 }
2537 else {
2538 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2539 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2540 emit_swapl_reg_reg ( s1, reg1 );
2541 emit_movb_reg_regmem ( s1, reg2 );
2542 emit_swapl_reg_reg ( s1, reg1 );
2543 }
2544 break;
njne427a662002-10-02 11:08:25 +00002545 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002546 }
2547}
2548
2549
sewardjf0f12aa2002-12-28 00:04:08 +00002550static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002551 Opcode opcode, Int size,
2552 Int reg )
2553{
2554 /* NB! opcode is a uinstr opcode, not an x86 one! */
2555 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002556 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002557 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002558 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002559 break;
2560 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002561 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002562 } else {
njn25e49d8e72002-09-23 09:36:25 +00002563 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002564 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002565 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002566 }
2567 break;
njne427a662002-10-02 11:08:25 +00002568 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002569 }
2570}
2571
2572
2573
sewardjf0f12aa2002-12-28 00:04:08 +00002574static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002575 Opcode opcode, Int size,
2576 Int reg1, Int reg2 )
2577{
2578 /* NB! opcode is a uinstr opcode, not an x86 one! */
2579 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002580 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002581 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002582 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002583 break;
2584 case 1: { /* Horrible ... */
2585 Int s1, s2;
2586 /* Choose s1 and s2 to be x86 regs which we can talk about the
2587 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2588 sure s1 != s2 and that neither of them equal either reg1 or
2589 reg2. Then use them as temporaries to make things work. */
2590 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002591 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002592 break;
2593 }
2594 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2595 if (reg1 >= 4 && reg2 < 4) {
2596 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002597 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002598 emit_swapl_reg_reg ( reg1, s1 );
2599 break;
2600 }
2601 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2602 if (reg1 < 4 && reg2 >= 4) {
2603 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002604 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002605 emit_swapl_reg_reg ( reg2, s2 );
2606 break;
2607 }
2608 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2609 emit_swapl_reg_reg ( reg1, s1 );
2610 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002611 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002612 emit_swapl_reg_reg ( reg1, s1 );
2613 emit_swapl_reg_reg ( reg2, s2 );
2614 break;
2615 }
2616 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2617 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002618 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002619 emit_swapl_reg_reg ( reg1, s1 );
2620 break;
2621 }
njne427a662002-10-02 11:08:25 +00002622 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002623 }
njne427a662002-10-02 11:08:25 +00002624 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002625 }
2626}
2627
sewardja2c5a732002-12-15 03:10:42 +00002628#if 0
2629/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002630static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002631 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002632 Opcode opcode, Int size,
2633 Int off, Int areg, Int reg )
2634{
2635 switch (size) {
2636 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002637 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002638 break;
2639 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002640 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002641 break;
2642 case 1:
2643 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002644 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002645 } else {
2646 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002647 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002648 VG_(emit_swapl_reg_EAX) ( reg );
2649 }
2650 break;
2651 default:
2652 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2653 }
2654}
sewardja2c5a732002-12-15 03:10:42 +00002655#endif
sewardjfa492d42002-12-08 18:20:01 +00002656
sewardjde4a1d02002-03-22 01:27:54 +00002657static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002658 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002659 Opcode opcode, Int size,
2660 Int off, Int areg, Int reg )
2661{
2662 switch (size) {
2663 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002664 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002665 break;
2666 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002667 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002668 break;
2669 case 1:
2670 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002671 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002672 } else {
njn25e49d8e72002-09-23 09:36:25 +00002673 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002674 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002675 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002676 }
2677 break;
2678 default:
njne427a662002-10-02 11:08:25 +00002679 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002680 }
2681}
2682
2683
sewardjf0f12aa2002-12-28 00:04:08 +00002684static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002685 Opcode opcode, Int size,
2686 UInt lit, Int reg )
2687{
2688 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002689 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002690 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002691 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002692 break;
2693 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002694 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002695 } else {
njn25e49d8e72002-09-23 09:36:25 +00002696 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002697 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002698 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002699 }
2700 break;
njne427a662002-10-02 11:08:25 +00002701 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002702 }
2703}
2704
sewardjf0f12aa2002-12-28 00:04:08 +00002705static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002706 Opcode opcode, Int size,
2707 UInt lit, Int off, Int regmem )
2708{
2709 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002710 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002711 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002712 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002713 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002714 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002715 break;
2716 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2717 }
2718}
2719
sewardjde4a1d02002-03-22 01:27:54 +00002720
2721static void synth_push_reg ( Int size, Int reg )
2722{
2723 switch (size) {
2724 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002725 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002726 break;
2727 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002728 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002729 break;
2730 /* Pray that we don't have to generate this really cruddy bit of
2731 code very often. Could do better, but can I be bothered? */
2732 case 1:
2733 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002734 VG_(emit_add_lit_to_esp)(-1);
2735 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002736 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002737 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002738 break;
2739 default:
njne427a662002-10-02 11:08:25 +00002740 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002741 }
2742}
2743
2744
2745static void synth_pop_reg ( Int size, Int reg )
2746{
2747 switch (size) {
2748 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002749 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002750 break;
2751 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002752 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002753 break;
2754 case 1:
2755 /* Same comment as above applies. */
2756 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002757 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002758 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002759 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2760 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002761 break;
njne427a662002-10-02 11:08:25 +00002762 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002763 }
2764}
2765
2766
sewardjf0f12aa2002-12-28 00:04:08 +00002767static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002768 Opcode opcode, Int size,
2769 Int regs, Int regd )
2770{
2771 synth_push_reg ( size, regd );
2772 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002773 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002774 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2775 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2776 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002777 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002778 }
sewardjde4a1d02002-03-22 01:27:54 +00002779 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2780 synth_pop_reg ( size, regd );
2781}
2782
2783
sewardjf0f12aa2002-12-28 00:04:08 +00002784static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002785 Opcode opcode, Int size,
2786 UInt lit, Int reg )
2787{
2788 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002789 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002790 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002791 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002792 break;
2793 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002794 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002795 } else {
njn25e49d8e72002-09-23 09:36:25 +00002796 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002797 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002798 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002799 }
2800 break;
njne427a662002-10-02 11:08:25 +00002801 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002802 }
2803}
2804
2805
sewardjf0f12aa2002-12-28 00:04:08 +00002806static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002807{
sewardjde4a1d02002-03-22 01:27:54 +00002808 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002809 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002810 } else {
njn25e49d8e72002-09-23 09:36:25 +00002811 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002812 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002813 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002814 }
2815}
2816
2817
sewardj3d7c9c82003-03-26 21:08:13 +00002818static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2819 UChar first_byte,
2820 UChar second_byte,
2821 Int ireg )
2822{
2823 emit_MMX2_regmem ( uses_flags, sets_flags,
2824 first_byte, second_byte, ireg );
2825}
2826
2827
sewardjca860012003-03-27 23:52:58 +00002828static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2829 UChar first_byte,
2830 UChar second_byte,
2831 Int ireg )
2832{
2833 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2834 first_byte, second_byte, ireg );
2835}
2836
sewardjd1c9e432003-04-04 20:40:34 +00002837static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2838 UChar first_byte,
2839 UChar second_byte,
2840 Int ireg )
2841{
2842 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2843 first_byte, second_byte, ireg );
2844}
2845
sewardj3d7c9c82003-03-26 21:08:13 +00002846static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2847 UChar first_byte,
2848 UChar second_byte )
2849{
2850 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2851}
2852
2853
sewardjca860012003-03-27 23:52:58 +00002854static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2855 UChar first_byte,
2856 UChar second_byte,
2857 UChar third_byte )
2858{
2859 emit_MMX3_no_mem ( uses_flags, sets_flags,
2860 first_byte, second_byte, third_byte );
2861}
2862
2863
sewardj3d7c9c82003-03-26 21:08:13 +00002864static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2865 UChar first_byte )
2866{
2867 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2868}
2869
2870
sewardjfa492d42002-12-08 18:20:01 +00002871static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2872 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002873 UChar second_byte_masked,
2874 Int reg )
2875{
sewardj3d7c9c82003-03-26 21:08:13 +00002876 emit_fpu_regmem ( uses_flags, sets_flags,
2877 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002878}
2879
2880
sewardjfa492d42002-12-08 18:20:01 +00002881static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2882 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002883 UChar second_byte )
2884{
sewardjfa492d42002-12-08 18:20:01 +00002885 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002886}
2887
2888
2889static void synth_movl_reg_reg ( Int src, Int dst )
2890{
2891 emit_movl_reg_reg ( src, dst );
2892}
2893
2894static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2895{
sewardja2113f92002-12-12 23:42:48 +00002896 Int tgt;
2897
2898 VG_(init_target)(&tgt);
2899
2900 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002901 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002902
2903 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002904}
2905
2906
sewardjde4a1d02002-03-22 01:27:54 +00002907/*----------------------------------------------------*/
2908/*--- Top level of the uinstr -> x86 translation. ---*/
2909/*----------------------------------------------------*/
2910
2911/* Return the byte offset from %ebp (ie, into baseBlock)
2912 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002913static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2914{
2915 if (tag == SpillNo) {
2916 vg_assert(size == 4);
2917 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2918 return 4 * (value + VGOFF_(spillslots));
2919 }
2920 if (tag == ArchReg) {
2921 switch (value) {
2922 case R_EAX: return 4 * VGOFF_(m_eax);
2923 case R_ECX: return 4 * VGOFF_(m_ecx);
2924 case R_EDX: return 4 * VGOFF_(m_edx);
2925 case R_EBX: return 4 * VGOFF_(m_ebx);
2926 case R_ESP:
2927 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2928 else return 4 * VGOFF_(m_esp);
2929 case R_EBP:
2930 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2931 else return 4 * VGOFF_(m_ebp);
2932 case R_ESI:
2933 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2934 else return 4 * VGOFF_(m_esi);
2935 case R_EDI:
2936 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2937 else return 4 * VGOFF_(m_edi);
2938 }
2939 }
njne427a662002-10-02 11:08:25 +00002940 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002941}
2942
sewardjde4a1d02002-03-22 01:27:54 +00002943static Int eflagsOffset ( void )
2944{
2945 return 4 * VGOFF_(m_eflags);
2946}
2947
sewardje1042472002-09-30 12:33:11 +00002948static Int segRegOffset ( UInt archregs )
2949{
2950 switch (archregs) {
2951 case R_CS: return 4 * VGOFF_(m_cs);
2952 case R_SS: return 4 * VGOFF_(m_ss);
2953 case R_DS: return 4 * VGOFF_(m_ds);
2954 case R_ES: return 4 * VGOFF_(m_es);
2955 case R_FS: return 4 * VGOFF_(m_fs);
2956 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002957 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002958 }
2959}
2960
njnf4ce3d32003-02-10 10:17:26 +00002961UInt VG_(get_archreg) ( UInt arch )
2962{
2963 switch (arch) {
2964 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2965 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2966 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2967 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2968 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2969 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2970 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2971 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2972 default: VG_(core_panic)( "get_thread_archreg");
2973 }
2974}
2975
2976UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2977{
2978 ThreadState* tst;
2979
2980 vg_assert(VG_(is_valid_tid)(tid));
2981 tst = & VG_(threads)[tid];
2982
2983 switch (arch) {
2984 case R_EAX: return tst->m_eax;
2985 case R_ECX: return tst->m_ecx;
2986 case R_EDX: return tst->m_edx;
2987 case R_EBX: return tst->m_ebx;
2988 case R_ESP: return tst->m_esp;
2989 case R_EBP: return tst->m_ebp;
2990 case R_ESI: return tst->m_esi;
2991 case R_EDI: return tst->m_edi;
2992 default: VG_(core_panic)( "get_thread_archreg");
2993 }
2994}
2995
njnb93d1782003-02-03 12:03:22 +00002996/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00002997static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00002998{
2999 switch (arch) {
3000 case R_EAX: return VGOFF_(sh_eax);
3001 case R_ECX: return VGOFF_(sh_ecx);
3002 case R_EDX: return VGOFF_(sh_edx);
3003 case R_EBX: return VGOFF_(sh_ebx);
3004 case R_ESP: return VGOFF_(sh_esp);
3005 case R_EBP: return VGOFF_(sh_ebp);
3006 case R_ESI: return VGOFF_(sh_esi);
3007 case R_EDI: return VGOFF_(sh_edi);
3008 default: VG_(core_panic)( "shadow_reg_index");
3009 }
3010}
sewardjde4a1d02002-03-22 01:27:54 +00003011
njn25e49d8e72002-09-23 09:36:25 +00003012/* Return the byte offset from %ebp (ie, into baseBlock)
3013 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003014Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003015{
njnb93d1782003-02-03 12:03:22 +00003016 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003017}
3018
njn4ba5a792002-09-30 10:23:54 +00003019Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003020{
3021 return 4 * VGOFF_(sh_eflags);
3022}
3023
njnb93d1782003-02-03 12:03:22 +00003024/* Accessing shadow arch. registers */
3025UInt VG_(get_shadow_archreg) ( UInt archreg )
3026{
3027 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3028}
3029
3030void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3031{
3032 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3033}
3034
njnd3040452003-05-19 15:04:06 +00003035void VG_(set_shadow_eflags) ( UInt val )
3036{
3037 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3038}
3039
njnf4ce3d32003-02-10 10:17:26 +00003040UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3041{
3042 ThreadState* tst;
3043
3044 vg_assert(VG_(is_valid_tid)(tid));
3045 tst = & VG_(threads)[tid];
3046
3047 switch (archreg) {
3048 case R_EAX: return tst->sh_eax;
3049 case R_ECX: return tst->sh_ecx;
3050 case R_EDX: return tst->sh_edx;
3051 case R_EBX: return tst->sh_ebx;
3052 case R_ESP: return tst->sh_esp;
3053 case R_EBP: return tst->sh_ebp;
3054 case R_ESI: return tst->sh_esi;
3055 case R_EDI: return tst->sh_edi;
3056 default: VG_(core_panic)( "get_thread_shadow_archreg");
3057 }
3058}
3059
3060void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3061{
3062 ThreadState* tst;
3063
3064 vg_assert(VG_(is_valid_tid)(tid));
3065 tst = & VG_(threads)[tid];
3066
3067 switch (archreg) {
3068 case R_EAX: tst->sh_eax = val; break;
3069 case R_ECX: tst->sh_ecx = val; break;
3070 case R_EDX: tst->sh_edx = val; break;
3071 case R_EBX: tst->sh_ebx = val; break;
3072 case R_ESP: tst->sh_esp = val; break;
3073 case R_EBP: tst->sh_ebp = val; break;
3074 case R_ESI: tst->sh_esi = val; break;
3075 case R_EDI: tst->sh_edi = val; break;
3076 default: VG_(core_panic)( "set_thread_shadow_archreg");
3077 }
3078}
3079
njnb93d1782003-02-03 12:03:22 +00003080Addr VG_(shadow_archreg_address) ( UInt archreg )
3081{
3082 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3083}
sewardjde4a1d02002-03-22 01:27:54 +00003084
sewardjde4a1d02002-03-22 01:27:54 +00003085static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3086{
3087 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003088 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3089 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003090 }
3091 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003092 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3093 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003094 }
3095 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003096 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3097 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003098 }
3099 else
njne427a662002-10-02 11:08:25 +00003100 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003101}
3102
3103
sewardjde4a1d02002-03-22 01:27:54 +00003104/*----------------------------------------------------*/
3105/*--- Generate code for a single UInstr. ---*/
3106/*----------------------------------------------------*/
3107
sewardj478335c2002-10-05 02:44:47 +00003108static __inline__
3109Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003110{
3111 return (u->flags_w != FlagsEmpty);
3112}
3113
sewardjfa492d42002-12-08 18:20:01 +00003114static __inline__
3115Bool readFlagUse ( UInstr* u )
3116{
3117 /* If the UInstr writes some flags but not all, then we still need
3118 to consider it as reading flags so that the unchanged values are
3119 passed through properly. (D is special) */
3120 return
3121 (u->flags_r != FlagsEmpty) ||
3122 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3123}
3124
sewardj478335c2002-10-05 02:44:47 +00003125static __inline__
3126Bool anyFlagUse ( UInstr* u )
3127{
sewardjfa492d42002-12-08 18:20:01 +00003128 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003129}
3130
3131
sewardjb91ae7f2003-04-29 23:50:00 +00003132/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3133 the real machine's cpu. If so we need to be very careful not to trash it.
3134 If FPU/SSE state is live and we deem it necessary to copy it back to
3135 the simulated machine's FPU/SSE state, we do so. The final state of
3136 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003137 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003138 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003139*/
sewardjb5ff83e2002-12-01 19:40:49 +00003140static void emitUInstr ( UCodeBlock* cb, Int i,
3141 RRegSet regs_live_before,
3142 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003143 Bool* sselive, /* True<==>FPU/SSE
3144 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003145 Addr* orig_eip, /* previous curr_eip, or zero */
3146 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003147{
njn25e49d8e72002-09-23 09:36:25 +00003148 Int old_emitted_code_used;
3149 UInstr* u = &cb->instrs[i];
3150
sewardjde4a1d02002-03-22 01:27:54 +00003151 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003152 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003153
njn25e49d8e72002-09-23 09:36:25 +00003154 old_emitted_code_used = emitted_code_used;
3155
sewardjde4a1d02002-03-22 01:27:54 +00003156 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003157 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003158
sewardjb5ff83e2002-12-01 19:40:49 +00003159 case INCEIP:
3160 /* Advance %EIP some small amount. */
3161 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003162
sewardjb5ff83e2002-12-01 19:40:49 +00003163 if (*orig_eip == 0 /* we don't know what the old value was */
3164 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3165 /* We have to update all 32 bits of the value. */
3166 VG_(emit_movv_lit_offregmem)(
3167 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3168 } else {
3169 /* Cool! we only need to update lowest 8 bits */
3170 VG_(emit_movb_lit_offregmem)(
3171 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003172 }
njn25e49d8e72002-09-23 09:36:25 +00003173
sewardjb5ff83e2002-12-01 19:40:49 +00003174 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003175 break;
sewardjde4a1d02002-03-22 01:27:54 +00003176
3177 case LEA1: {
3178 vg_assert(u->tag1 == RealReg);
3179 vg_assert(u->tag2 == RealReg);
3180 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3181 break;
3182 }
3183
3184 case LEA2: {
3185 vg_assert(u->tag1 == RealReg);
3186 vg_assert(u->tag2 == RealReg);
3187 vg_assert(u->tag3 == RealReg);
3188 emit_lea_sib_reg ( u->lit32, u->extra4b,
3189 u->val1, u->val2, u->val3 );
3190 break;
3191 }
3192
3193 case WIDEN: {
3194 vg_assert(u->tag1 == RealReg);
3195 if (u->signed_widen) {
3196 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3197 } else {
3198 /* no need to generate any code. */
3199 }
3200 break;
3201 }
3202
sewardjde4a1d02002-03-22 01:27:54 +00003203 case STORE: {
3204 vg_assert(u->tag1 == RealReg);
3205 vg_assert(u->tag2 == RealReg);
3206 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003207 break;
3208 }
3209
3210 case LOAD: {
3211 vg_assert(u->tag1 == RealReg);
3212 vg_assert(u->tag2 == RealReg);
3213 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3214 break;
3215 }
3216
sewardjde4a1d02002-03-22 01:27:54 +00003217 case GET: {
3218 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3219 vg_assert(u->tag2 == RealReg);
3220 synth_mov_offregmem_reg (
3221 u->size,
3222 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3223 R_EBP,
3224 u->val2
3225 );
3226 break;
3227 }
3228
3229 case PUT: {
3230 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3231 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003232 synth_mov_reg_offregmem (
3233 u->size,
3234 u->val1,
3235 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3236 R_EBP
3237 );
sewardjde4a1d02002-03-22 01:27:54 +00003238 break;
3239 }
3240
sewardje1042472002-09-30 12:33:11 +00003241 case GETSEG: {
3242 vg_assert(u->tag1 == ArchRegS);
3243 vg_assert(u->tag2 == RealReg);
3244 vg_assert(u->size == 2);
3245 synth_mov_offregmem_reg (
3246 4,
3247 segRegOffset( u->val1 ),
3248 R_EBP,
3249 u->val2
3250 );
3251 break;
3252 }
3253
3254 case PUTSEG: {
3255 vg_assert(u->tag1 == RealReg);
3256 vg_assert(u->tag2 == ArchRegS);
3257 vg_assert(u->size == 2);
3258 synth_mov_reg_offregmem (
3259 4,
3260 u->val1,
3261 segRegOffset( u->val2 ),
3262 R_EBP
3263 );
3264 break;
3265 }
3266
sewardjde4a1d02002-03-22 01:27:54 +00003267 case GETF: {
3268 vg_assert(u->size == 2 || u->size == 4);
3269 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003270
3271 /* This complexity is because the D(irection) flag is stored
3272 separately from the rest of EFLAGS. */
3273
3274 /* We're only fetching from the Simd state, so make sure it's
3275 up to date. */
3276 maybe_emit_put_eflags();
3277
3278 /* get D in u->val1 (== 1 or -1) */
3279 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3280
3281 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3282 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3283
3284 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3285 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3286 eflagsOffset(), R_EBP);
3287
3288 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3289 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3290 eflagsOffset(), R_EBP);
3291
3292 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3293 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3294 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003295 break;
3296 }
3297
3298 case PUTF: {
3299 vg_assert(u->size == 2 || u->size == 4);
3300 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003301
3302 /* When putting a value into EFLAGS, this generates the
3303 correct value for m_dflag (-1 or 1), and clears the D bit
3304 in EFLAGS. */
3305
3306 /* We're updating the whole flag state, so the old state
3307 doesn't matter; make sure that the new simulated state
3308 will be fetched when needed. */
3309 eflags_state = UPD_Simd;
3310
3311 /* store EFLAGS (with D) */
3312 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3313
3314 /* u->val1 &= EFlagD */
3315 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3316
3317 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3318 synth_unaryop_reg(False, NEG, u->size, u->val1);
3319 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3320 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3321
3322 /* save D */
3323 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3324
3325 /* EFLAGS &= ~EFlagD */
3326 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3327 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003328 break;
3329 }
3330
3331 case MOV: {
3332 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3333 vg_assert(u->tag2 == RealReg);
3334 switch (u->tag1) {
3335 case RealReg: vg_assert(u->size == 4);
3336 if (u->val1 != u->val2)
3337 synth_movl_reg_reg ( u->val1, u->val2 );
3338 break;
3339 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3340 break;
njne427a662002-10-02 11:08:25 +00003341 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003342 }
3343 break;
3344 }
3345
sewardje1042472002-09-30 12:33:11 +00003346 case USESEG: {
3347 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3348 ones. */
sewardjd077f532002-09-30 21:52:50 +00003349 UInt argv[] = { u->val1, u->val2 };
3350 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003351 UInt ret_reg = u->val2;
3352
3353 vg_assert(u->tag1 == RealReg);
3354 vg_assert(u->tag2 == RealReg);
3355 vg_assert(u->size == 0);
3356
sewardjb91ae7f2003-04-29 23:50:00 +00003357 if (*sselive) {
3358 emit_put_sse_state();
3359 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003360 }
3361
sewardje1042472002-09-30 12:33:11 +00003362 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3363 2, /* args */
3364 0, /* regparms_n */
3365 argv, tagv,
3366 ret_reg, regs_live_before, u->regs_live_after );
3367 break;
3368 }
3369
sewardj478335c2002-10-05 02:44:47 +00003370 case SBB:
3371 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003372 case XOR:
3373 case OR:
3374 case AND:
3375 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003376 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003377 vg_assert(u->tag2 == RealReg);
3378 switch (u->tag1) {
3379 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003380 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003381 u->opcode, u->size, u->lit32, u->val2 );
3382 break;
3383 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003384 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003385 u->opcode, u->size, u->val1, u->val2 );
3386 break;
3387 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003388 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003389 u->opcode, u->size,
3390 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3391 R_EBP,
3392 u->val2 );
3393 break;
njne427a662002-10-02 11:08:25 +00003394 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003395 }
3396 break;
3397 }
3398
sewardj478335c2002-10-05 02:44:47 +00003399 case RCR:
3400 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003401 case ROR:
3402 case ROL:
3403 case SAR:
3404 case SHR:
3405 case SHL: {
3406 vg_assert(u->tag2 == RealReg);
3407 switch (u->tag1) {
3408 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003409 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003410 u->opcode, u->size, u->lit32, u->val2 );
3411 break;
3412 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003413 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003414 u->opcode, u->size, u->val1, u->val2 );
3415 break;
njne427a662002-10-02 11:08:25 +00003416 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003417 }
3418 break;
3419 }
3420
3421 case INC:
3422 case DEC:
3423 case NEG:
3424 case NOT:
3425 vg_assert(u->tag1 == RealReg);
3426 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003427 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003428 break;
3429
3430 case BSWAP:
3431 vg_assert(u->tag1 == RealReg);
3432 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003433 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003434 emit_bswapl_reg ( u->val1 );
3435 break;
3436
3437 case CMOV:
3438 vg_assert(u->tag1 == RealReg);
3439 vg_assert(u->tag2 == RealReg);
3440 vg_assert(u->cond != CondAlways);
3441 vg_assert(u->size == 4);
3442 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3443 break;
3444
3445 case JMP: {
3446 vg_assert(u->tag2 == NoValue);
3447 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003448 if (*sselive) {
3449 emit_put_sse_state();
3450 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003451 }
sewardjde4a1d02002-03-22 01:27:54 +00003452 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003453 switch (u->tag1) {
3454 case RealReg:
3455 synth_jmp_reg ( u->val1, u->jmpkind );
3456 break;
3457 case Literal:
3458 synth_jmp_lit ( u->lit32, u->jmpkind );
3459 break;
3460 default:
njne427a662002-10-02 11:08:25 +00003461 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003462 break;
sewardjde4a1d02002-03-22 01:27:54 +00003463 }
3464 } else {
sewardj2e93c502002-04-12 11:12:52 +00003465 switch (u->tag1) {
3466 case RealReg:
njne427a662002-10-02 11:08:25 +00003467 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003468 break;
3469 case Literal:
3470 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003471 /* %eax had better not be live since synth_jcond_lit
3472 trashes it in some circumstances. If that turns
3473 out to be a problem we can get synth_jcond_lit to
3474 push/pop it when it is live. */
3475 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3476 u->regs_live_after));
3477 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003478 break;
3479 default:
njne427a662002-10-02 11:08:25 +00003480 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003481 break;
sewardjde4a1d02002-03-22 01:27:54 +00003482 }
3483 }
3484 break;
3485 }
3486
3487 case JIFZ:
3488 vg_assert(u->tag1 == RealReg);
3489 vg_assert(u->tag2 == Literal);
3490 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003491 if (*sselive) {
3492 emit_put_sse_state();
3493 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003494 }
sewardjde4a1d02002-03-22 01:27:54 +00003495 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3496 break;
3497
sewardjde4a1d02002-03-22 01:27:54 +00003498 case PUSH:
3499 vg_assert(u->tag1 == RealReg);
3500 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003501 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003502 break;
3503
3504 case POP:
3505 vg_assert(u->tag1 == RealReg);
3506 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003507 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003508 break;
3509
3510 case CALLM:
3511 vg_assert(u->tag1 == Lit16);
3512 vg_assert(u->tag2 == NoValue);
3513 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003514 if (*sselive) {
3515 emit_put_sse_state();
3516 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003517 }
sewardjfa492d42002-12-08 18:20:01 +00003518 /* Call to a helper which is pretending to be a real CPU
3519 instruction (and therefore operates on Real flags and
3520 registers) */
3521 VG_(synth_call) ( False, u->val1,
3522 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003523 break;
3524
njn25e49d8e72002-09-23 09:36:25 +00003525 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003526 /* If you change this, remember to change USESEG above, since
3527 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003528 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3529 ones. */
3530 UInt argv[] = { u->val1, u->val2, u->val3 };
3531 UInt tagv[] = { RealReg, RealReg, RealReg };
3532 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3533
3534 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3535 else vg_assert(u->tag1 == NoValue);
3536 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3537 else vg_assert(u->tag2 == NoValue);
3538 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3539 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003540 vg_assert(u->size == 0);
3541
sewardjb91ae7f2003-04-29 23:50:00 +00003542 if (*sselive) {
3543 emit_put_sse_state();
3544 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003545 }
njn25e49d8e72002-09-23 09:36:25 +00003546 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3547 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003548 break;
njn25e49d8e72002-09-23 09:36:25 +00003549 }
sewardje1042472002-09-30 12:33:11 +00003550
sewardjde4a1d02002-03-22 01:27:54 +00003551 case CLEAR:
3552 vg_assert(u->tag1 == Lit16);
3553 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003554 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003555 break;
3556
3557 case CC2VAL:
3558 vg_assert(u->tag1 == RealReg);
3559 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003560 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003561 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003562 break;
3563
sewardjde4a1d02002-03-22 01:27:54 +00003564 case FPU_R:
3565 case FPU_W:
3566 vg_assert(u->tag1 == Lit16);
3567 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003568 if (!(*sselive)) {
3569 emit_get_sse_state();
3570 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003571 }
sewardjfa492d42002-12-08 18:20:01 +00003572 synth_fpu_regmem ( u->flags_r, u->flags_w,
3573 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003574 u->val1 & 0xFF,
3575 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003576 break;
3577
3578 case FPU:
3579 vg_assert(u->tag1 == Lit16);
3580 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003581 if (!(*sselive)) {
3582 emit_get_sse_state();
3583 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003584 }
sewardjfa492d42002-12-08 18:20:01 +00003585 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3586 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003587 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003588 break;
3589
sewardj3d7c9c82003-03-26 21:08:13 +00003590 case MMX2_MemWr:
3591 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003592 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003593 vg_assert(u->tag1 == Lit16);
3594 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003595 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003596 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003597 if (!(*sselive)) {
3598 emit_get_sse_state();
3599 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003600 }
3601 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3602 (u->val1 >> 8) & 0xFF,
3603 u->val1 & 0xFF,
3604 u->val2 );
3605 break;
3606
sewardjca860012003-03-27 23:52:58 +00003607 case MMX2_RegRd:
3608 vg_assert(u->tag1 == Lit16);
3609 vg_assert(u->tag2 == RealReg);
3610 vg_assert(u->tag3 == NoValue);
3611 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003612 if (!(*sselive)) {
3613 emit_get_sse_state();
3614 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003615 }
3616 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3617 (u->val1 >> 8) & 0xFF,
3618 u->val1 & 0xFF,
3619 u->val2 );
3620 break;
3621
sewardjd1c9e432003-04-04 20:40:34 +00003622 case MMX2_RegWr:
3623 vg_assert(u->tag1 == Lit16);
3624 vg_assert(u->tag2 == RealReg);
3625 vg_assert(u->tag3 == NoValue);
3626 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003627 if (!(*sselive)) {
3628 emit_get_sse_state();
3629 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003630 }
3631 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3632 (u->val1 >> 8) & 0xFF,
3633 u->val1 & 0xFF,
3634 u->val2 );
3635 break;
3636
sewardj3d7c9c82003-03-26 21:08:13 +00003637 case MMX1:
3638 vg_assert(u->tag1 == Lit16);
3639 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003640 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003641 if (!(*sselive)) {
3642 emit_get_sse_state();
3643 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003644 }
3645 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3646 u->val1 & 0xFF );
3647 break;
3648
3649 case MMX2:
3650 vg_assert(u->tag1 == Lit16);
3651 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003652 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003653 if (!(*sselive)) {
3654 emit_get_sse_state();
3655 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003656 }
3657 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3658 (u->val1 >> 8) & 0xFF,
3659 u->val1 & 0xFF );
3660 break;
3661
sewardjca860012003-03-27 23:52:58 +00003662 case MMX3:
3663 vg_assert(u->tag1 == Lit16);
3664 vg_assert(u->tag2 == Lit16);
3665 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003666 if (!(*sselive)) {
3667 emit_get_sse_state();
3668 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003669 }
3670 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3671 (u->val1 >> 8) & 0xFF,
3672 u->val1 & 0xFF,
3673 u->val2 & 0xFF );
3674 break;
3675
sewardjfebaa3b2003-05-25 01:07:34 +00003676 case SSE2a_MemWr:
3677 case SSE2a_MemRd:
3678 vg_assert(u->size == 4 || u->size == 16);
3679 vg_assert(u->tag1 == Lit16);
3680 vg_assert(u->tag2 == Lit16);
3681 vg_assert(u->tag3 == RealReg);
3682 vg_assert(!anyFlagUse(u));
3683 if (!(*sselive)) {
3684 emit_get_sse_state();
3685 *sselive = True;
3686 }
3687 emit_SSE2a ( u->flags_r, u->flags_w,
3688 (u->val1 >> 8) & 0xFF,
3689 u->val1 & 0xFF,
3690 u->val2 & 0xFF,
3691 u->val3 );
3692 break;
3693
3694 case SSE3a_MemWr:
3695 case SSE3a_MemRd:
3696 vg_assert(u->size == 4 || u->size == 16);
3697 vg_assert(u->tag1 == Lit16);
3698 vg_assert(u->tag2 == Lit16);
3699 vg_assert(u->tag3 == RealReg);
3700 vg_assert(!anyFlagUse(u));
3701 if (!(*sselive)) {
3702 emit_get_sse_state();
3703 *sselive = True;
3704 }
3705 emit_SSE3a ( u->flags_r, u->flags_w,
3706 (u->val1 >> 8) & 0xFF,
3707 u->val1 & 0xFF,
3708 (u->val2 >> 8) & 0xFF,
3709 u->val2 & 0xFF,
3710 u->val3 );
3711 break;
3712
3713 case SSE3g_RegRd:
3714 vg_assert(u->size == 4);
3715 vg_assert(u->tag1 == Lit16);
3716 vg_assert(u->tag2 == Lit16);
3717 vg_assert(u->tag3 == RealReg);
3718 vg_assert(!anyFlagUse(u));
3719 if (!(*sselive)) {
3720 emit_get_sse_state();
3721 *sselive = True;
3722 }
3723 emit_SSE3g ( u->flags_r, u->flags_w,
3724 (u->val1 >> 8) & 0xFF,
3725 u->val1 & 0xFF,
3726 (u->val2 >> 8) & 0xFF,
3727 u->val2 & 0xFF,
3728 u->val3 );
3729 break;
3730
3731 case SSE4:
3732 vg_assert(u->size == 0);
3733 vg_assert(u->tag1 == Lit16);
3734 vg_assert(u->tag2 == Lit16);
3735 vg_assert(u->tag3 == NoValue);
3736 vg_assert(!anyFlagUse(u));
3737 if (!(*sselive)) {
3738 emit_get_sse_state();
3739 *sselive = True;
3740 }
3741 emit_SSE4 ( u->flags_r, u->flags_w,
3742 (u->val1 >> 8) & 0xFF,
3743 u->val1 & 0xFF,
3744 (u->val2 >> 8) & 0xFF,
3745 u->val2 & 0xFF );
3746 break;
3747
sewardjde4a1d02002-03-22 01:27:54 +00003748 default:
sewardj1b7d8022002-11-30 12:35:42 +00003749 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003750 if (*sselive) {
3751 emit_put_sse_state();
3752 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003753 }
njn4ba5a792002-09-30 10:23:54 +00003754 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003755 } else {
njn25e49d8e72002-09-23 09:36:25 +00003756 VG_(printf)("\nError:\n"
3757 " unhandled opcode: %u. Perhaps "
3758 " VG_(needs).extended_UCode should be set?\n",
3759 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003760 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003761 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003762 }
sewardjde4a1d02002-03-22 01:27:54 +00003763 }
3764
sewardjb91ae7f2003-04-29 23:50:00 +00003765 if (0 && (*sselive)) {
3766 emit_put_sse_state();
3767 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003768 }
3769
njn25e49d8e72002-09-23 09:36:25 +00003770 /* Update UInstr histogram */
3771 vg_assert(u->opcode < 100);
3772 histogram[u->opcode].counts++;
3773 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003774}
3775
3776
3777/* Emit x86 for the ucode in cb, returning the address of the
3778 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003779UChar* VG_(emit_code) ( UCodeBlock* cb,
3780 Int* nbytes,
3781 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003782{
3783 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003784 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003785 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003786 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003787 Int tgt;
3788
sewardjfa492d42002-12-08 18:20:01 +00003789 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003790
njn25e49d8e72002-09-23 09:36:25 +00003791 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003792
sewardj22854b92002-11-30 14:00:47 +00003793 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3794 zero. We have to do this regardless of whether we're t-chaining
3795 or not. */
sewardja2113f92002-12-12 23:42:48 +00003796 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003797 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003798 VG_(emitB) (0xFF); /* decl */
3799 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3800 if (dis)
3801 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003802 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003803 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3804 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003805 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003806
sewardjb5ff83e2002-12-01 19:40:49 +00003807 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00003808 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00003809 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003810 curr_eip = cb->orig_eip;
3811 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3812 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003813 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003814 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003815 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003816 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003817
sewardjde4a1d02002-03-22 01:27:54 +00003818 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003819 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003820 if (!sane) {
3821 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003822 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003823 }
3824 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003825 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00003826 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003827 }
njn25e49d8e72002-09-23 09:36:25 +00003828 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003829 }
njn25e49d8e72002-09-23 09:36:25 +00003830 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00003831 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00003832 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003833
sewardj22854b92002-11-30 14:00:47 +00003834 if (j != NULL) {
3835 vg_assert(jumpidx <= VG_MAX_JUMPS);
3836 for(i = 0; i < jumpidx; i++)
3837 j[i] = jumps[i];
3838 }
3839
sewardjde4a1d02002-03-22 01:27:54 +00003840 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003841 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003842 *nbytes = emitted_code_used;
3843 return emitted_code;
3844}
3845
njn25e49d8e72002-09-23 09:36:25 +00003846#undef dis
3847
sewardjde4a1d02002-03-22 01:27:54 +00003848/*--------------------------------------------------------------------*/
3849/*--- end vg_from_ucode.c ---*/
3850/*--------------------------------------------------------------------*/