blob: 8abf767ef6b45e96c5ccf0951fab097375dbaa08 [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)
sewardjabf8bf82003-06-15 22:28:05 +00001435 VG_(printf)("\n\t\tsse2a-0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001436 (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)
sewardjabf8bf82003-06-15 22:28:05 +00001455 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001456 (UInt)first_byte, (UInt)second_byte,
1457 (UInt)third_byte, (UInt)fourth_byte,
1458 nameIReg(4,ireg) );
1459}
1460
sewardjabf8bf82003-06-15 22:28:05 +00001461static void emit_SSE3e ( 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)(
sewardjabf8bf82003-06-15 22:28:05 +00001479 "\n\t\tsse3e--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
sewardjabf8bf82003-06-15 22:28:05 +00001486static void emit_SSE3e1 ( 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 )
sewardj8f33ba62003-06-14 12:00:45 +00001494{
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)(
sewardjabf8bf82003-06-15 22:28:05 +00001506 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001507 (UInt)first_byte, (UInt)second_byte,
1508 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1509 nameIReg(4,ireg)
1510 );
1511}
1512
sewardjabf8bf82003-06-15 22:28:05 +00001513static void emit_SSE3g1 ( 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 )
sewardjb31b06d2003-06-13 00:26:02 +00001521{
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)(
sewardjabf8bf82003-06-15 22:28:05 +00001533 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001534 (UInt)first_byte, (UInt)second_byte,
1535 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1536 nameIReg(4,ireg)
1537 );
1538}
1539
sewardjabf8bf82003-06-15 22:28:05 +00001540static void emit_SSE3g ( 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)(
sewardjabf8bf82003-06-15 22:28:05 +00001558 "\n\t\tsse3g--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,
sewardje3891fa2003-06-15 03:13:48 +00001566 FlagSet sets_sflags,
1567 UChar first_byte,
1568 UChar second_byte,
1569 UChar third_byte,
1570 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001571{
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)
sewardjabf8bf82003-06-15 22:28:05 +00001578 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001579 (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,
sewardje3891fa2003-06-15 03:13:48 +00001584 FlagSet sets_sflags,
1585 UChar first_byte,
1586 UChar second_byte,
1587 UChar third_byte,
1588 UChar fourth_byte,
1589 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001590{
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)
sewardjabf8bf82003-06-15 22:28:05 +00001598 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001599 (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,
sewardje3891fa2003-06-15 03:13:48 +00001605 FlagSet sets_sflags,
1606 UChar first_byte,
1607 UChar second_byte,
1608 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001609{
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)
sewardjabf8bf82003-06-15 22:28:05 +00001615 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001616 (UInt)first_byte, (UInt)second_byte,
1617 (UInt)third_byte );
1618}
1619
sewardje3891fa2003-06-15 03:13:48 +00001620static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1621 FlagSet sets_sflags,
1622 UChar first_byte,
1623 UChar second_byte,
1624 UChar third_byte,
1625 Int addr_reg,
1626 Int dest_reg )
1627{
1628 VG_(new_emit)(True, uses_sflags, sets_sflags);
1629 VG_(emitB) ( first_byte );
1630 VG_(emitB) ( second_byte );
1631 VG_(emitB) ( third_byte );
1632 /* 4th byte can be completely synthesised from addr_reg and
1633 dest_reg. */
1634 emit_amode_regmem_reg ( addr_reg, dest_reg );
1635 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001636 VG_(printf)("\n\t\tsse3ag_mem_rd_reg_wr-0x%x:0x%x:0x%x(addr=%s, dest=%s)\n",
sewardje3891fa2003-06-15 03:13:48 +00001637 (UInt)first_byte, (UInt)second_byte,
1638 (UInt)third_byte, nameIReg(4, addr_reg),
1639 nameIReg(4, dest_reg));
1640}
1641
sewardjca860012003-03-27 23:52:58 +00001642static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1643 FlagSet sets_sflags,
1644 UChar first_byte,
1645 UChar second_byte,
1646 Int ireg )
1647{
1648 VG_(new_emit)(True, uses_sflags, sets_sflags);
1649 VG_(emitB) ( 0x0F );
1650 VG_(emitB) ( first_byte );
1651 second_byte &= 0x38; /* mask out mod and rm fields */
1652 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1653 second_byte |= (ireg & 7); /* patch in our ireg */
1654 VG_(emitB) ( second_byte );
1655 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001656 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1657 (UInt)first_byte, (UInt)second_byte,
1658 nameIReg(4,ireg) );
1659}
1660
1661static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1662 FlagSet sets_sflags,
1663 UChar first_byte,
1664 UChar second_byte,
1665 Int ireg )
1666{
1667 VG_(new_emit)(True, uses_sflags, sets_sflags);
1668 VG_(emitB) ( 0x0F );
1669 VG_(emitB) ( first_byte );
1670 second_byte &= 0x38; /* mask out mod and rm fields */
1671 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1672 second_byte |= (ireg & 7); /* patch in our ireg */
1673 VG_(emitB) ( second_byte );
1674 if (dis)
1675 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001676 (UInt)first_byte, (UInt)second_byte,
1677 nameIReg(4,ireg) );
1678}
1679
1680static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1681 FlagSet sets_sflags,
1682 UChar first_byte,
1683 UChar second_byte,
1684 UChar third_byte )
1685{
1686 VG_(new_emit)(True, uses_sflags, sets_sflags);
1687 VG_(emitB) ( 0x0F );
1688 VG_(emitB) ( first_byte );
1689 VG_(emitB) ( second_byte );
1690 VG_(emitB) ( third_byte );
1691 if (dis)
1692 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1693 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1694}
1695
sewardj3d7c9c82003-03-26 21:08:13 +00001696static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1697 FlagSet sets_sflags,
1698 UChar first_byte,
1699 UChar second_byte )
1700{
1701 VG_(new_emit)(True, uses_sflags, sets_sflags);
1702 VG_(emitB) ( 0x0F );
1703 VG_(emitB) ( first_byte );
1704 VG_(emitB) ( second_byte );
1705 if (dis)
1706 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1707 (UInt)first_byte, (UInt)second_byte );
1708}
1709
1710static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1711 FlagSet sets_sflags,
1712 UChar first_byte )
1713{
1714 VG_(new_emit)(True, uses_sflags, sets_sflags);
1715 VG_(emitB) ( 0x0F );
1716 VG_(emitB) ( first_byte );
1717 if (dis)
1718 VG_(printf)("\n\t\tmmx1-0x%x\n",
1719 (UInt)first_byte );
1720}
1721
sewardjde4a1d02002-03-22 01:27:54 +00001722
1723/*----------------------------------------------------*/
1724/*--- misc instruction emitters ---*/
1725/*----------------------------------------------------*/
1726
njn25e49d8e72002-09-23 09:36:25 +00001727void VG_(emit_call_reg) ( Int reg )
1728{
sewardjfa492d42002-12-08 18:20:01 +00001729 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001730 VG_(emitB) ( 0xFF ); /* Grp5 */
1731 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1732 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001733 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001734}
1735
sewardjf0f12aa2002-12-28 00:04:08 +00001736static
1737void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1738 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001739{
sewardjfa492d42002-12-08 18:20:01 +00001740 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001741 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001742
1743 if (byte_off < -128 || byte_off > 127) {
1744 VG_(emitB) ( 0xFF );
1745 VG_(emitB) ( 0x95 );
1746 VG_(emitL) ( byte_off );
1747 } else {
1748 VG_(emitB) ( 0xFF );
1749 VG_(emitB) ( 0x55 );
1750 VG_(emitB) ( byte_off );
1751 }
1752 if (dis)
1753 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001754}
1755
sewardja2c5a732002-12-15 03:10:42 +00001756#if 0
1757/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001758static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1759{
1760 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001761 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001762 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1763 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001764 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001765 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001766 if (dis)
1767 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1768 nameIReg(4,regmem));
1769}
sewardja2c5a732002-12-15 03:10:42 +00001770#endif
sewardjde4a1d02002-03-22 01:27:54 +00001771
njn25e49d8e72002-09-23 09:36:25 +00001772void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001773{
njne427a662002-10-02 11:08:25 +00001774 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001775 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1776 VG_(emitB) ( 0x8D );
1777 VG_(emitB) ( 0x64 );
1778 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001779 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001780 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001781 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001782}
1783
1784
1785static void emit_movb_AL_zeroESPmem ( void )
1786{
1787 /* movb %al, 0(%esp) */
1788 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001789 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001790 VG_(emitB) ( 0x88 );
1791 VG_(emitB) ( 0x44 );
1792 VG_(emitB) ( 0x24 );
1793 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001794 if (dis)
1795 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1796}
1797
1798static void emit_movb_zeroESPmem_AL ( void )
1799{
1800 /* movb 0(%esp), %al */
1801 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001802 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001803 VG_(emitB) ( 0x8A );
1804 VG_(emitB) ( 0x44 );
1805 VG_(emitB) ( 0x24 );
1806 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001807 if (dis)
1808 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1809}
1810
sewardja2113f92002-12-12 23:42:48 +00001811/* Jump target states */
1812#define TGT_UNDEF (1 << 16)
1813#define TGT_FORWARD (2 << 16)
1814#define TGT_BACKWARD (3 << 16)
1815
1816static inline Int tgt_state(Int tgt)
1817{
1818 return tgt & 0xffff0000;
1819}
1820
1821static inline Int tgt_addr(Int tgt)
1822{
1823 return tgt & 0x0000ffff;
1824}
1825
1826static inline Int mk_tgt(Int state, Int addr)
1827{
1828 vg_assert(state == TGT_UNDEF
1829 || state == TGT_FORWARD || state == TGT_BACKWARD);
1830 vg_assert((addr & 0xffff0000) == 0);
1831
1832 return state | addr;
1833}
1834
1835void VG_(init_target) ( Int *tgt )
1836{
1837 *tgt = TGT_UNDEF;
1838}
1839
1840void VG_(target_back) ( Int *tgt )
1841{
1842 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1843
1844 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1845}
1846
1847void VG_(target_forward) ( Int *tgt )
1848{
1849 Int delta;
1850
1851 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1852 tgt_state(*tgt) == TGT_UNDEF);
1853
1854 if (tgt_state(*tgt) == TGT_UNDEF)
1855 return; /* target not used */
1856
1857 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1858 vg_assert(delta >= -128 && delta <= 127);
1859 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001860 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001861 emitted_code[tgt_addr(*tgt)] = delta;
1862 if (dis)
1863 VG_(printf)("(target to jump site %d; delta: %d)\n",
1864 tgt_addr(*tgt), delta);
1865}
1866
1867void VG_(emit_target_delta) ( Int *tgt )
1868{
1869 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1870 tgt_state(*tgt) == TGT_BACKWARD);
1871
1872 if (tgt_state(*tgt) == TGT_UNDEF) {
1873 /* forward jump */
1874 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1875 VG_(emitB) (0x00);
1876 } else {
1877 /* backward jump */
1878 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1879 vg_assert(delta >= -128 && delta <= 127);
1880 VG_(emitB) (delta);
1881 }
1882}
1883
sewardjde4a1d02002-03-22 01:27:54 +00001884
1885/* Emit a jump short with an 8-bit signed offset. Note that the
1886 offset is that which should be added to %eip once %eip has been
1887 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001888void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001889{
1890 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001891 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001892 VG_(emitB) ( 0x70 + (UInt)cond );
1893 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001894 if (dis)
1895 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001896 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001897}
1898
sewardja2113f92002-12-12 23:42:48 +00001899/* Same as above, but defers emitting the delta */
1900void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1901{
sewardj706240d2002-12-26 17:10:12 +00001902 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001903 VG_(emitB) ( 0x70 + (UInt)cond );
1904 VG_(emit_target_delta) (tgt);
1905 if (dis)
1906 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001907 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001908}
1909
1910
1911
sewardjf0f12aa2002-12-28 00:04:08 +00001912static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001913{
sewardjf0f12aa2002-12-28 00:04:08 +00001914 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001915 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1916 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001917 if (dis)
1918 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001919 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001920}
1921
1922static void emit_ret ( void )
1923{
sewardjfa492d42002-12-08 18:20:01 +00001924 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001925 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001926 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001927 if (dis)
1928 VG_(printf)("\n\t\tret\n");
1929}
1930
sewardj22854b92002-11-30 14:00:47 +00001931/* Predicate used in sanity checks elsewhere - returns true if any
1932 jump-site is an actual chained jump */
1933Bool VG_(is_chained_jumpsite)(Addr a)
1934{
1935 UChar *cp = (UChar *)a;
1936
1937 return (*cp == 0xE9); /* 0xE9 -- jmp */
1938}
1939
sewardj83f11862002-12-01 02:07:08 +00001940static
1941Bool is_fresh_jumpsite(UChar *cp)
1942{
1943 return
1944 cp[0] == 0x0F && /* UD2 */
1945 cp[1] == 0x0B &&
1946 cp[2] == 0x0F && /* UD2 */
1947 cp[3] == 0x0B &&
1948 cp[4] == 0x90; /* NOP */
1949}
1950
sewardj22854b92002-11-30 14:00:47 +00001951/* Predicate used in sanity checks elsewhere - returns true if all
1952 jump-sites are calls to VG_(patch_me) */
1953Bool VG_(is_unchained_jumpsite)(Addr a)
1954{
1955 UChar *cp = (UChar *)a;
1956 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1957 Int idelta;
1958
1959 if (*cp++ != 0xE8) /* 0xE8 == call */
1960 return False;
1961
1962 idelta = (*cp++) << 0;
1963 idelta |= (*cp++) << 8;
1964 idelta |= (*cp++) << 16;
1965 idelta |= (*cp++) << 24;
1966
1967 return idelta == delta;
1968}
1969
1970/* Return target address for a direct jmp */
1971Addr VG_(get_jmp_dest)(Addr a)
1972{
1973 Int delta;
1974 UChar *cp = (UChar *)a;
1975
1976 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1977 return 0;
1978
1979 delta = (*cp++) << 0;
1980 delta |= (*cp++) << 8;
1981 delta |= (*cp++) << 16;
1982 delta |= (*cp++) << 24;
1983
1984 return a + VG_PATCHME_JMPSZ + delta;
1985}
1986
1987/* unchain a BB by generating a call to VG_(patch_me) */
1988void VG_(unchain_jumpsite)(Addr a)
1989{
1990 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1991 UChar *cp = (UChar *)a;
1992
1993 if (VG_(is_unchained_jumpsite)(a))
1994 return; /* don't write unnecessarily */
1995
sewardj83f11862002-12-01 02:07:08 +00001996 if (!is_fresh_jumpsite(cp))
1997 VG_(bb_dechain_count)++; /* update stats */
1998
sewardj22854b92002-11-30 14:00:47 +00001999 *cp++ = 0xE8; /* call */
2000 *cp++ = (delta >> 0) & 0xff;
2001 *cp++ = (delta >> 8) & 0xff;
2002 *cp++ = (delta >> 16) & 0xff;
2003 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002004}
2005
2006/* This doesn't actually generate a call to VG_(patch_me), but
2007 reserves enough space in the instruction stream for it to happen
2008 and records the offset into the jump table. This is because call
2009 is a relative jump, and so will be affected when this code gets
2010 moved about. The translation table will "unchain" this basic block
2011 on insertion (with VG_(unchain_BB)()), and thereby generate a
2012 proper call instruction. */
2013static void emit_call_patchme( void )
2014{
2015 vg_assert(VG_PATCHME_CALLSZ == 5);
2016
sewardjfa492d42002-12-08 18:20:01 +00002017 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002018 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002019
2020 if (jumpidx >= VG_MAX_JUMPS) {
2021 /* If there too many jumps in this basic block, fall back to
2022 dispatch loop. We still need to keep it the same size as the
2023 call sequence. */
2024 VG_(emitB) ( 0xC3 ); /* ret */
2025 VG_(emitB) ( 0x90 ); /* nop */
2026 VG_(emitB) ( 0x90 ); /* nop */
2027 VG_(emitB) ( 0x90 ); /* nop */
2028 VG_(emitB) ( 0x90 ); /* nop */
2029
2030 if (dis)
2031 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
2032
2033 if (0 && VG_(clo_verbosity))
2034 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2035 } else {
2036 jumps[jumpidx++] = emitted_code_used;
2037
2038 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2039 VG_(emitB) ( 0x0B );
2040 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2041 VG_(emitB) ( 0x0B );
2042 VG_(emitB) ( 0x90 ); /* NOP */
2043
2044 if (dis)
2045 VG_(printf)("\n\t\tud2; ud2; nop\n");
2046 }
2047}
2048
njn25e49d8e72002-09-23 09:36:25 +00002049void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002050{
sewardjf0f12aa2002-12-28 00:04:08 +00002051 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002052 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002053 if (dis)
2054 VG_(printf)("\n\t\tpushal\n");
2055}
2056
njn25e49d8e72002-09-23 09:36:25 +00002057void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002058{
sewardjf0f12aa2002-12-28 00:04:08 +00002059 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002060 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002061 if (dis)
2062 VG_(printf)("\n\t\tpopal\n");
2063}
2064
2065static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2066{
sewardjf0f12aa2002-12-28 00:04:08 +00002067 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002068 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2069 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002070 if (dis)
2071 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2072 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2073}
2074
2075static void emit_lea_sib_reg ( UInt lit, Int scale,
2076 Int regbase, Int regindex, Int reg )
2077{
sewardjf0f12aa2002-12-28 00:04:08 +00002078 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002079 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002080 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2081 if (dis)
2082 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2083 lit, nameIReg(4,regbase),
2084 nameIReg(4,regindex), scale,
2085 nameIReg(4,reg) );
2086}
2087
njn25e49d8e72002-09-23 09:36:25 +00002088void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002089{
sewardjf0f12aa2002-12-28 00:04:08 +00002090 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002091 VG_(emitB) ( 0x0F );
2092 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002093 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2094 if (dis)
2095 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2096}
2097
2098/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002099/*--- Helper offset -> addr translation ---*/
2100/*----------------------------------------------------*/
2101
2102/* Finds the baseBlock offset of a skin-specified helper.
2103 * Searches through compacts first, then non-compacts. */
2104Int VG_(helper_offset)(Addr a)
2105{
sewardj05bcdcb2003-05-18 10:05:38 +00002106 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002107 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002108
2109 for (i = 0; i < VG_(n_compact_helpers); i++)
2110 if (VG_(compact_helper_addrs)[i] == a)
2111 return VG_(compact_helper_offsets)[i];
2112 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2113 if (VG_(noncompact_helper_addrs)[i] == a)
2114 return VG_(noncompact_helper_offsets)[i];
2115
2116 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002117 VG_(get_fnname) ( a, buf, 100 );
2118
njn25e49d8e72002-09-23 09:36:25 +00002119 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002120 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2121 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002122
2123 VG_(printf)(" compact helpers: ");
2124 for (i = 0; i < VG_(n_compact_helpers); i++)
2125 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2126
2127 VG_(printf)("\n non-compact helpers: ");
2128 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2129 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2130
2131 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002132 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002133}
2134
2135/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002136/*--- Instruction synthesisers ---*/
2137/*----------------------------------------------------*/
2138
2139static Condcode invertCondition ( Condcode cond )
2140{
2141 return (Condcode)(1 ^ (UInt)cond);
2142}
2143
2144
2145/* Synthesise a call to *baseBlock[offset], ie,
2146 call * (4 x offset)(%ebp).
2147*/
sewardjfa492d42002-12-08 18:20:01 +00002148void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002149 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002150{
2151 vg_assert(word_offset >= 0);
2152 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002153 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002154 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002155 }
sewardjf0f12aa2002-12-28 00:04:08 +00002156 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002157}
2158
njn25e49d8e72002-09-23 09:36:25 +00002159static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002160{
njn25e49d8e72002-09-23 09:36:25 +00002161 if (src != dst) {
2162 VG_(emit_movv_reg_reg) ( 4, src, dst );
2163 ccall_arg_setup_instrs++;
2164 }
njn6431be72002-07-28 09:53:34 +00002165}
njn25e49d8e72002-09-23 09:36:25 +00002166
2167/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2168static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2169{
2170 if (RealReg == tag) {
2171 maybe_emit_movl_reg_reg ( litOrReg, reg );
2172 } else if (Literal == tag) {
2173 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2174 ccall_arg_setup_instrs++;
2175 }
2176 else
njne427a662002-10-02 11:08:25 +00002177 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002178}
2179
2180static
2181void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2182{
2183 if (R_EAX == reg1) {
2184 VG_(emit_swapl_reg_EAX) ( reg2 );
2185 } else if (R_EAX == reg2) {
2186 VG_(emit_swapl_reg_EAX) ( reg1 );
2187 } else {
2188 emit_swapl_reg_reg ( reg1, reg2 );
2189 }
2190 ccall_arg_setup_instrs++;
2191}
2192
2193static
2194void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2195{
2196 if (dst1 != src2) {
2197 maybe_emit_movl_reg_reg ( src1, dst1 );
2198 maybe_emit_movl_reg_reg ( src2, dst2 );
2199
2200 } else if (dst2 != src1) {
2201 maybe_emit_movl_reg_reg ( src2, dst2 );
2202 maybe_emit_movl_reg_reg ( src1, dst1 );
2203
2204 } else {
2205 /* swap to break cycle */
2206 emit_swapl_arg_regs ( dst1, dst2 );
2207 }
2208}
2209
2210static
2211void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2212 UInt dst1, UInt dst2, UInt dst3)
2213{
2214 if (dst1 != src2 && dst1 != src3) {
2215 maybe_emit_movl_reg_reg ( src1, dst1 );
2216 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2217
2218 } else if (dst2 != src1 && dst2 != src3) {
2219 maybe_emit_movl_reg_reg ( src2, dst2 );
2220 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2221
2222 } else if (dst3 != src1 && dst3 != src2) {
2223 maybe_emit_movl_reg_reg ( src3, dst3 );
2224 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2225
2226 } else {
2227 /* break cycle */
2228 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2229 emit_swapl_arg_regs ( dst1, dst2 );
2230 emit_swapl_arg_regs ( dst1, dst3 );
2231
2232 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2233 emit_swapl_arg_regs ( dst1, dst3 );
2234 emit_swapl_arg_regs ( dst1, dst2 );
2235
2236 } else {
njne427a662002-10-02 11:08:25 +00002237 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002238 }
2239 }
2240}
2241
2242static
2243void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2244 UInt src1, UInt src2,
2245 UInt dst1, UInt dst2)
2246{
2247 /* If either are lits, order doesn't matter */
2248 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2249 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2250 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2251
2252 } else {
2253 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2254 }
2255}
2256
2257static
2258void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2259 UInt src1, UInt src2, UInt src3,
2260 UInt dst1, UInt dst2, UInt dst3)
2261{
2262 // SSS: fix this eventually -- make STOREV use two RealRegs?
2263 /* Not supporting literals for 3-arg C functions -- they're only used
2264 by STOREV which has 2 args */
2265 vg_assert(RealReg == tagv[src1] &&
2266 RealReg == tagv[src2] &&
2267 RealReg == tagv[src3]);
2268 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2269 dst1, dst2, dst3 );
2270}
2271
2272/* Synthesise a call to a C function `fn' (which must be registered in
2273 baseBlock) doing all the reg saving and arg handling work.
2274
2275 WARNING: a UInstr should *not* be translated with synth_ccall followed
2276 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2277 such behaviour and everything will fall over.
2278 */
2279void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2280 Tag tagv[], Int ret_reg,
2281 RRegSet regs_live_before, RRegSet regs_live_after )
2282{
2283 Int i;
2284 Int stack_used = 0;
2285 Bool preserve_eax, preserve_ecx, preserve_edx;
2286
2287 vg_assert(0 <= regparms_n && regparms_n <= 3);
2288
2289 ccalls++;
2290
2291 /* If %e[acd]x is live before and after the C call, save/restore it.
2292 Unless the return values clobbers the reg; in this case we must not
2293 save/restore the reg, because the restore would clobber the return
2294 value. (Before and after the UInstr really constitute separate live
2295 ranges, but you miss this if you don't consider what happens during
2296 the UInstr.) */
2297# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002298 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2299 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002300 ret_reg != realReg)
2301
2302 preserve_eax = PRESERVE_REG(R_EAX);
2303 preserve_ecx = PRESERVE_REG(R_ECX);
2304 preserve_edx = PRESERVE_REG(R_EDX);
2305
2306# undef PRESERVE_REG
2307
2308 /* Save caller-save regs as required */
2309 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2310 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2311 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2312
2313 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2314 is the number of args passed in regs (maximum 3 for GCC on x86). */
2315
2316 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002317
njn25e49d8e72002-09-23 09:36:25 +00002318 /* First push stack args (RealRegs or Literals) in reverse order. */
2319 for (i = argc-1; i >= regparms_n; i--) {
2320 switch (tagv[i]) {
2321 case RealReg:
2322 VG_(emit_pushv_reg) ( 4, argv[i] );
2323 break;
2324 case Literal:
2325 /* Use short form of pushl if possible. */
2326 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2327 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2328 else
2329 VG_(emit_pushl_lit32)( argv[i] );
2330 break;
2331 default:
2332 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002333 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002334 }
2335 stack_used += 4;
2336 ccall_arg_setup_instrs++;
2337 }
njn6431be72002-07-28 09:53:34 +00002338
njn25e49d8e72002-09-23 09:36:25 +00002339 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2340 If moving values between registers, be careful not to clobber any on
2341 the way. Happily we can use xchgl to swap registers.
2342 */
2343 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002344
njn25e49d8e72002-09-23 09:36:25 +00002345 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2346 case 3:
2347 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2348 R_EAX, R_EDX, R_ECX );
2349 break;
njn6431be72002-07-28 09:53:34 +00002350
njn25e49d8e72002-09-23 09:36:25 +00002351 /* Less-tricky. Args passed in %eax and %edx. */
2352 case 2:
2353 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2354 break;
2355
2356 /* Easy. Just move arg1 into %eax (if not already in there). */
2357 case 1:
2358 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2359 break;
2360
2361 case 0:
2362 break;
2363
2364 default:
njne427a662002-10-02 11:08:25 +00002365 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002366 }
2367
sewardjfa492d42002-12-08 18:20:01 +00002368 /* Call the function - may trash all flags */
2369 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002370
2371 /* Clear any args from stack */
2372 if (0 != stack_used) {
2373 VG_(emit_add_lit_to_esp) ( stack_used );
2374 ccall_stack_clears++;
2375 }
2376
2377 /* Move return value into ret_reg if necessary and not already there */
2378 if (INVALID_REALREG != ret_reg) {
2379 ccall_retvals++;
2380 if (R_EAX != ret_reg) {
2381 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2382 ccall_retval_movs++;
2383 }
2384 }
2385
2386 /* Restore live caller-save regs as required */
2387 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2388 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2389 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002390}
sewardjde4a1d02002-03-22 01:27:54 +00002391
sewardj2e93c502002-04-12 11:12:52 +00002392static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002393{
sewardj2e93c502002-04-12 11:12:52 +00002394 switch (jmpkind) {
2395 case JmpBoring:
2396 break;
sewardj2e93c502002-04-12 11:12:52 +00002397 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002398 break;
2399 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002400 break;
2401 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002402 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002403 break;
2404 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002405 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002406 break;
2407 default:
njne427a662002-10-02 11:08:25 +00002408 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002409 }
2410}
2411
2412/* Jump to the next translation, by loading its original addr into
2413 %eax and returning to the scheduler. Signal special requirements
2414 by loading a special value into %ebp first.
2415*/
2416static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2417{
sewardjfa492d42002-12-08 18:20:01 +00002418 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002419 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002420 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002421 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002422 emit_ret();
2423}
2424
sewardj22854b92002-11-30 14:00:47 +00002425static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002426
2427/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002428static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002429{
sewardjfa492d42002-12-08 18:20:01 +00002430 maybe_emit_put_eflags(); /* save flags here */
2431
njn25e49d8e72002-09-23 09:36:25 +00002432 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002433
2434 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2435 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2436 emit_call_patchme();
2437 } else {
2438 load_ebp_from_JmpKind ( jmpkind );
2439 emit_ret();
2440 }
sewardjde4a1d02002-03-22 01:27:54 +00002441}
2442
2443
sewardj2370f3b2002-11-30 15:01:01 +00002444static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002445static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002446 Opcode opcode, Int size,
2447 UInt lit, Int reg );
2448
sewardjfa492d42002-12-08 18:20:01 +00002449static void synth_jcond_lit ( Condcode cond,
2450 Addr addr,
2451 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002452{
sewardj2370f3b2002-11-30 15:01:01 +00002453 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002454 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002455 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002456
sewardja2113f92002-12-12 23:42:48 +00002457 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002458 VG_(init_target)(&tgt2);
2459 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002460
sewardjfa492d42002-12-08 18:20:01 +00002461 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2462 if need be */
2463 maybe_emit_put_eflags();
2464 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2465
2466 if (eflags_state == UPD_Both) {
2467 /* The flags are already set up, so we just use them as is. */
2468 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002469 cond = invertCondition(cond);
2470 } else {
sewardj75f04932002-12-12 23:13:21 +00002471 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002472
2473 /* The simd state contains the most recent version, so we emit a
2474 sequence to calculate the relevant condition directly out of
2475 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2476 copying them back to the real flags via popf. Notice that
2477 some of these sequences trash %eax, but that should be free
2478 now since this is the end of a bb and therefore all regs are
2479 dead. */
2480 simd = False;
2481
2482 switch (cond) {
2483
sewardjbb6c1182002-12-12 23:54:47 +00002484 case CondLE: /* Z || S != O -> S || !P */
2485 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002486 vg_assert(eax_trashable);
2487
2488 VG_(emit_movv_offregmem_reg)
2489 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2490 /* eax == %EFLAGS */
2491
sewardjbb6c1182002-12-12 23:54:47 +00002492 VG_(emit_nonshiftopv_lit_reg)
2493 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2494 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002495
sewardjbb6c1182002-12-12 23:54:47 +00002496 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2497 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002498
sewardj09736622002-12-28 00:19:00 +00002499 /* actually set the real cpu flags, since ROR changes
2500 neither P nor Z */
2501 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2502
sewardjbb6c1182002-12-12 23:54:47 +00002503 if (cond == CondLE) {
2504 /* test Z */
2505 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2506 /* test OF != SF */
2507 cond = CondP;
2508 } else {
2509 /* test Z */
2510 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2511 /* test OF == SF */
2512 cond = CondNP;
2513 }
sewardj2370f3b2002-11-30 15:01:01 +00002514 break;
2515
sewardjfa492d42002-12-08 18:20:01 +00002516 case CondL:
2517 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002518 vg_assert(eax_trashable);
2519
2520 VG_(emit_movv_offregmem_reg)
2521 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2522 /* eax == %EFLAGS */
2523
sewardj75f04932002-12-12 23:13:21 +00002524 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2525 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002526
sewardj75f04932002-12-12 23:13:21 +00002527 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2528 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002529
sewardj09736622002-12-28 00:19:00 +00002530 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002531 if (cond == CondL) cond = CondP; else cond = CondNP;
2532 break;
sewardjfa492d42002-12-08 18:20:01 +00002533
2534 case CondB:
2535 case CondNB:
2536 mask = EFlagC; goto simple; /* C=1 */
2537
2538 case CondZ:
2539 case CondNZ:
2540 mask = EFlagZ; goto simple; /* Z=1 */
2541
2542 case CondBE:
2543 case CondNBE:
2544 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2545
2546 case CondS:
2547 case CondNS:
2548 mask = EFlagS; goto simple; /* S=1 */
2549
2550 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002551 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002552 mask = EFlagP; goto simple; /* P=1 */
2553
sewardj39542072002-12-09 22:44:00 +00002554 case CondO:
2555 case CondNO:
2556 mask = EFlagO; goto simple; /* O=1 */
2557
sewardjfa492d42002-12-08 18:20:01 +00002558 default:
2559 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002560 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002561 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2562
2563 simple:
2564 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002565 if ((mask & 0xff) == mask) {
2566 VG_(emitB) ( 0xF6 ); /* Grp3 */
2567 VG_(emit_amode_offregmem_reg)(
2568 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2569 VG_(emitB) (mask);
2570 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002571 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002572 mask, VGOFF_(m_eflags) * 4);
2573 } else {
sewardjfa492d42002-12-08 18:20:01 +00002574 /* all cond codes are in lower 16 bits */
2575 vg_assert((mask & 0xffff) == mask);
2576
2577 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002578 VG_(emitB) ( 0xF7 );
2579 VG_(emit_amode_offregmem_reg)(
2580 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002581 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002582 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002583 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002584 mask, VGOFF_(m_eflags) * 4);
2585 }
2586
sewardj75f04932002-12-12 23:13:21 +00002587 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002588 break;
2589 }
2590 }
2591
sewardja2113f92002-12-12 23:42:48 +00002592 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002593
2594 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002595 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002596
2597 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002598 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002599}
2600
2601
sewardj2370f3b2002-11-30 15:01:01 +00002602
sewardjde4a1d02002-03-22 01:27:54 +00002603static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2604{
sewardja2113f92002-12-12 23:42:48 +00002605 Int tgt;
2606
2607 VG_(init_target)(&tgt);
2608
sewardjfa492d42002-12-08 18:20:01 +00002609 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002610
2611 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002612 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002613
2614 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002615}
2616
2617
2618static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2619{
2620 /* Load the zero-extended literal into reg, at size l,
2621 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002622 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002623}
2624
2625
2626static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2627{
2628 switch (size) {
2629 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
2630 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
2631 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002632 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002633 }
2634}
2635
2636
2637static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2638{
2639 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002640 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2641 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2642 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002643 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002644 }
2645}
2646
2647
2648static void synth_mov_reg_offregmem ( Int size, Int reg,
2649 Int off, Int areg )
2650{
2651 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002652 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2653 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002654 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002655 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002656 }
2657 else {
njn25e49d8e72002-09-23 09:36:25 +00002658 VG_(emit_swapl_reg_EAX) ( reg );
2659 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2660 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002661 }
2662 break;
njne427a662002-10-02 11:08:25 +00002663 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002664 }
2665}
2666
2667
2668static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2669{
2670 Int s1;
2671 switch (size) {
2672 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2673 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2674 case 1: if (reg1 < 4) {
2675 emit_movb_reg_regmem ( reg1, reg2 );
2676 }
2677 else {
2678 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2679 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2680 emit_swapl_reg_reg ( s1, reg1 );
2681 emit_movb_reg_regmem ( s1, reg2 );
2682 emit_swapl_reg_reg ( s1, reg1 );
2683 }
2684 break;
njne427a662002-10-02 11:08:25 +00002685 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002686 }
2687}
2688
2689
sewardjf0f12aa2002-12-28 00:04:08 +00002690static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002691 Opcode opcode, Int size,
2692 Int reg )
2693{
2694 /* NB! opcode is a uinstr opcode, not an x86 one! */
2695 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002696 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002697 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002698 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002699 break;
2700 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002701 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002702 } else {
njn25e49d8e72002-09-23 09:36:25 +00002703 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002704 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002705 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002706 }
2707 break;
njne427a662002-10-02 11:08:25 +00002708 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002709 }
2710}
2711
2712
2713
sewardjf0f12aa2002-12-28 00:04:08 +00002714static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002715 Opcode opcode, Int size,
2716 Int reg1, Int reg2 )
2717{
2718 /* NB! opcode is a uinstr opcode, not an x86 one! */
2719 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002720 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002721 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002722 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002723 break;
2724 case 1: { /* Horrible ... */
2725 Int s1, s2;
2726 /* Choose s1 and s2 to be x86 regs which we can talk about the
2727 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2728 sure s1 != s2 and that neither of them equal either reg1 or
2729 reg2. Then use them as temporaries to make things work. */
2730 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002731 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002732 break;
2733 }
2734 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2735 if (reg1 >= 4 && reg2 < 4) {
2736 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002737 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002738 emit_swapl_reg_reg ( reg1, s1 );
2739 break;
2740 }
2741 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2742 if (reg1 < 4 && reg2 >= 4) {
2743 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002744 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002745 emit_swapl_reg_reg ( reg2, s2 );
2746 break;
2747 }
2748 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2749 emit_swapl_reg_reg ( reg1, s1 );
2750 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002751 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002752 emit_swapl_reg_reg ( reg1, s1 );
2753 emit_swapl_reg_reg ( reg2, s2 );
2754 break;
2755 }
2756 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2757 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002758 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002759 emit_swapl_reg_reg ( reg1, s1 );
2760 break;
2761 }
njne427a662002-10-02 11:08:25 +00002762 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002763 }
njne427a662002-10-02 11:08:25 +00002764 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002765 }
2766}
2767
sewardja2c5a732002-12-15 03:10:42 +00002768#if 0
2769/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002770static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002771 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002772 Opcode opcode, Int size,
2773 Int off, Int areg, Int reg )
2774{
2775 switch (size) {
2776 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002777 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002778 break;
2779 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002780 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002781 break;
2782 case 1:
2783 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002784 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002785 } else {
2786 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002787 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002788 VG_(emit_swapl_reg_EAX) ( reg );
2789 }
2790 break;
2791 default:
2792 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2793 }
2794}
sewardja2c5a732002-12-15 03:10:42 +00002795#endif
sewardjfa492d42002-12-08 18:20:01 +00002796
sewardjde4a1d02002-03-22 01:27:54 +00002797static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002798 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002799 Opcode opcode, Int size,
2800 Int off, Int areg, Int reg )
2801{
2802 switch (size) {
2803 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002804 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002805 break;
2806 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002807 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002808 break;
2809 case 1:
2810 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002811 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002812 } else {
njn25e49d8e72002-09-23 09:36:25 +00002813 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002814 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002815 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002816 }
2817 break;
2818 default:
njne427a662002-10-02 11:08:25 +00002819 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002820 }
2821}
2822
2823
sewardjf0f12aa2002-12-28 00:04:08 +00002824static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002825 Opcode opcode, Int size,
2826 UInt lit, Int reg )
2827{
2828 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002829 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002830 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002831 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002832 break;
2833 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002834 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002835 } else {
njn25e49d8e72002-09-23 09:36:25 +00002836 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002837 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002838 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002839 }
2840 break;
njne427a662002-10-02 11:08:25 +00002841 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002842 }
2843}
2844
sewardjf0f12aa2002-12-28 00:04:08 +00002845static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002846 Opcode opcode, Int size,
2847 UInt lit, Int off, Int regmem )
2848{
2849 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002850 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002851 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002852 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002853 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002854 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002855 break;
2856 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2857 }
2858}
2859
sewardjde4a1d02002-03-22 01:27:54 +00002860
2861static void synth_push_reg ( Int size, Int reg )
2862{
2863 switch (size) {
2864 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002865 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002866 break;
2867 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002868 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002869 break;
2870 /* Pray that we don't have to generate this really cruddy bit of
2871 code very often. Could do better, but can I be bothered? */
2872 case 1:
2873 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002874 VG_(emit_add_lit_to_esp)(-1);
2875 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002876 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002877 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002878 break;
2879 default:
njne427a662002-10-02 11:08:25 +00002880 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002881 }
2882}
2883
2884
2885static void synth_pop_reg ( Int size, Int reg )
2886{
2887 switch (size) {
2888 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002889 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002890 break;
2891 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002892 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002893 break;
2894 case 1:
2895 /* Same comment as above applies. */
2896 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002897 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002898 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00002899 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
2900 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00002901 break;
njne427a662002-10-02 11:08:25 +00002902 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002903 }
2904}
2905
2906
sewardjf0f12aa2002-12-28 00:04:08 +00002907static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002908 Opcode opcode, Int size,
2909 Int regs, Int regd )
2910{
2911 synth_push_reg ( size, regd );
2912 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00002913 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002914 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
2915 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
2916 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00002917 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002918 }
sewardjde4a1d02002-03-22 01:27:54 +00002919 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
2920 synth_pop_reg ( size, regd );
2921}
2922
2923
sewardjf0f12aa2002-12-28 00:04:08 +00002924static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002925 Opcode opcode, Int size,
2926 UInt lit, Int reg )
2927{
2928 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002929 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002930 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002931 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002932 break;
2933 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002934 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002935 } else {
njn25e49d8e72002-09-23 09:36:25 +00002936 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002937 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002938 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002939 }
2940 break;
njne427a662002-10-02 11:08:25 +00002941 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002942 }
2943}
2944
2945
sewardjf0f12aa2002-12-28 00:04:08 +00002946static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002947{
sewardjde4a1d02002-03-22 01:27:54 +00002948 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002949 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00002950 } else {
njn25e49d8e72002-09-23 09:36:25 +00002951 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002952 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002953 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002954 }
2955}
2956
2957
sewardj3d7c9c82003-03-26 21:08:13 +00002958static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
2959 UChar first_byte,
2960 UChar second_byte,
2961 Int ireg )
2962{
2963 emit_MMX2_regmem ( uses_flags, sets_flags,
2964 first_byte, second_byte, ireg );
2965}
2966
2967
sewardjca860012003-03-27 23:52:58 +00002968static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
2969 UChar first_byte,
2970 UChar second_byte,
2971 Int ireg )
2972{
2973 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
2974 first_byte, second_byte, ireg );
2975}
2976
sewardjd1c9e432003-04-04 20:40:34 +00002977static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
2978 UChar first_byte,
2979 UChar second_byte,
2980 Int ireg )
2981{
2982 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
2983 first_byte, second_byte, ireg );
2984}
2985
sewardj3d7c9c82003-03-26 21:08:13 +00002986static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
2987 UChar first_byte,
2988 UChar second_byte )
2989{
2990 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
2991}
2992
2993
sewardjca860012003-03-27 23:52:58 +00002994static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
2995 UChar first_byte,
2996 UChar second_byte,
2997 UChar third_byte )
2998{
2999 emit_MMX3_no_mem ( uses_flags, sets_flags,
3000 first_byte, second_byte, third_byte );
3001}
3002
3003
sewardj3d7c9c82003-03-26 21:08:13 +00003004static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3005 UChar first_byte )
3006{
3007 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3008}
3009
3010
sewardjfa492d42002-12-08 18:20:01 +00003011static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3012 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003013 UChar second_byte_masked,
3014 Int reg )
3015{
sewardj3d7c9c82003-03-26 21:08:13 +00003016 emit_fpu_regmem ( uses_flags, sets_flags,
3017 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003018}
3019
3020
sewardjfa492d42002-12-08 18:20:01 +00003021static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3022 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003023 UChar second_byte )
3024{
sewardjfa492d42002-12-08 18:20:01 +00003025 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003026}
3027
3028
3029static void synth_movl_reg_reg ( Int src, Int dst )
3030{
3031 emit_movl_reg_reg ( src, dst );
3032}
3033
3034static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3035{
sewardja2113f92002-12-12 23:42:48 +00003036 Int tgt;
3037
3038 VG_(init_target)(&tgt);
3039
3040 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003041 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003042
3043 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003044}
3045
3046
sewardjde4a1d02002-03-22 01:27:54 +00003047/*----------------------------------------------------*/
3048/*--- Top level of the uinstr -> x86 translation. ---*/
3049/*----------------------------------------------------*/
3050
3051/* Return the byte offset from %ebp (ie, into baseBlock)
3052 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003053static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3054{
3055 if (tag == SpillNo) {
3056 vg_assert(size == 4);
3057 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3058 return 4 * (value + VGOFF_(spillslots));
3059 }
3060 if (tag == ArchReg) {
3061 switch (value) {
3062 case R_EAX: return 4 * VGOFF_(m_eax);
3063 case R_ECX: return 4 * VGOFF_(m_ecx);
3064 case R_EDX: return 4 * VGOFF_(m_edx);
3065 case R_EBX: return 4 * VGOFF_(m_ebx);
3066 case R_ESP:
3067 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3068 else return 4 * VGOFF_(m_esp);
3069 case R_EBP:
3070 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3071 else return 4 * VGOFF_(m_ebp);
3072 case R_ESI:
3073 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3074 else return 4 * VGOFF_(m_esi);
3075 case R_EDI:
3076 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3077 else return 4 * VGOFF_(m_edi);
3078 }
3079 }
njne427a662002-10-02 11:08:25 +00003080 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003081}
3082
sewardjde4a1d02002-03-22 01:27:54 +00003083static Int eflagsOffset ( void )
3084{
3085 return 4 * VGOFF_(m_eflags);
3086}
3087
sewardje1042472002-09-30 12:33:11 +00003088static Int segRegOffset ( UInt archregs )
3089{
3090 switch (archregs) {
3091 case R_CS: return 4 * VGOFF_(m_cs);
3092 case R_SS: return 4 * VGOFF_(m_ss);
3093 case R_DS: return 4 * VGOFF_(m_ds);
3094 case R_ES: return 4 * VGOFF_(m_es);
3095 case R_FS: return 4 * VGOFF_(m_fs);
3096 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003097 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003098 }
3099}
3100
njnf4ce3d32003-02-10 10:17:26 +00003101UInt VG_(get_archreg) ( UInt arch )
3102{
3103 switch (arch) {
3104 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3105 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3106 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3107 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3108 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3109 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3110 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3111 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
3112 default: VG_(core_panic)( "get_thread_archreg");
3113 }
3114}
3115
3116UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3117{
3118 ThreadState* tst;
3119
3120 vg_assert(VG_(is_valid_tid)(tid));
3121 tst = & VG_(threads)[tid];
3122
3123 switch (arch) {
3124 case R_EAX: return tst->m_eax;
3125 case R_ECX: return tst->m_ecx;
3126 case R_EDX: return tst->m_edx;
3127 case R_EBX: return tst->m_ebx;
3128 case R_ESP: return tst->m_esp;
3129 case R_EBP: return tst->m_ebp;
3130 case R_ESI: return tst->m_esi;
3131 case R_EDI: return tst->m_edi;
3132 default: VG_(core_panic)( "get_thread_archreg");
3133 }
3134}
3135
njnb93d1782003-02-03 12:03:22 +00003136/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003137static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003138{
3139 switch (arch) {
3140 case R_EAX: return VGOFF_(sh_eax);
3141 case R_ECX: return VGOFF_(sh_ecx);
3142 case R_EDX: return VGOFF_(sh_edx);
3143 case R_EBX: return VGOFF_(sh_ebx);
3144 case R_ESP: return VGOFF_(sh_esp);
3145 case R_EBP: return VGOFF_(sh_ebp);
3146 case R_ESI: return VGOFF_(sh_esi);
3147 case R_EDI: return VGOFF_(sh_edi);
3148 default: VG_(core_panic)( "shadow_reg_index");
3149 }
3150}
sewardjde4a1d02002-03-22 01:27:54 +00003151
njn25e49d8e72002-09-23 09:36:25 +00003152/* Return the byte offset from %ebp (ie, into baseBlock)
3153 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003154Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003155{
njnb93d1782003-02-03 12:03:22 +00003156 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003157}
3158
njn4ba5a792002-09-30 10:23:54 +00003159Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003160{
3161 return 4 * VGOFF_(sh_eflags);
3162}
3163
njnb93d1782003-02-03 12:03:22 +00003164/* Accessing shadow arch. registers */
3165UInt VG_(get_shadow_archreg) ( UInt archreg )
3166{
3167 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3168}
3169
3170void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3171{
3172 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3173}
3174
njnd3040452003-05-19 15:04:06 +00003175void VG_(set_shadow_eflags) ( UInt val )
3176{
3177 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3178}
3179
njnf4ce3d32003-02-10 10:17:26 +00003180UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3181{
3182 ThreadState* tst;
3183
3184 vg_assert(VG_(is_valid_tid)(tid));
3185 tst = & VG_(threads)[tid];
3186
3187 switch (archreg) {
3188 case R_EAX: return tst->sh_eax;
3189 case R_ECX: return tst->sh_ecx;
3190 case R_EDX: return tst->sh_edx;
3191 case R_EBX: return tst->sh_ebx;
3192 case R_ESP: return tst->sh_esp;
3193 case R_EBP: return tst->sh_ebp;
3194 case R_ESI: return tst->sh_esi;
3195 case R_EDI: return tst->sh_edi;
3196 default: VG_(core_panic)( "get_thread_shadow_archreg");
3197 }
3198}
3199
3200void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3201{
3202 ThreadState* tst;
3203
3204 vg_assert(VG_(is_valid_tid)(tid));
3205 tst = & VG_(threads)[tid];
3206
3207 switch (archreg) {
3208 case R_EAX: tst->sh_eax = val; break;
3209 case R_ECX: tst->sh_ecx = val; break;
3210 case R_EDX: tst->sh_edx = val; break;
3211 case R_EBX: tst->sh_ebx = val; break;
3212 case R_ESP: tst->sh_esp = val; break;
3213 case R_EBP: tst->sh_ebp = val; break;
3214 case R_ESI: tst->sh_esi = val; break;
3215 case R_EDI: tst->sh_edi = val; break;
3216 default: VG_(core_panic)( "set_thread_shadow_archreg");
3217 }
3218}
3219
njnb93d1782003-02-03 12:03:22 +00003220Addr VG_(shadow_archreg_address) ( UInt archreg )
3221{
3222 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3223}
sewardjde4a1d02002-03-22 01:27:54 +00003224
sewardjde4a1d02002-03-22 01:27:54 +00003225static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3226{
3227 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003228 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3229 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003230 }
3231 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003232 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3233 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003234 }
3235 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003236 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3237 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003238 }
3239 else
njne427a662002-10-02 11:08:25 +00003240 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003241}
3242
3243
sewardjde4a1d02002-03-22 01:27:54 +00003244/*----------------------------------------------------*/
3245/*--- Generate code for a single UInstr. ---*/
3246/*----------------------------------------------------*/
3247
sewardj478335c2002-10-05 02:44:47 +00003248static __inline__
3249Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003250{
3251 return (u->flags_w != FlagsEmpty);
3252}
3253
sewardjfa492d42002-12-08 18:20:01 +00003254static __inline__
3255Bool readFlagUse ( UInstr* u )
3256{
3257 /* If the UInstr writes some flags but not all, then we still need
3258 to consider it as reading flags so that the unchanged values are
3259 passed through properly. (D is special) */
3260 return
3261 (u->flags_r != FlagsEmpty) ||
3262 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3263}
3264
sewardj478335c2002-10-05 02:44:47 +00003265static __inline__
3266Bool anyFlagUse ( UInstr* u )
3267{
sewardjfa492d42002-12-08 18:20:01 +00003268 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003269}
3270
3271
sewardjb91ae7f2003-04-29 23:50:00 +00003272/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3273 the real machine's cpu. If so we need to be very careful not to trash it.
3274 If FPU/SSE state is live and we deem it necessary to copy it back to
3275 the simulated machine's FPU/SSE state, we do so. The final state of
3276 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003277 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003278 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003279*/
sewardjb5ff83e2002-12-01 19:40:49 +00003280static void emitUInstr ( UCodeBlock* cb, Int i,
3281 RRegSet regs_live_before,
3282 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003283 Bool* sselive, /* True<==>FPU/SSE
3284 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003285 Addr* orig_eip, /* previous curr_eip, or zero */
3286 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003287{
njn25e49d8e72002-09-23 09:36:25 +00003288 Int old_emitted_code_used;
3289 UInstr* u = &cb->instrs[i];
3290
sewardjde4a1d02002-03-22 01:27:54 +00003291 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003292 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003293
njn25e49d8e72002-09-23 09:36:25 +00003294 old_emitted_code_used = emitted_code_used;
3295
sewardjde4a1d02002-03-22 01:27:54 +00003296 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003297 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003298
sewardjb5ff83e2002-12-01 19:40:49 +00003299 case INCEIP:
3300 /* Advance %EIP some small amount. */
3301 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003302
sewardjb5ff83e2002-12-01 19:40:49 +00003303 if (*orig_eip == 0 /* we don't know what the old value was */
3304 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3305 /* We have to update all 32 bits of the value. */
3306 VG_(emit_movv_lit_offregmem)(
3307 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3308 } else {
3309 /* Cool! we only need to update lowest 8 bits */
3310 VG_(emit_movb_lit_offregmem)(
3311 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003312 }
njn25e49d8e72002-09-23 09:36:25 +00003313
sewardjb5ff83e2002-12-01 19:40:49 +00003314 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003315 break;
sewardjde4a1d02002-03-22 01:27:54 +00003316
3317 case LEA1: {
3318 vg_assert(u->tag1 == RealReg);
3319 vg_assert(u->tag2 == RealReg);
3320 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3321 break;
3322 }
3323
3324 case LEA2: {
3325 vg_assert(u->tag1 == RealReg);
3326 vg_assert(u->tag2 == RealReg);
3327 vg_assert(u->tag3 == RealReg);
3328 emit_lea_sib_reg ( u->lit32, u->extra4b,
3329 u->val1, u->val2, u->val3 );
3330 break;
3331 }
3332
3333 case WIDEN: {
3334 vg_assert(u->tag1 == RealReg);
3335 if (u->signed_widen) {
3336 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3337 } else {
3338 /* no need to generate any code. */
3339 }
3340 break;
3341 }
3342
sewardjde4a1d02002-03-22 01:27:54 +00003343 case STORE: {
3344 vg_assert(u->tag1 == RealReg);
3345 vg_assert(u->tag2 == RealReg);
3346 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003347 break;
3348 }
3349
3350 case LOAD: {
3351 vg_assert(u->tag1 == RealReg);
3352 vg_assert(u->tag2 == RealReg);
3353 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3354 break;
3355 }
3356
sewardjde4a1d02002-03-22 01:27:54 +00003357 case GET: {
3358 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3359 vg_assert(u->tag2 == RealReg);
3360 synth_mov_offregmem_reg (
3361 u->size,
3362 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3363 R_EBP,
3364 u->val2
3365 );
3366 break;
3367 }
3368
3369 case PUT: {
3370 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3371 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003372 synth_mov_reg_offregmem (
3373 u->size,
3374 u->val1,
3375 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3376 R_EBP
3377 );
sewardjde4a1d02002-03-22 01:27:54 +00003378 break;
3379 }
3380
sewardje1042472002-09-30 12:33:11 +00003381 case GETSEG: {
3382 vg_assert(u->tag1 == ArchRegS);
3383 vg_assert(u->tag2 == RealReg);
3384 vg_assert(u->size == 2);
3385 synth_mov_offregmem_reg (
3386 4,
3387 segRegOffset( u->val1 ),
3388 R_EBP,
3389 u->val2
3390 );
3391 break;
3392 }
3393
3394 case PUTSEG: {
3395 vg_assert(u->tag1 == RealReg);
3396 vg_assert(u->tag2 == ArchRegS);
3397 vg_assert(u->size == 2);
3398 synth_mov_reg_offregmem (
3399 4,
3400 u->val1,
3401 segRegOffset( u->val2 ),
3402 R_EBP
3403 );
3404 break;
3405 }
3406
sewardjde4a1d02002-03-22 01:27:54 +00003407 case GETF: {
3408 vg_assert(u->size == 2 || u->size == 4);
3409 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003410
3411 /* This complexity is because the D(irection) flag is stored
3412 separately from the rest of EFLAGS. */
3413
3414 /* We're only fetching from the Simd state, so make sure it's
3415 up to date. */
3416 maybe_emit_put_eflags();
3417
3418 /* get D in u->val1 (== 1 or -1) */
3419 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3420
3421 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3422 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3423
3424 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3425 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3426 eflagsOffset(), R_EBP);
3427
3428 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3429 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3430 eflagsOffset(), R_EBP);
3431
3432 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3433 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3434 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003435 break;
3436 }
3437
3438 case PUTF: {
3439 vg_assert(u->size == 2 || u->size == 4);
3440 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003441
3442 /* When putting a value into EFLAGS, this generates the
3443 correct value for m_dflag (-1 or 1), and clears the D bit
3444 in EFLAGS. */
3445
3446 /* We're updating the whole flag state, so the old state
3447 doesn't matter; make sure that the new simulated state
3448 will be fetched when needed. */
3449 eflags_state = UPD_Simd;
3450
3451 /* store EFLAGS (with D) */
3452 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3453
3454 /* u->val1 &= EFlagD */
3455 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3456
3457 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3458 synth_unaryop_reg(False, NEG, u->size, u->val1);
3459 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3460 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3461
3462 /* save D */
3463 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3464
3465 /* EFLAGS &= ~EFlagD */
3466 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3467 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003468 break;
3469 }
3470
3471 case MOV: {
3472 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3473 vg_assert(u->tag2 == RealReg);
3474 switch (u->tag1) {
3475 case RealReg: vg_assert(u->size == 4);
3476 if (u->val1 != u->val2)
3477 synth_movl_reg_reg ( u->val1, u->val2 );
3478 break;
3479 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3480 break;
njne427a662002-10-02 11:08:25 +00003481 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003482 }
3483 break;
3484 }
3485
sewardje1042472002-09-30 12:33:11 +00003486 case USESEG: {
3487 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3488 ones. */
sewardjd077f532002-09-30 21:52:50 +00003489 UInt argv[] = { u->val1, u->val2 };
3490 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003491 UInt ret_reg = u->val2;
3492
3493 vg_assert(u->tag1 == RealReg);
3494 vg_assert(u->tag2 == RealReg);
3495 vg_assert(u->size == 0);
3496
sewardjb91ae7f2003-04-29 23:50:00 +00003497 if (*sselive) {
3498 emit_put_sse_state();
3499 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003500 }
3501
sewardje1042472002-09-30 12:33:11 +00003502 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3503 2, /* args */
3504 0, /* regparms_n */
3505 argv, tagv,
3506 ret_reg, regs_live_before, u->regs_live_after );
3507 break;
3508 }
3509
sewardj478335c2002-10-05 02:44:47 +00003510 case SBB:
3511 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003512 case XOR:
3513 case OR:
3514 case AND:
3515 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003516 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003517 vg_assert(u->tag2 == RealReg);
3518 switch (u->tag1) {
3519 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003520 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003521 u->opcode, u->size, u->lit32, u->val2 );
3522 break;
3523 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003524 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003525 u->opcode, u->size, u->val1, u->val2 );
3526 break;
3527 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003528 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003529 u->opcode, u->size,
3530 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3531 R_EBP,
3532 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
sewardj478335c2002-10-05 02:44:47 +00003539 case RCR:
3540 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003541 case ROR:
3542 case ROL:
3543 case SAR:
3544 case SHR:
3545 case SHL: {
3546 vg_assert(u->tag2 == RealReg);
3547 switch (u->tag1) {
3548 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003549 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003550 u->opcode, u->size, u->lit32, u->val2 );
3551 break;
3552 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003553 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003554 u->opcode, u->size, u->val1, u->val2 );
3555 break;
njne427a662002-10-02 11:08:25 +00003556 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003557 }
3558 break;
3559 }
3560
3561 case INC:
3562 case DEC:
3563 case NEG:
3564 case NOT:
3565 vg_assert(u->tag1 == RealReg);
3566 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003567 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003568 break;
3569
3570 case BSWAP:
3571 vg_assert(u->tag1 == RealReg);
3572 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003573 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003574 emit_bswapl_reg ( u->val1 );
3575 break;
3576
3577 case CMOV:
3578 vg_assert(u->tag1 == RealReg);
3579 vg_assert(u->tag2 == RealReg);
3580 vg_assert(u->cond != CondAlways);
3581 vg_assert(u->size == 4);
3582 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3583 break;
3584
3585 case JMP: {
3586 vg_assert(u->tag2 == NoValue);
3587 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003588 if (*sselive) {
3589 emit_put_sse_state();
3590 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003591 }
sewardjde4a1d02002-03-22 01:27:54 +00003592 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003593 switch (u->tag1) {
3594 case RealReg:
3595 synth_jmp_reg ( u->val1, u->jmpkind );
3596 break;
3597 case Literal:
3598 synth_jmp_lit ( u->lit32, u->jmpkind );
3599 break;
3600 default:
njne427a662002-10-02 11:08:25 +00003601 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003602 break;
sewardjde4a1d02002-03-22 01:27:54 +00003603 }
3604 } else {
sewardj2e93c502002-04-12 11:12:52 +00003605 switch (u->tag1) {
3606 case RealReg:
njne427a662002-10-02 11:08:25 +00003607 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003608 break;
3609 case Literal:
3610 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003611 /* %eax had better not be live since synth_jcond_lit
3612 trashes it in some circumstances. If that turns
3613 out to be a problem we can get synth_jcond_lit to
3614 push/pop it when it is live. */
3615 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3616 u->regs_live_after));
3617 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003618 break;
3619 default:
njne427a662002-10-02 11:08:25 +00003620 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003621 break;
sewardjde4a1d02002-03-22 01:27:54 +00003622 }
3623 }
3624 break;
3625 }
3626
3627 case JIFZ:
3628 vg_assert(u->tag1 == RealReg);
3629 vg_assert(u->tag2 == Literal);
3630 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003631 if (*sselive) {
3632 emit_put_sse_state();
3633 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003634 }
sewardjde4a1d02002-03-22 01:27:54 +00003635 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3636 break;
3637
sewardjde4a1d02002-03-22 01:27:54 +00003638 case PUSH:
3639 vg_assert(u->tag1 == RealReg);
3640 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003641 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003642 break;
3643
3644 case POP:
3645 vg_assert(u->tag1 == RealReg);
3646 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003647 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003648 break;
3649
3650 case CALLM:
3651 vg_assert(u->tag1 == Lit16);
3652 vg_assert(u->tag2 == NoValue);
3653 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003654 if (*sselive) {
3655 emit_put_sse_state();
3656 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003657 }
sewardjfa492d42002-12-08 18:20:01 +00003658 /* Call to a helper which is pretending to be a real CPU
3659 instruction (and therefore operates on Real flags and
3660 registers) */
3661 VG_(synth_call) ( False, u->val1,
3662 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003663 break;
3664
njn25e49d8e72002-09-23 09:36:25 +00003665 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003666 /* If you change this, remember to change USESEG above, since
3667 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003668 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3669 ones. */
3670 UInt argv[] = { u->val1, u->val2, u->val3 };
3671 UInt tagv[] = { RealReg, RealReg, RealReg };
3672 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3673
3674 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3675 else vg_assert(u->tag1 == NoValue);
3676 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3677 else vg_assert(u->tag2 == NoValue);
3678 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3679 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003680 vg_assert(u->size == 0);
3681
sewardjb91ae7f2003-04-29 23:50:00 +00003682 if (*sselive) {
3683 emit_put_sse_state();
3684 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003685 }
njn25e49d8e72002-09-23 09:36:25 +00003686 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3687 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003688 break;
njn25e49d8e72002-09-23 09:36:25 +00003689 }
sewardje1042472002-09-30 12:33:11 +00003690
sewardjde4a1d02002-03-22 01:27:54 +00003691 case CLEAR:
3692 vg_assert(u->tag1 == Lit16);
3693 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003694 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003695 break;
3696
3697 case CC2VAL:
3698 vg_assert(u->tag1 == RealReg);
3699 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003700 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003701 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003702 break;
3703
sewardjde4a1d02002-03-22 01:27:54 +00003704 case FPU_R:
3705 case FPU_W:
3706 vg_assert(u->tag1 == Lit16);
3707 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003708 if (!(*sselive)) {
3709 emit_get_sse_state();
3710 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003711 }
sewardjfa492d42002-12-08 18:20:01 +00003712 synth_fpu_regmem ( u->flags_r, u->flags_w,
3713 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003714 u->val1 & 0xFF,
3715 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003716 break;
3717
3718 case FPU:
3719 vg_assert(u->tag1 == Lit16);
3720 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003721 if (!(*sselive)) {
3722 emit_get_sse_state();
3723 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003724 }
sewardjfa492d42002-12-08 18:20:01 +00003725 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3726 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003727 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003728 break;
3729
sewardj3d7c9c82003-03-26 21:08:13 +00003730 case MMX2_MemWr:
3731 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003732 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003733 vg_assert(u->tag1 == Lit16);
3734 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003735 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003736 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003737 if (!(*sselive)) {
3738 emit_get_sse_state();
3739 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003740 }
3741 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3742 (u->val1 >> 8) & 0xFF,
3743 u->val1 & 0xFF,
3744 u->val2 );
3745 break;
3746
sewardj4fbe6e92003-06-15 21:54:34 +00003747 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00003748 vg_assert(u->tag1 == Lit16);
3749 vg_assert(u->tag2 == RealReg);
3750 vg_assert(u->tag3 == NoValue);
3751 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003752 if (!(*sselive)) {
3753 emit_get_sse_state();
3754 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003755 }
3756 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3757 (u->val1 >> 8) & 0xFF,
3758 u->val1 & 0xFF,
3759 u->val2 );
3760 break;
3761
sewardj4fbe6e92003-06-15 21:54:34 +00003762 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00003763 vg_assert(u->tag1 == Lit16);
3764 vg_assert(u->tag2 == RealReg);
3765 vg_assert(u->tag3 == NoValue);
3766 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003767 if (!(*sselive)) {
3768 emit_get_sse_state();
3769 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003770 }
3771 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3772 (u->val1 >> 8) & 0xFF,
3773 u->val1 & 0xFF,
3774 u->val2 );
3775 break;
3776
sewardj3d7c9c82003-03-26 21:08:13 +00003777 case MMX1:
3778 vg_assert(u->tag1 == Lit16);
3779 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003780 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003781 if (!(*sselive)) {
3782 emit_get_sse_state();
3783 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003784 }
3785 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3786 u->val1 & 0xFF );
3787 break;
3788
3789 case MMX2:
3790 vg_assert(u->tag1 == Lit16);
3791 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003792 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003793 if (!(*sselive)) {
3794 emit_get_sse_state();
3795 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003796 }
3797 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3798 (u->val1 >> 8) & 0xFF,
3799 u->val1 & 0xFF );
3800 break;
3801
sewardjca860012003-03-27 23:52:58 +00003802 case MMX3:
3803 vg_assert(u->tag1 == Lit16);
3804 vg_assert(u->tag2 == Lit16);
3805 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003806 if (!(*sselive)) {
3807 emit_get_sse_state();
3808 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003809 }
3810 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3811 (u->val1 >> 8) & 0xFF,
3812 u->val1 & 0xFF,
3813 u->val2 & 0xFF );
3814 break;
3815
sewardjfebaa3b2003-05-25 01:07:34 +00003816 case SSE2a_MemWr:
3817 case SSE2a_MemRd:
3818 vg_assert(u->size == 4 || u->size == 16);
3819 vg_assert(u->tag1 == Lit16);
3820 vg_assert(u->tag2 == Lit16);
3821 vg_assert(u->tag3 == RealReg);
3822 vg_assert(!anyFlagUse(u));
3823 if (!(*sselive)) {
3824 emit_get_sse_state();
3825 *sselive = True;
3826 }
3827 emit_SSE2a ( u->flags_r, u->flags_w,
3828 (u->val1 >> 8) & 0xFF,
3829 u->val1 & 0xFF,
3830 u->val2 & 0xFF,
3831 u->val3 );
3832 break;
3833
3834 case SSE3a_MemWr:
3835 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00003836 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00003837 vg_assert(u->tag1 == Lit16);
3838 vg_assert(u->tag2 == Lit16);
3839 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003840 if (!(*sselive)) {
3841 emit_get_sse_state();
3842 *sselive = True;
3843 }
3844 emit_SSE3a ( u->flags_r, u->flags_w,
3845 (u->val1 >> 8) & 0xFF,
3846 u->val1 & 0xFF,
3847 (u->val2 >> 8) & 0xFF,
3848 u->val2 & 0xFF,
3849 u->val3 );
3850 break;
3851
sewardjabf8bf82003-06-15 22:28:05 +00003852 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00003853 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00003854 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00003855 vg_assert(u->size == 4);
3856 vg_assert(u->tag1 == Lit16);
3857 vg_assert(u->tag2 == Lit16);
3858 vg_assert(u->tag3 == RealReg);
3859 vg_assert(!anyFlagUse(u));
3860 if (!(*sselive)) {
3861 emit_get_sse_state();
3862 *sselive = True;
3863 }
sewardjabf8bf82003-06-15 22:28:05 +00003864 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
3865 emit_SSE3e ( u->flags_r, u->flags_w,
3866 (u->val1 >> 8) & 0xFF,
3867 u->val1 & 0xFF,
3868 (u->val2 >> 8) & 0xFF,
3869 u->val2 & 0xFF,
3870 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00003871 } else {
sewardjabf8bf82003-06-15 22:28:05 +00003872 emit_SSE3g ( u->flags_r, u->flags_w,
3873 (u->val1 >> 8) & 0xFF,
3874 u->val1 & 0xFF,
3875 (u->val2 >> 8) & 0xFF,
3876 u->val2 & 0xFF,
3877 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00003878 }
sewardjfebaa3b2003-05-25 01:07:34 +00003879 break;
3880
sewardjb31b06d2003-06-13 00:26:02 +00003881 case SSE3g1_RegWr:
3882 vg_assert(u->size == 4);
3883 vg_assert(u->tag1 == Lit16);
3884 vg_assert(u->tag2 == Lit16);
3885 vg_assert(u->tag3 == RealReg);
3886 vg_assert(!anyFlagUse(u));
3887 if (!(*sselive)) {
3888 emit_get_sse_state();
3889 *sselive = True;
3890 }
sewardjabf8bf82003-06-15 22:28:05 +00003891 emit_SSE3g1 ( u->flags_r, u->flags_w,
3892 (u->val1 >> 8) & 0xFF,
3893 u->val1 & 0xFF,
3894 (u->val2 >> 8) & 0xFF,
3895 u->val2 & 0xFF,
3896 u->lit32 & 0xFF,
3897 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00003898 break;
3899
sewardj4fbe6e92003-06-15 21:54:34 +00003900 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00003901 vg_assert(u->size == 2);
3902 vg_assert(u->tag1 == Lit16);
3903 vg_assert(u->tag2 == Lit16);
3904 vg_assert(u->tag3 == RealReg);
3905 vg_assert(!anyFlagUse(u));
3906 if (!(*sselive)) {
3907 emit_get_sse_state();
3908 *sselive = True;
3909 }
sewardjabf8bf82003-06-15 22:28:05 +00003910 emit_SSE3e1 ( u->flags_r, u->flags_w,
3911 (u->val1 >> 8) & 0xFF,
3912 u->val1 & 0xFF,
3913 (u->val2 >> 8) & 0xFF,
3914 u->val2 & 0xFF,
3915 u->lit32 & 0xFF,
3916 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00003917 break;
3918
sewardja453fb02003-06-14 13:22:36 +00003919 case SSE5:
3920 vg_assert(u->size == 0);
3921 vg_assert(u->tag1 == Lit16);
3922 vg_assert(u->tag2 == Lit16);
3923 vg_assert(u->tag3 == Lit16);
3924 vg_assert(!anyFlagUse(u));
3925 if (!(*sselive)) {
3926 emit_get_sse_state();
3927 *sselive = True;
3928 }
3929 emit_SSE5 ( u->flags_r, u->flags_w,
3930 (u->val1 >> 8) & 0xFF,
3931 u->val1 & 0xFF,
3932 (u->val2 >> 8) & 0xFF,
3933 u->val2 & 0xFF,
3934 u->val3 & 0xFF );
3935 break;
3936
sewardjfebaa3b2003-05-25 01:07:34 +00003937 case SSE4:
3938 vg_assert(u->size == 0);
3939 vg_assert(u->tag1 == Lit16);
3940 vg_assert(u->tag2 == Lit16);
3941 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00003942 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00003943 if (!(*sselive)) {
3944 emit_get_sse_state();
3945 *sselive = True;
3946 }
3947 emit_SSE4 ( u->flags_r, u->flags_w,
3948 (u->val1 >> 8) & 0xFF,
3949 u->val1 & 0xFF,
3950 (u->val2 >> 8) & 0xFF,
3951 u->val2 & 0xFF );
3952 break;
3953
sewardja60be0e2003-05-26 08:47:27 +00003954 case SSE3:
3955 vg_assert(u->size == 0);
3956 vg_assert(u->tag1 == Lit16);
3957 vg_assert(u->tag2 == Lit16);
3958 vg_assert(u->tag3 == NoValue);
3959 vg_assert(!anyFlagUse(u));
3960 if (!(*sselive)) {
3961 emit_get_sse_state();
3962 *sselive = True;
3963 }
3964 emit_SSE3 ( u->flags_r, u->flags_w,
3965 (u->val1 >> 8) & 0xFF,
3966 u->val1 & 0xFF,
3967 u->val2 & 0xFF );
3968 break;
3969
sewardje3891fa2003-06-15 03:13:48 +00003970 case SSE3ag_MemRd_RegWr:
3971 vg_assert(u->size == 4 || u->size == 8);
3972 vg_assert(u->tag1 == RealReg);
3973 vg_assert(u->tag2 == RealReg);
3974 vg_assert(u->tag3 == NoValue);
3975 vg_assert(!anyFlagUse(u));
3976 if (!(*sselive)) {
3977 emit_get_sse_state();
3978 *sselive = True;
3979 }
3980 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
3981 (u->lit32 >> 24) & 0xFF,
3982 (u->lit32 >> 16) & 0xFF,
3983 (u->lit32 >> 8) & 0xFF,
3984 u->val1, u->val2 );
3985 break;
3986
sewardjde4a1d02002-03-22 01:27:54 +00003987 default:
sewardj1b7d8022002-11-30 12:35:42 +00003988 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00003989 if (*sselive) {
3990 emit_put_sse_state();
3991 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003992 }
njn4ba5a792002-09-30 10:23:54 +00003993 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00003994 } else {
njn25e49d8e72002-09-23 09:36:25 +00003995 VG_(printf)("\nError:\n"
3996 " unhandled opcode: %u. Perhaps "
3997 " VG_(needs).extended_UCode should be set?\n",
3998 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00003999 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004000 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004001 }
sewardjde4a1d02002-03-22 01:27:54 +00004002 }
4003
sewardjb91ae7f2003-04-29 23:50:00 +00004004 if (0 && (*sselive)) {
4005 emit_put_sse_state();
4006 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004007 }
4008
njn25e49d8e72002-09-23 09:36:25 +00004009 /* Update UInstr histogram */
4010 vg_assert(u->opcode < 100);
4011 histogram[u->opcode].counts++;
4012 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004013}
4014
4015
4016/* Emit x86 for the ucode in cb, returning the address of the
4017 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004018UChar* VG_(emit_code) ( UCodeBlock* cb,
4019 Int* nbytes,
4020 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004021{
4022 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004023 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004024 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004025 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004026 Int tgt;
4027
sewardjfa492d42002-12-08 18:20:01 +00004028 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004029
njn25e49d8e72002-09-23 09:36:25 +00004030 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004031
sewardj22854b92002-11-30 14:00:47 +00004032 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
4033 zero. We have to do this regardless of whether we're t-chaining
4034 or not. */
sewardja2113f92002-12-12 23:42:48 +00004035 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004036 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00004037 VG_(emitB) (0xFF); /* decl */
4038 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
4039 if (dis)
4040 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00004041 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00004042 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4043 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004044 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004045
sewardjb5ff83e2002-12-01 19:40:49 +00004046 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004047 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004048 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004049 curr_eip = cb->orig_eip;
4050 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4051 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004052 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004053 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004054 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004055 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004056
sewardjde4a1d02002-03-22 01:27:54 +00004057 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004058 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004059 if (!sane) {
4060 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004061 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004062 }
4063 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004064 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004065 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004066 }
njn25e49d8e72002-09-23 09:36:25 +00004067 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004068 }
njn25e49d8e72002-09-23 09:36:25 +00004069 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004070 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004071 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004072
sewardj22854b92002-11-30 14:00:47 +00004073 if (j != NULL) {
4074 vg_assert(jumpidx <= VG_MAX_JUMPS);
4075 for(i = 0; i < jumpidx; i++)
4076 j[i] = jumps[i];
4077 }
4078
sewardjde4a1d02002-03-22 01:27:54 +00004079 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004080 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004081 *nbytes = emitted_code_used;
4082 return emitted_code;
4083}
4084
njn25e49d8e72002-09-23 09:36:25 +00004085#undef dis
4086
sewardjde4a1d02002-03-22 01:27:54 +00004087/*--------------------------------------------------------------------*/
4088/*--- end vg_from_ucode.c ---*/
4089/*--------------------------------------------------------------------*/