blob: 613f663e6345274903e47776f4e9a0bdccfdf13b [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
sewardja60be0e2003-05-26 08:47:27 +00001502static void emit_SSE3 ( FlagSet uses_sflags,
1503 FlagSet sets_sflags,
1504 UChar first_byte,
1505 UChar second_byte,
1506 UChar third_byte )
1507{
1508 VG_(new_emit)(True, uses_sflags, sets_sflags);
1509 VG_(emitB) ( first_byte );
1510 VG_(emitB) ( second_byte );
1511 VG_(emitB) ( third_byte );
1512 if (dis)
1513 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x\n",
1514 (UInt)first_byte, (UInt)second_byte,
1515 (UInt)third_byte );
1516}
1517
sewardjca860012003-03-27 23:52:58 +00001518static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1519 FlagSet sets_sflags,
1520 UChar first_byte,
1521 UChar second_byte,
1522 Int ireg )
1523{
1524 VG_(new_emit)(True, uses_sflags, sets_sflags);
1525 VG_(emitB) ( 0x0F );
1526 VG_(emitB) ( first_byte );
1527 second_byte &= 0x38; /* mask out mod and rm fields */
1528 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1529 second_byte |= (ireg & 7); /* patch in our ireg */
1530 VG_(emitB) ( second_byte );
1531 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001532 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1533 (UInt)first_byte, (UInt)second_byte,
1534 nameIReg(4,ireg) );
1535}
1536
1537static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1538 FlagSet sets_sflags,
1539 UChar first_byte,
1540 UChar second_byte,
1541 Int ireg )
1542{
1543 VG_(new_emit)(True, uses_sflags, sets_sflags);
1544 VG_(emitB) ( 0x0F );
1545 VG_(emitB) ( first_byte );
1546 second_byte &= 0x38; /* mask out mod and rm fields */
1547 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1548 second_byte |= (ireg & 7); /* patch in our ireg */
1549 VG_(emitB) ( second_byte );
1550 if (dis)
1551 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001552 (UInt)first_byte, (UInt)second_byte,
1553 nameIReg(4,ireg) );
1554}
1555
1556static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1557 FlagSet sets_sflags,
1558 UChar first_byte,
1559 UChar second_byte,
1560 UChar third_byte )
1561{
1562 VG_(new_emit)(True, uses_sflags, sets_sflags);
1563 VG_(emitB) ( 0x0F );
1564 VG_(emitB) ( first_byte );
1565 VG_(emitB) ( second_byte );
1566 VG_(emitB) ( third_byte );
1567 if (dis)
1568 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1569 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1570}
1571
sewardj3d7c9c82003-03-26 21:08:13 +00001572static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1573 FlagSet sets_sflags,
1574 UChar first_byte,
1575 UChar second_byte )
1576{
1577 VG_(new_emit)(True, uses_sflags, sets_sflags);
1578 VG_(emitB) ( 0x0F );
1579 VG_(emitB) ( first_byte );
1580 VG_(emitB) ( second_byte );
1581 if (dis)
1582 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1583 (UInt)first_byte, (UInt)second_byte );
1584}
1585
1586static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1587 FlagSet sets_sflags,
1588 UChar first_byte )
1589{
1590 VG_(new_emit)(True, uses_sflags, sets_sflags);
1591 VG_(emitB) ( 0x0F );
1592 VG_(emitB) ( first_byte );
1593 if (dis)
1594 VG_(printf)("\n\t\tmmx1-0x%x\n",
1595 (UInt)first_byte );
1596}
1597
sewardjde4a1d02002-03-22 01:27:54 +00001598
1599/*----------------------------------------------------*/
1600/*--- misc instruction emitters ---*/
1601/*----------------------------------------------------*/
1602
njn25e49d8e72002-09-23 09:36:25 +00001603void VG_(emit_call_reg) ( Int reg )
1604{
sewardjfa492d42002-12-08 18:20:01 +00001605 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001606 VG_(emitB) ( 0xFF ); /* Grp5 */
1607 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1608 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001609 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001610}
1611
sewardjf0f12aa2002-12-28 00:04:08 +00001612static
1613void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1614 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001615{
sewardjfa492d42002-12-08 18:20:01 +00001616 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001617 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001618
1619 if (byte_off < -128 || byte_off > 127) {
1620 VG_(emitB) ( 0xFF );
1621 VG_(emitB) ( 0x95 );
1622 VG_(emitL) ( byte_off );
1623 } else {
1624 VG_(emitB) ( 0xFF );
1625 VG_(emitB) ( 0x55 );
1626 VG_(emitB) ( byte_off );
1627 }
1628 if (dis)
1629 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001630}
1631
sewardja2c5a732002-12-15 03:10:42 +00001632#if 0
1633/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001634static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1635{
1636 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001637 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001638 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1639 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001640 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001641 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001642 if (dis)
1643 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1644 nameIReg(4,regmem));
1645}
sewardja2c5a732002-12-15 03:10:42 +00001646#endif
sewardjde4a1d02002-03-22 01:27:54 +00001647
njn25e49d8e72002-09-23 09:36:25 +00001648void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001649{
njne427a662002-10-02 11:08:25 +00001650 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001651 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1652 VG_(emitB) ( 0x8D );
1653 VG_(emitB) ( 0x64 );
1654 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001655 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001656 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001657 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001658}
1659
1660
1661static void emit_movb_AL_zeroESPmem ( void )
1662{
1663 /* movb %al, 0(%esp) */
1664 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001665 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001666 VG_(emitB) ( 0x88 );
1667 VG_(emitB) ( 0x44 );
1668 VG_(emitB) ( 0x24 );
1669 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001670 if (dis)
1671 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1672}
1673
1674static void emit_movb_zeroESPmem_AL ( void )
1675{
1676 /* movb 0(%esp), %al */
1677 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001678 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001679 VG_(emitB) ( 0x8A );
1680 VG_(emitB) ( 0x44 );
1681 VG_(emitB) ( 0x24 );
1682 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001683 if (dis)
1684 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1685}
1686
sewardja2113f92002-12-12 23:42:48 +00001687/* Jump target states */
1688#define TGT_UNDEF (1 << 16)
1689#define TGT_FORWARD (2 << 16)
1690#define TGT_BACKWARD (3 << 16)
1691
1692static inline Int tgt_state(Int tgt)
1693{
1694 return tgt & 0xffff0000;
1695}
1696
1697static inline Int tgt_addr(Int tgt)
1698{
1699 return tgt & 0x0000ffff;
1700}
1701
1702static inline Int mk_tgt(Int state, Int addr)
1703{
1704 vg_assert(state == TGT_UNDEF
1705 || state == TGT_FORWARD || state == TGT_BACKWARD);
1706 vg_assert((addr & 0xffff0000) == 0);
1707
1708 return state | addr;
1709}
1710
1711void VG_(init_target) ( Int *tgt )
1712{
1713 *tgt = TGT_UNDEF;
1714}
1715
1716void VG_(target_back) ( Int *tgt )
1717{
1718 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1719
1720 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1721}
1722
1723void VG_(target_forward) ( Int *tgt )
1724{
1725 Int delta;
1726
1727 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1728 tgt_state(*tgt) == TGT_UNDEF);
1729
1730 if (tgt_state(*tgt) == TGT_UNDEF)
1731 return; /* target not used */
1732
1733 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1734 vg_assert(delta >= -128 && delta <= 127);
1735 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001736 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001737 emitted_code[tgt_addr(*tgt)] = delta;
1738 if (dis)
1739 VG_(printf)("(target to jump site %d; delta: %d)\n",
1740 tgt_addr(*tgt), delta);
1741}
1742
1743void VG_(emit_target_delta) ( Int *tgt )
1744{
1745 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1746 tgt_state(*tgt) == TGT_BACKWARD);
1747
1748 if (tgt_state(*tgt) == TGT_UNDEF) {
1749 /* forward jump */
1750 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1751 VG_(emitB) (0x00);
1752 } else {
1753 /* backward jump */
1754 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1755 vg_assert(delta >= -128 && delta <= 127);
1756 VG_(emitB) (delta);
1757 }
1758}
1759
sewardjde4a1d02002-03-22 01:27:54 +00001760
1761/* Emit a jump short with an 8-bit signed offset. Note that the
1762 offset is that which should be added to %eip once %eip has been
1763 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001764void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001765{
1766 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001767 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001768 VG_(emitB) ( 0x70 + (UInt)cond );
1769 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001770 if (dis)
1771 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001772 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001773}
1774
sewardja2113f92002-12-12 23:42:48 +00001775/* Same as above, but defers emitting the delta */
1776void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1777{
sewardj706240d2002-12-26 17:10:12 +00001778 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001779 VG_(emitB) ( 0x70 + (UInt)cond );
1780 VG_(emit_target_delta) (tgt);
1781 if (dis)
1782 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001783 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001784}
1785
1786
1787
sewardjf0f12aa2002-12-28 00:04:08 +00001788static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001789{
sewardjf0f12aa2002-12-28 00:04:08 +00001790 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001791 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1792 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001793 if (dis)
1794 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001795 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001796}
1797
1798static void emit_ret ( void )
1799{
sewardjfa492d42002-12-08 18:20:01 +00001800 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001801 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001802 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001803 if (dis)
1804 VG_(printf)("\n\t\tret\n");
1805}
1806
sewardj22854b92002-11-30 14:00:47 +00001807/* Predicate used in sanity checks elsewhere - returns true if any
1808 jump-site is an actual chained jump */
1809Bool VG_(is_chained_jumpsite)(Addr a)
1810{
1811 UChar *cp = (UChar *)a;
1812
1813 return (*cp == 0xE9); /* 0xE9 -- jmp */
1814}
1815
sewardj83f11862002-12-01 02:07:08 +00001816static
1817Bool is_fresh_jumpsite(UChar *cp)
1818{
1819 return
1820 cp[0] == 0x0F && /* UD2 */
1821 cp[1] == 0x0B &&
1822 cp[2] == 0x0F && /* UD2 */
1823 cp[3] == 0x0B &&
1824 cp[4] == 0x90; /* NOP */
1825}
1826
sewardj22854b92002-11-30 14:00:47 +00001827/* Predicate used in sanity checks elsewhere - returns true if all
1828 jump-sites are calls to VG_(patch_me) */
1829Bool VG_(is_unchained_jumpsite)(Addr a)
1830{
1831 UChar *cp = (UChar *)a;
1832 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1833 Int idelta;
1834
1835 if (*cp++ != 0xE8) /* 0xE8 == call */
1836 return False;
1837
1838 idelta = (*cp++) << 0;
1839 idelta |= (*cp++) << 8;
1840 idelta |= (*cp++) << 16;
1841 idelta |= (*cp++) << 24;
1842
1843 return idelta == delta;
1844}
1845
1846/* Return target address for a direct jmp */
1847Addr VG_(get_jmp_dest)(Addr a)
1848{
1849 Int delta;
1850 UChar *cp = (UChar *)a;
1851
1852 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1853 return 0;
1854
1855 delta = (*cp++) << 0;
1856 delta |= (*cp++) << 8;
1857 delta |= (*cp++) << 16;
1858 delta |= (*cp++) << 24;
1859
1860 return a + VG_PATCHME_JMPSZ + delta;
1861}
1862
1863/* unchain a BB by generating a call to VG_(patch_me) */
1864void VG_(unchain_jumpsite)(Addr a)
1865{
1866 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1867 UChar *cp = (UChar *)a;
1868
1869 if (VG_(is_unchained_jumpsite)(a))
1870 return; /* don't write unnecessarily */
1871
sewardj83f11862002-12-01 02:07:08 +00001872 if (!is_fresh_jumpsite(cp))
1873 VG_(bb_dechain_count)++; /* update stats */
1874
sewardj22854b92002-11-30 14:00:47 +00001875 *cp++ = 0xE8; /* call */
1876 *cp++ = (delta >> 0) & 0xff;
1877 *cp++ = (delta >> 8) & 0xff;
1878 *cp++ = (delta >> 16) & 0xff;
1879 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001880}
1881
1882/* This doesn't actually generate a call to VG_(patch_me), but
1883 reserves enough space in the instruction stream for it to happen
1884 and records the offset into the jump table. This is because call
1885 is a relative jump, and so will be affected when this code gets
1886 moved about. The translation table will "unchain" this basic block
1887 on insertion (with VG_(unchain_BB)()), and thereby generate a
1888 proper call instruction. */
1889static void emit_call_patchme( void )
1890{
1891 vg_assert(VG_PATCHME_CALLSZ == 5);
1892
sewardjfa492d42002-12-08 18:20:01 +00001893 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001894 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001895
1896 if (jumpidx >= VG_MAX_JUMPS) {
1897 /* If there too many jumps in this basic block, fall back to
1898 dispatch loop. We still need to keep it the same size as the
1899 call sequence. */
1900 VG_(emitB) ( 0xC3 ); /* ret */
1901 VG_(emitB) ( 0x90 ); /* nop */
1902 VG_(emitB) ( 0x90 ); /* nop */
1903 VG_(emitB) ( 0x90 ); /* nop */
1904 VG_(emitB) ( 0x90 ); /* nop */
1905
1906 if (dis)
1907 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1908
1909 if (0 && VG_(clo_verbosity))
1910 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1911 } else {
1912 jumps[jumpidx++] = emitted_code_used;
1913
1914 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1915 VG_(emitB) ( 0x0B );
1916 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1917 VG_(emitB) ( 0x0B );
1918 VG_(emitB) ( 0x90 ); /* NOP */
1919
1920 if (dis)
1921 VG_(printf)("\n\t\tud2; ud2; nop\n");
1922 }
1923}
1924
njn25e49d8e72002-09-23 09:36:25 +00001925void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001926{
sewardjf0f12aa2002-12-28 00:04:08 +00001927 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001928 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001929 if (dis)
1930 VG_(printf)("\n\t\tpushal\n");
1931}
1932
njn25e49d8e72002-09-23 09:36:25 +00001933void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001934{
sewardjf0f12aa2002-12-28 00:04:08 +00001935 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001936 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001937 if (dis)
1938 VG_(printf)("\n\t\tpopal\n");
1939}
1940
1941static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1942{
sewardjf0f12aa2002-12-28 00:04:08 +00001943 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001944 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1945 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001946 if (dis)
1947 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1948 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1949}
1950
1951static void emit_lea_sib_reg ( UInt lit, Int scale,
1952 Int regbase, Int regindex, Int reg )
1953{
sewardjf0f12aa2002-12-28 00:04:08 +00001954 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001955 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001956 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1957 if (dis)
1958 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1959 lit, nameIReg(4,regbase),
1960 nameIReg(4,regindex), scale,
1961 nameIReg(4,reg) );
1962}
1963
njn25e49d8e72002-09-23 09:36:25 +00001964void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001965{
sewardjf0f12aa2002-12-28 00:04:08 +00001966 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001967 VG_(emitB) ( 0x0F );
1968 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001969 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1970 if (dis)
1971 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1972}
1973
1974/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001975/*--- Helper offset -> addr translation ---*/
1976/*----------------------------------------------------*/
1977
1978/* Finds the baseBlock offset of a skin-specified helper.
1979 * Searches through compacts first, then non-compacts. */
1980Int VG_(helper_offset)(Addr a)
1981{
sewardj05bcdcb2003-05-18 10:05:38 +00001982 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00001983 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00001984
1985 for (i = 0; i < VG_(n_compact_helpers); i++)
1986 if (VG_(compact_helper_addrs)[i] == a)
1987 return VG_(compact_helper_offsets)[i];
1988 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1989 if (VG_(noncompact_helper_addrs)[i] == a)
1990 return VG_(noncompact_helper_offsets)[i];
1991
1992 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00001993 VG_(get_fnname) ( a, buf, 100 );
1994
njn25e49d8e72002-09-23 09:36:25 +00001995 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00001996 "\nCouldn't find offset of helper from its address (%p: %s).\n"
1997 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00001998
1999 VG_(printf)(" compact helpers: ");
2000 for (i = 0; i < VG_(n_compact_helpers); i++)
2001 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2002
2003 VG_(printf)("\n non-compact helpers: ");
2004 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2005 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2006
2007 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002008 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002009}
2010
2011/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002012/*--- Instruction synthesisers ---*/
2013/*----------------------------------------------------*/
2014
2015static Condcode invertCondition ( Condcode cond )
2016{
2017 return (Condcode)(1 ^ (UInt)cond);
2018}
2019
2020
2021/* Synthesise a call to *baseBlock[offset], ie,
2022 call * (4 x offset)(%ebp).
2023*/
sewardjfa492d42002-12-08 18:20:01 +00002024void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002025 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002026{
2027 vg_assert(word_offset >= 0);
2028 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002029 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002030 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002031 }
sewardjf0f12aa2002-12-28 00:04:08 +00002032 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002033}
2034
njn25e49d8e72002-09-23 09:36:25 +00002035static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002036{
njn25e49d8e72002-09-23 09:36:25 +00002037 if (src != dst) {
2038 VG_(emit_movv_reg_reg) ( 4, src, dst );
2039 ccall_arg_setup_instrs++;
2040 }
njn6431be72002-07-28 09:53:34 +00002041}
njn25e49d8e72002-09-23 09:36:25 +00002042
2043/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2044static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2045{
2046 if (RealReg == tag) {
2047 maybe_emit_movl_reg_reg ( litOrReg, reg );
2048 } else if (Literal == tag) {
2049 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2050 ccall_arg_setup_instrs++;
2051 }
2052 else
njne427a662002-10-02 11:08:25 +00002053 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002054}
2055
2056static
2057void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2058{
2059 if (R_EAX == reg1) {
2060 VG_(emit_swapl_reg_EAX) ( reg2 );
2061 } else if (R_EAX == reg2) {
2062 VG_(emit_swapl_reg_EAX) ( reg1 );
2063 } else {
2064 emit_swapl_reg_reg ( reg1, reg2 );
2065 }
2066 ccall_arg_setup_instrs++;
2067}
2068
2069static
2070void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2071{
2072 if (dst1 != src2) {
2073 maybe_emit_movl_reg_reg ( src1, dst1 );
2074 maybe_emit_movl_reg_reg ( src2, dst2 );
2075
2076 } else if (dst2 != src1) {
2077 maybe_emit_movl_reg_reg ( src2, dst2 );
2078 maybe_emit_movl_reg_reg ( src1, dst1 );
2079
2080 } else {
2081 /* swap to break cycle */
2082 emit_swapl_arg_regs ( dst1, dst2 );
2083 }
2084}
2085
2086static
2087void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2088 UInt dst1, UInt dst2, UInt dst3)
2089{
2090 if (dst1 != src2 && dst1 != src3) {
2091 maybe_emit_movl_reg_reg ( src1, dst1 );
2092 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2093
2094 } else if (dst2 != src1 && dst2 != src3) {
2095 maybe_emit_movl_reg_reg ( src2, dst2 );
2096 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2097
2098 } else if (dst3 != src1 && dst3 != src2) {
2099 maybe_emit_movl_reg_reg ( src3, dst3 );
2100 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2101
2102 } else {
2103 /* break cycle */
2104 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2105 emit_swapl_arg_regs ( dst1, dst2 );
2106 emit_swapl_arg_regs ( dst1, dst3 );
2107
2108 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2109 emit_swapl_arg_regs ( dst1, dst3 );
2110 emit_swapl_arg_regs ( dst1, dst2 );
2111
2112 } else {
njne427a662002-10-02 11:08:25 +00002113 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002114 }
2115 }
2116}
2117
2118static
2119void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2120 UInt src1, UInt src2,
2121 UInt dst1, UInt dst2)
2122{
2123 /* If either are lits, order doesn't matter */
2124 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2125 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2126 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2127
2128 } else {
2129 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2130 }
2131}
2132
2133static
2134void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2135 UInt src1, UInt src2, UInt src3,
2136 UInt dst1, UInt dst2, UInt dst3)
2137{
2138 // SSS: fix this eventually -- make STOREV use two RealRegs?
2139 /* Not supporting literals for 3-arg C functions -- they're only used
2140 by STOREV which has 2 args */
2141 vg_assert(RealReg == tagv[src1] &&
2142 RealReg == tagv[src2] &&
2143 RealReg == tagv[src3]);
2144 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2145 dst1, dst2, dst3 );
2146}
2147
2148/* Synthesise a call to a C function `fn' (which must be registered in
2149 baseBlock) doing all the reg saving and arg handling work.
2150
2151 WARNING: a UInstr should *not* be translated with synth_ccall followed
2152 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2153 such behaviour and everything will fall over.
2154 */
2155void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2156 Tag tagv[], Int ret_reg,
2157 RRegSet regs_live_before, RRegSet regs_live_after )
2158{
2159 Int i;
2160 Int stack_used = 0;
2161 Bool preserve_eax, preserve_ecx, preserve_edx;
2162
2163 vg_assert(0 <= regparms_n && regparms_n <= 3);
2164
2165 ccalls++;
2166
2167 /* If %e[acd]x is live before and after the C call, save/restore it.
2168 Unless the return values clobbers the reg; in this case we must not
2169 save/restore the reg, because the restore would clobber the return
2170 value. (Before and after the UInstr really constitute separate live
2171 ranges, but you miss this if you don't consider what happens during
2172 the UInstr.) */
2173# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002174 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2175 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002176 ret_reg != realReg)
2177
2178 preserve_eax = PRESERVE_REG(R_EAX);
2179 preserve_ecx = PRESERVE_REG(R_ECX);
2180 preserve_edx = PRESERVE_REG(R_EDX);
2181
2182# undef PRESERVE_REG
2183
2184 /* Save caller-save regs as required */
2185 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2186 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2187 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2188
2189 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2190 is the number of args passed in regs (maximum 3 for GCC on x86). */
2191
2192 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002193
njn25e49d8e72002-09-23 09:36:25 +00002194 /* First push stack args (RealRegs or Literals) in reverse order. */
2195 for (i = argc-1; i >= regparms_n; i--) {
2196 switch (tagv[i]) {
2197 case RealReg:
2198 VG_(emit_pushv_reg) ( 4, argv[i] );
2199 break;
2200 case Literal:
2201 /* Use short form of pushl if possible. */
2202 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2203 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2204 else
2205 VG_(emit_pushl_lit32)( argv[i] );
2206 break;
2207 default:
2208 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002209 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002210 }
2211 stack_used += 4;
2212 ccall_arg_setup_instrs++;
2213 }
njn6431be72002-07-28 09:53:34 +00002214
njn25e49d8e72002-09-23 09:36:25 +00002215 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2216 If moving values between registers, be careful not to clobber any on
2217 the way. Happily we can use xchgl to swap registers.
2218 */
2219 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002220
njn25e49d8e72002-09-23 09:36:25 +00002221 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2222 case 3:
2223 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2224 R_EAX, R_EDX, R_ECX );
2225 break;
njn6431be72002-07-28 09:53:34 +00002226
njn25e49d8e72002-09-23 09:36:25 +00002227 /* Less-tricky. Args passed in %eax and %edx. */
2228 case 2:
2229 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2230 break;
2231
2232 /* Easy. Just move arg1 into %eax (if not already in there). */
2233 case 1:
2234 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2235 break;
2236
2237 case 0:
2238 break;
2239
2240 default:
njne427a662002-10-02 11:08:25 +00002241 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002242 }
2243
sewardjfa492d42002-12-08 18:20:01 +00002244 /* Call the function - may trash all flags */
2245 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002246
2247 /* Clear any args from stack */
2248 if (0 != stack_used) {
2249 VG_(emit_add_lit_to_esp) ( stack_used );
2250 ccall_stack_clears++;
2251 }
2252
2253 /* Move return value into ret_reg if necessary and not already there */
2254 if (INVALID_REALREG != ret_reg) {
2255 ccall_retvals++;
2256 if (R_EAX != ret_reg) {
2257 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2258 ccall_retval_movs++;
2259 }
2260 }
2261
2262 /* Restore live caller-save regs as required */
2263 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2264 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2265 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002266}
sewardjde4a1d02002-03-22 01:27:54 +00002267
sewardj2e93c502002-04-12 11:12:52 +00002268static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002269{
sewardj2e93c502002-04-12 11:12:52 +00002270 switch (jmpkind) {
2271 case JmpBoring:
2272 break;
sewardj2e93c502002-04-12 11:12:52 +00002273 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002274 break;
2275 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002276 break;
2277 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002278 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002279 break;
2280 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002281 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002282 break;
2283 default:
njne427a662002-10-02 11:08:25 +00002284 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002285 }
2286}
2287
2288/* Jump to the next translation, by loading its original addr into
2289 %eax and returning to the scheduler. Signal special requirements
2290 by loading a special value into %ebp first.
2291*/
2292static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2293{
sewardjfa492d42002-12-08 18:20:01 +00002294 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002295 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002296 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002297 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002298 emit_ret();
2299}
2300
sewardj22854b92002-11-30 14:00:47 +00002301static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002302
2303/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002304static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002305{
sewardjfa492d42002-12-08 18:20:01 +00002306 maybe_emit_put_eflags(); /* save flags here */
2307
njn25e49d8e72002-09-23 09:36:25 +00002308 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002309
2310 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2311 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2312 emit_call_patchme();
2313 } else {
2314 load_ebp_from_JmpKind ( jmpkind );
2315 emit_ret();
2316 }
sewardjde4a1d02002-03-22 01:27:54 +00002317}
2318
2319
sewardj2370f3b2002-11-30 15:01:01 +00002320static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002321static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002322 Opcode opcode, Int size,
2323 UInt lit, Int reg );
2324
sewardjfa492d42002-12-08 18:20:01 +00002325static void synth_jcond_lit ( Condcode cond,
2326 Addr addr,
2327 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002328{
sewardj2370f3b2002-11-30 15:01:01 +00002329 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002330 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002331 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002332
sewardja2113f92002-12-12 23:42:48 +00002333 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002334 VG_(init_target)(&tgt2);
2335 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002336
sewardjfa492d42002-12-08 18:20:01 +00002337 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2338 if need be */
2339 maybe_emit_put_eflags();
2340 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2341
2342 if (eflags_state == UPD_Both) {
2343 /* The flags are already set up, so we just use them as is. */
2344 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002345 cond = invertCondition(cond);
2346 } else {
sewardj75f04932002-12-12 23:13:21 +00002347 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002348
2349 /* The simd state contains the most recent version, so we emit a
2350 sequence to calculate the relevant condition directly out of
2351 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2352 copying them back to the real flags via popf. Notice that
2353 some of these sequences trash %eax, but that should be free
2354 now since this is the end of a bb and therefore all regs are
2355 dead. */
2356 simd = False;
2357
2358 switch (cond) {
2359
sewardjbb6c1182002-12-12 23:54:47 +00002360 case CondLE: /* Z || S != O -> S || !P */
2361 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002362 vg_assert(eax_trashable);
2363
2364 VG_(emit_movv_offregmem_reg)
2365 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2366 /* eax == %EFLAGS */
2367
sewardjbb6c1182002-12-12 23:54:47 +00002368 VG_(emit_nonshiftopv_lit_reg)
2369 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2370 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002371
sewardjbb6c1182002-12-12 23:54:47 +00002372 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2373 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002374
sewardj09736622002-12-28 00:19:00 +00002375 /* actually set the real cpu flags, since ROR changes
2376 neither P nor Z */
2377 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2378
sewardjbb6c1182002-12-12 23:54:47 +00002379 if (cond == CondLE) {
2380 /* test Z */
2381 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2382 /* test OF != SF */
2383 cond = CondP;
2384 } else {
2385 /* test Z */
2386 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2387 /* test OF == SF */
2388 cond = CondNP;
2389 }
sewardj2370f3b2002-11-30 15:01:01 +00002390 break;
2391
sewardjfa492d42002-12-08 18:20:01 +00002392 case CondL:
2393 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002394 vg_assert(eax_trashable);
2395
2396 VG_(emit_movv_offregmem_reg)
2397 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2398 /* eax == %EFLAGS */
2399
sewardj75f04932002-12-12 23:13:21 +00002400 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2401 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002402
sewardj75f04932002-12-12 23:13:21 +00002403 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2404 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002405
sewardj09736622002-12-28 00:19:00 +00002406 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002407 if (cond == CondL) cond = CondP; else cond = CondNP;
2408 break;
sewardjfa492d42002-12-08 18:20:01 +00002409
2410 case CondB:
2411 case CondNB:
2412 mask = EFlagC; goto simple; /* C=1 */
2413
2414 case CondZ:
2415 case CondNZ:
2416 mask = EFlagZ; goto simple; /* Z=1 */
2417
2418 case CondBE:
2419 case CondNBE:
2420 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2421
2422 case CondS:
2423 case CondNS:
2424 mask = EFlagS; goto simple; /* S=1 */
2425
2426 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002427 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002428 mask = EFlagP; goto simple; /* P=1 */
2429
sewardj39542072002-12-09 22:44:00 +00002430 case CondO:
2431 case CondNO:
2432 mask = EFlagO; goto simple; /* O=1 */
2433
sewardjfa492d42002-12-08 18:20:01 +00002434 default:
2435 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002436 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002437 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2438
2439 simple:
2440 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002441 if ((mask & 0xff) == mask) {
2442 VG_(emitB) ( 0xF6 ); /* Grp3 */
2443 VG_(emit_amode_offregmem_reg)(
2444 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2445 VG_(emitB) (mask);
2446 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002447 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002448 mask, VGOFF_(m_eflags) * 4);
2449 } else {
sewardjfa492d42002-12-08 18:20:01 +00002450 /* all cond codes are in lower 16 bits */
2451 vg_assert((mask & 0xffff) == mask);
2452
2453 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002454 VG_(emitB) ( 0xF7 );
2455 VG_(emit_amode_offregmem_reg)(
2456 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002457 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002458 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002459 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002460 mask, VGOFF_(m_eflags) * 4);
2461 }
2462
sewardj75f04932002-12-12 23:13:21 +00002463 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002464 break;
2465 }
2466 }
2467
sewardja2113f92002-12-12 23:42:48 +00002468 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002469
2470 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002471 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002472
2473 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002474 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002475}
2476
2477
sewardj2370f3b2002-11-30 15:01:01 +00002478
sewardjde4a1d02002-03-22 01:27:54 +00002479static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2480{
sewardja2113f92002-12-12 23:42:48 +00002481 Int tgt;
2482
2483 VG_(init_target)(&tgt);
2484
sewardjfa492d42002-12-08 18:20:01 +00002485 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002486
2487 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002488 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002489
2490 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002491}
2492
2493
2494static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2495{
2496 /* Load the zero-extended literal into reg, at size l,
2497 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002498 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002499}
2500
2501
2502static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2503{
2504 switch (size) {
2505 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2506 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2507 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002508 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002509 }
2510}
2511
2512
2513static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2514{
2515 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002516 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2517 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2518 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002519 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002520 }
2521}
2522
2523
2524static void synth_mov_reg_offregmem ( Int size, Int reg,
2525 Int off, Int areg )
2526{
2527 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002528 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2529 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002530 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002531 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002532 }
2533 else {
njn25e49d8e72002-09-23 09:36:25 +00002534 VG_(emit_swapl_reg_EAX) ( reg );
2535 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2536 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002537 }
2538 break;
njne427a662002-10-02 11:08:25 +00002539 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002540 }
2541}
2542
2543
2544static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2545{
2546 Int s1;
2547 switch (size) {
2548 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2549 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2550 case 1: if (reg1 < 4) {
2551 emit_movb_reg_regmem ( reg1, reg2 );
2552 }
2553 else {
2554 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2555 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2556 emit_swapl_reg_reg ( s1, reg1 );
2557 emit_movb_reg_regmem ( s1, reg2 );
2558 emit_swapl_reg_reg ( s1, reg1 );
2559 }
2560 break;
njne427a662002-10-02 11:08:25 +00002561 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002562 }
2563}
2564
2565
sewardjf0f12aa2002-12-28 00:04:08 +00002566static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002567 Opcode opcode, Int size,
2568 Int reg )
2569{
2570 /* NB! opcode is a uinstr opcode, not an x86 one! */
2571 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002572 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002573 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002574 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002575 break;
2576 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002577 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002578 } else {
njn25e49d8e72002-09-23 09:36:25 +00002579 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002580 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002581 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002582 }
2583 break;
njne427a662002-10-02 11:08:25 +00002584 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002585 }
2586}
2587
2588
2589
sewardjf0f12aa2002-12-28 00:04:08 +00002590static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002591 Opcode opcode, Int size,
2592 Int reg1, Int reg2 )
2593{
2594 /* NB! opcode is a uinstr opcode, not an x86 one! */
2595 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002596 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002597 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002598 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002599 break;
2600 case 1: { /* Horrible ... */
2601 Int s1, s2;
2602 /* Choose s1 and s2 to be x86 regs which we can talk about the
2603 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2604 sure s1 != s2 and that neither of them equal either reg1 or
2605 reg2. Then use them as temporaries to make things work. */
2606 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002607 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002608 break;
2609 }
2610 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2611 if (reg1 >= 4 && reg2 < 4) {
2612 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002613 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002614 emit_swapl_reg_reg ( reg1, s1 );
2615 break;
2616 }
2617 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2618 if (reg1 < 4 && reg2 >= 4) {
2619 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002620 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002621 emit_swapl_reg_reg ( reg2, s2 );
2622 break;
2623 }
2624 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2625 emit_swapl_reg_reg ( reg1, s1 );
2626 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002627 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002628 emit_swapl_reg_reg ( reg1, s1 );
2629 emit_swapl_reg_reg ( reg2, s2 );
2630 break;
2631 }
2632 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2633 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002634 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002635 emit_swapl_reg_reg ( reg1, s1 );
2636 break;
2637 }
njne427a662002-10-02 11:08:25 +00002638 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002639 }
njne427a662002-10-02 11:08:25 +00002640 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002641 }
2642}
2643
sewardja2c5a732002-12-15 03:10:42 +00002644#if 0
2645/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002646static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002647 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002648 Opcode opcode, Int size,
2649 Int off, Int areg, Int reg )
2650{
2651 switch (size) {
2652 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002653 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002654 break;
2655 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002656 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002657 break;
2658 case 1:
2659 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002660 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002661 } else {
2662 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002663 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002664 VG_(emit_swapl_reg_EAX) ( reg );
2665 }
2666 break;
2667 default:
2668 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2669 }
2670}
sewardja2c5a732002-12-15 03:10:42 +00002671#endif
sewardjfa492d42002-12-08 18:20:01 +00002672
sewardjde4a1d02002-03-22 01:27:54 +00002673static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002674 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002675 Opcode opcode, Int size,
2676 Int off, Int areg, Int reg )
2677{
2678 switch (size) {
2679 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002680 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002681 break;
2682 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002683 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002684 break;
2685 case 1:
2686 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002687 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002688 } else {
njn25e49d8e72002-09-23 09:36:25 +00002689 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002690 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002691 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002692 }
2693 break;
2694 default:
njne427a662002-10-02 11:08:25 +00002695 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002696 }
2697}
2698
2699
sewardjf0f12aa2002-12-28 00:04:08 +00002700static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002701 Opcode opcode, Int size,
2702 UInt lit, Int reg )
2703{
2704 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002705 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002706 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002707 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002708 break;
2709 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002710 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002711 } else {
njn25e49d8e72002-09-23 09:36:25 +00002712 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002713 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002714 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002715 }
2716 break;
njne427a662002-10-02 11:08:25 +00002717 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002718 }
2719}
2720
sewardjf0f12aa2002-12-28 00:04:08 +00002721static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002722 Opcode opcode, Int size,
2723 UInt lit, Int off, Int regmem )
2724{
2725 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002726 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002727 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002728 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002729 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002730 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002731 break;
2732 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2733 }
2734}
2735
sewardjde4a1d02002-03-22 01:27:54 +00002736
2737static void synth_push_reg ( Int size, Int reg )
2738{
2739 switch (size) {
2740 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002741 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002742 break;
2743 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002744 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002745 break;
2746 /* Pray that we don't have to generate this really cruddy bit of
2747 code very often. Could do better, but can I be bothered? */
2748 case 1:
2749 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002750 VG_(emit_add_lit_to_esp)(-1);
2751 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002752 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002753 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002754 break;
2755 default:
njne427a662002-10-02 11:08:25 +00002756 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002757 }
2758}
2759
2760
2761static void synth_pop_reg ( Int size, Int reg )
2762{
2763 switch (size) {
2764 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002765 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002766 break;
2767 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002768 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002769 break;
2770 case 1:
2771 /* Same comment as above applies. */
2772 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002773 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002774 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002775 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2776 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002777 break;
njne427a662002-10-02 11:08:25 +00002778 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002779 }
2780}
2781
2782
sewardjf0f12aa2002-12-28 00:04:08 +00002783static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002784 Opcode opcode, Int size,
2785 Int regs, Int regd )
2786{
2787 synth_push_reg ( size, regd );
2788 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002789 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002790 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2791 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2792 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002793 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002794 }
sewardjde4a1d02002-03-22 01:27:54 +00002795 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2796 synth_pop_reg ( size, regd );
2797}
2798
2799
sewardjf0f12aa2002-12-28 00:04:08 +00002800static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002801 Opcode opcode, Int size,
2802 UInt lit, Int reg )
2803{
2804 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002805 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002806 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002807 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002808 break;
2809 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002810 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002811 } else {
njn25e49d8e72002-09-23 09:36:25 +00002812 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002813 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002814 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002815 }
2816 break;
njne427a662002-10-02 11:08:25 +00002817 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002818 }
2819}
2820
2821
sewardjf0f12aa2002-12-28 00:04:08 +00002822static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002823{
sewardjde4a1d02002-03-22 01:27:54 +00002824 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002825 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002826 } else {
njn25e49d8e72002-09-23 09:36:25 +00002827 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002828 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002829 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002830 }
2831}
2832
2833
sewardj3d7c9c82003-03-26 21:08:13 +00002834static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2835 UChar first_byte,
2836 UChar second_byte,
2837 Int ireg )
2838{
2839 emit_MMX2_regmem ( uses_flags, sets_flags,
2840 first_byte, second_byte, ireg );
2841}
2842
2843
sewardjca860012003-03-27 23:52:58 +00002844static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2845 UChar first_byte,
2846 UChar second_byte,
2847 Int ireg )
2848{
2849 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2850 first_byte, second_byte, ireg );
2851}
2852
sewardjd1c9e432003-04-04 20:40:34 +00002853static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2854 UChar first_byte,
2855 UChar second_byte,
2856 Int ireg )
2857{
2858 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2859 first_byte, second_byte, ireg );
2860}
2861
sewardj3d7c9c82003-03-26 21:08:13 +00002862static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2863 UChar first_byte,
2864 UChar second_byte )
2865{
2866 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2867}
2868
2869
sewardjca860012003-03-27 23:52:58 +00002870static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2871 UChar first_byte,
2872 UChar second_byte,
2873 UChar third_byte )
2874{
2875 emit_MMX3_no_mem ( uses_flags, sets_flags,
2876 first_byte, second_byte, third_byte );
2877}
2878
2879
sewardj3d7c9c82003-03-26 21:08:13 +00002880static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2881 UChar first_byte )
2882{
2883 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2884}
2885
2886
sewardjfa492d42002-12-08 18:20:01 +00002887static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2888 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002889 UChar second_byte_masked,
2890 Int reg )
2891{
sewardj3d7c9c82003-03-26 21:08:13 +00002892 emit_fpu_regmem ( uses_flags, sets_flags,
2893 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002894}
2895
2896
sewardjfa492d42002-12-08 18:20:01 +00002897static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
2898 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002899 UChar second_byte )
2900{
sewardjfa492d42002-12-08 18:20:01 +00002901 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002902}
2903
2904
2905static void synth_movl_reg_reg ( Int src, Int dst )
2906{
2907 emit_movl_reg_reg ( src, dst );
2908}
2909
2910static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2911{
sewardja2113f92002-12-12 23:42:48 +00002912 Int tgt;
2913
2914 VG_(init_target)(&tgt);
2915
2916 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002917 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00002918
2919 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002920}
2921
2922
sewardjde4a1d02002-03-22 01:27:54 +00002923/*----------------------------------------------------*/
2924/*--- Top level of the uinstr -> x86 translation. ---*/
2925/*----------------------------------------------------*/
2926
2927/* Return the byte offset from %ebp (ie, into baseBlock)
2928 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002929static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2930{
2931 if (tag == SpillNo) {
2932 vg_assert(size == 4);
2933 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2934 return 4 * (value + VGOFF_(spillslots));
2935 }
2936 if (tag == ArchReg) {
2937 switch (value) {
2938 case R_EAX: return 4 * VGOFF_(m_eax);
2939 case R_ECX: return 4 * VGOFF_(m_ecx);
2940 case R_EDX: return 4 * VGOFF_(m_edx);
2941 case R_EBX: return 4 * VGOFF_(m_ebx);
2942 case R_ESP:
2943 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2944 else return 4 * VGOFF_(m_esp);
2945 case R_EBP:
2946 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2947 else return 4 * VGOFF_(m_ebp);
2948 case R_ESI:
2949 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2950 else return 4 * VGOFF_(m_esi);
2951 case R_EDI:
2952 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2953 else return 4 * VGOFF_(m_edi);
2954 }
2955 }
njne427a662002-10-02 11:08:25 +00002956 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002957}
2958
sewardjde4a1d02002-03-22 01:27:54 +00002959static Int eflagsOffset ( void )
2960{
2961 return 4 * VGOFF_(m_eflags);
2962}
2963
sewardje1042472002-09-30 12:33:11 +00002964static Int segRegOffset ( UInt archregs )
2965{
2966 switch (archregs) {
2967 case R_CS: return 4 * VGOFF_(m_cs);
2968 case R_SS: return 4 * VGOFF_(m_ss);
2969 case R_DS: return 4 * VGOFF_(m_ds);
2970 case R_ES: return 4 * VGOFF_(m_es);
2971 case R_FS: return 4 * VGOFF_(m_fs);
2972 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002973 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002974 }
2975}
2976
njnf4ce3d32003-02-10 10:17:26 +00002977UInt VG_(get_archreg) ( UInt arch )
2978{
2979 switch (arch) {
2980 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
2981 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
2982 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
2983 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
2984 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
2985 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
2986 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
2987 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
2988 default: VG_(core_panic)( "get_thread_archreg");
2989 }
2990}
2991
2992UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
2993{
2994 ThreadState* tst;
2995
2996 vg_assert(VG_(is_valid_tid)(tid));
2997 tst = & VG_(threads)[tid];
2998
2999 switch (arch) {
3000 case R_EAX: return tst->m_eax;
3001 case R_ECX: return tst->m_ecx;
3002 case R_EDX: return tst->m_edx;
3003 case R_EBX: return tst->m_ebx;
3004 case R_ESP: return tst->m_esp;
3005 case R_EBP: return tst->m_ebp;
3006 case R_ESI: return tst->m_esi;
3007 case R_EDI: return tst->m_edi;
3008 default: VG_(core_panic)( "get_thread_archreg");
3009 }
3010}
3011
njnb93d1782003-02-03 12:03:22 +00003012/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003013static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003014{
3015 switch (arch) {
3016 case R_EAX: return VGOFF_(sh_eax);
3017 case R_ECX: return VGOFF_(sh_ecx);
3018 case R_EDX: return VGOFF_(sh_edx);
3019 case R_EBX: return VGOFF_(sh_ebx);
3020 case R_ESP: return VGOFF_(sh_esp);
3021 case R_EBP: return VGOFF_(sh_ebp);
3022 case R_ESI: return VGOFF_(sh_esi);
3023 case R_EDI: return VGOFF_(sh_edi);
3024 default: VG_(core_panic)( "shadow_reg_index");
3025 }
3026}
sewardjde4a1d02002-03-22 01:27:54 +00003027
njn25e49d8e72002-09-23 09:36:25 +00003028/* Return the byte offset from %ebp (ie, into baseBlock)
3029 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003030Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003031{
njnb93d1782003-02-03 12:03:22 +00003032 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003033}
3034
njn4ba5a792002-09-30 10:23:54 +00003035Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003036{
3037 return 4 * VGOFF_(sh_eflags);
3038}
3039
njnb93d1782003-02-03 12:03:22 +00003040/* Accessing shadow arch. registers */
3041UInt VG_(get_shadow_archreg) ( UInt archreg )
3042{
3043 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3044}
3045
3046void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3047{
3048 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3049}
3050
njnd3040452003-05-19 15:04:06 +00003051void VG_(set_shadow_eflags) ( UInt val )
3052{
3053 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3054}
3055
njnf4ce3d32003-02-10 10:17:26 +00003056UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3057{
3058 ThreadState* tst;
3059
3060 vg_assert(VG_(is_valid_tid)(tid));
3061 tst = & VG_(threads)[tid];
3062
3063 switch (archreg) {
3064 case R_EAX: return tst->sh_eax;
3065 case R_ECX: return tst->sh_ecx;
3066 case R_EDX: return tst->sh_edx;
3067 case R_EBX: return tst->sh_ebx;
3068 case R_ESP: return tst->sh_esp;
3069 case R_EBP: return tst->sh_ebp;
3070 case R_ESI: return tst->sh_esi;
3071 case R_EDI: return tst->sh_edi;
3072 default: VG_(core_panic)( "get_thread_shadow_archreg");
3073 }
3074}
3075
3076void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3077{
3078 ThreadState* tst;
3079
3080 vg_assert(VG_(is_valid_tid)(tid));
3081 tst = & VG_(threads)[tid];
3082
3083 switch (archreg) {
3084 case R_EAX: tst->sh_eax = val; break;
3085 case R_ECX: tst->sh_ecx = val; break;
3086 case R_EDX: tst->sh_edx = val; break;
3087 case R_EBX: tst->sh_ebx = val; break;
3088 case R_ESP: tst->sh_esp = val; break;
3089 case R_EBP: tst->sh_ebp = val; break;
3090 case R_ESI: tst->sh_esi = val; break;
3091 case R_EDI: tst->sh_edi = val; break;
3092 default: VG_(core_panic)( "set_thread_shadow_archreg");
3093 }
3094}
3095
njnb93d1782003-02-03 12:03:22 +00003096Addr VG_(shadow_archreg_address) ( UInt archreg )
3097{
3098 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3099}
sewardjde4a1d02002-03-22 01:27:54 +00003100
sewardjde4a1d02002-03-22 01:27:54 +00003101static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3102{
3103 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003104 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3105 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003106 }
3107 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003108 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3109 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003110 }
3111 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003112 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3113 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003114 }
3115 else
njne427a662002-10-02 11:08:25 +00003116 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003117}
3118
3119
sewardjde4a1d02002-03-22 01:27:54 +00003120/*----------------------------------------------------*/
3121/*--- Generate code for a single UInstr. ---*/
3122/*----------------------------------------------------*/
3123
sewardj478335c2002-10-05 02:44:47 +00003124static __inline__
3125Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003126{
3127 return (u->flags_w != FlagsEmpty);
3128}
3129
sewardjfa492d42002-12-08 18:20:01 +00003130static __inline__
3131Bool readFlagUse ( UInstr* u )
3132{
3133 /* If the UInstr writes some flags but not all, then we still need
3134 to consider it as reading flags so that the unchanged values are
3135 passed through properly. (D is special) */
3136 return
3137 (u->flags_r != FlagsEmpty) ||
3138 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3139}
3140
sewardj478335c2002-10-05 02:44:47 +00003141static __inline__
3142Bool anyFlagUse ( UInstr* u )
3143{
sewardjfa492d42002-12-08 18:20:01 +00003144 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003145}
3146
3147
sewardjb91ae7f2003-04-29 23:50:00 +00003148/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3149 the real machine's cpu. If so we need to be very careful not to trash it.
3150 If FPU/SSE state is live and we deem it necessary to copy it back to
3151 the simulated machine's FPU/SSE state, we do so. The final state of
3152 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003153 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003154 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003155*/
sewardjb5ff83e2002-12-01 19:40:49 +00003156static void emitUInstr ( UCodeBlock* cb, Int i,
3157 RRegSet regs_live_before,
3158 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003159 Bool* sselive, /* True<==>FPU/SSE
3160 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003161 Addr* orig_eip, /* previous curr_eip, or zero */
3162 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003163{
njn25e49d8e72002-09-23 09:36:25 +00003164 Int old_emitted_code_used;
3165 UInstr* u = &cb->instrs[i];
3166
sewardjde4a1d02002-03-22 01:27:54 +00003167 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003168 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003169
njn25e49d8e72002-09-23 09:36:25 +00003170 old_emitted_code_used = emitted_code_used;
3171
sewardjde4a1d02002-03-22 01:27:54 +00003172 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003173 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003174
sewardjb5ff83e2002-12-01 19:40:49 +00003175 case INCEIP:
3176 /* Advance %EIP some small amount. */
3177 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003178
sewardjb5ff83e2002-12-01 19:40:49 +00003179 if (*orig_eip == 0 /* we don't know what the old value was */
3180 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3181 /* We have to update all 32 bits of the value. */
3182 VG_(emit_movv_lit_offregmem)(
3183 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3184 } else {
3185 /* Cool! we only need to update lowest 8 bits */
3186 VG_(emit_movb_lit_offregmem)(
3187 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003188 }
njn25e49d8e72002-09-23 09:36:25 +00003189
sewardjb5ff83e2002-12-01 19:40:49 +00003190 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003191 break;
sewardjde4a1d02002-03-22 01:27:54 +00003192
3193 case LEA1: {
3194 vg_assert(u->tag1 == RealReg);
3195 vg_assert(u->tag2 == RealReg);
3196 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3197 break;
3198 }
3199
3200 case LEA2: {
3201 vg_assert(u->tag1 == RealReg);
3202 vg_assert(u->tag2 == RealReg);
3203 vg_assert(u->tag3 == RealReg);
3204 emit_lea_sib_reg ( u->lit32, u->extra4b,
3205 u->val1, u->val2, u->val3 );
3206 break;
3207 }
3208
3209 case WIDEN: {
3210 vg_assert(u->tag1 == RealReg);
3211 if (u->signed_widen) {
3212 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3213 } else {
3214 /* no need to generate any code. */
3215 }
3216 break;
3217 }
3218
sewardjde4a1d02002-03-22 01:27:54 +00003219 case STORE: {
3220 vg_assert(u->tag1 == RealReg);
3221 vg_assert(u->tag2 == RealReg);
3222 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003223 break;
3224 }
3225
3226 case LOAD: {
3227 vg_assert(u->tag1 == RealReg);
3228 vg_assert(u->tag2 == RealReg);
3229 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3230 break;
3231 }
3232
sewardjde4a1d02002-03-22 01:27:54 +00003233 case GET: {
3234 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3235 vg_assert(u->tag2 == RealReg);
3236 synth_mov_offregmem_reg (
3237 u->size,
3238 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3239 R_EBP,
3240 u->val2
3241 );
3242 break;
3243 }
3244
3245 case PUT: {
3246 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3247 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003248 synth_mov_reg_offregmem (
3249 u->size,
3250 u->val1,
3251 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3252 R_EBP
3253 );
sewardjde4a1d02002-03-22 01:27:54 +00003254 break;
3255 }
3256
sewardje1042472002-09-30 12:33:11 +00003257 case GETSEG: {
3258 vg_assert(u->tag1 == ArchRegS);
3259 vg_assert(u->tag2 == RealReg);
3260 vg_assert(u->size == 2);
3261 synth_mov_offregmem_reg (
3262 4,
3263 segRegOffset( u->val1 ),
3264 R_EBP,
3265 u->val2
3266 );
3267 break;
3268 }
3269
3270 case PUTSEG: {
3271 vg_assert(u->tag1 == RealReg);
3272 vg_assert(u->tag2 == ArchRegS);
3273 vg_assert(u->size == 2);
3274 synth_mov_reg_offregmem (
3275 4,
3276 u->val1,
3277 segRegOffset( u->val2 ),
3278 R_EBP
3279 );
3280 break;
3281 }
3282
sewardjde4a1d02002-03-22 01:27:54 +00003283 case GETF: {
3284 vg_assert(u->size == 2 || u->size == 4);
3285 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003286
3287 /* This complexity is because the D(irection) flag is stored
3288 separately from the rest of EFLAGS. */
3289
3290 /* We're only fetching from the Simd state, so make sure it's
3291 up to date. */
3292 maybe_emit_put_eflags();
3293
3294 /* get D in u->val1 (== 1 or -1) */
3295 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3296
3297 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3298 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3299
3300 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3301 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3302 eflagsOffset(), R_EBP);
3303
3304 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3305 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3306 eflagsOffset(), R_EBP);
3307
3308 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3309 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3310 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003311 break;
3312 }
3313
3314 case PUTF: {
3315 vg_assert(u->size == 2 || u->size == 4);
3316 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003317
3318 /* When putting a value into EFLAGS, this generates the
3319 correct value for m_dflag (-1 or 1), and clears the D bit
3320 in EFLAGS. */
3321
3322 /* We're updating the whole flag state, so the old state
3323 doesn't matter; make sure that the new simulated state
3324 will be fetched when needed. */
3325 eflags_state = UPD_Simd;
3326
3327 /* store EFLAGS (with D) */
3328 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3329
3330 /* u->val1 &= EFlagD */
3331 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3332
3333 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3334 synth_unaryop_reg(False, NEG, u->size, u->val1);
3335 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3336 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3337
3338 /* save D */
3339 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3340
3341 /* EFLAGS &= ~EFlagD */
3342 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3343 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003344 break;
3345 }
3346
3347 case MOV: {
3348 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3349 vg_assert(u->tag2 == RealReg);
3350 switch (u->tag1) {
3351 case RealReg: vg_assert(u->size == 4);
3352 if (u->val1 != u->val2)
3353 synth_movl_reg_reg ( u->val1, u->val2 );
3354 break;
3355 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3356 break;
njne427a662002-10-02 11:08:25 +00003357 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003358 }
3359 break;
3360 }
3361
sewardje1042472002-09-30 12:33:11 +00003362 case USESEG: {
3363 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3364 ones. */
sewardjd077f532002-09-30 21:52:50 +00003365 UInt argv[] = { u->val1, u->val2 };
3366 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003367 UInt ret_reg = u->val2;
3368
3369 vg_assert(u->tag1 == RealReg);
3370 vg_assert(u->tag2 == RealReg);
3371 vg_assert(u->size == 0);
3372
sewardjb91ae7f2003-04-29 23:50:00 +00003373 if (*sselive) {
3374 emit_put_sse_state();
3375 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003376 }
3377
sewardje1042472002-09-30 12:33:11 +00003378 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3379 2, /* args */
3380 0, /* regparms_n */
3381 argv, tagv,
3382 ret_reg, regs_live_before, u->regs_live_after );
3383 break;
3384 }
3385
sewardj478335c2002-10-05 02:44:47 +00003386 case SBB:
3387 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003388 case XOR:
3389 case OR:
3390 case AND:
3391 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003392 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003393 vg_assert(u->tag2 == RealReg);
3394 switch (u->tag1) {
3395 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003396 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003397 u->opcode, u->size, u->lit32, u->val2 );
3398 break;
3399 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003400 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003401 u->opcode, u->size, u->val1, u->val2 );
3402 break;
3403 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003404 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003405 u->opcode, u->size,
3406 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3407 R_EBP,
3408 u->val2 );
3409 break;
njne427a662002-10-02 11:08:25 +00003410 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003411 }
3412 break;
3413 }
3414
sewardj478335c2002-10-05 02:44:47 +00003415 case RCR:
3416 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003417 case ROR:
3418 case ROL:
3419 case SAR:
3420 case SHR:
3421 case SHL: {
3422 vg_assert(u->tag2 == RealReg);
3423 switch (u->tag1) {
3424 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003425 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003426 u->opcode, u->size, u->lit32, u->val2 );
3427 break;
3428 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003429 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003430 u->opcode, u->size, u->val1, u->val2 );
3431 break;
njne427a662002-10-02 11:08:25 +00003432 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003433 }
3434 break;
3435 }
3436
3437 case INC:
3438 case DEC:
3439 case NEG:
3440 case NOT:
3441 vg_assert(u->tag1 == RealReg);
3442 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003443 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003444 break;
3445
3446 case BSWAP:
3447 vg_assert(u->tag1 == RealReg);
3448 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003449 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003450 emit_bswapl_reg ( u->val1 );
3451 break;
3452
3453 case CMOV:
3454 vg_assert(u->tag1 == RealReg);
3455 vg_assert(u->tag2 == RealReg);
3456 vg_assert(u->cond != CondAlways);
3457 vg_assert(u->size == 4);
3458 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3459 break;
3460
3461 case JMP: {
3462 vg_assert(u->tag2 == NoValue);
3463 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003464 if (*sselive) {
3465 emit_put_sse_state();
3466 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003467 }
sewardjde4a1d02002-03-22 01:27:54 +00003468 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003469 switch (u->tag1) {
3470 case RealReg:
3471 synth_jmp_reg ( u->val1, u->jmpkind );
3472 break;
3473 case Literal:
3474 synth_jmp_lit ( u->lit32, u->jmpkind );
3475 break;
3476 default:
njne427a662002-10-02 11:08:25 +00003477 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003478 break;
sewardjde4a1d02002-03-22 01:27:54 +00003479 }
3480 } else {
sewardj2e93c502002-04-12 11:12:52 +00003481 switch (u->tag1) {
3482 case RealReg:
njne427a662002-10-02 11:08:25 +00003483 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003484 break;
3485 case Literal:
3486 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003487 /* %eax had better not be live since synth_jcond_lit
3488 trashes it in some circumstances. If that turns
3489 out to be a problem we can get synth_jcond_lit to
3490 push/pop it when it is live. */
3491 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3492 u->regs_live_after));
3493 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003494 break;
3495 default:
njne427a662002-10-02 11:08:25 +00003496 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003497 break;
sewardjde4a1d02002-03-22 01:27:54 +00003498 }
3499 }
3500 break;
3501 }
3502
3503 case JIFZ:
3504 vg_assert(u->tag1 == RealReg);
3505 vg_assert(u->tag2 == Literal);
3506 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003507 if (*sselive) {
3508 emit_put_sse_state();
3509 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003510 }
sewardjde4a1d02002-03-22 01:27:54 +00003511 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3512 break;
3513
sewardjde4a1d02002-03-22 01:27:54 +00003514 case PUSH:
3515 vg_assert(u->tag1 == RealReg);
3516 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003517 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003518 break;
3519
3520 case POP:
3521 vg_assert(u->tag1 == RealReg);
3522 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003523 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003524 break;
3525
3526 case CALLM:
3527 vg_assert(u->tag1 == Lit16);
3528 vg_assert(u->tag2 == NoValue);
3529 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003530 if (*sselive) {
3531 emit_put_sse_state();
3532 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003533 }
sewardjfa492d42002-12-08 18:20:01 +00003534 /* Call to a helper which is pretending to be a real CPU
3535 instruction (and therefore operates on Real flags and
3536 registers) */
3537 VG_(synth_call) ( False, u->val1,
3538 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003539 break;
3540
njn25e49d8e72002-09-23 09:36:25 +00003541 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003542 /* If you change this, remember to change USESEG above, since
3543 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003544 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3545 ones. */
3546 UInt argv[] = { u->val1, u->val2, u->val3 };
3547 UInt tagv[] = { RealReg, RealReg, RealReg };
3548 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3549
3550 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3551 else vg_assert(u->tag1 == NoValue);
3552 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3553 else vg_assert(u->tag2 == NoValue);
3554 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3555 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003556 vg_assert(u->size == 0);
3557
sewardjb91ae7f2003-04-29 23:50:00 +00003558 if (*sselive) {
3559 emit_put_sse_state();
3560 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003561 }
njn25e49d8e72002-09-23 09:36:25 +00003562 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3563 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003564 break;
njn25e49d8e72002-09-23 09:36:25 +00003565 }
sewardje1042472002-09-30 12:33:11 +00003566
sewardjde4a1d02002-03-22 01:27:54 +00003567 case CLEAR:
3568 vg_assert(u->tag1 == Lit16);
3569 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003570 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003571 break;
3572
3573 case CC2VAL:
3574 vg_assert(u->tag1 == RealReg);
3575 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003576 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003577 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003578 break;
3579
sewardjde4a1d02002-03-22 01:27:54 +00003580 case FPU_R:
3581 case FPU_W:
3582 vg_assert(u->tag1 == Lit16);
3583 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003584 if (!(*sselive)) {
3585 emit_get_sse_state();
3586 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003587 }
sewardjfa492d42002-12-08 18:20:01 +00003588 synth_fpu_regmem ( u->flags_r, u->flags_w,
3589 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003590 u->val1 & 0xFF,
3591 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003592 break;
3593
3594 case FPU:
3595 vg_assert(u->tag1 == Lit16);
3596 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003597 if (!(*sselive)) {
3598 emit_get_sse_state();
3599 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003600 }
sewardjfa492d42002-12-08 18:20:01 +00003601 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3602 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003603 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003604 break;
3605
sewardj3d7c9c82003-03-26 21:08:13 +00003606 case MMX2_MemWr:
3607 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003608 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003609 vg_assert(u->tag1 == Lit16);
3610 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003611 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003612 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003613 if (!(*sselive)) {
3614 emit_get_sse_state();
3615 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003616 }
3617 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3618 (u->val1 >> 8) & 0xFF,
3619 u->val1 & 0xFF,
3620 u->val2 );
3621 break;
3622
sewardjca860012003-03-27 23:52:58 +00003623 case MMX2_RegRd:
3624 vg_assert(u->tag1 == Lit16);
3625 vg_assert(u->tag2 == RealReg);
3626 vg_assert(u->tag3 == NoValue);
3627 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003628 if (!(*sselive)) {
3629 emit_get_sse_state();
3630 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003631 }
3632 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3633 (u->val1 >> 8) & 0xFF,
3634 u->val1 & 0xFF,
3635 u->val2 );
3636 break;
3637
sewardjd1c9e432003-04-04 20:40:34 +00003638 case MMX2_RegWr:
3639 vg_assert(u->tag1 == Lit16);
3640 vg_assert(u->tag2 == RealReg);
3641 vg_assert(u->tag3 == NoValue);
3642 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003643 if (!(*sselive)) {
3644 emit_get_sse_state();
3645 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003646 }
3647 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3648 (u->val1 >> 8) & 0xFF,
3649 u->val1 & 0xFF,
3650 u->val2 );
3651 break;
3652
sewardj3d7c9c82003-03-26 21:08:13 +00003653 case MMX1:
3654 vg_assert(u->tag1 == Lit16);
3655 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003656 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003657 if (!(*sselive)) {
3658 emit_get_sse_state();
3659 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003660 }
3661 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3662 u->val1 & 0xFF );
3663 break;
3664
3665 case MMX2:
3666 vg_assert(u->tag1 == Lit16);
3667 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003668 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003669 if (!(*sselive)) {
3670 emit_get_sse_state();
3671 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003672 }
3673 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3674 (u->val1 >> 8) & 0xFF,
3675 u->val1 & 0xFF );
3676 break;
3677
sewardjca860012003-03-27 23:52:58 +00003678 case MMX3:
3679 vg_assert(u->tag1 == Lit16);
3680 vg_assert(u->tag2 == Lit16);
3681 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003682 if (!(*sselive)) {
3683 emit_get_sse_state();
3684 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003685 }
3686 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3687 (u->val1 >> 8) & 0xFF,
3688 u->val1 & 0xFF,
3689 u->val2 & 0xFF );
3690 break;
3691
sewardjfebaa3b2003-05-25 01:07:34 +00003692 case SSE2a_MemWr:
3693 case SSE2a_MemRd:
3694 vg_assert(u->size == 4 || u->size == 16);
3695 vg_assert(u->tag1 == Lit16);
3696 vg_assert(u->tag2 == Lit16);
3697 vg_assert(u->tag3 == RealReg);
3698 vg_assert(!anyFlagUse(u));
3699 if (!(*sselive)) {
3700 emit_get_sse_state();
3701 *sselive = True;
3702 }
3703 emit_SSE2a ( u->flags_r, u->flags_w,
3704 (u->val1 >> 8) & 0xFF,
3705 u->val1 & 0xFF,
3706 u->val2 & 0xFF,
3707 u->val3 );
3708 break;
3709
3710 case SSE3a_MemWr:
3711 case SSE3a_MemRd:
3712 vg_assert(u->size == 4 || u->size == 16);
3713 vg_assert(u->tag1 == Lit16);
3714 vg_assert(u->tag2 == Lit16);
3715 vg_assert(u->tag3 == RealReg);
3716 vg_assert(!anyFlagUse(u));
3717 if (!(*sselive)) {
3718 emit_get_sse_state();
3719 *sselive = True;
3720 }
3721 emit_SSE3a ( u->flags_r, u->flags_w,
3722 (u->val1 >> 8) & 0xFF,
3723 u->val1 & 0xFF,
3724 (u->val2 >> 8) & 0xFF,
3725 u->val2 & 0xFF,
3726 u->val3 );
3727 break;
3728
3729 case SSE3g_RegRd:
3730 vg_assert(u->size == 4);
3731 vg_assert(u->tag1 == Lit16);
3732 vg_assert(u->tag2 == Lit16);
3733 vg_assert(u->tag3 == RealReg);
3734 vg_assert(!anyFlagUse(u));
3735 if (!(*sselive)) {
3736 emit_get_sse_state();
3737 *sselive = True;
3738 }
3739 emit_SSE3g ( u->flags_r, u->flags_w,
3740 (u->val1 >> 8) & 0xFF,
3741 u->val1 & 0xFF,
3742 (u->val2 >> 8) & 0xFF,
3743 u->val2 & 0xFF,
3744 u->val3 );
3745 break;
3746
3747 case SSE4:
3748 vg_assert(u->size == 0);
3749 vg_assert(u->tag1 == Lit16);
3750 vg_assert(u->tag2 == Lit16);
3751 vg_assert(u->tag3 == NoValue);
3752 vg_assert(!anyFlagUse(u));
3753 if (!(*sselive)) {
3754 emit_get_sse_state();
3755 *sselive = True;
3756 }
3757 emit_SSE4 ( u->flags_r, u->flags_w,
3758 (u->val1 >> 8) & 0xFF,
3759 u->val1 & 0xFF,
3760 (u->val2 >> 8) & 0xFF,
3761 u->val2 & 0xFF );
3762 break;
3763
sewardja60be0e2003-05-26 08:47:27 +00003764 case SSE3:
3765 vg_assert(u->size == 0);
3766 vg_assert(u->tag1 == Lit16);
3767 vg_assert(u->tag2 == Lit16);
3768 vg_assert(u->tag3 == NoValue);
3769 vg_assert(!anyFlagUse(u));
3770 if (!(*sselive)) {
3771 emit_get_sse_state();
3772 *sselive = True;
3773 }
3774 emit_SSE3 ( u->flags_r, u->flags_w,
3775 (u->val1 >> 8) & 0xFF,
3776 u->val1 & 0xFF,
3777 u->val2 & 0xFF );
3778 break;
3779
sewardjde4a1d02002-03-22 01:27:54 +00003780 default:
sewardj1b7d8022002-11-30 12:35:42 +00003781 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003782 if (*sselive) {
3783 emit_put_sse_state();
3784 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003785 }
njn4ba5a792002-09-30 10:23:54 +00003786 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003787 } else {
njn25e49d8e72002-09-23 09:36:25 +00003788 VG_(printf)("\nError:\n"
3789 " unhandled opcode: %u. Perhaps "
3790 " VG_(needs).extended_UCode should be set?\n",
3791 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003792 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003793 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003794 }
sewardjde4a1d02002-03-22 01:27:54 +00003795 }
3796
sewardjb91ae7f2003-04-29 23:50:00 +00003797 if (0 && (*sselive)) {
3798 emit_put_sse_state();
3799 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003800 }
3801
njn25e49d8e72002-09-23 09:36:25 +00003802 /* Update UInstr histogram */
3803 vg_assert(u->opcode < 100);
3804 histogram[u->opcode].counts++;
3805 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003806}
3807
3808
3809/* Emit x86 for the ucode in cb, returning the address of the
3810 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003811UChar* VG_(emit_code) ( UCodeBlock* cb,
3812 Int* nbytes,
3813 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003814{
3815 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003816 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003817 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003818 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003819 Int tgt;
3820
sewardjfa492d42002-12-08 18:20:01 +00003821 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003822
njn25e49d8e72002-09-23 09:36:25 +00003823 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003824
sewardj22854b92002-11-30 14:00:47 +00003825 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3826 zero. We have to do this regardless of whether we're t-chaining
3827 or not. */
sewardja2113f92002-12-12 23:42:48 +00003828 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003829 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003830 VG_(emitB) (0xFF); /* decl */
3831 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3832 if (dis)
3833 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00003834 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00003835 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
3836 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00003837 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00003838
sewardjb5ff83e2002-12-01 19:40:49 +00003839 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00003840 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00003841 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00003842 curr_eip = cb->orig_eip;
3843 vg_assert(curr_eip != 0); /* otherwise the incremental updating
3844 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00003845 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00003846 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00003847 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00003848 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00003849
sewardjde4a1d02002-03-22 01:27:54 +00003850 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00003851 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00003852 if (!sane) {
3853 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00003854 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00003855 }
3856 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00003857 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00003858 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00003859 }
njn25e49d8e72002-09-23 09:36:25 +00003860 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00003861 }
njn25e49d8e72002-09-23 09:36:25 +00003862 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00003863 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00003864 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00003865
sewardj22854b92002-11-30 14:00:47 +00003866 if (j != NULL) {
3867 vg_assert(jumpidx <= VG_MAX_JUMPS);
3868 for(i = 0; i < jumpidx; i++)
3869 j[i] = jumps[i];
3870 }
3871
sewardjde4a1d02002-03-22 01:27:54 +00003872 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00003873 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00003874 *nbytes = emitted_code_used;
3875 return emitted_code;
3876}
3877
njn25e49d8e72002-09-23 09:36:25 +00003878#undef dis
3879
sewardjde4a1d02002-03-22 01:27:54 +00003880/*--------------------------------------------------------------------*/
3881/*--- end vg_from_ucode.c ---*/
3882/*--------------------------------------------------------------------*/