blob: af63fa22f4ed7b31c909917bbe748566e1873bf8 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- The JITter: translate ucode back to x86 code. ---*/
4/*--- vg_from_ucode.c ---*/
5/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00006
sewardjde4a1d02002-03-22 01:27:54 +00007/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32#include "vg_include.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Renamings of frequently-used global functions. ---*/
37/*------------------------------------------------------------*/
38
njn25e49d8e72002-09-23 09:36:25 +000039#define dis VG_(print_codegen)
sewardjde4a1d02002-03-22 01:27:54 +000040
41/*------------------------------------------------------------*/
42/*--- Instruction emission -- turning final uinstrs back ---*/
43/*--- into x86 code. ---*/
44/*------------------------------------------------------------*/
45
46/* [2001-07-08 This comment is now somewhat out of date.]
47
48 This is straightforward but for one thing: to facilitate generating
49 code in a single pass, we generate position-independent code. To
50 do this, calls and jmps to fixed addresses must specify the address
51 by first loading it into a register, and jump to/call that
52 register. Fortunately, the only jump to a literal is the jump back
njn25e49d8e72002-09-23 09:36:25 +000053 to vg_dispatch, and only %eax is live then, conveniently. UCode
sewardjde4a1d02002-03-22 01:27:54 +000054 call insns may only have a register as target anyway, so there's no
55 need to do anything fancy for them.
56
57 The emit_* routines constitute the lowest level of instruction
58 emission. They simply emit the sequence of bytes corresponding to
59 the relevant instruction, with no further ado. In particular there
60 is no checking about whether uses of byte registers makes sense,
61 nor whether shift insns have their first operand in %cl, etc.
62
63 These issues are taken care of by the level above, the synth_*
64 routines. These detect impossible operand combinations and turn
65 them into sequences of legal instructions. Finally, emitUInstr is
66 phrased in terms of the synth_* abstraction layer. */
67
sewardjfa492d42002-12-08 18:20:01 +000068/* Static state for the current basic block */
sewardjde4a1d02002-03-22 01:27:54 +000069static UChar* emitted_code;
70static Int emitted_code_used;
71static Int emitted_code_size;
72
sewardj22854b92002-11-30 14:00:47 +000073/* offset (in bytes into the basic block) */
74static UShort jumps[VG_MAX_JUMPS];
75static Int jumpidx;
76
sewardjf0f12aa2002-12-28 00:04:08 +000077static enum _eflags_state {
sewardjfa492d42002-12-08 18:20:01 +000078 UPD_Simd, /* baseblock copy is up to date */
79 UPD_Real, /* CPU copy is up to date */
80 UPD_Both, /* both are current */
81} eflags_state;
82
83/* single site for resetting state */
84static void reset_state(void)
85{
86 emitted_code_used = 0;
87 emitted_code_size = 500; /* reasonable initial size */
88 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
89 jumpidx = 0;
90 eflags_state = UPD_Simd;
91}
92
93
njn25e49d8e72002-09-23 09:36:25 +000094/* Statistics about C functions called from generated code. */
95static UInt ccalls = 0;
96static UInt ccall_reg_saves = 0;
97static UInt ccall_args = 0;
98static UInt ccall_arg_setup_instrs = 0;
99static UInt ccall_stack_clears = 0;
100static UInt ccall_retvals = 0;
101static UInt ccall_retval_movs = 0;
102
103/* Statistics about frequency of each UInstr */
104typedef
105 struct {
106 UInt counts;
107 UInt size;
108 } Histogram;
109
110/* Automatically zeroed because it's static. */
111static Histogram histogram[100];
112
113void VG_(print_ccall_stats)(void)
114{
115 VG_(message)(Vg_DebugMsg,
116 " ccalls: %u C calls, %u%% saves+restores avoided"
117 " (%d bytes)",
118 ccalls,
119 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
120 ((ccalls*3) - ccall_reg_saves)*2);
121 VG_(message)(Vg_DebugMsg,
122 " %u args, avg 0.%d setup instrs each (%d bytes)",
123 ccall_args,
124 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
125 (ccall_args - ccall_arg_setup_instrs)*2);
126 VG_(message)(Vg_DebugMsg,
127 " %d%% clear the stack (%d bytes)",
128 (UInt)(ccall_stack_clears/(double)ccalls*100),
129 (ccalls - ccall_stack_clears)*3);
130 VG_(message)(Vg_DebugMsg,
131 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
132 ccall_retvals,
133 ( ccall_retvals == 0
134 ? 100
135 : 100-(UInt)(ccall_retval_movs /
136 (double)ccall_retvals*100)),
137 (ccall_retvals-ccall_retval_movs)*2);
138}
139
140void VG_(print_UInstr_histogram)(void)
141{
142 Int i, j;
143 UInt total_counts = 0;
144 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000145
njn25e49d8e72002-09-23 09:36:25 +0000146 for (i = 0; i < 100; i++) {
147 total_counts += histogram[i].counts;
148 total_size += histogram[i].size;
149 }
150
151 VG_(printf)("-- UInstr frequencies -----------\n");
152 for (i = 0; i < 100; i++) {
153 if (0 != histogram[i].counts) {
154
155 UInt count_pc =
156 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
157 UInt size_pc =
158 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
159 UInt avg_size =
160 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
161
162 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000163 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000164 histogram[i].counts, count_pc,
165 avg_size, size_pc);
166
sewardj05bcdcb2003-05-18 10:05:38 +0000167 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000168 VG_(printf)("\n");
169
170 } else {
171 vg_assert(0 == histogram[i].size);
172 }
173 }
174
175 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
176}
177
sewardjde4a1d02002-03-22 01:27:54 +0000178static void expandEmittedCode ( void )
179{
180 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000181 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000182 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
183 for (i = 0; i < emitted_code_size; i++)
184 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000185 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000186 emitted_code = tmp;
187 emitted_code_size *= 2;
188}
189
njn25e49d8e72002-09-23 09:36:25 +0000190/* Local calls will be inlined, cross-module ones not */
191__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
193 if (dis) {
194 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
195 }
196 if (emitted_code_used == emitted_code_size)
197 expandEmittedCode();
198
199 emitted_code[emitted_code_used] = (UChar)b;
200 emitted_code_used++;
201}
202
njn25e49d8e72002-09-23 09:36:25 +0000203__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000204{
njn25e49d8e72002-09-23 09:36:25 +0000205 VG_(emitB) ( (l) & 0x000000FF );
206 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000207}
208
njn25e49d8e72002-09-23 09:36:25 +0000209__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000210{
njn25e49d8e72002-09-23 09:36:25 +0000211 VG_(emitB) ( (l) & 0x000000FF );
212 VG_(emitB) ( (l >> 8) & 0x000000FF );
213 VG_(emitB) ( (l >> 16) & 0x000000FF );
214 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000215}
216
sewardjfa492d42002-12-08 18:20:01 +0000217static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000218{
sewardjfa492d42002-12-08 18:20:01 +0000219 Int off = 4 * VGOFF_(m_eflags);
220 vg_assert(off >= 0 && off < 128);
221
222 if (dis)
223 VG_(printf)("\t %4d: ", emitted_code_used );
224
225 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
226 VG_(emitB) ( 0x75 );
227 VG_(emitB) ( off );
228 VG_(emitB) ( 0x9D ); /* POPFL */
229 if (dis)
230 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
231}
232
233static void emit_put_eflags ( void )
234{
235 Int off = 4 * VGOFF_(m_eflags);
236 vg_assert(off >= 0 && off < 128);
237
238 if (dis)
239 VG_(printf)("\t %4d: ", emitted_code_used );
240
241 VG_(emitB) ( 0x9C ); /* PUSHFL */
242 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
243 VG_(emitB) ( 0x45 );
244 VG_(emitB) ( off );
245 if (dis)
246 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
247}
248
249static void maybe_emit_put_eflags( void )
250{
251 if (eflags_state == UPD_Real) {
252 eflags_state = UPD_Both;
253 emit_put_eflags();
254 }
255}
256
sewardja2c5a732002-12-15 03:10:42 +0000257
258/* evidently unused */
259#if 0
sewardjfa492d42002-12-08 18:20:01 +0000260static void maybe_emit_get_eflags( void )
261{
262 if (eflags_state == UPD_Simd) {
263 eflags_state = UPD_Both;
264 emit_get_eflags();
265 }
266}
sewardja2c5a732002-12-15 03:10:42 +0000267#endif
sewardjfa492d42002-12-08 18:20:01 +0000268
sewardjf0f12aa2002-12-28 00:04:08 +0000269
270#if 0
271/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
272/* An alternative implementation of new_emit in which the
273 state space is explicitly enumerated. */
274__inline__
275void VG_(new_emit) ( Bool upds_simd_flags,
276 FlagSet use_flags, FlagSet set_flags )
277{
278 Bool simd = upds_simd_flags;
279 enum _eflags_state where = eflags_state;
280
281 enum { WNone, WSome, WAll } ww;
282 Bool rr;
283
284#define DIS_HEADER \
285 if (dis) \
286 VG_(printf)("\t %4d: ", emitted_code_used );
287
288 if (use_flags == FlagsEmpty) {
289 rr = False;
290 } else {
291 rr = True;
292 }
293
294 if (set_flags == FlagsEmpty) {
295 ww = WNone;
296 } else
297 if (set_flags == FlagsOSZACP) {
298 ww = WAll;
299 } else {
300 ww = WSome;
301 }
302
303 /* If we're not wanting to interact with simd flags, and the simd
304 flags are not in the real flags, then do nothing. */
305 if (simd == False && where == UPD_Simd)
306 goto noaction;
307
308 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
309 /* We're going to generate a complete new simd flag state without
310 consulting the old one first, so just deem this insn to create
311 the state in the real flags. */
312 eflags_state = UPD_Real;
313 DIS_HEADER;
314 return;
315 }
316
317 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
318 /* Want to partially update the flags state, but is in simd. So
319 fetch it first, then declare that the real state is the most
320 recent. */
321 emit_get_eflags();
322 eflags_state = UPD_Real;
323 DIS_HEADER;
324 return;
325 }
326
327 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
328 /* want to read simd flags, but not in real -> copy to real. */
329 emit_get_eflags();
330 eflags_state = UPD_Both;
331 DIS_HEADER;
332 return;
333 }
334
335 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
336 /* want to read and write simd flags, but not in real -> copy to
337 real. State is then Real since they get updated. */
338 emit_get_eflags();
339 eflags_state = UPD_Real;
340 DIS_HEADER;
341 return;
342 }
343
344 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
345 /* Doesn't really make sense. Want to interact with simd flags,
346 but insn doesn't modify them. So don't do anything. ??? */
347 goto noaction;
348 }
349
350 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
351 /* Doesn't really make sense. Want to interact with simd flags,
352 but insn doesn't modify them. So don't do anything. ??? */
353 goto noaction;
354 }
355
356 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
357 /* simd is in real. Insn reads real but does not change. --> do
358 nothing. */
359 goto noaction;
360 }
361
362 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
363 /* simd is in real. we want to capture changes made by it. -->
364 do nothing */
365 goto noaction;
366 }
367
368 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
369 /* simd is in real. Insn creates new simd state. --> leave in
370 real */
371 goto noaction;
372 }
373
374 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
375 /* simd is in both. Insn creates new simd state. --> change
376 state to Real. */
377 narrow_Both_to_Real:
378 eflags_state = UPD_Real;
379 DIS_HEADER;
380 return;
381 }
382
383 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
384 /* simd is in both. Insn creates partial new simd state. -->
385 change state to Real. No need to get, since Both holds. */
386 goto narrow_Both_to_Real;
387 }
388
389 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
390 /* simd is in real. Insn creates new simd state. --> leave in
391 real */
392 goto noaction;
393 }
394
395 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
396 /* want to read the simd flags, but already have a copy in real,
397 and not planning to modify it --> do nothing. */
398 goto noaction;
399
400 ////////////////
401
402 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
403 /* simd state is in real, but insn doesn't touch it --> do nothing */
404 goto noaction;
405
406 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
407 /* simd state is in both, insn doesn't touch it --> do nothing */
408 goto noaction;
409
410 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
411 /* simd state is in both. insn trashes real, therefore declare
412 simd state only in simd. */
413 narrow_Both_to_Simd:
414 eflags_state = UPD_Simd;
415 DIS_HEADER;
416 return;
417 }
418
419 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
420 /* simd state is in both. insn trashes real, therefore declare
421 simd state only in simd. */
422 goto narrow_Both_to_Simd;
423 }
424
425 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
426 /* simd state is in real; we don't want simd state changed, but
427 insn writes the flags. Therefore have to copy back first. */
428 put_flags_and_continue:
429 emit_put_eflags();
430 eflags_state = UPD_Simd;
431 DIS_HEADER;
432 return;
433 }
434
435 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
436 /* simd state is in real; we don't want simd state changed, but
437 insn writes the flags. Therefore have to copy back first. */
438 goto put_flags_and_continue;
439 }
440
441 goto unhandled;
442
443 noaction:
444 DIS_HEADER;
445 return;
446
447 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
448 // return;
449 //}
450
451 unhandled:
452 VG_(printf)("simd %s, where %s, read %s, write %s\n",
453 simd ? "True " : "False",
454 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
455 ? "Real" : "Both")),
456 rr ? "True " : "False",
457 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
458 );
459
460 VG_(core_panic)("new_emit");
461}
462/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
463#endif
464
465
sewardjfa492d42002-12-08 18:20:01 +0000466/* Call this before emitting each instruction.
467
468 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000469 interacts_with_simd_flags:
470 if true, this instruction wants to interact (read and/or write)
471 the simulated %EFLAGS state,
472 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000473 use_flags: set of (real) flags the instruction uses
474 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000475*/
sewardjfa492d42002-12-08 18:20:01 +0000476__inline__
sewardjf0f12aa2002-12-28 00:04:08 +0000477void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000478 FlagSet use_flags, FlagSet set_flags )
479{
480 Bool use, set;
481
482 use = use_flags != FlagsEmpty
483 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
484 set = set_flags != FlagsEmpty;
485
486 if (0)
487 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000488 "new_emit: state=%d interacts_with_simd_flags=%d "
489 "use_flags=%x set_flags=%x\n",
490 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000491
sewardjf0f12aa2002-12-28 00:04:08 +0000492 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000493 if (use && eflags_state == UPD_Simd) {
494 /* we need the CPU flags set, but they're not already */
495 eflags_state = UPD_Both;
496 emit_get_eflags();
497 }
498 if (set) {
499 /* if we're setting the flags, then the CPU will have the
500 only good copy */
501 eflags_state = UPD_Real;
502 }
503 } else {
504 /* presume that if non-simd code is using flags, it knows what
505 it's doing (ie, it just set up the flags). */
506 if (set) {
507 /* This instruction is going to trash the flags, so we'd
508 better save them away and say that they're only in the
509 simulated state. */
510 maybe_emit_put_eflags();
511 eflags_state = UPD_Simd;
512 }
513 }
514
sewardjde4a1d02002-03-22 01:27:54 +0000515 if (dis)
516 VG_(printf)("\t %4d: ", emitted_code_used );
517}
518
sewardjde4a1d02002-03-22 01:27:54 +0000519
520/*----------------------------------------------------*/
521/*--- Addressing modes ---*/
522/*----------------------------------------------------*/
523
524static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
525{
526 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
527}
528
529static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
530{
531 Int shift;
532 switch (scale) {
533 case 1: shift = 0; break;
534 case 2: shift = 1; break;
535 case 4: shift = 2; break;
536 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000537 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
540}
541
542static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
543{
544 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000545 VG_(emitB) ( mkModRegRM(0, reg, 5) );
546 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000547}
548
549static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
550{
551 /* (regmem), reg */
552 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000553 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( mkModRegRM(1, reg, 5) );
556 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000557 } else {
njn25e49d8e72002-09-23 09:36:25 +0000558 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000559 }
560}
561
njn25e49d8e72002-09-23 09:36:25 +0000562void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000563{
564 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 if (off < -128 || off > 127) {
567 /* Use a large offset */
568 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
570 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000571 } else {
572 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
574 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000575 }
576}
577
578static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
579 Int regindex, Int reg )
580{
581 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000582 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000583 if (off < -128 || off > 127) {
584 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000585 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
586 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
587 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000588 } else {
589 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
591 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
592 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000593 }
594}
595
njn25e49d8e72002-09-23 09:36:25 +0000596void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000597{
598 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000599 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000600}
601
602static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
603{
604 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000606}
607
608
609/*----------------------------------------------------*/
610/*--- Opcode translation ---*/
611/*----------------------------------------------------*/
612
613static __inline__ Int mkGrp1opcode ( Opcode opc )
614{
615 switch (opc) {
616 case ADD: return 0;
617 case OR: return 1;
618 case ADC: return 2;
619 case SBB: return 3;
620 case AND: return 4;
621 case SUB: return 5;
622 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000623 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000624 }
625}
626
sewardjfa492d42002-12-08 18:20:01 +0000627static __inline__ FlagSet nonshiftop_use(Opcode opc)
628{
629 switch(opc) {
630 case ADC:
631 case SBB:
632 return FlagC;
633
634 case ADD:
635 case OR:
636 case AND:
637 case SUB:
638 case XOR:
639 return FlagsEmpty;
640
641 default:
642 VG_(core_panic)("nonshiftop_use");
643 }
644}
645
646static __inline__ FlagSet nonshiftop_set(Opcode opc)
647{
648 switch(opc) {
649 case ADC:
650 case SBB:
651 case ADD:
652 case OR:
653 case AND:
654 case SUB:
655 case XOR:
656 return FlagsOSZACP;
657
658 default:
659 VG_(core_panic)("nonshiftop_set");
660 }
661}
662
sewardjde4a1d02002-03-22 01:27:54 +0000663static __inline__ Int mkGrp2opcode ( Opcode opc )
664{
665 switch (opc) {
666 case ROL: return 0;
667 case ROR: return 1;
668 case RCL: return 2;
669 case RCR: return 3;
670 case SHL: return 4;
671 case SHR: return 5;
672 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000673 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000674 }
675}
676
sewardjfa492d42002-12-08 18:20:01 +0000677static __inline__ FlagSet shiftop_use(Opcode opc)
678{
679 switch(opc) {
680 case ROR:
681 case ROL:
682 case SHL:
683 case SHR:
684 case SAR:
685 return FlagsEmpty;
686
687 case RCL:
688 case RCR:
689 return FlagC;
690
691 default:
692 VG_(core_panic)("shiftop_use");
693 }
694}
695
696static __inline__ FlagSet shiftop_set(Opcode opc)
697{
698 switch(opc) {
699 case ROR:
700 case ROL:
701 case RCL:
702 case RCR:
703 return FlagsOC;
704
705 case SHL:
706 case SHR:
707 case SAR:
708 return FlagsOSZACP;
709
710 default:
711 VG_(core_panic)("shiftop_set");
712 }
713}
714
sewardjde4a1d02002-03-22 01:27:54 +0000715static __inline__ Int mkGrp3opcode ( Opcode opc )
716{
717 switch (opc) {
718 case NOT: return 2;
719 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000720 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000721 }
722}
723
724static __inline__ Int mkGrp4opcode ( Opcode opc )
725{
726 switch (opc) {
727 case INC: return 0;
728 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000729 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000730 }
731}
732
733static __inline__ Int mkGrp5opcode ( Opcode opc )
734{
735 switch (opc) {
736 case CALLM: return 2;
737 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000738 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000739 }
740}
741
742static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
743{
744 switch (opc) {
745 case ADD: return 0x00;
746 case ADC: return 0x10;
747 case AND: return 0x20;
748 case XOR: return 0x30;
749 case OR: return 0x08;
750 case SBB: return 0x18;
751 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000752 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000753 }
754}
755
756/*----------------------------------------------------*/
757/*--- v-size (4, or 2 with OSO) insn emitters ---*/
758/*----------------------------------------------------*/
759
njn25e49d8e72002-09-23 09:36:25 +0000760void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000761{
sewardjf0f12aa2002-12-28 00:04:08 +0000762 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000763 if (sz == 2) VG_(emitB) ( 0x66 );
764 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
765 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000766 if (dis)
767 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
768 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
769}
770
njn25e49d8e72002-09-23 09:36:25 +0000771void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000772{
sewardjf0f12aa2002-12-28 00:04:08 +0000773 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000774 if (sz == 2) VG_(emitB) ( 0x66 );
775 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
776 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
779 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
780}
781
782static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
783{
sewardjf0f12aa2002-12-28 00:04:08 +0000784 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000785 if (sz == 2) VG_(emitB) ( 0x66 );
786 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000787 emit_amode_regmem_reg ( reg1, reg2 );
788 if (dis)
789 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
790 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
791}
792
793static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
794{
sewardjf0f12aa2002-12-28 00:04:08 +0000795 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000796 if (sz == 2) VG_(emitB) ( 0x66 );
797 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000798 emit_amode_regmem_reg ( reg2, reg1 );
799 if (dis)
800 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
801 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
802}
803
njn25e49d8e72002-09-23 09:36:25 +0000804void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000805{
sewardjf0f12aa2002-12-28 00:04:08 +0000806 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000807 if (sz == 2) VG_(emitB) ( 0x66 );
808 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
809 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000810 if (dis)
811 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
812 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
813}
814
sewardjf0f12aa2002-12-28 00:04:08 +0000815void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
816 Int sz, Opcode opc,
817 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
sewardjf0f12aa2002-12-28 00:04:08 +0000819 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000820
njn25e49d8e72002-09-23 09:36:25 +0000821 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
823 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000824 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
825 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
826 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000827 } else {
njn25e49d8e72002-09-23 09:36:25 +0000828 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
829 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
830 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000831 }
832 if (dis)
833 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000834 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000835 lit, nameIReg(sz,reg));
836}
837
sewardjf0f12aa2002-12-28 00:04:08 +0000838void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
839 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000840 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000841{
sewardjf0f12aa2002-12-28 00:04:08 +0000842 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000843 if (sz == 2) VG_(emitB) ( 0x66 );
844 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
845 /* short form OK */
846 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
847 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
848 VG_(emitB) ( lit & 0x000000FF );
849 } else {
850 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
851 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
852 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
853 }
854 if (dis)
855 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
856 VG_(name_UOpcode)(False,opc), nameISize(sz),
857 lit, off, nameIReg(sz,regmem));
858}
859
sewardjf0f12aa2002-12-28 00:04:08 +0000860void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
861 Int sz, Opcode opc,
862 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000863{
sewardjf0f12aa2002-12-28 00:04:08 +0000864 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000865
njn25e49d8e72002-09-23 09:36:25 +0000866 if (sz == 2) VG_(emitB) ( 0x66 );
867 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
868 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
869 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000870 if (dis)
871 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000872 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000873 lit, nameIReg(sz,reg));
874}
875
sewardjf0f12aa2002-12-28 00:04:08 +0000876static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000877{
sewardjf0f12aa2002-12-28 00:04:08 +0000878 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000879 if (sz == 2) VG_(emitB) ( 0x66 );
880 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
881 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
882 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
883 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000884 if (dis)
885 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000886 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000887}
888
sewardjf0f12aa2002-12-28 00:04:08 +0000889static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000890{
sewardjf0f12aa2002-12-28 00:04:08 +0000891 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000892 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
893 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
894 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
895 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000896 if (dis)
897 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000898 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000899}
900
sewardjf0f12aa2002-12-28 00:04:08 +0000901static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
902 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000903 Int off, Int areg, Int reg )
904{
sewardjf0f12aa2002-12-28 00:04:08 +0000905 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000906 if (sz == 2) VG_(emitB) ( 0x66 );
907 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
908 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000909 if (dis)
910 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000911 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000912 off, nameIReg(4,areg), nameIReg(sz,reg));
913}
914
sewardja2c5a732002-12-15 03:10:42 +0000915#if 0
916/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000917static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000918 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000919{
sewardjf0f12aa2002-12-28 00:04:08 +0000920 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000921 if (sz == 2) VG_(emitB) ( 0x66 );
922 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
923 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
926 VG_(name_UOpcode)(False,opc), nameISize(sz),
927 nameIReg(sz,reg), off, nameIReg(4,areg));
928}
sewardja2c5a732002-12-15 03:10:42 +0000929#endif
sewardjfa492d42002-12-08 18:20:01 +0000930
sewardjf0f12aa2002-12-28 00:04:08 +0000931void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000932 Int reg1, Int reg2 )
933{
sewardjf0f12aa2002-12-28 00:04:08 +0000934 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000935 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000936# if 0
937 /* Perfectly correct, but the GNU assembler uses the other form.
938 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
940 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000941# else
njn25e49d8e72002-09-23 09:36:25 +0000942 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000943 emit_amode_greg_ereg ( reg1, reg2 );
944# endif
945 if (dis)
946 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000947 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000948 nameIReg(sz,reg1), nameIReg(sz,reg2));
949}
950
njn25e49d8e72002-09-23 09:36:25 +0000951void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000952{
sewardjf0f12aa2002-12-28 00:04:08 +0000953#if 0
sewardjfa492d42002-12-08 18:20:01 +0000954 if (lit == 0 && eflags_state != UPD_Real) {
955 /* Only emit this for zeroing if it won't stomp flags */
956 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000957 return;
958 }
sewardjf0f12aa2002-12-28 00:04:08 +0000959#endif
960 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000961 if (sz == 2) VG_(emitB) ( 0x66 );
962 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
963 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000964 if (dis)
965 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
966 nameISize(sz), lit, nameIReg(sz,reg));
967}
968
sewardjf0f12aa2002-12-28 00:04:08 +0000969void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000970{
sewardjde4a1d02002-03-22 01:27:54 +0000971 switch (opc) {
972 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +0000973 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +0000974 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000975 VG_(emitB) ( 0xF7 );
976 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000977 if (dis)
978 VG_(printf)( "\n\t\tneg%c\t%s\n",
979 nameISize(sz), nameIReg(sz,reg));
980 break;
981 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +0000982 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +0000983 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000984 VG_(emitB) ( 0xF7 );
985 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000986 if (dis)
987 VG_(printf)( "\n\t\tnot%c\t%s\n",
988 nameISize(sz), nameIReg(sz,reg));
989 break;
990 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +0000991 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +0000992 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tdec%c\t%s\n",
996 nameISize(sz), nameIReg(sz,reg));
997 break;
998 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +0000999 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001000 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001001 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (dis)
1003 VG_(printf)( "\n\t\tinc%c\t%s\n",
1004 nameISize(sz), nameIReg(sz,reg));
1005 break;
1006 default:
njne427a662002-10-02 11:08:25 +00001007 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001008 }
1009}
1010
njn25e49d8e72002-09-23 09:36:25 +00001011void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001012{
sewardjf0f12aa2002-12-28 00:04:08 +00001013 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001014 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001015 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001016 } else {
1017 vg_assert(sz == 4);
1018 }
njn25e49d8e72002-09-23 09:36:25 +00001019 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001020 if (dis)
1021 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1022}
1023
njn25e49d8e72002-09-23 09:36:25 +00001024void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001025{
sewardjf0f12aa2002-12-28 00:04:08 +00001026 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001027 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001029 } else {
1030 vg_assert(sz == 4);
1031 }
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001033 if (dis)
1034 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1035}
1036
njn25e49d8e72002-09-23 09:36:25 +00001037void VG_(emit_pushl_lit32) ( UInt int32 )
1038{
sewardjf0f12aa2002-12-28 00:04:08 +00001039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001040 VG_(emitB) ( 0x68 );
1041 VG_(emitL) ( int32 );
1042 if (dis)
1043 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1044}
1045
1046void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001047{
1048 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001049 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001050 VG_(emitB) ( 0x6A );
1051 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001052 if (dis)
1053 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1054}
1055
sewardjf0f12aa2002-12-28 00:04:08 +00001056void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001057{
sewardjf0f12aa2002-12-28 00:04:08 +00001058 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001059 VG_(emitB) ( 0x83 );
1060 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1061 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001062 if (dis)
1063 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1064}
1065
1066static void emit_swapl_reg_ECX ( Int reg )
1067{
sewardjf0f12aa2002-12-28 00:04:08 +00001068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1070 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001071 if (dis)
1072 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1073}
1074
njn25e49d8e72002-09-23 09:36:25 +00001075void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001076{
sewardjf0f12aa2002-12-28 00:04:08 +00001077 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001078 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001079 if (dis)
1080 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1081}
1082
1083static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1084{
sewardjf0f12aa2002-12-28 00:04:08 +00001085 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1087 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001088 if (dis)
1089 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1090 nameIReg(4,reg2));
1091}
1092
1093static void emit_bswapl_reg ( Int reg )
1094{
sewardjf0f12aa2002-12-28 00:04:08 +00001095 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001096 VG_(emitB) ( 0x0F );
1097 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001098 if (dis)
1099 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1100}
1101
1102static void emit_movl_reg_reg ( Int regs, Int regd )
1103{
sewardjf0f12aa2002-12-28 00:04:08 +00001104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001105 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1106 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001107 if (dis)
1108 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1109}
1110
njn25e49d8e72002-09-23 09:36:25 +00001111void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001112{
sewardjf0f12aa2002-12-28 00:04:08 +00001113 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001114 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001115 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 } else {
1117 vg_assert(sz == 4);
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1120 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1121 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001122 if (dis)
1123 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1124 nameISize(sz), lit, off, nameIReg(4,memreg) );
1125}
1126
1127
1128/*----------------------------------------------------*/
1129/*--- b-size (1 byte) instruction emitters ---*/
1130/*----------------------------------------------------*/
1131
1132/* There is some doubt as to whether C6 (Grp 11) is in the
1133 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001134void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1135{
sewardjf0f12aa2002-12-28 00:04:08 +00001136 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001137 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1138 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1139 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (dis)
1141 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1142 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001143}
1144
sewardjf0f12aa2002-12-28 00:04:08 +00001145static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001146 Int off, Int areg, Int reg )
1147{
sewardjf0f12aa2002-12-28 00:04:08 +00001148 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001149 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1150 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001151 if (dis)
1152 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001154 nameIReg(1,reg));
1155}
1156
sewardjf0f12aa2002-12-28 00:04:08 +00001157static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001158 UInt lit, Int off, Int areg )
1159{
sewardjf0f12aa2002-12-28 00:04:08 +00001160 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001161 VG_(emitB) ( 0x80 );
1162 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1163 VG_(emitB) ( lit );
1164 if (dis)
1165 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1166 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1167}
1168
sewardja2c5a732002-12-15 03:10:42 +00001169#if 0
1170/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001171static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001172 Int off, Int areg, Int reg )
1173{
sewardjf0f12aa2002-12-28 00:04:08 +00001174 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001175 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1176 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1177 if (dis)
1178 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1179 VG_(name_UOpcode)(False,opc),
1180 nameIReg(1,reg),
1181 off, nameIReg(4,areg));
1182}
sewardja2c5a732002-12-15 03:10:42 +00001183#endif
sewardjfa492d42002-12-08 18:20:01 +00001184
njn25e49d8e72002-09-23 09:36:25 +00001185void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001186{
1187 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001188 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001189 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1190 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001191 if (dis)
1192 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1193 nameIReg(1,reg), off, nameIReg(4,areg));
1194}
1195
sewardjf0f12aa2002-12-28 00:04:08 +00001196static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1197 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001198{
sewardjf0f12aa2002-12-28 00:04:08 +00001199 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001200 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1201 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001202 if (dis)
1203 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001204 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001205 nameIReg(1,reg1), nameIReg(1,reg2));
1206}
1207
1208static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
1209{
sewardjf0f12aa2002-12-28 00:04:08 +00001210 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001211 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001212 emit_amode_regmem_reg ( reg2, reg1 );
1213 if (dis)
1214 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1215 nameIReg(4,reg2));
1216}
1217
sewardjf0f12aa2002-12-28 00:04:08 +00001218static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1219 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001220{
sewardjf0f12aa2002-12-28 00:04:08 +00001221 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001222 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1223 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1224 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001225 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001226 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001227 lit, nameIReg(1,reg));
1228}
1229
sewardjf0f12aa2002-12-28 00:04:08 +00001230static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1231 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001232{
sewardjf0f12aa2002-12-28 00:04:08 +00001233 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001234 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1235 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1236 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001237 if (dis)
1238 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001239 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001240 lit, nameIReg(1,reg));
1241}
1242
sewardjf0f12aa2002-12-28 00:04:08 +00001243void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001244{
sewardjde4a1d02002-03-22 01:27:54 +00001245 switch (opc) {
1246 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001247 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001248 VG_(emitB) ( 0xFE );
1249 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001250 if (dis)
1251 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1252 break;
1253 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001254 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001255 VG_(emitB) ( 0xFE );
1256 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001257 if (dis)
1258 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1259 break;
1260 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001261 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001262 VG_(emitB) ( 0xF6 );
1263 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001264 if (dis)
1265 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1266 break;
1267 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001268 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0xF6 );
1270 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001271 if (dis)
1272 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1273 break;
1274 default:
njne427a662002-10-02 11:08:25 +00001275 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001276 }
1277}
1278
sewardjf0f12aa2002-12-28 00:04:08 +00001279void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001280{
sewardjf0f12aa2002-12-28 00:04:08 +00001281 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001282 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1283 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1284 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001285 if (dis)
1286 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1287}
1288
sewardjde4a1d02002-03-22 01:27:54 +00001289/*----------------------------------------------------*/
1290/*--- zero-extended load emitters ---*/
1291/*----------------------------------------------------*/
1292
njn25e49d8e72002-09-23 09:36:25 +00001293void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001294{
sewardjf0f12aa2002-12-28 00:04:08 +00001295 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001296 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1297 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001298 if (dis)
1299 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1300 off, nameIReg(4,regmem), nameIReg(4,reg));
1301}
1302
1303static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
1304{
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001307 emit_amode_regmem_reg ( reg1, reg2 );
1308 if (dis)
1309 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1310 nameIReg(4,reg2));
1311}
1312
njn25e49d8e72002-09-23 09:36:25 +00001313void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001314{
sewardjf0f12aa2002-12-28 00:04:08 +00001315 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001316 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1317 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001318 if (dis)
1319 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1320 off, nameIReg(4,areg), nameIReg(4,reg));
1321}
1322
1323static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
1324{
sewardjf0f12aa2002-12-28 00:04:08 +00001325 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001326 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001327 emit_amode_regmem_reg ( reg1, reg2 );
1328 if (dis)
1329 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1330 nameIReg(4,reg2));
1331}
1332
1333/*----------------------------------------------------*/
1334/*--- FPU instruction emitters ---*/
1335/*----------------------------------------------------*/
1336
sewardjb91ae7f2003-04-29 23:50:00 +00001337static void emit_get_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001338{
sewardjb91ae7f2003-04-29 23:50:00 +00001339 Int off = 4 * VGOFF_(m_ssestate);
1340 if (VG_(have_ssestate)) {
1341 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1342 VG_(emitB) ( 0x0F );
1343 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x8D ); /* fxrstor d32(%ebp) */
1344 VG_(emitL) ( off );
1345 if (dis)
1346 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1347 } else {
1348 /* Not a SSE-capable CPU. Just do frstor. */
1349 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1350 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1351 VG_(emitL) ( off );
1352 if (dis)
1353 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1354 }
sewardjde4a1d02002-03-22 01:27:54 +00001355}
1356
sewardjb91ae7f2003-04-29 23:50:00 +00001357static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001358{
sewardjb91ae7f2003-04-29 23:50:00 +00001359 Int off = 4 * VGOFF_(m_ssestate);
1360 if (VG_(have_ssestate)) {
1361 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1362 VG_(emitB) ( 0x0F );
1363 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1364 VG_(emitL) ( off );
1365 if (dis)
1366 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1367 } else {
1368 /* Not a SSE-capable CPU. Just do fnsave. */
1369 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1370 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1371 VG_(emitL) ( off );
1372 if (dis)
1373 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1374 }
sewardjde4a1d02002-03-22 01:27:54 +00001375}
1376
sewardjf0f12aa2002-12-28 00:04:08 +00001377static void emit_fpu_no_mem ( FlagSet uses_sflags,
1378 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001379 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001380 UChar second_byte )
1381{
sewardjf0f12aa2002-12-28 00:04:08 +00001382 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001383 VG_(emitB) ( first_byte );
1384 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001385 if (dis)
1386 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1387 (UInt)first_byte, (UInt)second_byte );
1388}
1389
sewardjf0f12aa2002-12-28 00:04:08 +00001390static void emit_fpu_regmem ( FlagSet uses_sflags,
1391 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001392 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001393 UChar second_byte_masked,
1394 Int reg )
1395{
sewardjf0f12aa2002-12-28 00:04:08 +00001396 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001397 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001398 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1399 if (dis)
1400 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1401 (UInt)first_byte, (UInt)second_byte_masked,
1402 nameIReg(4,reg) );
1403}
1404
sewardj3d7c9c82003-03-26 21:08:13 +00001405static void emit_MMX2_regmem ( FlagSet uses_sflags,
1406 FlagSet sets_sflags,
1407 UChar first_byte,
1408 UChar second_byte,
1409 Int ireg )
1410{
1411 VG_(new_emit)(True, uses_sflags, sets_sflags);
1412 VG_(emitB) ( 0x0F );
1413 VG_(emitB) ( first_byte );
1414 second_byte &= 0x38; /* mask out mod and rm fields */
1415 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1416 if (dis)
1417 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1418 (UInt)first_byte, (UInt)second_byte,
1419 nameIReg(4,ireg) );
1420}
1421
sewardjfebaa3b2003-05-25 01:07:34 +00001422static void emit_SSE2a ( FlagSet uses_sflags,
1423 FlagSet sets_sflags,
1424 UChar first_byte,
1425 UChar second_byte,
1426 UChar third_byte,
1427 Int ireg )
1428{
1429 VG_(new_emit)(True, uses_sflags, sets_sflags);
1430 VG_(emitB) ( first_byte );
1431 VG_(emitB) ( second_byte );
1432 third_byte &= 0x38; /* mask out mod and rm fields */
1433 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1434 if (dis)
1435 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x-(%s)\n",
1436 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1437 nameIReg(4,ireg) );
1438}
1439
1440static void emit_SSE3a ( FlagSet uses_sflags,
1441 FlagSet sets_sflags,
1442 UChar first_byte,
1443 UChar second_byte,
1444 UChar third_byte,
1445 UChar fourth_byte,
1446 Int ireg )
1447{
1448 VG_(new_emit)(True, uses_sflags, sets_sflags);
1449 VG_(emitB) ( first_byte );
1450 VG_(emitB) ( second_byte );
1451 VG_(emitB) ( third_byte );
1452 fourth_byte &= 0x38; /* mask out mod and rm fields */
1453 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1454 if (dis)
1455 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1456 (UInt)first_byte, (UInt)second_byte,
1457 (UInt)third_byte, (UInt)fourth_byte,
1458 nameIReg(4,ireg) );
1459}
1460
sewardj8f33ba62003-06-14 12:00:45 +00001461static void emit_SSE3g_RegRd ( FlagSet uses_sflags,
1462 FlagSet sets_sflags,
1463 UChar first_byte,
1464 UChar second_byte,
1465 UChar third_byte,
1466 UChar fourth_byte,
1467 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001468{
1469 VG_(new_emit)(True, uses_sflags, sets_sflags);
1470 VG_(emitB) ( first_byte );
1471 VG_(emitB) ( second_byte );
1472 VG_(emitB) ( third_byte );
1473 fourth_byte &= 0x38; /* mask out mod and rm fields */
1474 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1475 fourth_byte |= (ireg & 7); /* patch in our ireg */
1476 VG_(emitB) ( fourth_byte );
1477 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001478 VG_(printf)(
sewardj8f33ba62003-06-14 12:00:45 +00001479 "\n\t\tireg-to-ssereg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001480 (UInt)first_byte, (UInt)second_byte,
1481 (UInt)third_byte, (UInt)fourth_byte,
1482 nameIReg(4,ireg)
1483 );
sewardjfebaa3b2003-05-25 01:07:34 +00001484}
1485
sewardj8f33ba62003-06-14 12:00:45 +00001486static void emit_SSE3g1_RegRd ( FlagSet uses_sflags,
1487 FlagSet sets_sflags,
1488 UChar first_byte,
1489 UChar second_byte,
1490 UChar third_byte,
1491 UChar fourth_byte,
1492 UChar fifth_byte,
1493 Int ireg )
1494{
1495 VG_(new_emit)(True, uses_sflags, sets_sflags);
1496 VG_(emitB) ( first_byte );
1497 VG_(emitB) ( second_byte );
1498 VG_(emitB) ( third_byte );
1499 fourth_byte &= 0x38; /* mask out mod and rm fields */
1500 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1501 fourth_byte |= (ireg & 7); /* patch in our ireg */
1502 VG_(emitB) ( fourth_byte );
1503 VG_(emitB) ( fifth_byte );
1504 if (dis)
1505 VG_(printf)(
1506 "\n\t\tireg-to-ssereg--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1507 (UInt)first_byte, (UInt)second_byte,
1508 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1509 nameIReg(4,ireg)
1510 );
1511}
1512
sewardjb31b06d2003-06-13 00:26:02 +00001513static void emit_SSE3g1_RegWr ( FlagSet uses_sflags,
1514 FlagSet sets_sflags,
1515 UChar first_byte,
1516 UChar second_byte,
1517 UChar third_byte,
1518 UChar fourth_byte,
1519 UChar fifth_byte,
1520 Int ireg )
1521{
1522 VG_(new_emit)(True, uses_sflags, sets_sflags);
1523 VG_(emitB) ( first_byte );
1524 VG_(emitB) ( second_byte );
1525 VG_(emitB) ( third_byte );
1526 fourth_byte &= 0xC7; /* mask out reg field */
1527 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1528 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1529 VG_(emitB) ( fourth_byte );
1530 VG_(emitB) ( fifth_byte );
1531 if (dis)
1532 VG_(printf)(
1533 "\n\t\tssereg-to-ireg--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1534 (UInt)first_byte, (UInt)second_byte,
1535 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1536 nameIReg(4,ireg)
1537 );
1538}
1539
sewardj8f33ba62003-06-14 12:00:45 +00001540static void emit_SSE3g_RegWr ( FlagSet uses_sflags,
1541 FlagSet sets_sflags,
1542 UChar first_byte,
1543 UChar second_byte,
1544 UChar third_byte,
1545 UChar fourth_byte,
1546 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001547{
1548 VG_(new_emit)(True, uses_sflags, sets_sflags);
1549 VG_(emitB) ( first_byte );
1550 VG_(emitB) ( second_byte );
1551 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001552 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001553 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001554 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001555 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001556 if (dis)
1557 VG_(printf)(
sewardj8f33ba62003-06-14 12:00:45 +00001558 "\n\t\tssereg-to-ireg--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001559 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001560 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001561 nameIReg(4,ireg)
1562 );
1563}
1564
sewardjfebaa3b2003-05-25 01:07:34 +00001565static void emit_SSE4 ( FlagSet uses_sflags,
1566 FlagSet sets_sflags,
1567 UChar first_byte,
1568 UChar second_byte,
1569 UChar third_byte,
1570 UChar fourth_byte )
1571{
1572 VG_(new_emit)(True, uses_sflags, sets_sflags);
1573 VG_(emitB) ( first_byte );
1574 VG_(emitB) ( second_byte );
1575 VG_(emitB) ( third_byte );
1576 VG_(emitB) ( fourth_byte );
1577 if (dis)
1578 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x\n",
1579 (UInt)first_byte, (UInt)second_byte,
1580 (UInt)third_byte, (UInt)fourth_byte );
1581}
1582
sewardja453fb02003-06-14 13:22:36 +00001583static void emit_SSE5 ( FlagSet uses_sflags,
1584 FlagSet sets_sflags,
1585 UChar first_byte,
1586 UChar second_byte,
1587 UChar third_byte,
1588 UChar fourth_byte,
1589 UChar fifth_byte )
1590{
1591 VG_(new_emit)(True, uses_sflags, sets_sflags);
1592 VG_(emitB) ( first_byte );
1593 VG_(emitB) ( second_byte );
1594 VG_(emitB) ( third_byte );
1595 VG_(emitB) ( fourth_byte );
1596 VG_(emitB) ( fifth_byte );
1597 if (dis)
1598 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x:0x%x:0x%x\n",
1599 (UInt)first_byte, (UInt)second_byte,
1600 (UInt)third_byte, (UInt)fourth_byte,
1601 (UInt)fifth_byte );
1602}
1603
sewardja60be0e2003-05-26 08:47:27 +00001604static void emit_SSE3 ( FlagSet uses_sflags,
1605 FlagSet sets_sflags,
1606 UChar first_byte,
1607 UChar second_byte,
1608 UChar third_byte )
1609{
1610 VG_(new_emit)(True, uses_sflags, sets_sflags);
1611 VG_(emitB) ( first_byte );
1612 VG_(emitB) ( second_byte );
1613 VG_(emitB) ( third_byte );
1614 if (dis)
1615 VG_(printf)("\n\t\tsse-0x%x:0x%x:0x%x\n",
1616 (UInt)first_byte, (UInt)second_byte,
1617 (UInt)third_byte );
1618}
1619
sewardjca860012003-03-27 23:52:58 +00001620static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1621 FlagSet sets_sflags,
1622 UChar first_byte,
1623 UChar second_byte,
1624 Int ireg )
1625{
1626 VG_(new_emit)(True, uses_sflags, sets_sflags);
1627 VG_(emitB) ( 0x0F );
1628 VG_(emitB) ( first_byte );
1629 second_byte &= 0x38; /* mask out mod and rm fields */
1630 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1631 second_byte |= (ireg & 7); /* patch in our ireg */
1632 VG_(emitB) ( second_byte );
1633 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001634 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1635 (UInt)first_byte, (UInt)second_byte,
1636 nameIReg(4,ireg) );
1637}
1638
1639static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1640 FlagSet sets_sflags,
1641 UChar first_byte,
1642 UChar second_byte,
1643 Int ireg )
1644{
1645 VG_(new_emit)(True, uses_sflags, sets_sflags);
1646 VG_(emitB) ( 0x0F );
1647 VG_(emitB) ( first_byte );
1648 second_byte &= 0x38; /* mask out mod and rm fields */
1649 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1650 second_byte |= (ireg & 7); /* patch in our ireg */
1651 VG_(emitB) ( second_byte );
1652 if (dis)
1653 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001654 (UInt)first_byte, (UInt)second_byte,
1655 nameIReg(4,ireg) );
1656}
1657
1658static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1659 FlagSet sets_sflags,
1660 UChar first_byte,
1661 UChar second_byte,
1662 UChar third_byte )
1663{
1664 VG_(new_emit)(True, uses_sflags, sets_sflags);
1665 VG_(emitB) ( 0x0F );
1666 VG_(emitB) ( first_byte );
1667 VG_(emitB) ( second_byte );
1668 VG_(emitB) ( third_byte );
1669 if (dis)
1670 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1671 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1672}
1673
sewardj3d7c9c82003-03-26 21:08:13 +00001674static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1675 FlagSet sets_sflags,
1676 UChar first_byte,
1677 UChar second_byte )
1678{
1679 VG_(new_emit)(True, uses_sflags, sets_sflags);
1680 VG_(emitB) ( 0x0F );
1681 VG_(emitB) ( first_byte );
1682 VG_(emitB) ( second_byte );
1683 if (dis)
1684 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1685 (UInt)first_byte, (UInt)second_byte );
1686}
1687
1688static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1689 FlagSet sets_sflags,
1690 UChar first_byte )
1691{
1692 VG_(new_emit)(True, uses_sflags, sets_sflags);
1693 VG_(emitB) ( 0x0F );
1694 VG_(emitB) ( first_byte );
1695 if (dis)
1696 VG_(printf)("\n\t\tmmx1-0x%x\n",
1697 (UInt)first_byte );
1698}
1699
sewardjde4a1d02002-03-22 01:27:54 +00001700
1701/*----------------------------------------------------*/
1702/*--- misc instruction emitters ---*/
1703/*----------------------------------------------------*/
1704
njn25e49d8e72002-09-23 09:36:25 +00001705void VG_(emit_call_reg) ( Int reg )
1706{
sewardjfa492d42002-12-08 18:20:01 +00001707 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001708 VG_(emitB) ( 0xFF ); /* Grp5 */
1709 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1710 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001711 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001712}
1713
sewardjf0f12aa2002-12-28 00:04:08 +00001714static
1715void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1716 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001717{
sewardjfa492d42002-12-08 18:20:01 +00001718 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001719 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001720
1721 if (byte_off < -128 || byte_off > 127) {
1722 VG_(emitB) ( 0xFF );
1723 VG_(emitB) ( 0x95 );
1724 VG_(emitL) ( byte_off );
1725 } else {
1726 VG_(emitB) ( 0xFF );
1727 VG_(emitB) ( 0x55 );
1728 VG_(emitB) ( byte_off );
1729 }
1730 if (dis)
1731 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001732}
1733
sewardja2c5a732002-12-15 03:10:42 +00001734#if 0
1735/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001736static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1737{
1738 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001739 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001740 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1741 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001742 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001743 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001744 if (dis)
1745 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1746 nameIReg(4,regmem));
1747}
sewardja2c5a732002-12-15 03:10:42 +00001748#endif
sewardjde4a1d02002-03-22 01:27:54 +00001749
njn25e49d8e72002-09-23 09:36:25 +00001750void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001751{
njne427a662002-10-02 11:08:25 +00001752 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001753 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1754 VG_(emitB) ( 0x8D );
1755 VG_(emitB) ( 0x64 );
1756 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001757 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001758 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001759 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001760}
1761
1762
1763static void emit_movb_AL_zeroESPmem ( void )
1764{
1765 /* movb %al, 0(%esp) */
1766 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001767 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001768 VG_(emitB) ( 0x88 );
1769 VG_(emitB) ( 0x44 );
1770 VG_(emitB) ( 0x24 );
1771 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001772 if (dis)
1773 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1774}
1775
1776static void emit_movb_zeroESPmem_AL ( void )
1777{
1778 /* movb 0(%esp), %al */
1779 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001780 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001781 VG_(emitB) ( 0x8A );
1782 VG_(emitB) ( 0x44 );
1783 VG_(emitB) ( 0x24 );
1784 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001785 if (dis)
1786 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1787}
1788
sewardja2113f92002-12-12 23:42:48 +00001789/* Jump target states */
1790#define TGT_UNDEF (1 << 16)
1791#define TGT_FORWARD (2 << 16)
1792#define TGT_BACKWARD (3 << 16)
1793
1794static inline Int tgt_state(Int tgt)
1795{
1796 return tgt & 0xffff0000;
1797}
1798
1799static inline Int tgt_addr(Int tgt)
1800{
1801 return tgt & 0x0000ffff;
1802}
1803
1804static inline Int mk_tgt(Int state, Int addr)
1805{
1806 vg_assert(state == TGT_UNDEF
1807 || state == TGT_FORWARD || state == TGT_BACKWARD);
1808 vg_assert((addr & 0xffff0000) == 0);
1809
1810 return state | addr;
1811}
1812
1813void VG_(init_target) ( Int *tgt )
1814{
1815 *tgt = TGT_UNDEF;
1816}
1817
1818void VG_(target_back) ( Int *tgt )
1819{
1820 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1821
1822 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1823}
1824
1825void VG_(target_forward) ( Int *tgt )
1826{
1827 Int delta;
1828
1829 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1830 tgt_state(*tgt) == TGT_UNDEF);
1831
1832 if (tgt_state(*tgt) == TGT_UNDEF)
1833 return; /* target not used */
1834
1835 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1836 vg_assert(delta >= -128 && delta <= 127);
1837 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001838 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001839 emitted_code[tgt_addr(*tgt)] = delta;
1840 if (dis)
1841 VG_(printf)("(target to jump site %d; delta: %d)\n",
1842 tgt_addr(*tgt), delta);
1843}
1844
1845void VG_(emit_target_delta) ( Int *tgt )
1846{
1847 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1848 tgt_state(*tgt) == TGT_BACKWARD);
1849
1850 if (tgt_state(*tgt) == TGT_UNDEF) {
1851 /* forward jump */
1852 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1853 VG_(emitB) (0x00);
1854 } else {
1855 /* backward jump */
1856 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1857 vg_assert(delta >= -128 && delta <= 127);
1858 VG_(emitB) (delta);
1859 }
1860}
1861
sewardjde4a1d02002-03-22 01:27:54 +00001862
1863/* Emit a jump short with an 8-bit signed offset. Note that the
1864 offset is that which should be added to %eip once %eip has been
1865 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001866void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001867{
1868 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001869 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001870 VG_(emitB) ( 0x70 + (UInt)cond );
1871 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001872 if (dis)
1873 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001874 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001875}
1876
sewardja2113f92002-12-12 23:42:48 +00001877/* Same as above, but defers emitting the delta */
1878void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1879{
sewardj706240d2002-12-26 17:10:12 +00001880 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001881 VG_(emitB) ( 0x70 + (UInt)cond );
1882 VG_(emit_target_delta) (tgt);
1883 if (dis)
1884 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001885 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001886}
1887
1888
1889
sewardjf0f12aa2002-12-28 00:04:08 +00001890static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001891{
sewardjf0f12aa2002-12-28 00:04:08 +00001892 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001893 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1894 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001895 if (dis)
1896 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001897 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001898}
1899
1900static void emit_ret ( void )
1901{
sewardjfa492d42002-12-08 18:20:01 +00001902 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001903 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001904 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001905 if (dis)
1906 VG_(printf)("\n\t\tret\n");
1907}
1908
sewardj22854b92002-11-30 14:00:47 +00001909/* Predicate used in sanity checks elsewhere - returns true if any
1910 jump-site is an actual chained jump */
1911Bool VG_(is_chained_jumpsite)(Addr a)
1912{
1913 UChar *cp = (UChar *)a;
1914
1915 return (*cp == 0xE9); /* 0xE9 -- jmp */
1916}
1917
sewardj83f11862002-12-01 02:07:08 +00001918static
1919Bool is_fresh_jumpsite(UChar *cp)
1920{
1921 return
1922 cp[0] == 0x0F && /* UD2 */
1923 cp[1] == 0x0B &&
1924 cp[2] == 0x0F && /* UD2 */
1925 cp[3] == 0x0B &&
1926 cp[4] == 0x90; /* NOP */
1927}
1928
sewardj22854b92002-11-30 14:00:47 +00001929/* Predicate used in sanity checks elsewhere - returns true if all
1930 jump-sites are calls to VG_(patch_me) */
1931Bool VG_(is_unchained_jumpsite)(Addr a)
1932{
1933 UChar *cp = (UChar *)a;
1934 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1935 Int idelta;
1936
1937 if (*cp++ != 0xE8) /* 0xE8 == call */
1938 return False;
1939
1940 idelta = (*cp++) << 0;
1941 idelta |= (*cp++) << 8;
1942 idelta |= (*cp++) << 16;
1943 idelta |= (*cp++) << 24;
1944
1945 return idelta == delta;
1946}
1947
1948/* Return target address for a direct jmp */
1949Addr VG_(get_jmp_dest)(Addr a)
1950{
1951 Int delta;
1952 UChar *cp = (UChar *)a;
1953
1954 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1955 return 0;
1956
1957 delta = (*cp++) << 0;
1958 delta |= (*cp++) << 8;
1959 delta |= (*cp++) << 16;
1960 delta |= (*cp++) << 24;
1961
1962 return a + VG_PATCHME_JMPSZ + delta;
1963}
1964
1965/* unchain a BB by generating a call to VG_(patch_me) */
1966void VG_(unchain_jumpsite)(Addr a)
1967{
1968 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1969 UChar *cp = (UChar *)a;
1970
1971 if (VG_(is_unchained_jumpsite)(a))
1972 return; /* don't write unnecessarily */
1973
sewardj83f11862002-12-01 02:07:08 +00001974 if (!is_fresh_jumpsite(cp))
1975 VG_(bb_dechain_count)++; /* update stats */
1976
sewardj22854b92002-11-30 14:00:47 +00001977 *cp++ = 0xE8; /* call */
1978 *cp++ = (delta >> 0) & 0xff;
1979 *cp++ = (delta >> 8) & 0xff;
1980 *cp++ = (delta >> 16) & 0xff;
1981 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001982}
1983
1984/* This doesn't actually generate a call to VG_(patch_me), but
1985 reserves enough space in the instruction stream for it to happen
1986 and records the offset into the jump table. This is because call
1987 is a relative jump, and so will be affected when this code gets
1988 moved about. The translation table will "unchain" this basic block
1989 on insertion (with VG_(unchain_BB)()), and thereby generate a
1990 proper call instruction. */
1991static void emit_call_patchme( void )
1992{
1993 vg_assert(VG_PATCHME_CALLSZ == 5);
1994
sewardjfa492d42002-12-08 18:20:01 +00001995 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00001996 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00001997
1998 if (jumpidx >= VG_MAX_JUMPS) {
1999 /* If there too many jumps in this basic block, fall back to
2000 dispatch loop. We still need to keep it the same size as the
2001 call sequence. */
2002 VG_(emitB) ( 0xC3 ); /* ret */
2003 VG_(emitB) ( 0x90 ); /* nop */
2004 VG_(emitB) ( 0x90 ); /* nop */
2005 VG_(emitB) ( 0x90 ); /* nop */
2006 VG_(emitB) ( 0x90 ); /* nop */
2007
2008 if (dis)
2009 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
2010
2011 if (0 && VG_(clo_verbosity))
2012 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2013 } else {
2014 jumps[jumpidx++] = emitted_code_used;
2015
2016 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2017 VG_(emitB) ( 0x0B );
2018 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2019 VG_(emitB) ( 0x0B );
2020 VG_(emitB) ( 0x90 ); /* NOP */
2021
2022 if (dis)
2023 VG_(printf)("\n\t\tud2; ud2; nop\n");
2024 }
2025}
2026
njn25e49d8e72002-09-23 09:36:25 +00002027void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002028{
sewardjf0f12aa2002-12-28 00:04:08 +00002029 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002030 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002031 if (dis)
2032 VG_(printf)("\n\t\tpushal\n");
2033}
2034
njn25e49d8e72002-09-23 09:36:25 +00002035void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002036{
sewardjf0f12aa2002-12-28 00:04:08 +00002037 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002038 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002039 if (dis)
2040 VG_(printf)("\n\t\tpopal\n");
2041}
2042
2043static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2044{
sewardjf0f12aa2002-12-28 00:04:08 +00002045 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002046 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2047 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002048 if (dis)
2049 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2050 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2051}
2052
2053static void emit_lea_sib_reg ( UInt lit, Int scale,
2054 Int regbase, Int regindex, Int reg )
2055{
sewardjf0f12aa2002-12-28 00:04:08 +00002056 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002057 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002058 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2059 if (dis)
2060 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2061 lit, nameIReg(4,regbase),
2062 nameIReg(4,regindex), scale,
2063 nameIReg(4,reg) );
2064}
2065
njn25e49d8e72002-09-23 09:36:25 +00002066void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002067{
sewardjf0f12aa2002-12-28 00:04:08 +00002068 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002069 VG_(emitB) ( 0x0F );
2070 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002071 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2072 if (dis)
2073 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2074}
2075
2076/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002077/*--- Helper offset -> addr translation ---*/
2078/*----------------------------------------------------*/
2079
2080/* Finds the baseBlock offset of a skin-specified helper.
2081 * Searches through compacts first, then non-compacts. */
2082Int VG_(helper_offset)(Addr a)
2083{
sewardj05bcdcb2003-05-18 10:05:38 +00002084 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002085 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002086
2087 for (i = 0; i < VG_(n_compact_helpers); i++)
2088 if (VG_(compact_helper_addrs)[i] == a)
2089 return VG_(compact_helper_offsets)[i];
2090 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2091 if (VG_(noncompact_helper_addrs)[i] == a)
2092 return VG_(noncompact_helper_offsets)[i];
2093
2094 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002095 VG_(get_fnname) ( a, buf, 100 );
2096
njn25e49d8e72002-09-23 09:36:25 +00002097 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002098 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2099 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002100
2101 VG_(printf)(" compact helpers: ");
2102 for (i = 0; i < VG_(n_compact_helpers); i++)
2103 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2104
2105 VG_(printf)("\n non-compact helpers: ");
2106 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2107 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2108
2109 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002110 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002111}
2112
2113/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002114/*--- Instruction synthesisers ---*/
2115/*----------------------------------------------------*/
2116
2117static Condcode invertCondition ( Condcode cond )
2118{
2119 return (Condcode)(1 ^ (UInt)cond);
2120}
2121
2122
2123/* Synthesise a call to *baseBlock[offset], ie,
2124 call * (4 x offset)(%ebp).
2125*/
sewardjfa492d42002-12-08 18:20:01 +00002126void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002127 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002128{
2129 vg_assert(word_offset >= 0);
2130 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002131 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002132 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002133 }
sewardjf0f12aa2002-12-28 00:04:08 +00002134 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002135}
2136
njn25e49d8e72002-09-23 09:36:25 +00002137static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002138{
njn25e49d8e72002-09-23 09:36:25 +00002139 if (src != dst) {
2140 VG_(emit_movv_reg_reg) ( 4, src, dst );
2141 ccall_arg_setup_instrs++;
2142 }
njn6431be72002-07-28 09:53:34 +00002143}
njn25e49d8e72002-09-23 09:36:25 +00002144
2145/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2146static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2147{
2148 if (RealReg == tag) {
2149 maybe_emit_movl_reg_reg ( litOrReg, reg );
2150 } else if (Literal == tag) {
2151 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2152 ccall_arg_setup_instrs++;
2153 }
2154 else
njne427a662002-10-02 11:08:25 +00002155 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002156}
2157
2158static
2159void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2160{
2161 if (R_EAX == reg1) {
2162 VG_(emit_swapl_reg_EAX) ( reg2 );
2163 } else if (R_EAX == reg2) {
2164 VG_(emit_swapl_reg_EAX) ( reg1 );
2165 } else {
2166 emit_swapl_reg_reg ( reg1, reg2 );
2167 }
2168 ccall_arg_setup_instrs++;
2169}
2170
2171static
2172void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2173{
2174 if (dst1 != src2) {
2175 maybe_emit_movl_reg_reg ( src1, dst1 );
2176 maybe_emit_movl_reg_reg ( src2, dst2 );
2177
2178 } else if (dst2 != src1) {
2179 maybe_emit_movl_reg_reg ( src2, dst2 );
2180 maybe_emit_movl_reg_reg ( src1, dst1 );
2181
2182 } else {
2183 /* swap to break cycle */
2184 emit_swapl_arg_regs ( dst1, dst2 );
2185 }
2186}
2187
2188static
2189void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2190 UInt dst1, UInt dst2, UInt dst3)
2191{
2192 if (dst1 != src2 && dst1 != src3) {
2193 maybe_emit_movl_reg_reg ( src1, dst1 );
2194 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2195
2196 } else if (dst2 != src1 && dst2 != src3) {
2197 maybe_emit_movl_reg_reg ( src2, dst2 );
2198 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2199
2200 } else if (dst3 != src1 && dst3 != src2) {
2201 maybe_emit_movl_reg_reg ( src3, dst3 );
2202 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2203
2204 } else {
2205 /* break cycle */
2206 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2207 emit_swapl_arg_regs ( dst1, dst2 );
2208 emit_swapl_arg_regs ( dst1, dst3 );
2209
2210 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2211 emit_swapl_arg_regs ( dst1, dst3 );
2212 emit_swapl_arg_regs ( dst1, dst2 );
2213
2214 } else {
njne427a662002-10-02 11:08:25 +00002215 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002216 }
2217 }
2218}
2219
2220static
2221void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2222 UInt src1, UInt src2,
2223 UInt dst1, UInt dst2)
2224{
2225 /* If either are lits, order doesn't matter */
2226 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2227 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2228 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2229
2230 } else {
2231 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2232 }
2233}
2234
2235static
2236void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2237 UInt src1, UInt src2, UInt src3,
2238 UInt dst1, UInt dst2, UInt dst3)
2239{
2240 // SSS: fix this eventually -- make STOREV use two RealRegs?
2241 /* Not supporting literals for 3-arg C functions -- they're only used
2242 by STOREV which has 2 args */
2243 vg_assert(RealReg == tagv[src1] &&
2244 RealReg == tagv[src2] &&
2245 RealReg == tagv[src3]);
2246 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2247 dst1, dst2, dst3 );
2248}
2249
2250/* Synthesise a call to a C function `fn' (which must be registered in
2251 baseBlock) doing all the reg saving and arg handling work.
2252
2253 WARNING: a UInstr should *not* be translated with synth_ccall followed
2254 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2255 such behaviour and everything will fall over.
2256 */
2257void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2258 Tag tagv[], Int ret_reg,
2259 RRegSet regs_live_before, RRegSet regs_live_after )
2260{
2261 Int i;
2262 Int stack_used = 0;
2263 Bool preserve_eax, preserve_ecx, preserve_edx;
2264
2265 vg_assert(0 <= regparms_n && regparms_n <= 3);
2266
2267 ccalls++;
2268
2269 /* If %e[acd]x is live before and after the C call, save/restore it.
2270 Unless the return values clobbers the reg; in this case we must not
2271 save/restore the reg, because the restore would clobber the return
2272 value. (Before and after the UInstr really constitute separate live
2273 ranges, but you miss this if you don't consider what happens during
2274 the UInstr.) */
2275# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002276 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2277 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002278 ret_reg != realReg)
2279
2280 preserve_eax = PRESERVE_REG(R_EAX);
2281 preserve_ecx = PRESERVE_REG(R_ECX);
2282 preserve_edx = PRESERVE_REG(R_EDX);
2283
2284# undef PRESERVE_REG
2285
2286 /* Save caller-save regs as required */
2287 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2288 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2289 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2290
2291 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2292 is the number of args passed in regs (maximum 3 for GCC on x86). */
2293
2294 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002295
njn25e49d8e72002-09-23 09:36:25 +00002296 /* First push stack args (RealRegs or Literals) in reverse order. */
2297 for (i = argc-1; i >= regparms_n; i--) {
2298 switch (tagv[i]) {
2299 case RealReg:
2300 VG_(emit_pushv_reg) ( 4, argv[i] );
2301 break;
2302 case Literal:
2303 /* Use short form of pushl if possible. */
2304 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2305 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2306 else
2307 VG_(emit_pushl_lit32)( argv[i] );
2308 break;
2309 default:
2310 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002311 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002312 }
2313 stack_used += 4;
2314 ccall_arg_setup_instrs++;
2315 }
njn6431be72002-07-28 09:53:34 +00002316
njn25e49d8e72002-09-23 09:36:25 +00002317 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2318 If moving values between registers, be careful not to clobber any on
2319 the way. Happily we can use xchgl to swap registers.
2320 */
2321 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002322
njn25e49d8e72002-09-23 09:36:25 +00002323 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2324 case 3:
2325 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2326 R_EAX, R_EDX, R_ECX );
2327 break;
njn6431be72002-07-28 09:53:34 +00002328
njn25e49d8e72002-09-23 09:36:25 +00002329 /* Less-tricky. Args passed in %eax and %edx. */
2330 case 2:
2331 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2332 break;
2333
2334 /* Easy. Just move arg1 into %eax (if not already in there). */
2335 case 1:
2336 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2337 break;
2338
2339 case 0:
2340 break;
2341
2342 default:
njne427a662002-10-02 11:08:25 +00002343 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002344 }
2345
sewardjfa492d42002-12-08 18:20:01 +00002346 /* Call the function - may trash all flags */
2347 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002348
2349 /* Clear any args from stack */
2350 if (0 != stack_used) {
2351 VG_(emit_add_lit_to_esp) ( stack_used );
2352 ccall_stack_clears++;
2353 }
2354
2355 /* Move return value into ret_reg if necessary and not already there */
2356 if (INVALID_REALREG != ret_reg) {
2357 ccall_retvals++;
2358 if (R_EAX != ret_reg) {
2359 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2360 ccall_retval_movs++;
2361 }
2362 }
2363
2364 /* Restore live caller-save regs as required */
2365 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2366 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2367 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002368}
sewardjde4a1d02002-03-22 01:27:54 +00002369
sewardj2e93c502002-04-12 11:12:52 +00002370static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002371{
sewardj2e93c502002-04-12 11:12:52 +00002372 switch (jmpkind) {
2373 case JmpBoring:
2374 break;
sewardj2e93c502002-04-12 11:12:52 +00002375 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002376 break;
2377 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002378 break;
2379 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002380 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002381 break;
2382 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002383 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002384 break;
2385 default:
njne427a662002-10-02 11:08:25 +00002386 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002387 }
2388}
2389
2390/* Jump to the next translation, by loading its original addr into
2391 %eax and returning to the scheduler. Signal special requirements
2392 by loading a special value into %ebp first.
2393*/
2394static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2395{
sewardjfa492d42002-12-08 18:20:01 +00002396 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002397 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002398 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002399 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002400 emit_ret();
2401}
2402
sewardj22854b92002-11-30 14:00:47 +00002403static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002404
2405/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002406static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002407{
sewardjfa492d42002-12-08 18:20:01 +00002408 maybe_emit_put_eflags(); /* save flags here */
2409
njn25e49d8e72002-09-23 09:36:25 +00002410 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002411
2412 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2413 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2414 emit_call_patchme();
2415 } else {
2416 load_ebp_from_JmpKind ( jmpkind );
2417 emit_ret();
2418 }
sewardjde4a1d02002-03-22 01:27:54 +00002419}
2420
2421
sewardj2370f3b2002-11-30 15:01:01 +00002422static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002423static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002424 Opcode opcode, Int size,
2425 UInt lit, Int reg );
2426
sewardjfa492d42002-12-08 18:20:01 +00002427static void synth_jcond_lit ( Condcode cond,
2428 Addr addr,
2429 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002430{
sewardj2370f3b2002-11-30 15:01:01 +00002431 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002432 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002433 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002434
sewardja2113f92002-12-12 23:42:48 +00002435 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002436 VG_(init_target)(&tgt2);
2437 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002438
sewardjfa492d42002-12-08 18:20:01 +00002439 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2440 if need be */
2441 maybe_emit_put_eflags();
2442 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2443
2444 if (eflags_state == UPD_Both) {
2445 /* The flags are already set up, so we just use them as is. */
2446 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002447 cond = invertCondition(cond);
2448 } else {
sewardj75f04932002-12-12 23:13:21 +00002449 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002450
2451 /* The simd state contains the most recent version, so we emit a
2452 sequence to calculate the relevant condition directly out of
2453 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2454 copying them back to the real flags via popf. Notice that
2455 some of these sequences trash %eax, but that should be free
2456 now since this is the end of a bb and therefore all regs are
2457 dead. */
2458 simd = False;
2459
2460 switch (cond) {
2461
sewardjbb6c1182002-12-12 23:54:47 +00002462 case CondLE: /* Z || S != O -> S || !P */
2463 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002464 vg_assert(eax_trashable);
2465
2466 VG_(emit_movv_offregmem_reg)
2467 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2468 /* eax == %EFLAGS */
2469
sewardjbb6c1182002-12-12 23:54:47 +00002470 VG_(emit_nonshiftopv_lit_reg)
2471 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2472 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002473
sewardjbb6c1182002-12-12 23:54:47 +00002474 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2475 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002476
sewardj09736622002-12-28 00:19:00 +00002477 /* actually set the real cpu flags, since ROR changes
2478 neither P nor Z */
2479 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2480
sewardjbb6c1182002-12-12 23:54:47 +00002481 if (cond == CondLE) {
2482 /* test Z */
2483 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2484 /* test OF != SF */
2485 cond = CondP;
2486 } else {
2487 /* test Z */
2488 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2489 /* test OF == SF */
2490 cond = CondNP;
2491 }
sewardj2370f3b2002-11-30 15:01:01 +00002492 break;
2493
sewardjfa492d42002-12-08 18:20:01 +00002494 case CondL:
2495 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002496 vg_assert(eax_trashable);
2497
2498 VG_(emit_movv_offregmem_reg)
2499 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2500 /* eax == %EFLAGS */
2501
sewardj75f04932002-12-12 23:13:21 +00002502 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2503 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002504
sewardj75f04932002-12-12 23:13:21 +00002505 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2506 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002507
sewardj09736622002-12-28 00:19:00 +00002508 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002509 if (cond == CondL) cond = CondP; else cond = CondNP;
2510 break;
sewardjfa492d42002-12-08 18:20:01 +00002511
2512 case CondB:
2513 case CondNB:
2514 mask = EFlagC; goto simple; /* C=1 */
2515
2516 case CondZ:
2517 case CondNZ:
2518 mask = EFlagZ; goto simple; /* Z=1 */
2519
2520 case CondBE:
2521 case CondNBE:
2522 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2523
2524 case CondS:
2525 case CondNS:
2526 mask = EFlagS; goto simple; /* S=1 */
2527
2528 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002529 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002530 mask = EFlagP; goto simple; /* P=1 */
2531
sewardj39542072002-12-09 22:44:00 +00002532 case CondO:
2533 case CondNO:
2534 mask = EFlagO; goto simple; /* O=1 */
2535
sewardjfa492d42002-12-08 18:20:01 +00002536 default:
2537 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002538 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002539 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2540
2541 simple:
2542 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002543 if ((mask & 0xff) == mask) {
2544 VG_(emitB) ( 0xF6 ); /* Grp3 */
2545 VG_(emit_amode_offregmem_reg)(
2546 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2547 VG_(emitB) (mask);
2548 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002549 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002550 mask, VGOFF_(m_eflags) * 4);
2551 } else {
sewardjfa492d42002-12-08 18:20:01 +00002552 /* all cond codes are in lower 16 bits */
2553 vg_assert((mask & 0xffff) == mask);
2554
2555 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002556 VG_(emitB) ( 0xF7 );
2557 VG_(emit_amode_offregmem_reg)(
2558 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002559 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002560 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002561 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002562 mask, VGOFF_(m_eflags) * 4);
2563 }
2564
sewardj75f04932002-12-12 23:13:21 +00002565 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002566 break;
2567 }
2568 }
2569
sewardja2113f92002-12-12 23:42:48 +00002570 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002571
2572 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002573 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002574
2575 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002576 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002577}
2578
2579
sewardj2370f3b2002-11-30 15:01:01 +00002580
sewardjde4a1d02002-03-22 01:27:54 +00002581static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2582{
sewardja2113f92002-12-12 23:42:48 +00002583 Int tgt;
2584
2585 VG_(init_target)(&tgt);
2586
sewardjfa492d42002-12-08 18:20:01 +00002587 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002588
2589 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002590 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002591
2592 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002593}
2594
2595
2596static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2597{
2598 /* Load the zero-extended literal into reg, at size l,
2599 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002600 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002601}
2602
2603
2604static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2605{
2606 switch (size) {
2607 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2608 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2609 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002610 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002611 }
2612}
2613
2614
2615static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2616{
2617 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002618 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2619 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2620 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002621 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002622 }
2623}
2624
2625
2626static void synth_mov_reg_offregmem ( Int size, Int reg,
2627 Int off, Int areg )
2628{
2629 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002630 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2631 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002632 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002633 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002634 }
2635 else {
njn25e49d8e72002-09-23 09:36:25 +00002636 VG_(emit_swapl_reg_EAX) ( reg );
2637 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2638 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002639 }
2640 break;
njne427a662002-10-02 11:08:25 +00002641 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002642 }
2643}
2644
2645
2646static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2647{
2648 Int s1;
2649 switch (size) {
2650 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2651 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2652 case 1: if (reg1 < 4) {
2653 emit_movb_reg_regmem ( reg1, reg2 );
2654 }
2655 else {
2656 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2657 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2658 emit_swapl_reg_reg ( s1, reg1 );
2659 emit_movb_reg_regmem ( s1, reg2 );
2660 emit_swapl_reg_reg ( s1, reg1 );
2661 }
2662 break;
njne427a662002-10-02 11:08:25 +00002663 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002664 }
2665}
2666
2667
sewardjf0f12aa2002-12-28 00:04:08 +00002668static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002669 Opcode opcode, Int size,
2670 Int reg )
2671{
2672 /* NB! opcode is a uinstr opcode, not an x86 one! */
2673 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002674 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002675 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002676 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002677 break;
2678 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002679 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002680 } else {
njn25e49d8e72002-09-23 09:36:25 +00002681 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002682 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002683 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002684 }
2685 break;
njne427a662002-10-02 11:08:25 +00002686 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002687 }
2688}
2689
2690
2691
sewardjf0f12aa2002-12-28 00:04:08 +00002692static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002693 Opcode opcode, Int size,
2694 Int reg1, Int reg2 )
2695{
2696 /* NB! opcode is a uinstr opcode, not an x86 one! */
2697 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002698 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002699 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002700 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002701 break;
2702 case 1: { /* Horrible ... */
2703 Int s1, s2;
2704 /* Choose s1 and s2 to be x86 regs which we can talk about the
2705 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2706 sure s1 != s2 and that neither of them equal either reg1 or
2707 reg2. Then use them as temporaries to make things work. */
2708 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002709 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002710 break;
2711 }
2712 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2713 if (reg1 >= 4 && reg2 < 4) {
2714 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002715 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002716 emit_swapl_reg_reg ( reg1, s1 );
2717 break;
2718 }
2719 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2720 if (reg1 < 4 && reg2 >= 4) {
2721 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002722 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002723 emit_swapl_reg_reg ( reg2, s2 );
2724 break;
2725 }
2726 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2727 emit_swapl_reg_reg ( reg1, s1 );
2728 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002729 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002730 emit_swapl_reg_reg ( reg1, s1 );
2731 emit_swapl_reg_reg ( reg2, s2 );
2732 break;
2733 }
2734 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2735 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002736 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002737 emit_swapl_reg_reg ( reg1, s1 );
2738 break;
2739 }
njne427a662002-10-02 11:08:25 +00002740 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002741 }
njne427a662002-10-02 11:08:25 +00002742 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002743 }
2744}
2745
sewardja2c5a732002-12-15 03:10:42 +00002746#if 0
2747/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002748static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002749 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002750 Opcode opcode, Int size,
2751 Int off, Int areg, Int reg )
2752{
2753 switch (size) {
2754 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002755 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002756 break;
2757 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002758 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002759 break;
2760 case 1:
2761 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002762 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002763 } else {
2764 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002765 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002766 VG_(emit_swapl_reg_EAX) ( reg );
2767 }
2768 break;
2769 default:
2770 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2771 }
2772}
sewardja2c5a732002-12-15 03:10:42 +00002773#endif
sewardjfa492d42002-12-08 18:20:01 +00002774
sewardjde4a1d02002-03-22 01:27:54 +00002775static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002776 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002777 Opcode opcode, Int size,
2778 Int off, Int areg, Int reg )
2779{
2780 switch (size) {
2781 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002782 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002783 break;
2784 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002785 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002786 break;
2787 case 1:
2788 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002789 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002790 } else {
njn25e49d8e72002-09-23 09:36:25 +00002791 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002792 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002793 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002794 }
2795 break;
2796 default:
njne427a662002-10-02 11:08:25 +00002797 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002798 }
2799}
2800
2801
sewardjf0f12aa2002-12-28 00:04:08 +00002802static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002803 Opcode opcode, Int size,
2804 UInt lit, Int reg )
2805{
2806 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002807 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002808 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002809 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002810 break;
2811 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002812 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002813 } else {
njn25e49d8e72002-09-23 09:36:25 +00002814 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002815 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002816 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002817 }
2818 break;
njne427a662002-10-02 11:08:25 +00002819 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002820 }
2821}
2822
sewardjf0f12aa2002-12-28 00:04:08 +00002823static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002824 Opcode opcode, Int size,
2825 UInt lit, Int off, Int regmem )
2826{
2827 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002828 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002829 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002830 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002831 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002832 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002833 break;
2834 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2835 }
2836}
2837
sewardjde4a1d02002-03-22 01:27:54 +00002838
2839static void synth_push_reg ( Int size, Int reg )
2840{
2841 switch (size) {
2842 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002843 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002844 break;
2845 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002846 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002847 break;
2848 /* Pray that we don't have to generate this really cruddy bit of
2849 code very often. Could do better, but can I be bothered? */
2850 case 1:
2851 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002852 VG_(emit_add_lit_to_esp)(-1);
2853 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002854 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002855 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002856 break;
2857 default:
njne427a662002-10-02 11:08:25 +00002858 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002859 }
2860}
2861
2862
2863static void synth_pop_reg ( Int size, Int reg )
2864{
2865 switch (size) {
2866 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002867 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002868 break;
2869 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002870 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002871 break;
2872 case 1:
2873 /* Same comment as above applies. */
2874 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002875 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002876 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002877 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2878 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002879 break;
njne427a662002-10-02 11:08:25 +00002880 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002881 }
2882}
2883
2884
sewardjf0f12aa2002-12-28 00:04:08 +00002885static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002886 Opcode opcode, Int size,
2887 Int regs, Int regd )
2888{
2889 synth_push_reg ( size, regd );
2890 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002891 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002892 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2893 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2894 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002895 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002896 }
sewardjde4a1d02002-03-22 01:27:54 +00002897 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2898 synth_pop_reg ( size, regd );
2899}
2900
2901
sewardjf0f12aa2002-12-28 00:04:08 +00002902static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002903 Opcode opcode, Int size,
2904 UInt lit, Int reg )
2905{
2906 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002907 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002908 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002909 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002910 break;
2911 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002912 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002913 } else {
njn25e49d8e72002-09-23 09:36:25 +00002914 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002915 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002916 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002917 }
2918 break;
njne427a662002-10-02 11:08:25 +00002919 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002920 }
2921}
2922
2923
sewardjf0f12aa2002-12-28 00:04:08 +00002924static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002925{
sewardjde4a1d02002-03-22 01:27:54 +00002926 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002927 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002928 } else {
njn25e49d8e72002-09-23 09:36:25 +00002929 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002930 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002931 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002932 }
2933}
2934
2935
sewardj3d7c9c82003-03-26 21:08:13 +00002936static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2937 UChar first_byte,
2938 UChar second_byte,
2939 Int ireg )
2940{
2941 emit_MMX2_regmem ( uses_flags, sets_flags,
2942 first_byte, second_byte, ireg );
2943}
2944
2945
sewardjca860012003-03-27 23:52:58 +00002946static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2947 UChar first_byte,
2948 UChar second_byte,
2949 Int ireg )
2950{
2951 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2952 first_byte, second_byte, ireg );
2953}
2954
sewardjd1c9e432003-04-04 20:40:34 +00002955static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2956 UChar first_byte,
2957 UChar second_byte,
2958 Int ireg )
2959{
2960 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2961 first_byte, second_byte, ireg );
2962}
2963
sewardj3d7c9c82003-03-26 21:08:13 +00002964static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2965 UChar first_byte,
2966 UChar second_byte )
2967{
2968 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2969}
2970
2971
sewardjca860012003-03-27 23:52:58 +00002972static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2973 UChar first_byte,
2974 UChar second_byte,
2975 UChar third_byte )
2976{
2977 emit_MMX3_no_mem ( uses_flags, sets_flags,
2978 first_byte, second_byte, third_byte );
2979}
2980
2981
sewardj3d7c9c82003-03-26 21:08:13 +00002982static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
2983 UChar first_byte )
2984{
2985 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
2986}
2987
2988
sewardjfa492d42002-12-08 18:20:01 +00002989static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
2990 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00002991 UChar second_byte_masked,
2992 Int reg )
2993{
sewardj3d7c9c82003-03-26 21:08:13 +00002994 emit_fpu_regmem ( uses_flags, sets_flags,
2995 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002996}
2997
2998
sewardjfa492d42002-12-08 18:20:01 +00002999static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3000 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003001 UChar second_byte )
3002{
sewardjfa492d42002-12-08 18:20:01 +00003003 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003004}
3005
3006
3007static void synth_movl_reg_reg ( Int src, Int dst )
3008{
3009 emit_movl_reg_reg ( src, dst );
3010}
3011
3012static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3013{
sewardja2113f92002-12-12 23:42:48 +00003014 Int tgt;
3015
3016 VG_(init_target)(&tgt);
3017
3018 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003019 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003020
3021 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003022}
3023
3024
sewardjde4a1d02002-03-22 01:27:54 +00003025/*----------------------------------------------------*/
3026/*--- Top level of the uinstr -> x86 translation. ---*/
3027/*----------------------------------------------------*/
3028
3029/* Return the byte offset from %ebp (ie, into baseBlock)
3030 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003031static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3032{
3033 if (tag == SpillNo) {
3034 vg_assert(size == 4);
3035 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3036 return 4 * (value + VGOFF_(spillslots));
3037 }
3038 if (tag == ArchReg) {
3039 switch (value) {
3040 case R_EAX: return 4 * VGOFF_(m_eax);
3041 case R_ECX: return 4 * VGOFF_(m_ecx);
3042 case R_EDX: return 4 * VGOFF_(m_edx);
3043 case R_EBX: return 4 * VGOFF_(m_ebx);
3044 case R_ESP:
3045 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3046 else return 4 * VGOFF_(m_esp);
3047 case R_EBP:
3048 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3049 else return 4 * VGOFF_(m_ebp);
3050 case R_ESI:
3051 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3052 else return 4 * VGOFF_(m_esi);
3053 case R_EDI:
3054 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3055 else return 4 * VGOFF_(m_edi);
3056 }
3057 }
njne427a662002-10-02 11:08:25 +00003058 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003059}
3060
sewardjde4a1d02002-03-22 01:27:54 +00003061static Int eflagsOffset ( void )
3062{
3063 return 4 * VGOFF_(m_eflags);
3064}
3065
sewardje1042472002-09-30 12:33:11 +00003066static Int segRegOffset ( UInt archregs )
3067{
3068 switch (archregs) {
3069 case R_CS: return 4 * VGOFF_(m_cs);
3070 case R_SS: return 4 * VGOFF_(m_ss);
3071 case R_DS: return 4 * VGOFF_(m_ds);
3072 case R_ES: return 4 * VGOFF_(m_es);
3073 case R_FS: return 4 * VGOFF_(m_fs);
3074 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003075 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003076 }
3077}
3078
njnf4ce3d32003-02-10 10:17:26 +00003079UInt VG_(get_archreg) ( UInt arch )
3080{
3081 switch (arch) {
3082 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3083 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3084 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3085 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3086 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3087 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3088 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3089 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
3090 default: VG_(core_panic)( "get_thread_archreg");
3091 }
3092}
3093
3094UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3095{
3096 ThreadState* tst;
3097
3098 vg_assert(VG_(is_valid_tid)(tid));
3099 tst = & VG_(threads)[tid];
3100
3101 switch (arch) {
3102 case R_EAX: return tst->m_eax;
3103 case R_ECX: return tst->m_ecx;
3104 case R_EDX: return tst->m_edx;
3105 case R_EBX: return tst->m_ebx;
3106 case R_ESP: return tst->m_esp;
3107 case R_EBP: return tst->m_ebp;
3108 case R_ESI: return tst->m_esi;
3109 case R_EDI: return tst->m_edi;
3110 default: VG_(core_panic)( "get_thread_archreg");
3111 }
3112}
3113
njnb93d1782003-02-03 12:03:22 +00003114/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003115static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003116{
3117 switch (arch) {
3118 case R_EAX: return VGOFF_(sh_eax);
3119 case R_ECX: return VGOFF_(sh_ecx);
3120 case R_EDX: return VGOFF_(sh_edx);
3121 case R_EBX: return VGOFF_(sh_ebx);
3122 case R_ESP: return VGOFF_(sh_esp);
3123 case R_EBP: return VGOFF_(sh_ebp);
3124 case R_ESI: return VGOFF_(sh_esi);
3125 case R_EDI: return VGOFF_(sh_edi);
3126 default: VG_(core_panic)( "shadow_reg_index");
3127 }
3128}
sewardjde4a1d02002-03-22 01:27:54 +00003129
njn25e49d8e72002-09-23 09:36:25 +00003130/* Return the byte offset from %ebp (ie, into baseBlock)
3131 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003132Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003133{
njnb93d1782003-02-03 12:03:22 +00003134 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003135}
3136
njn4ba5a792002-09-30 10:23:54 +00003137Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003138{
3139 return 4 * VGOFF_(sh_eflags);
3140}
3141
njnb93d1782003-02-03 12:03:22 +00003142/* Accessing shadow arch. registers */
3143UInt VG_(get_shadow_archreg) ( UInt archreg )
3144{
3145 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3146}
3147
3148void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3149{
3150 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3151}
3152
njnd3040452003-05-19 15:04:06 +00003153void VG_(set_shadow_eflags) ( UInt val )
3154{
3155 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3156}
3157
njnf4ce3d32003-02-10 10:17:26 +00003158UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3159{
3160 ThreadState* tst;
3161
3162 vg_assert(VG_(is_valid_tid)(tid));
3163 tst = & VG_(threads)[tid];
3164
3165 switch (archreg) {
3166 case R_EAX: return tst->sh_eax;
3167 case R_ECX: return tst->sh_ecx;
3168 case R_EDX: return tst->sh_edx;
3169 case R_EBX: return tst->sh_ebx;
3170 case R_ESP: return tst->sh_esp;
3171 case R_EBP: return tst->sh_ebp;
3172 case R_ESI: return tst->sh_esi;
3173 case R_EDI: return tst->sh_edi;
3174 default: VG_(core_panic)( "get_thread_shadow_archreg");
3175 }
3176}
3177
3178void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3179{
3180 ThreadState* tst;
3181
3182 vg_assert(VG_(is_valid_tid)(tid));
3183 tst = & VG_(threads)[tid];
3184
3185 switch (archreg) {
3186 case R_EAX: tst->sh_eax = val; break;
3187 case R_ECX: tst->sh_ecx = val; break;
3188 case R_EDX: tst->sh_edx = val; break;
3189 case R_EBX: tst->sh_ebx = val; break;
3190 case R_ESP: tst->sh_esp = val; break;
3191 case R_EBP: tst->sh_ebp = val; break;
3192 case R_ESI: tst->sh_esi = val; break;
3193 case R_EDI: tst->sh_edi = val; break;
3194 default: VG_(core_panic)( "set_thread_shadow_archreg");
3195 }
3196}
3197
njnb93d1782003-02-03 12:03:22 +00003198Addr VG_(shadow_archreg_address) ( UInt archreg )
3199{
3200 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3201}
sewardjde4a1d02002-03-22 01:27:54 +00003202
sewardjde4a1d02002-03-22 01:27:54 +00003203static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3204{
3205 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003206 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3207 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003208 }
3209 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003210 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3211 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003212 }
3213 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003214 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3215 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003216 }
3217 else
njne427a662002-10-02 11:08:25 +00003218 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003219}
3220
3221
sewardjde4a1d02002-03-22 01:27:54 +00003222/*----------------------------------------------------*/
3223/*--- Generate code for a single UInstr. ---*/
3224/*----------------------------------------------------*/
3225
sewardj478335c2002-10-05 02:44:47 +00003226static __inline__
3227Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003228{
3229 return (u->flags_w != FlagsEmpty);
3230}
3231
sewardjfa492d42002-12-08 18:20:01 +00003232static __inline__
3233Bool readFlagUse ( UInstr* u )
3234{
3235 /* If the UInstr writes some flags but not all, then we still need
3236 to consider it as reading flags so that the unchanged values are
3237 passed through properly. (D is special) */
3238 return
3239 (u->flags_r != FlagsEmpty) ||
3240 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3241}
3242
sewardj478335c2002-10-05 02:44:47 +00003243static __inline__
3244Bool anyFlagUse ( UInstr* u )
3245{
sewardjfa492d42002-12-08 18:20:01 +00003246 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003247}
3248
3249
sewardjb91ae7f2003-04-29 23:50:00 +00003250/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3251 the real machine's cpu. If so we need to be very careful not to trash it.
3252 If FPU/SSE state is live and we deem it necessary to copy it back to
3253 the simulated machine's FPU/SSE state, we do so. The final state of
3254 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003255 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003256 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003257*/
sewardjb5ff83e2002-12-01 19:40:49 +00003258static void emitUInstr ( UCodeBlock* cb, Int i,
3259 RRegSet regs_live_before,
3260 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003261 Bool* sselive, /* True<==>FPU/SSE
3262 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003263 Addr* orig_eip, /* previous curr_eip, or zero */
3264 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003265{
njn25e49d8e72002-09-23 09:36:25 +00003266 Int old_emitted_code_used;
3267 UInstr* u = &cb->instrs[i];
3268
sewardjde4a1d02002-03-22 01:27:54 +00003269 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003270 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003271
njn25e49d8e72002-09-23 09:36:25 +00003272 old_emitted_code_used = emitted_code_used;
3273
sewardjde4a1d02002-03-22 01:27:54 +00003274 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003275 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003276
sewardjb5ff83e2002-12-01 19:40:49 +00003277 case INCEIP:
3278 /* Advance %EIP some small amount. */
3279 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003280
sewardjb5ff83e2002-12-01 19:40:49 +00003281 if (*orig_eip == 0 /* we don't know what the old value was */
3282 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3283 /* We have to update all 32 bits of the value. */
3284 VG_(emit_movv_lit_offregmem)(
3285 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3286 } else {
3287 /* Cool! we only need to update lowest 8 bits */
3288 VG_(emit_movb_lit_offregmem)(
3289 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003290 }
njn25e49d8e72002-09-23 09:36:25 +00003291
sewardjb5ff83e2002-12-01 19:40:49 +00003292 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003293 break;
sewardjde4a1d02002-03-22 01:27:54 +00003294
3295 case LEA1: {
3296 vg_assert(u->tag1 == RealReg);
3297 vg_assert(u->tag2 == RealReg);
3298 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3299 break;
3300 }
3301
3302 case LEA2: {
3303 vg_assert(u->tag1 == RealReg);
3304 vg_assert(u->tag2 == RealReg);
3305 vg_assert(u->tag3 == RealReg);
3306 emit_lea_sib_reg ( u->lit32, u->extra4b,
3307 u->val1, u->val2, u->val3 );
3308 break;
3309 }
3310
3311 case WIDEN: {
3312 vg_assert(u->tag1 == RealReg);
3313 if (u->signed_widen) {
3314 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3315 } else {
3316 /* no need to generate any code. */
3317 }
3318 break;
3319 }
3320
sewardjde4a1d02002-03-22 01:27:54 +00003321 case STORE: {
3322 vg_assert(u->tag1 == RealReg);
3323 vg_assert(u->tag2 == RealReg);
3324 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003325 break;
3326 }
3327
3328 case LOAD: {
3329 vg_assert(u->tag1 == RealReg);
3330 vg_assert(u->tag2 == RealReg);
3331 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3332 break;
3333 }
3334
sewardjde4a1d02002-03-22 01:27:54 +00003335 case GET: {
3336 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3337 vg_assert(u->tag2 == RealReg);
3338 synth_mov_offregmem_reg (
3339 u->size,
3340 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3341 R_EBP,
3342 u->val2
3343 );
3344 break;
3345 }
3346
3347 case PUT: {
3348 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3349 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003350 synth_mov_reg_offregmem (
3351 u->size,
3352 u->val1,
3353 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3354 R_EBP
3355 );
sewardjde4a1d02002-03-22 01:27:54 +00003356 break;
3357 }
3358
sewardje1042472002-09-30 12:33:11 +00003359 case GETSEG: {
3360 vg_assert(u->tag1 == ArchRegS);
3361 vg_assert(u->tag2 == RealReg);
3362 vg_assert(u->size == 2);
3363 synth_mov_offregmem_reg (
3364 4,
3365 segRegOffset( u->val1 ),
3366 R_EBP,
3367 u->val2
3368 );
3369 break;
3370 }
3371
3372 case PUTSEG: {
3373 vg_assert(u->tag1 == RealReg);
3374 vg_assert(u->tag2 == ArchRegS);
3375 vg_assert(u->size == 2);
3376 synth_mov_reg_offregmem (
3377 4,
3378 u->val1,
3379 segRegOffset( u->val2 ),
3380 R_EBP
3381 );
3382 break;
3383 }
3384
sewardjde4a1d02002-03-22 01:27:54 +00003385 case GETF: {
3386 vg_assert(u->size == 2 || u->size == 4);
3387 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003388
3389 /* This complexity is because the D(irection) flag is stored
3390 separately from the rest of EFLAGS. */
3391
3392 /* We're only fetching from the Simd state, so make sure it's
3393 up to date. */
3394 maybe_emit_put_eflags();
3395
3396 /* get D in u->val1 (== 1 or -1) */
3397 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3398
3399 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3400 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3401
3402 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3403 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3404 eflagsOffset(), R_EBP);
3405
3406 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3407 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3408 eflagsOffset(), R_EBP);
3409
3410 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3411 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3412 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003413 break;
3414 }
3415
3416 case PUTF: {
3417 vg_assert(u->size == 2 || u->size == 4);
3418 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003419
3420 /* When putting a value into EFLAGS, this generates the
3421 correct value for m_dflag (-1 or 1), and clears the D bit
3422 in EFLAGS. */
3423
3424 /* We're updating the whole flag state, so the old state
3425 doesn't matter; make sure that the new simulated state
3426 will be fetched when needed. */
3427 eflags_state = UPD_Simd;
3428
3429 /* store EFLAGS (with D) */
3430 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3431
3432 /* u->val1 &= EFlagD */
3433 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3434
3435 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3436 synth_unaryop_reg(False, NEG, u->size, u->val1);
3437 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3438 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3439
3440 /* save D */
3441 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3442
3443 /* EFLAGS &= ~EFlagD */
3444 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3445 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003446 break;
3447 }
3448
3449 case MOV: {
3450 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3451 vg_assert(u->tag2 == RealReg);
3452 switch (u->tag1) {
3453 case RealReg: vg_assert(u->size == 4);
3454 if (u->val1 != u->val2)
3455 synth_movl_reg_reg ( u->val1, u->val2 );
3456 break;
3457 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3458 break;
njne427a662002-10-02 11:08:25 +00003459 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003460 }
3461 break;
3462 }
3463
sewardje1042472002-09-30 12:33:11 +00003464 case USESEG: {
3465 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3466 ones. */
sewardjd077f532002-09-30 21:52:50 +00003467 UInt argv[] = { u->val1, u->val2 };
3468 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003469 UInt ret_reg = u->val2;
3470
3471 vg_assert(u->tag1 == RealReg);
3472 vg_assert(u->tag2 == RealReg);
3473 vg_assert(u->size == 0);
3474
sewardjb91ae7f2003-04-29 23:50:00 +00003475 if (*sselive) {
3476 emit_put_sse_state();
3477 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003478 }
3479
sewardje1042472002-09-30 12:33:11 +00003480 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3481 2, /* args */
3482 0, /* regparms_n */
3483 argv, tagv,
3484 ret_reg, regs_live_before, u->regs_live_after );
3485 break;
3486 }
3487
sewardj478335c2002-10-05 02:44:47 +00003488 case SBB:
3489 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003490 case XOR:
3491 case OR:
3492 case AND:
3493 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003494 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003495 vg_assert(u->tag2 == RealReg);
3496 switch (u->tag1) {
3497 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003498 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003499 u->opcode, u->size, u->lit32, u->val2 );
3500 break;
3501 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003502 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003503 u->opcode, u->size, u->val1, u->val2 );
3504 break;
3505 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003506 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003507 u->opcode, u->size,
3508 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3509 R_EBP,
3510 u->val2 );
3511 break;
njne427a662002-10-02 11:08:25 +00003512 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003513 }
3514 break;
3515 }
3516
sewardj478335c2002-10-05 02:44:47 +00003517 case RCR:
3518 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003519 case ROR:
3520 case ROL:
3521 case SAR:
3522 case SHR:
3523 case SHL: {
3524 vg_assert(u->tag2 == RealReg);
3525 switch (u->tag1) {
3526 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003527 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003528 u->opcode, u->size, u->lit32, u->val2 );
3529 break;
3530 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003531 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003532 u->opcode, u->size, u->val1, u->val2 );
3533 break;
njne427a662002-10-02 11:08:25 +00003534 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003535 }
3536 break;
3537 }
3538
3539 case INC:
3540 case DEC:
3541 case NEG:
3542 case NOT:
3543 vg_assert(u->tag1 == RealReg);
3544 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003545 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003546 break;
3547
3548 case BSWAP:
3549 vg_assert(u->tag1 == RealReg);
3550 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003551 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003552 emit_bswapl_reg ( u->val1 );
3553 break;
3554
3555 case CMOV:
3556 vg_assert(u->tag1 == RealReg);
3557 vg_assert(u->tag2 == RealReg);
3558 vg_assert(u->cond != CondAlways);
3559 vg_assert(u->size == 4);
3560 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3561 break;
3562
3563 case JMP: {
3564 vg_assert(u->tag2 == NoValue);
3565 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003566 if (*sselive) {
3567 emit_put_sse_state();
3568 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003569 }
sewardjde4a1d02002-03-22 01:27:54 +00003570 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003571 switch (u->tag1) {
3572 case RealReg:
3573 synth_jmp_reg ( u->val1, u->jmpkind );
3574 break;
3575 case Literal:
3576 synth_jmp_lit ( u->lit32, u->jmpkind );
3577 break;
3578 default:
njne427a662002-10-02 11:08:25 +00003579 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003580 break;
sewardjde4a1d02002-03-22 01:27:54 +00003581 }
3582 } else {
sewardj2e93c502002-04-12 11:12:52 +00003583 switch (u->tag1) {
3584 case RealReg:
njne427a662002-10-02 11:08:25 +00003585 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003586 break;
3587 case Literal:
3588 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003589 /* %eax had better not be live since synth_jcond_lit
3590 trashes it in some circumstances. If that turns
3591 out to be a problem we can get synth_jcond_lit to
3592 push/pop it when it is live. */
3593 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3594 u->regs_live_after));
3595 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003596 break;
3597 default:
njne427a662002-10-02 11:08:25 +00003598 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003599 break;
sewardjde4a1d02002-03-22 01:27:54 +00003600 }
3601 }
3602 break;
3603 }
3604
3605 case JIFZ:
3606 vg_assert(u->tag1 == RealReg);
3607 vg_assert(u->tag2 == Literal);
3608 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003609 if (*sselive) {
3610 emit_put_sse_state();
3611 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003612 }
sewardjde4a1d02002-03-22 01:27:54 +00003613 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3614 break;
3615
sewardjde4a1d02002-03-22 01:27:54 +00003616 case PUSH:
3617 vg_assert(u->tag1 == RealReg);
3618 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003619 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003620 break;
3621
3622 case POP:
3623 vg_assert(u->tag1 == RealReg);
3624 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003625 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003626 break;
3627
3628 case CALLM:
3629 vg_assert(u->tag1 == Lit16);
3630 vg_assert(u->tag2 == NoValue);
3631 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003632 if (*sselive) {
3633 emit_put_sse_state();
3634 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003635 }
sewardjfa492d42002-12-08 18:20:01 +00003636 /* Call to a helper which is pretending to be a real CPU
3637 instruction (and therefore operates on Real flags and
3638 registers) */
3639 VG_(synth_call) ( False, u->val1,
3640 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003641 break;
3642
njn25e49d8e72002-09-23 09:36:25 +00003643 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003644 /* If you change this, remember to change USESEG above, since
3645 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003646 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3647 ones. */
3648 UInt argv[] = { u->val1, u->val2, u->val3 };
3649 UInt tagv[] = { RealReg, RealReg, RealReg };
3650 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3651
3652 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3653 else vg_assert(u->tag1 == NoValue);
3654 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3655 else vg_assert(u->tag2 == NoValue);
3656 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3657 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003658 vg_assert(u->size == 0);
3659
sewardjb91ae7f2003-04-29 23:50:00 +00003660 if (*sselive) {
3661 emit_put_sse_state();
3662 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003663 }
njn25e49d8e72002-09-23 09:36:25 +00003664 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3665 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003666 break;
njn25e49d8e72002-09-23 09:36:25 +00003667 }
sewardje1042472002-09-30 12:33:11 +00003668
sewardjde4a1d02002-03-22 01:27:54 +00003669 case CLEAR:
3670 vg_assert(u->tag1 == Lit16);
3671 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003672 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003673 break;
3674
3675 case CC2VAL:
3676 vg_assert(u->tag1 == RealReg);
3677 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003678 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003679 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003680 break;
3681
sewardjde4a1d02002-03-22 01:27:54 +00003682 case FPU_R:
3683 case FPU_W:
3684 vg_assert(u->tag1 == Lit16);
3685 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003686 if (!(*sselive)) {
3687 emit_get_sse_state();
3688 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003689 }
sewardjfa492d42002-12-08 18:20:01 +00003690 synth_fpu_regmem ( u->flags_r, u->flags_w,
3691 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003692 u->val1 & 0xFF,
3693 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003694 break;
3695
3696 case FPU:
3697 vg_assert(u->tag1 == Lit16);
3698 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003699 if (!(*sselive)) {
3700 emit_get_sse_state();
3701 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003702 }
sewardjfa492d42002-12-08 18:20:01 +00003703 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3704 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003705 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003706 break;
3707
sewardj3d7c9c82003-03-26 21:08:13 +00003708 case MMX2_MemWr:
3709 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003710 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003711 vg_assert(u->tag1 == Lit16);
3712 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003713 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003714 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003715 if (!(*sselive)) {
3716 emit_get_sse_state();
3717 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003718 }
3719 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3720 (u->val1 >> 8) & 0xFF,
3721 u->val1 & 0xFF,
3722 u->val2 );
3723 break;
3724
sewardjca860012003-03-27 23:52:58 +00003725 case MMX2_RegRd:
3726 vg_assert(u->tag1 == Lit16);
3727 vg_assert(u->tag2 == RealReg);
3728 vg_assert(u->tag3 == NoValue);
3729 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003730 if (!(*sselive)) {
3731 emit_get_sse_state();
3732 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003733 }
3734 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3735 (u->val1 >> 8) & 0xFF,
3736 u->val1 & 0xFF,
3737 u->val2 );
3738 break;
3739
sewardjd1c9e432003-04-04 20:40:34 +00003740 case MMX2_RegWr:
3741 vg_assert(u->tag1 == Lit16);
3742 vg_assert(u->tag2 == RealReg);
3743 vg_assert(u->tag3 == NoValue);
3744 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003745 if (!(*sselive)) {
3746 emit_get_sse_state();
3747 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003748 }
3749 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3750 (u->val1 >> 8) & 0xFF,
3751 u->val1 & 0xFF,
3752 u->val2 );
3753 break;
3754
sewardj3d7c9c82003-03-26 21:08:13 +00003755 case MMX1:
3756 vg_assert(u->tag1 == Lit16);
3757 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003758 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003759 if (!(*sselive)) {
3760 emit_get_sse_state();
3761 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003762 }
3763 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3764 u->val1 & 0xFF );
3765 break;
3766
3767 case MMX2:
3768 vg_assert(u->tag1 == Lit16);
3769 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003770 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003771 if (!(*sselive)) {
3772 emit_get_sse_state();
3773 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003774 }
3775 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3776 (u->val1 >> 8) & 0xFF,
3777 u->val1 & 0xFF );
3778 break;
3779
sewardjca860012003-03-27 23:52:58 +00003780 case MMX3:
3781 vg_assert(u->tag1 == Lit16);
3782 vg_assert(u->tag2 == Lit16);
3783 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003784 if (!(*sselive)) {
3785 emit_get_sse_state();
3786 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003787 }
3788 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3789 (u->val1 >> 8) & 0xFF,
3790 u->val1 & 0xFF,
3791 u->val2 & 0xFF );
3792 break;
3793
sewardjfebaa3b2003-05-25 01:07:34 +00003794 case SSE2a_MemWr:
3795 case SSE2a_MemRd:
3796 vg_assert(u->size == 4 || u->size == 16);
3797 vg_assert(u->tag1 == Lit16);
3798 vg_assert(u->tag2 == Lit16);
3799 vg_assert(u->tag3 == RealReg);
3800 vg_assert(!anyFlagUse(u));
3801 if (!(*sselive)) {
3802 emit_get_sse_state();
3803 *sselive = True;
3804 }
3805 emit_SSE2a ( u->flags_r, u->flags_w,
3806 (u->val1 >> 8) & 0xFF,
3807 u->val1 & 0xFF,
3808 u->val2 & 0xFF,
3809 u->val3 );
3810 break;
3811
3812 case SSE3a_MemWr:
3813 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00003814 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00003815 vg_assert(u->tag1 == Lit16);
3816 vg_assert(u->tag2 == Lit16);
3817 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003818 if (!(*sselive)) {
3819 emit_get_sse_state();
3820 *sselive = True;
3821 }
3822 emit_SSE3a ( u->flags_r, u->flags_w,
3823 (u->val1 >> 8) & 0xFF,
3824 u->val1 & 0xFF,
3825 (u->val2 >> 8) & 0xFF,
3826 u->val2 & 0xFF,
3827 u->val3 );
3828 break;
3829
3830 case SSE3g_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00003831 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00003832 vg_assert(u->size == 4);
3833 vg_assert(u->tag1 == Lit16);
3834 vg_assert(u->tag2 == Lit16);
3835 vg_assert(u->tag3 == RealReg);
3836 vg_assert(!anyFlagUse(u));
3837 if (!(*sselive)) {
3838 emit_get_sse_state();
3839 *sselive = True;
3840 }
sewardj8f33ba62003-06-14 12:00:45 +00003841 if (u->opcode==SSE3g_RegRd) {
3842 emit_SSE3g_RegRd ( u->flags_r, u->flags_w,
3843 (u->val1 >> 8) & 0xFF,
3844 u->val1 & 0xFF,
3845 (u->val2 >> 8) & 0xFF,
3846 u->val2 & 0xFF,
3847 u->val3 );
3848 } else {
3849 emit_SSE3g_RegWr ( u->flags_r, u->flags_w,
3850 (u->val1 >> 8) & 0xFF,
3851 u->val1 & 0xFF,
3852 (u->val2 >> 8) & 0xFF,
3853 u->val2 & 0xFF,
3854 u->val3 );
3855 }
sewardjfebaa3b2003-05-25 01:07:34 +00003856 break;
3857
sewardjb31b06d2003-06-13 00:26:02 +00003858 case SSE3g1_RegWr:
3859 vg_assert(u->size == 4);
3860 vg_assert(u->tag1 == Lit16);
3861 vg_assert(u->tag2 == Lit16);
3862 vg_assert(u->tag3 == RealReg);
3863 vg_assert(!anyFlagUse(u));
3864 if (!(*sselive)) {
3865 emit_get_sse_state();
3866 *sselive = True;
3867 }
3868 emit_SSE3g1_RegWr ( u->flags_r, u->flags_w,
3869 (u->val1 >> 8) & 0xFF,
3870 u->val1 & 0xFF,
3871 (u->val2 >> 8) & 0xFF,
3872 u->val2 & 0xFF,
3873 u->lit32 & 0xFF,
3874 u->val3 );
3875 break;
3876
3877 case SSE3g1_RegRd:
3878 vg_assert(u->size == 2);
3879 vg_assert(u->tag1 == Lit16);
3880 vg_assert(u->tag2 == Lit16);
3881 vg_assert(u->tag3 == RealReg);
3882 vg_assert(!anyFlagUse(u));
3883 if (!(*sselive)) {
3884 emit_get_sse_state();
3885 *sselive = True;
3886 }
3887 emit_SSE3g1_RegRd ( u->flags_r, u->flags_w,
3888 (u->val1 >> 8) & 0xFF,
3889 u->val1 & 0xFF,
3890 (u->val2 >> 8) & 0xFF,
3891 u->val2 & 0xFF,
3892 u->lit32 & 0xFF,
3893 u->val3 );
3894 break;
3895
sewardja453fb02003-06-14 13:22:36 +00003896 case SSE5:
3897 vg_assert(u->size == 0);
3898 vg_assert(u->tag1 == Lit16);
3899 vg_assert(u->tag2 == Lit16);
3900 vg_assert(u->tag3 == Lit16);
3901 vg_assert(!anyFlagUse(u));
3902 if (!(*sselive)) {
3903 emit_get_sse_state();
3904 *sselive = True;
3905 }
3906 emit_SSE5 ( u->flags_r, u->flags_w,
3907 (u->val1 >> 8) & 0xFF,
3908 u->val1 & 0xFF,
3909 (u->val2 >> 8) & 0xFF,
3910 u->val2 & 0xFF,
3911 u->val3 & 0xFF );
3912 break;
3913
sewardjfebaa3b2003-05-25 01:07:34 +00003914 case SSE4:
3915 vg_assert(u->size == 0);
3916 vg_assert(u->tag1 == Lit16);
3917 vg_assert(u->tag2 == Lit16);
3918 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00003919 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00003920 if (!(*sselive)) {
3921 emit_get_sse_state();
3922 *sselive = True;
3923 }
3924 emit_SSE4 ( u->flags_r, u->flags_w,
3925 (u->val1 >> 8) & 0xFF,
3926 u->val1 & 0xFF,
3927 (u->val2 >> 8) & 0xFF,
3928 u->val2 & 0xFF );
3929 break;
3930
sewardja60be0e2003-05-26 08:47:27 +00003931 case SSE3:
3932 vg_assert(u->size == 0);
3933 vg_assert(u->tag1 == Lit16);
3934 vg_assert(u->tag2 == Lit16);
3935 vg_assert(u->tag3 == NoValue);
3936 vg_assert(!anyFlagUse(u));
3937 if (!(*sselive)) {
3938 emit_get_sse_state();
3939 *sselive = True;
3940 }
3941 emit_SSE3 ( u->flags_r, u->flags_w,
3942 (u->val1 >> 8) & 0xFF,
3943 u->val1 & 0xFF,
3944 u->val2 & 0xFF );
3945 break;
3946
sewardjde4a1d02002-03-22 01:27:54 +00003947 default:
sewardj1b7d8022002-11-30 12:35:42 +00003948 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003949 if (*sselive) {
3950 emit_put_sse_state();
3951 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003952 }
njn4ba5a792002-09-30 10:23:54 +00003953 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003954 } else {
njn25e49d8e72002-09-23 09:36:25 +00003955 VG_(printf)("\nError:\n"
3956 " unhandled opcode: %u. Perhaps "
3957 " VG_(needs).extended_UCode should be set?\n",
3958 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003959 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00003960 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00003961 }
sewardjde4a1d02002-03-22 01:27:54 +00003962 }
3963
sewardjb91ae7f2003-04-29 23:50:00 +00003964 if (0 && (*sselive)) {
3965 emit_put_sse_state();
3966 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003967 }
3968
njn25e49d8e72002-09-23 09:36:25 +00003969 /* Update UInstr histogram */
3970 vg_assert(u->opcode < 100);
3971 histogram[u->opcode].counts++;
3972 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00003973}
3974
3975
3976/* Emit x86 for the ucode in cb, returning the address of the
3977 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00003978UChar* VG_(emit_code) ( UCodeBlock* cb,
3979 Int* nbytes,
3980 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00003981{
3982 Int i;
njn25e49d8e72002-09-23 09:36:25 +00003983 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00003984 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00003985 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00003986 Int tgt;
3987
sewardjfa492d42002-12-08 18:20:01 +00003988 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00003989
njn25e49d8e72002-09-23 09:36:25 +00003990 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00003991
sewardj22854b92002-11-30 14:00:47 +00003992 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
3993 zero. We have to do this regardless of whether we're t-chaining
3994 or not. */
sewardja2113f92002-12-12 23:42:48 +00003995 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00003996 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00003997 VG_(emitB) (0xFF); /* decl */
3998 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
3999 if (dis)
4000 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00004001 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00004002 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4003 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004004 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004005
sewardjb5ff83e2002-12-01 19:40:49 +00004006 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004007 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004008 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004009 curr_eip = cb->orig_eip;
4010 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4011 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004012 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004013 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004014 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004015 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004016
sewardjde4a1d02002-03-22 01:27:54 +00004017 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004018 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004019 if (!sane) {
4020 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004021 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004022 }
4023 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004024 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004025 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004026 }
njn25e49d8e72002-09-23 09:36:25 +00004027 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004028 }
njn25e49d8e72002-09-23 09:36:25 +00004029 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004030 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004031 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004032
sewardj22854b92002-11-30 14:00:47 +00004033 if (j != NULL) {
4034 vg_assert(jumpidx <= VG_MAX_JUMPS);
4035 for(i = 0; i < jumpidx; i++)
4036 j[i] = jumps[i];
4037 }
4038
sewardjde4a1d02002-03-22 01:27:54 +00004039 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004040 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004041 *nbytes = emitted_code_used;
4042 return emitted_code;
4043}
4044
njn25e49d8e72002-09-23 09:36:25 +00004045#undef dis
4046
sewardjde4a1d02002-03-22 01:27:54 +00004047/*--------------------------------------------------------------------*/
4048/*--- end vg_from_ucode.c ---*/
4049/*--------------------------------------------------------------------*/