blob: e5406c9ba220fa6f25ba9c804cb87bf0519c1385 [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
sewardj56867352003-10-12 10:27:06 +0000209/* __inline__ */
210void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000211{
njn25e49d8e72002-09-23 09:36:25 +0000212 VG_(emitB) ( (l) & 0x000000FF );
213 VG_(emitB) ( (l >> 8) & 0x000000FF );
214 VG_(emitB) ( (l >> 16) & 0x000000FF );
215 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000216}
217
sewardjfa492d42002-12-08 18:20:01 +0000218static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000219{
sewardjfa492d42002-12-08 18:20:01 +0000220 Int off = 4 * VGOFF_(m_eflags);
221 vg_assert(off >= 0 && off < 128);
222
223 if (dis)
224 VG_(printf)("\t %4d: ", emitted_code_used );
225
226 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
227 VG_(emitB) ( 0x75 );
228 VG_(emitB) ( off );
229 VG_(emitB) ( 0x9D ); /* POPFL */
230 if (dis)
231 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
232}
233
234static void emit_put_eflags ( void )
235{
236 Int off = 4 * VGOFF_(m_eflags);
237 vg_assert(off >= 0 && off < 128);
238
239 if (dis)
240 VG_(printf)("\t %4d: ", emitted_code_used );
241
242 VG_(emitB) ( 0x9C ); /* PUSHFL */
243 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
244 VG_(emitB) ( 0x45 );
245 VG_(emitB) ( off );
246 if (dis)
247 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
248}
249
250static void maybe_emit_put_eflags( void )
251{
252 if (eflags_state == UPD_Real) {
253 eflags_state = UPD_Both;
254 emit_put_eflags();
255 }
256}
257
sewardja2c5a732002-12-15 03:10:42 +0000258
259/* evidently unused */
260#if 0
sewardjfa492d42002-12-08 18:20:01 +0000261static void maybe_emit_get_eflags( void )
262{
263 if (eflags_state == UPD_Simd) {
264 eflags_state = UPD_Both;
265 emit_get_eflags();
266 }
267}
sewardja2c5a732002-12-15 03:10:42 +0000268#endif
sewardjfa492d42002-12-08 18:20:01 +0000269
sewardjf0f12aa2002-12-28 00:04:08 +0000270
271#if 0
272/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
273/* An alternative implementation of new_emit in which the
274 state space is explicitly enumerated. */
275__inline__
276void VG_(new_emit) ( Bool upds_simd_flags,
277 FlagSet use_flags, FlagSet set_flags )
278{
279 Bool simd = upds_simd_flags;
280 enum _eflags_state where = eflags_state;
281
282 enum { WNone, WSome, WAll } ww;
283 Bool rr;
284
285#define DIS_HEADER \
286 if (dis) \
287 VG_(printf)("\t %4d: ", emitted_code_used );
288
289 if (use_flags == FlagsEmpty) {
290 rr = False;
291 } else {
292 rr = True;
293 }
294
295 if (set_flags == FlagsEmpty) {
296 ww = WNone;
297 } else
298 if (set_flags == FlagsOSZACP) {
299 ww = WAll;
300 } else {
301 ww = WSome;
302 }
303
304 /* If we're not wanting to interact with simd flags, and the simd
305 flags are not in the real flags, then do nothing. */
306 if (simd == False && where == UPD_Simd)
307 goto noaction;
308
309 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
310 /* We're going to generate a complete new simd flag state without
311 consulting the old one first, so just deem this insn to create
312 the state in the real flags. */
313 eflags_state = UPD_Real;
314 DIS_HEADER;
315 return;
316 }
317
318 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
319 /* Want to partially update the flags state, but is in simd. So
320 fetch it first, then declare that the real state is the most
321 recent. */
322 emit_get_eflags();
323 eflags_state = UPD_Real;
324 DIS_HEADER;
325 return;
326 }
327
328 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
329 /* want to read simd flags, but not in real -> copy to real. */
330 emit_get_eflags();
331 eflags_state = UPD_Both;
332 DIS_HEADER;
333 return;
334 }
335
336 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
337 /* want to read and write simd flags, but not in real -> copy to
338 real. State is then Real since they get updated. */
339 emit_get_eflags();
340 eflags_state = UPD_Real;
341 DIS_HEADER;
342 return;
343 }
344
345 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
346 /* Doesn't really make sense. Want to interact with simd flags,
347 but insn doesn't modify them. So don't do anything. ??? */
348 goto noaction;
349 }
350
351 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
352 /* Doesn't really make sense. Want to interact with simd flags,
353 but insn doesn't modify them. So don't do anything. ??? */
354 goto noaction;
355 }
356
357 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
358 /* simd is in real. Insn reads real but does not change. --> do
359 nothing. */
360 goto noaction;
361 }
362
363 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
364 /* simd is in real. we want to capture changes made by it. -->
365 do nothing */
366 goto noaction;
367 }
368
369 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
370 /* simd is in real. Insn creates new simd state. --> leave in
371 real */
372 goto noaction;
373 }
374
375 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
376 /* simd is in both. Insn creates new simd state. --> change
377 state to Real. */
378 narrow_Both_to_Real:
379 eflags_state = UPD_Real;
380 DIS_HEADER;
381 return;
382 }
383
384 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
385 /* simd is in both. Insn creates partial new simd state. -->
386 change state to Real. No need to get, since Both holds. */
387 goto narrow_Both_to_Real;
388 }
389
390 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
391 /* simd is in real. Insn creates new simd state. --> leave in
392 real */
393 goto noaction;
394 }
395
396 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
397 /* want to read the simd flags, but already have a copy in real,
398 and not planning to modify it --> do nothing. */
399 goto noaction;
400
401 ////////////////
402
403 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
404 /* simd state is in real, but insn doesn't touch it --> do nothing */
405 goto noaction;
406
407 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
408 /* simd state is in both, insn doesn't touch it --> do nothing */
409 goto noaction;
410
411 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
412 /* simd state is in both. insn trashes real, therefore declare
413 simd state only in simd. */
414 narrow_Both_to_Simd:
415 eflags_state = UPD_Simd;
416 DIS_HEADER;
417 return;
418 }
419
420 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
421 /* simd state is in both. insn trashes real, therefore declare
422 simd state only in simd. */
423 goto narrow_Both_to_Simd;
424 }
425
426 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
427 /* simd state is in real; we don't want simd state changed, but
428 insn writes the flags. Therefore have to copy back first. */
429 put_flags_and_continue:
430 emit_put_eflags();
431 eflags_state = UPD_Simd;
432 DIS_HEADER;
433 return;
434 }
435
436 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
437 /* simd state is in real; we don't want simd state changed, but
438 insn writes the flags. Therefore have to copy back first. */
439 goto put_flags_and_continue;
440 }
441
442 goto unhandled;
443
444 noaction:
445 DIS_HEADER;
446 return;
447
448 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
449 // return;
450 //}
451
452 unhandled:
453 VG_(printf)("simd %s, where %s, read %s, write %s\n",
454 simd ? "True " : "False",
455 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
456 ? "Real" : "Both")),
457 rr ? "True " : "False",
458 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
459 );
460
461 VG_(core_panic)("new_emit");
462}
463/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
464#endif
465
466
sewardjfa492d42002-12-08 18:20:01 +0000467/* Call this before emitting each instruction.
468
469 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000470 interacts_with_simd_flags:
471 if true, this instruction wants to interact (read and/or write)
472 the simulated %EFLAGS state,
473 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000474 use_flags: set of (real) flags the instruction uses
475 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000476*/
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
daywalkerf26b2162003-09-30 23:01:50 +00001323void VG_( emit_movzwl_regmem_reg ) ( Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001324{
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
sewardj9dd209f2003-06-18 23:30:52 +00001440static void emit_SSE2a1 ( 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 third_byte &= 0x38; /* mask out mod and rm fields */
1452 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1453 VG_(emitB) ( fourth_byte );
1454 if (dis)
1455 VG_(printf)("\n\t\tsse2a1-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1456 (UInt)first_byte, (UInt)second_byte,
1457 (UInt)third_byte, (UInt)fourth_byte,
1458 nameIReg(4,ireg) );
1459}
1460
sewardjfebaa3b2003-05-25 01:07:34 +00001461static void emit_SSE3a ( FlagSet uses_sflags,
1462 FlagSet sets_sflags,
1463 UChar first_byte,
1464 UChar second_byte,
1465 UChar third_byte,
1466 UChar fourth_byte,
1467 Int ireg )
1468{
1469 VG_(new_emit)(True, uses_sflags, sets_sflags);
1470 VG_(emitB) ( first_byte );
1471 VG_(emitB) ( second_byte );
1472 VG_(emitB) ( third_byte );
1473 fourth_byte &= 0x38; /* mask out mod and rm fields */
1474 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1475 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001476 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001477 (UInt)first_byte, (UInt)second_byte,
1478 (UInt)third_byte, (UInt)fourth_byte,
1479 nameIReg(4,ireg) );
1480}
1481
sewardjabf8bf82003-06-15 22:28:05 +00001482static void emit_SSE3e ( FlagSet uses_sflags,
1483 FlagSet sets_sflags,
1484 UChar first_byte,
1485 UChar second_byte,
1486 UChar third_byte,
1487 UChar fourth_byte,
1488 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001489{
1490 VG_(new_emit)(True, uses_sflags, sets_sflags);
1491 VG_(emitB) ( first_byte );
1492 VG_(emitB) ( second_byte );
1493 VG_(emitB) ( third_byte );
1494 fourth_byte &= 0x38; /* mask out mod and rm fields */
1495 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1496 fourth_byte |= (ireg & 7); /* patch in our ireg */
1497 VG_(emitB) ( fourth_byte );
1498 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001499 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001500 "\n\t\tsse3e--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001501 (UInt)first_byte, (UInt)second_byte,
1502 (UInt)third_byte, (UInt)fourth_byte,
1503 nameIReg(4,ireg)
1504 );
sewardjfebaa3b2003-05-25 01:07:34 +00001505}
1506
sewardjabf8bf82003-06-15 22:28:05 +00001507static void emit_SSE3e1 ( FlagSet uses_sflags,
1508 FlagSet sets_sflags,
1509 UChar first_byte,
1510 UChar second_byte,
1511 UChar third_byte,
1512 UChar fourth_byte,
1513 UChar fifth_byte,
1514 Int ireg )
sewardj8f33ba62003-06-14 12:00:45 +00001515{
1516 VG_(new_emit)(True, uses_sflags, sets_sflags);
1517 VG_(emitB) ( first_byte );
1518 VG_(emitB) ( second_byte );
1519 VG_(emitB) ( third_byte );
1520 fourth_byte &= 0x38; /* mask out mod and rm fields */
1521 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1522 fourth_byte |= (ireg & 7); /* patch in our ireg */
1523 VG_(emitB) ( fourth_byte );
1524 VG_(emitB) ( fifth_byte );
1525 if (dis)
1526 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001527 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001528 (UInt)first_byte, (UInt)second_byte,
1529 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1530 nameIReg(4,ireg)
1531 );
1532}
1533
sewardjabf8bf82003-06-15 22:28:05 +00001534static void emit_SSE3g1 ( FlagSet uses_sflags,
1535 FlagSet sets_sflags,
1536 UChar first_byte,
1537 UChar second_byte,
1538 UChar third_byte,
1539 UChar fourth_byte,
1540 UChar fifth_byte,
1541 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001542{
1543 VG_(new_emit)(True, uses_sflags, sets_sflags);
1544 VG_(emitB) ( first_byte );
1545 VG_(emitB) ( second_byte );
1546 VG_(emitB) ( third_byte );
1547 fourth_byte &= 0xC7; /* mask out reg field */
1548 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1549 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1550 VG_(emitB) ( fourth_byte );
1551 VG_(emitB) ( fifth_byte );
1552 if (dis)
1553 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001554 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001555 (UInt)first_byte, (UInt)second_byte,
1556 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1557 nameIReg(4,ireg)
1558 );
1559}
1560
sewardjabf8bf82003-06-15 22:28:05 +00001561static void emit_SSE3g ( FlagSet uses_sflags,
1562 FlagSet sets_sflags,
1563 UChar first_byte,
1564 UChar second_byte,
1565 UChar third_byte,
1566 UChar fourth_byte,
1567 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001568{
1569 VG_(new_emit)(True, uses_sflags, sets_sflags);
1570 VG_(emitB) ( first_byte );
1571 VG_(emitB) ( second_byte );
1572 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001573 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001574 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001575 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001576 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001577 if (dis)
1578 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001579 "\n\t\tsse3g--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001580 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001581 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001582 nameIReg(4,ireg)
1583 );
1584}
1585
sewardj77d30a22003-10-19 08:18:52 +00001586static void emit_SSE3a1 ( FlagSet uses_sflags,
1587 FlagSet sets_sflags,
1588 UChar first_byte,
1589 UChar second_byte,
1590 UChar third_byte,
1591 UChar fourth_byte,
1592 UChar fifth_byte,
1593 Int ireg )
1594{
1595 VG_(new_emit)(True, uses_sflags, sets_sflags);
1596 VG_(emitB) ( first_byte );
1597 VG_(emitB) ( second_byte );
1598 VG_(emitB) ( third_byte );
1599 fourth_byte &= 0x38; /* mask out mod and rm fields */
1600 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1601 VG_(emitB) ( fifth_byte );
1602 if (dis)
1603 VG_(printf)("\n\t\tsse3a1-0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1604 (UInt)first_byte, (UInt)second_byte,
1605 (UInt)third_byte, (UInt)fourth_byte,
1606 (UInt)fifth_byte,
1607 nameIReg(4,ireg) );
1608}
1609
sewardjfebaa3b2003-05-25 01:07:34 +00001610static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001611 FlagSet sets_sflags,
1612 UChar first_byte,
1613 UChar second_byte,
1614 UChar third_byte,
1615 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001616{
1617 VG_(new_emit)(True, uses_sflags, sets_sflags);
1618 VG_(emitB) ( first_byte );
1619 VG_(emitB) ( second_byte );
1620 VG_(emitB) ( third_byte );
1621 VG_(emitB) ( fourth_byte );
1622 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001623 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001624 (UInt)first_byte, (UInt)second_byte,
1625 (UInt)third_byte, (UInt)fourth_byte );
1626}
1627
sewardja453fb02003-06-14 13:22:36 +00001628static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001629 FlagSet sets_sflags,
1630 UChar first_byte,
1631 UChar second_byte,
1632 UChar third_byte,
1633 UChar fourth_byte,
1634 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001635{
1636 VG_(new_emit)(True, uses_sflags, sets_sflags);
1637 VG_(emitB) ( first_byte );
1638 VG_(emitB) ( second_byte );
1639 VG_(emitB) ( third_byte );
1640 VG_(emitB) ( fourth_byte );
1641 VG_(emitB) ( fifth_byte );
1642 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001643 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001644 (UInt)first_byte, (UInt)second_byte,
1645 (UInt)third_byte, (UInt)fourth_byte,
1646 (UInt)fifth_byte );
1647}
1648
sewardja60be0e2003-05-26 08:47:27 +00001649static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001650 FlagSet sets_sflags,
1651 UChar first_byte,
1652 UChar second_byte,
1653 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001654{
1655 VG_(new_emit)(True, uses_sflags, sets_sflags);
1656 VG_(emitB) ( first_byte );
1657 VG_(emitB) ( second_byte );
1658 VG_(emitB) ( third_byte );
1659 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001660 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001661 (UInt)first_byte, (UInt)second_byte,
1662 (UInt)third_byte );
1663}
1664
sewardje3891fa2003-06-15 03:13:48 +00001665static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1666 FlagSet sets_sflags,
1667 UChar first_byte,
1668 UChar second_byte,
1669 UChar third_byte,
1670 Int addr_reg,
1671 Int dest_reg )
1672{
1673 VG_(new_emit)(True, uses_sflags, sets_sflags);
1674 VG_(emitB) ( first_byte );
1675 VG_(emitB) ( second_byte );
1676 VG_(emitB) ( third_byte );
1677 /* 4th byte can be completely synthesised from addr_reg and
1678 dest_reg. */
1679 emit_amode_regmem_reg ( addr_reg, dest_reg );
1680 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001681 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 +00001682 (UInt)first_byte, (UInt)second_byte,
1683 (UInt)third_byte, nameIReg(4, addr_reg),
1684 nameIReg(4, dest_reg));
1685}
1686
sewardjca860012003-03-27 23:52:58 +00001687static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1688 FlagSet sets_sflags,
1689 UChar first_byte,
1690 UChar second_byte,
1691 Int ireg )
1692{
1693 VG_(new_emit)(True, uses_sflags, sets_sflags);
1694 VG_(emitB) ( 0x0F );
1695 VG_(emitB) ( first_byte );
1696 second_byte &= 0x38; /* mask out mod and rm fields */
1697 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1698 second_byte |= (ireg & 7); /* patch in our ireg */
1699 VG_(emitB) ( second_byte );
1700 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001701 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1702 (UInt)first_byte, (UInt)second_byte,
1703 nameIReg(4,ireg) );
1704}
1705
1706static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1707 FlagSet sets_sflags,
1708 UChar first_byte,
1709 UChar second_byte,
1710 Int ireg )
1711{
1712 VG_(new_emit)(True, uses_sflags, sets_sflags);
1713 VG_(emitB) ( 0x0F );
1714 VG_(emitB) ( first_byte );
1715 second_byte &= 0x38; /* mask out mod and rm fields */
1716 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1717 second_byte |= (ireg & 7); /* patch in our ireg */
1718 VG_(emitB) ( second_byte );
1719 if (dis)
1720 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001721 (UInt)first_byte, (UInt)second_byte,
1722 nameIReg(4,ireg) );
1723}
1724
1725static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1726 FlagSet sets_sflags,
1727 UChar first_byte,
1728 UChar second_byte,
1729 UChar third_byte )
1730{
1731 VG_(new_emit)(True, uses_sflags, sets_sflags);
1732 VG_(emitB) ( 0x0F );
1733 VG_(emitB) ( first_byte );
1734 VG_(emitB) ( second_byte );
1735 VG_(emitB) ( third_byte );
1736 if (dis)
1737 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1738 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1739}
1740
sewardj3d7c9c82003-03-26 21:08:13 +00001741static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1742 FlagSet sets_sflags,
1743 UChar first_byte,
1744 UChar second_byte )
1745{
1746 VG_(new_emit)(True, uses_sflags, sets_sflags);
1747 VG_(emitB) ( 0x0F );
1748 VG_(emitB) ( first_byte );
1749 VG_(emitB) ( second_byte );
1750 if (dis)
1751 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1752 (UInt)first_byte, (UInt)second_byte );
1753}
1754
1755static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1756 FlagSet sets_sflags,
1757 UChar first_byte )
1758{
1759 VG_(new_emit)(True, uses_sflags, sets_sflags);
1760 VG_(emitB) ( 0x0F );
1761 VG_(emitB) ( first_byte );
1762 if (dis)
1763 VG_(printf)("\n\t\tmmx1-0x%x\n",
1764 (UInt)first_byte );
1765}
1766
sewardjde4a1d02002-03-22 01:27:54 +00001767
1768/*----------------------------------------------------*/
1769/*--- misc instruction emitters ---*/
1770/*----------------------------------------------------*/
1771
njn25e49d8e72002-09-23 09:36:25 +00001772void VG_(emit_call_reg) ( Int reg )
1773{
sewardjfa492d42002-12-08 18:20:01 +00001774 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001775 VG_(emitB) ( 0xFF ); /* Grp5 */
1776 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1777 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001778 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001779}
1780
sewardjf0f12aa2002-12-28 00:04:08 +00001781static
1782void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1783 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001784{
sewardjfa492d42002-12-08 18:20:01 +00001785 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001786 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001787
1788 if (byte_off < -128 || byte_off > 127) {
1789 VG_(emitB) ( 0xFF );
1790 VG_(emitB) ( 0x95 );
1791 VG_(emitL) ( byte_off );
1792 } else {
1793 VG_(emitB) ( 0xFF );
1794 VG_(emitB) ( 0x55 );
1795 VG_(emitB) ( byte_off );
1796 }
1797 if (dis)
1798 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001799}
1800
sewardja2c5a732002-12-15 03:10:42 +00001801#if 0
1802/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001803static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1804{
1805 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001806 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001807 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1808 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001809 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001810 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001811 if (dis)
1812 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1813 nameIReg(4,regmem));
1814}
sewardja2c5a732002-12-15 03:10:42 +00001815#endif
sewardjde4a1d02002-03-22 01:27:54 +00001816
njn25e49d8e72002-09-23 09:36:25 +00001817void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001818{
njne427a662002-10-02 11:08:25 +00001819 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001820 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1821 VG_(emitB) ( 0x8D );
1822 VG_(emitB) ( 0x64 );
1823 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001824 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001825 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001826 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001827}
1828
1829
1830static void emit_movb_AL_zeroESPmem ( void )
1831{
1832 /* movb %al, 0(%esp) */
1833 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001834 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001835 VG_(emitB) ( 0x88 );
1836 VG_(emitB) ( 0x44 );
1837 VG_(emitB) ( 0x24 );
1838 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001839 if (dis)
1840 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1841}
1842
1843static void emit_movb_zeroESPmem_AL ( void )
1844{
1845 /* movb 0(%esp), %al */
1846 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001847 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001848 VG_(emitB) ( 0x8A );
1849 VG_(emitB) ( 0x44 );
1850 VG_(emitB) ( 0x24 );
1851 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001852 if (dis)
1853 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1854}
1855
sewardja2113f92002-12-12 23:42:48 +00001856/* Jump target states */
1857#define TGT_UNDEF (1 << 16)
1858#define TGT_FORWARD (2 << 16)
1859#define TGT_BACKWARD (3 << 16)
1860
1861static inline Int tgt_state(Int tgt)
1862{
1863 return tgt & 0xffff0000;
1864}
1865
1866static inline Int tgt_addr(Int tgt)
1867{
1868 return tgt & 0x0000ffff;
1869}
1870
1871static inline Int mk_tgt(Int state, Int addr)
1872{
1873 vg_assert(state == TGT_UNDEF
1874 || state == TGT_FORWARD || state == TGT_BACKWARD);
1875 vg_assert((addr & 0xffff0000) == 0);
1876
1877 return state | addr;
1878}
1879
1880void VG_(init_target) ( Int *tgt )
1881{
1882 *tgt = TGT_UNDEF;
1883}
1884
1885void VG_(target_back) ( Int *tgt )
1886{
1887 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1888
1889 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1890}
1891
1892void VG_(target_forward) ( Int *tgt )
1893{
1894 Int delta;
1895
1896 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1897 tgt_state(*tgt) == TGT_UNDEF);
1898
1899 if (tgt_state(*tgt) == TGT_UNDEF)
1900 return; /* target not used */
1901
1902 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1903 vg_assert(delta >= -128 && delta <= 127);
1904 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001905 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001906 emitted_code[tgt_addr(*tgt)] = delta;
1907 if (dis)
1908 VG_(printf)("(target to jump site %d; delta: %d)\n",
1909 tgt_addr(*tgt), delta);
1910}
1911
1912void VG_(emit_target_delta) ( Int *tgt )
1913{
1914 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1915 tgt_state(*tgt) == TGT_BACKWARD);
1916
1917 if (tgt_state(*tgt) == TGT_UNDEF) {
1918 /* forward jump */
1919 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1920 VG_(emitB) (0x00);
1921 } else {
1922 /* backward jump */
1923 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1924 vg_assert(delta >= -128 && delta <= 127);
1925 VG_(emitB) (delta);
1926 }
1927}
1928
sewardjde4a1d02002-03-22 01:27:54 +00001929
1930/* Emit a jump short with an 8-bit signed offset. Note that the
1931 offset is that which should be added to %eip once %eip has been
1932 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001933void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001934{
1935 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001936 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001937 VG_(emitB) ( 0x70 + (UInt)cond );
1938 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001939 if (dis)
1940 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001941 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001942}
1943
sewardja2113f92002-12-12 23:42:48 +00001944/* Same as above, but defers emitting the delta */
1945void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1946{
sewardj706240d2002-12-26 17:10:12 +00001947 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001948 VG_(emitB) ( 0x70 + (UInt)cond );
1949 VG_(emit_target_delta) (tgt);
1950 if (dis)
1951 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001952 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001953}
1954
1955
1956
sewardjf0f12aa2002-12-28 00:04:08 +00001957static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001958{
sewardjf0f12aa2002-12-28 00:04:08 +00001959 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001960 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1961 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001962 if (dis)
1963 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001964 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001965}
1966
1967static void emit_ret ( void )
1968{
sewardjfa492d42002-12-08 18:20:01 +00001969 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001970 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001971 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001972 if (dis)
1973 VG_(printf)("\n\t\tret\n");
1974}
1975
sewardj22854b92002-11-30 14:00:47 +00001976/* Predicate used in sanity checks elsewhere - returns true if any
1977 jump-site is an actual chained jump */
1978Bool VG_(is_chained_jumpsite)(Addr a)
1979{
1980 UChar *cp = (UChar *)a;
1981
1982 return (*cp == 0xE9); /* 0xE9 -- jmp */
1983}
1984
sewardj83f11862002-12-01 02:07:08 +00001985static
1986Bool is_fresh_jumpsite(UChar *cp)
1987{
1988 return
1989 cp[0] == 0x0F && /* UD2 */
1990 cp[1] == 0x0B &&
1991 cp[2] == 0x0F && /* UD2 */
1992 cp[3] == 0x0B &&
1993 cp[4] == 0x90; /* NOP */
1994}
1995
sewardj22854b92002-11-30 14:00:47 +00001996/* Predicate used in sanity checks elsewhere - returns true if all
1997 jump-sites are calls to VG_(patch_me) */
1998Bool VG_(is_unchained_jumpsite)(Addr a)
1999{
2000 UChar *cp = (UChar *)a;
2001 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2002 Int idelta;
2003
2004 if (*cp++ != 0xE8) /* 0xE8 == call */
2005 return False;
2006
2007 idelta = (*cp++) << 0;
2008 idelta |= (*cp++) << 8;
2009 idelta |= (*cp++) << 16;
2010 idelta |= (*cp++) << 24;
2011
2012 return idelta == delta;
2013}
2014
2015/* Return target address for a direct jmp */
2016Addr VG_(get_jmp_dest)(Addr a)
2017{
2018 Int delta;
2019 UChar *cp = (UChar *)a;
2020
2021 if (*cp++ != 0xE9) /* 0xE9 == jmp */
2022 return 0;
2023
2024 delta = (*cp++) << 0;
2025 delta |= (*cp++) << 8;
2026 delta |= (*cp++) << 16;
2027 delta |= (*cp++) << 24;
2028
2029 return a + VG_PATCHME_JMPSZ + delta;
2030}
2031
2032/* unchain a BB by generating a call to VG_(patch_me) */
2033void VG_(unchain_jumpsite)(Addr a)
2034{
2035 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2036 UChar *cp = (UChar *)a;
2037
2038 if (VG_(is_unchained_jumpsite)(a))
2039 return; /* don't write unnecessarily */
2040
sewardj83f11862002-12-01 02:07:08 +00002041 if (!is_fresh_jumpsite(cp))
2042 VG_(bb_dechain_count)++; /* update stats */
2043
sewardj22854b92002-11-30 14:00:47 +00002044 *cp++ = 0xE8; /* call */
2045 *cp++ = (delta >> 0) & 0xff;
2046 *cp++ = (delta >> 8) & 0xff;
2047 *cp++ = (delta >> 16) & 0xff;
2048 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002049}
2050
2051/* This doesn't actually generate a call to VG_(patch_me), but
2052 reserves enough space in the instruction stream for it to happen
2053 and records the offset into the jump table. This is because call
2054 is a relative jump, and so will be affected when this code gets
2055 moved about. The translation table will "unchain" this basic block
2056 on insertion (with VG_(unchain_BB)()), and thereby generate a
2057 proper call instruction. */
2058static void emit_call_patchme( void )
2059{
2060 vg_assert(VG_PATCHME_CALLSZ == 5);
2061
sewardjfa492d42002-12-08 18:20:01 +00002062 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002063 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002064
2065 if (jumpidx >= VG_MAX_JUMPS) {
2066 /* If there too many jumps in this basic block, fall back to
2067 dispatch loop. We still need to keep it the same size as the
2068 call sequence. */
2069 VG_(emitB) ( 0xC3 ); /* ret */
2070 VG_(emitB) ( 0x90 ); /* nop */
2071 VG_(emitB) ( 0x90 ); /* nop */
2072 VG_(emitB) ( 0x90 ); /* nop */
2073 VG_(emitB) ( 0x90 ); /* nop */
2074
2075 if (dis)
2076 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
2077
2078 if (0 && VG_(clo_verbosity))
2079 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2080 } else {
2081 jumps[jumpidx++] = emitted_code_used;
2082
2083 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2084 VG_(emitB) ( 0x0B );
2085 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2086 VG_(emitB) ( 0x0B );
2087 VG_(emitB) ( 0x90 ); /* NOP */
2088
2089 if (dis)
2090 VG_(printf)("\n\t\tud2; ud2; nop\n");
2091 }
2092}
2093
njn25e49d8e72002-09-23 09:36:25 +00002094void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002095{
sewardjf0f12aa2002-12-28 00:04:08 +00002096 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002097 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002098 if (dis)
2099 VG_(printf)("\n\t\tpushal\n");
2100}
2101
njn25e49d8e72002-09-23 09:36:25 +00002102void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002103{
sewardjf0f12aa2002-12-28 00:04:08 +00002104 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002105 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002106 if (dis)
2107 VG_(printf)("\n\t\tpopal\n");
2108}
2109
2110static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2111{
sewardjf0f12aa2002-12-28 00:04:08 +00002112 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002113 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2114 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002115 if (dis)
2116 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2117 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2118}
2119
2120static void emit_lea_sib_reg ( UInt lit, Int scale,
2121 Int regbase, Int regindex, Int reg )
2122{
sewardjf0f12aa2002-12-28 00:04:08 +00002123 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002124 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002125 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2126 if (dis)
2127 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2128 lit, nameIReg(4,regbase),
2129 nameIReg(4,regindex), scale,
2130 nameIReg(4,reg) );
2131}
2132
njn25e49d8e72002-09-23 09:36:25 +00002133void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002134{
sewardjf0f12aa2002-12-28 00:04:08 +00002135 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002136 VG_(emitB) ( 0x0F );
2137 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002138 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2139 if (dis)
2140 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2141}
2142
2143/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002144/*--- Helper offset -> addr translation ---*/
2145/*----------------------------------------------------*/
2146
2147/* Finds the baseBlock offset of a skin-specified helper.
2148 * Searches through compacts first, then non-compacts. */
2149Int VG_(helper_offset)(Addr a)
2150{
sewardj05bcdcb2003-05-18 10:05:38 +00002151 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002152 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002153
2154 for (i = 0; i < VG_(n_compact_helpers); i++)
2155 if (VG_(compact_helper_addrs)[i] == a)
2156 return VG_(compact_helper_offsets)[i];
2157 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2158 if (VG_(noncompact_helper_addrs)[i] == a)
2159 return VG_(noncompact_helper_offsets)[i];
2160
2161 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002162 VG_(get_fnname) ( a, buf, 100 );
2163
njn25e49d8e72002-09-23 09:36:25 +00002164 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002165 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2166 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002167
2168 VG_(printf)(" compact helpers: ");
2169 for (i = 0; i < VG_(n_compact_helpers); i++)
2170 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2171
2172 VG_(printf)("\n non-compact helpers: ");
2173 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2174 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2175
2176 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002177 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002178}
2179
2180/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002181/*--- Instruction synthesisers ---*/
2182/*----------------------------------------------------*/
2183
2184static Condcode invertCondition ( Condcode cond )
2185{
2186 return (Condcode)(1 ^ (UInt)cond);
2187}
2188
2189
2190/* Synthesise a call to *baseBlock[offset], ie,
2191 call * (4 x offset)(%ebp).
2192*/
sewardjfa492d42002-12-08 18:20:01 +00002193void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002194 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002195{
2196 vg_assert(word_offset >= 0);
2197 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002198 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002199 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002200 }
sewardjf0f12aa2002-12-28 00:04:08 +00002201 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002202}
2203
njn25e49d8e72002-09-23 09:36:25 +00002204static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002205{
njn25e49d8e72002-09-23 09:36:25 +00002206 if (src != dst) {
2207 VG_(emit_movv_reg_reg) ( 4, src, dst );
2208 ccall_arg_setup_instrs++;
2209 }
njn6431be72002-07-28 09:53:34 +00002210}
njn25e49d8e72002-09-23 09:36:25 +00002211
2212/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2213static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2214{
2215 if (RealReg == tag) {
2216 maybe_emit_movl_reg_reg ( litOrReg, reg );
2217 } else if (Literal == tag) {
2218 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2219 ccall_arg_setup_instrs++;
2220 }
2221 else
njne427a662002-10-02 11:08:25 +00002222 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002223}
2224
2225static
2226void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2227{
2228 if (R_EAX == reg1) {
2229 VG_(emit_swapl_reg_EAX) ( reg2 );
2230 } else if (R_EAX == reg2) {
2231 VG_(emit_swapl_reg_EAX) ( reg1 );
2232 } else {
2233 emit_swapl_reg_reg ( reg1, reg2 );
2234 }
2235 ccall_arg_setup_instrs++;
2236}
2237
2238static
2239void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2240{
2241 if (dst1 != src2) {
2242 maybe_emit_movl_reg_reg ( src1, dst1 );
2243 maybe_emit_movl_reg_reg ( src2, dst2 );
2244
2245 } else if (dst2 != src1) {
2246 maybe_emit_movl_reg_reg ( src2, dst2 );
2247 maybe_emit_movl_reg_reg ( src1, dst1 );
2248
2249 } else {
2250 /* swap to break cycle */
2251 emit_swapl_arg_regs ( dst1, dst2 );
2252 }
2253}
2254
2255static
2256void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2257 UInt dst1, UInt dst2, UInt dst3)
2258{
2259 if (dst1 != src2 && dst1 != src3) {
2260 maybe_emit_movl_reg_reg ( src1, dst1 );
2261 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2262
2263 } else if (dst2 != src1 && dst2 != src3) {
2264 maybe_emit_movl_reg_reg ( src2, dst2 );
2265 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2266
2267 } else if (dst3 != src1 && dst3 != src2) {
2268 maybe_emit_movl_reg_reg ( src3, dst3 );
2269 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2270
2271 } else {
2272 /* break cycle */
2273 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2274 emit_swapl_arg_regs ( dst1, dst2 );
2275 emit_swapl_arg_regs ( dst1, dst3 );
2276
2277 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2278 emit_swapl_arg_regs ( dst1, dst3 );
2279 emit_swapl_arg_regs ( dst1, dst2 );
2280
2281 } else {
njne427a662002-10-02 11:08:25 +00002282 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002283 }
2284 }
2285}
2286
2287static
2288void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2289 UInt src1, UInt src2,
2290 UInt dst1, UInt dst2)
2291{
2292 /* If either are lits, order doesn't matter */
2293 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2294 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2295 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2296
2297 } else {
2298 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2299 }
2300}
2301
2302static
2303void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2304 UInt src1, UInt src2, UInt src3,
2305 UInt dst1, UInt dst2, UInt dst3)
2306{
2307 // SSS: fix this eventually -- make STOREV use two RealRegs?
2308 /* Not supporting literals for 3-arg C functions -- they're only used
2309 by STOREV which has 2 args */
2310 vg_assert(RealReg == tagv[src1] &&
2311 RealReg == tagv[src2] &&
2312 RealReg == tagv[src3]);
2313 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2314 dst1, dst2, dst3 );
2315}
2316
2317/* Synthesise a call to a C function `fn' (which must be registered in
2318 baseBlock) doing all the reg saving and arg handling work.
2319
2320 WARNING: a UInstr should *not* be translated with synth_ccall followed
2321 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2322 such behaviour and everything will fall over.
2323 */
2324void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2325 Tag tagv[], Int ret_reg,
2326 RRegSet regs_live_before, RRegSet regs_live_after )
2327{
2328 Int i;
2329 Int stack_used = 0;
2330 Bool preserve_eax, preserve_ecx, preserve_edx;
2331
2332 vg_assert(0 <= regparms_n && regparms_n <= 3);
2333
2334 ccalls++;
2335
2336 /* If %e[acd]x is live before and after the C call, save/restore it.
2337 Unless the return values clobbers the reg; in this case we must not
2338 save/restore the reg, because the restore would clobber the return
2339 value. (Before and after the UInstr really constitute separate live
2340 ranges, but you miss this if you don't consider what happens during
2341 the UInstr.) */
2342# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002343 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2344 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002345 ret_reg != realReg)
2346
2347 preserve_eax = PRESERVE_REG(R_EAX);
2348 preserve_ecx = PRESERVE_REG(R_ECX);
2349 preserve_edx = PRESERVE_REG(R_EDX);
2350
2351# undef PRESERVE_REG
2352
2353 /* Save caller-save regs as required */
2354 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2355 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2356 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2357
2358 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2359 is the number of args passed in regs (maximum 3 for GCC on x86). */
2360
2361 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002362
njn25e49d8e72002-09-23 09:36:25 +00002363 /* First push stack args (RealRegs or Literals) in reverse order. */
2364 for (i = argc-1; i >= regparms_n; i--) {
2365 switch (tagv[i]) {
2366 case RealReg:
2367 VG_(emit_pushv_reg) ( 4, argv[i] );
2368 break;
2369 case Literal:
2370 /* Use short form of pushl if possible. */
2371 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2372 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2373 else
2374 VG_(emit_pushl_lit32)( argv[i] );
2375 break;
2376 default:
2377 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002378 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002379 }
2380 stack_used += 4;
2381 ccall_arg_setup_instrs++;
2382 }
njn6431be72002-07-28 09:53:34 +00002383
njn25e49d8e72002-09-23 09:36:25 +00002384 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2385 If moving values between registers, be careful not to clobber any on
2386 the way. Happily we can use xchgl to swap registers.
2387 */
2388 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002389
njn25e49d8e72002-09-23 09:36:25 +00002390 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2391 case 3:
2392 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2393 R_EAX, R_EDX, R_ECX );
2394 break;
njn6431be72002-07-28 09:53:34 +00002395
njn25e49d8e72002-09-23 09:36:25 +00002396 /* Less-tricky. Args passed in %eax and %edx. */
2397 case 2:
2398 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2399 break;
2400
2401 /* Easy. Just move arg1 into %eax (if not already in there). */
2402 case 1:
2403 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2404 break;
2405
2406 case 0:
2407 break;
2408
2409 default:
njne427a662002-10-02 11:08:25 +00002410 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002411 }
2412
sewardjfa492d42002-12-08 18:20:01 +00002413 /* Call the function - may trash all flags */
2414 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002415
2416 /* Clear any args from stack */
2417 if (0 != stack_used) {
2418 VG_(emit_add_lit_to_esp) ( stack_used );
2419 ccall_stack_clears++;
2420 }
2421
2422 /* Move return value into ret_reg if necessary and not already there */
2423 if (INVALID_REALREG != ret_reg) {
2424 ccall_retvals++;
2425 if (R_EAX != ret_reg) {
2426 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2427 ccall_retval_movs++;
2428 }
2429 }
2430
2431 /* Restore live caller-save regs as required */
2432 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2433 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2434 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002435}
sewardjde4a1d02002-03-22 01:27:54 +00002436
sewardj2e93c502002-04-12 11:12:52 +00002437static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002438{
sewardj2e93c502002-04-12 11:12:52 +00002439 switch (jmpkind) {
2440 case JmpBoring:
2441 break;
sewardj2e93c502002-04-12 11:12:52 +00002442 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002443 break;
2444 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002445 break;
2446 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002447 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002448 break;
2449 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002450 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002451 break;
2452 default:
njne427a662002-10-02 11:08:25 +00002453 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002454 }
2455}
2456
2457/* Jump to the next translation, by loading its original addr into
2458 %eax and returning to the scheduler. Signal special requirements
2459 by loading a special value into %ebp first.
2460*/
2461static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2462{
sewardjfa492d42002-12-08 18:20:01 +00002463 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002464 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002465 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002466 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002467 emit_ret();
2468}
2469
sewardj22854b92002-11-30 14:00:47 +00002470static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002471
2472/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002473static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002474{
sewardjfa492d42002-12-08 18:20:01 +00002475 maybe_emit_put_eflags(); /* save flags here */
2476
njn25e49d8e72002-09-23 09:36:25 +00002477 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002478
2479 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2480 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2481 emit_call_patchme();
2482 } else {
2483 load_ebp_from_JmpKind ( jmpkind );
2484 emit_ret();
2485 }
sewardjde4a1d02002-03-22 01:27:54 +00002486}
2487
2488
sewardj2370f3b2002-11-30 15:01:01 +00002489static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002490static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002491 Opcode opcode, Int size,
2492 UInt lit, Int reg );
2493
sewardjfa492d42002-12-08 18:20:01 +00002494static void synth_jcond_lit ( Condcode cond,
2495 Addr addr,
2496 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002497{
sewardj2370f3b2002-11-30 15:01:01 +00002498 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002499 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002500 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002501
sewardja2113f92002-12-12 23:42:48 +00002502 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002503 VG_(init_target)(&tgt2);
2504 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002505
sewardjfa492d42002-12-08 18:20:01 +00002506 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2507 if need be */
2508 maybe_emit_put_eflags();
2509 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2510
2511 if (eflags_state == UPD_Both) {
2512 /* The flags are already set up, so we just use them as is. */
2513 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002514 cond = invertCondition(cond);
2515 } else {
sewardj75f04932002-12-12 23:13:21 +00002516 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002517
2518 /* The simd state contains the most recent version, so we emit a
2519 sequence to calculate the relevant condition directly out of
2520 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2521 copying them back to the real flags via popf. Notice that
2522 some of these sequences trash %eax, but that should be free
2523 now since this is the end of a bb and therefore all regs are
2524 dead. */
2525 simd = False;
2526
2527 switch (cond) {
2528
sewardjbb6c1182002-12-12 23:54:47 +00002529 case CondLE: /* Z || S != O -> S || !P */
2530 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002531 vg_assert(eax_trashable);
2532
2533 VG_(emit_movv_offregmem_reg)
2534 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2535 /* eax == %EFLAGS */
2536
sewardjbb6c1182002-12-12 23:54:47 +00002537 VG_(emit_nonshiftopv_lit_reg)
2538 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2539 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002540
sewardjbb6c1182002-12-12 23:54:47 +00002541 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2542 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002543
sewardj09736622002-12-28 00:19:00 +00002544 /* actually set the real cpu flags, since ROR changes
2545 neither P nor Z */
2546 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2547
sewardjbb6c1182002-12-12 23:54:47 +00002548 if (cond == CondLE) {
2549 /* test Z */
2550 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2551 /* test OF != SF */
2552 cond = CondP;
2553 } else {
2554 /* test Z */
2555 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2556 /* test OF == SF */
2557 cond = CondNP;
2558 }
sewardj2370f3b2002-11-30 15:01:01 +00002559 break;
2560
sewardjfa492d42002-12-08 18:20:01 +00002561 case CondL:
2562 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002563 vg_assert(eax_trashable);
2564
2565 VG_(emit_movv_offregmem_reg)
2566 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2567 /* eax == %EFLAGS */
2568
sewardj75f04932002-12-12 23:13:21 +00002569 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2570 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002571
sewardj75f04932002-12-12 23:13:21 +00002572 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2573 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002574
sewardj09736622002-12-28 00:19:00 +00002575 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002576 if (cond == CondL) cond = CondP; else cond = CondNP;
2577 break;
sewardjfa492d42002-12-08 18:20:01 +00002578
2579 case CondB:
2580 case CondNB:
2581 mask = EFlagC; goto simple; /* C=1 */
2582
2583 case CondZ:
2584 case CondNZ:
2585 mask = EFlagZ; goto simple; /* Z=1 */
2586
2587 case CondBE:
2588 case CondNBE:
2589 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2590
2591 case CondS:
2592 case CondNS:
2593 mask = EFlagS; goto simple; /* S=1 */
2594
2595 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002596 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002597 mask = EFlagP; goto simple; /* P=1 */
2598
sewardj39542072002-12-09 22:44:00 +00002599 case CondO:
2600 case CondNO:
2601 mask = EFlagO; goto simple; /* O=1 */
2602
sewardjfa492d42002-12-08 18:20:01 +00002603 default:
2604 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002605 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002606 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2607
2608 simple:
2609 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002610 if ((mask & 0xff) == mask) {
2611 VG_(emitB) ( 0xF6 ); /* Grp3 */
2612 VG_(emit_amode_offregmem_reg)(
2613 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2614 VG_(emitB) (mask);
2615 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002616 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002617 mask, VGOFF_(m_eflags) * 4);
2618 } else {
sewardjfa492d42002-12-08 18:20:01 +00002619 /* all cond codes are in lower 16 bits */
2620 vg_assert((mask & 0xffff) == mask);
2621
2622 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002623 VG_(emitB) ( 0xF7 );
2624 VG_(emit_amode_offregmem_reg)(
2625 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002626 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002627 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002628 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002629 mask, VGOFF_(m_eflags) * 4);
2630 }
2631
sewardj75f04932002-12-12 23:13:21 +00002632 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002633 break;
2634 }
2635 }
2636
sewardja2113f92002-12-12 23:42:48 +00002637 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002638
2639 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002640 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002641
2642 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002643 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002644}
2645
2646
sewardj2370f3b2002-11-30 15:01:01 +00002647
sewardjde4a1d02002-03-22 01:27:54 +00002648static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2649{
sewardja2113f92002-12-12 23:42:48 +00002650 Int tgt;
2651
2652 VG_(init_target)(&tgt);
2653
sewardjfa492d42002-12-08 18:20:01 +00002654 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002655
2656 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002657 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002658
2659 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002660}
2661
2662
2663static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2664{
2665 /* Load the zero-extended literal into reg, at size l,
2666 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002667 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002668}
2669
2670
2671static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2672{
2673 switch (size) {
2674 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
daywalkerf26b2162003-09-30 23:01:50 +00002675 case 2: VG_(emit_movzwl_regmem_reg) ( reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002676 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002677 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002678 }
2679}
2680
2681
2682static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2683{
2684 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002685 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2686 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2687 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002688 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002689 }
2690}
2691
2692
2693static void synth_mov_reg_offregmem ( Int size, Int reg,
2694 Int off, Int areg )
2695{
2696 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002697 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2698 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002699 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002700 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002701 }
2702 else {
njn25e49d8e72002-09-23 09:36:25 +00002703 VG_(emit_swapl_reg_EAX) ( reg );
2704 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2705 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_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002709 }
2710}
2711
2712
2713static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2714{
2715 Int s1;
2716 switch (size) {
2717 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2718 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2719 case 1: if (reg1 < 4) {
2720 emit_movb_reg_regmem ( reg1, reg2 );
2721 }
2722 else {
2723 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2724 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2725 emit_swapl_reg_reg ( s1, reg1 );
2726 emit_movb_reg_regmem ( s1, reg2 );
2727 emit_swapl_reg_reg ( s1, reg1 );
2728 }
2729 break;
njne427a662002-10-02 11:08:25 +00002730 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002731 }
2732}
2733
2734
sewardjf0f12aa2002-12-28 00:04:08 +00002735static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002736 Opcode opcode, Int size,
2737 Int reg )
2738{
2739 /* NB! opcode is a uinstr opcode, not an x86 one! */
2740 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002741 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002742 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002743 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002744 break;
2745 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002746 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002747 } else {
njn25e49d8e72002-09-23 09:36:25 +00002748 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002749 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002750 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002751 }
2752 break;
njne427a662002-10-02 11:08:25 +00002753 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002754 }
2755}
2756
2757
2758
sewardjf0f12aa2002-12-28 00:04:08 +00002759static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002760 Opcode opcode, Int size,
2761 Int reg1, Int reg2 )
2762{
2763 /* NB! opcode is a uinstr opcode, not an x86 one! */
2764 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002765 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002766 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002767 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002768 break;
2769 case 1: { /* Horrible ... */
2770 Int s1, s2;
2771 /* Choose s1 and s2 to be x86 regs which we can talk about the
2772 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2773 sure s1 != s2 and that neither of them equal either reg1 or
2774 reg2. Then use them as temporaries to make things work. */
2775 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002776 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002777 break;
2778 }
2779 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2780 if (reg1 >= 4 && reg2 < 4) {
2781 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002782 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002783 emit_swapl_reg_reg ( reg1, s1 );
2784 break;
2785 }
2786 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2787 if (reg1 < 4 && reg2 >= 4) {
2788 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002789 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002790 emit_swapl_reg_reg ( reg2, s2 );
2791 break;
2792 }
2793 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2794 emit_swapl_reg_reg ( reg1, s1 );
2795 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002796 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002797 emit_swapl_reg_reg ( reg1, s1 );
2798 emit_swapl_reg_reg ( reg2, s2 );
2799 break;
2800 }
2801 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2802 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002803 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002804 emit_swapl_reg_reg ( reg1, s1 );
2805 break;
2806 }
njne427a662002-10-02 11:08:25 +00002807 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002808 }
njne427a662002-10-02 11:08:25 +00002809 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002810 }
2811}
2812
sewardja2c5a732002-12-15 03:10:42 +00002813#if 0
2814/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002815static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002816 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002817 Opcode opcode, Int size,
2818 Int off, Int areg, Int reg )
2819{
2820 switch (size) {
2821 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002822 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002823 break;
2824 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002825 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002826 break;
2827 case 1:
2828 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002829 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002830 } else {
2831 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002832 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002833 VG_(emit_swapl_reg_EAX) ( reg );
2834 }
2835 break;
2836 default:
2837 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2838 }
2839}
sewardja2c5a732002-12-15 03:10:42 +00002840#endif
sewardjfa492d42002-12-08 18:20:01 +00002841
sewardjde4a1d02002-03-22 01:27:54 +00002842static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002843 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002844 Opcode opcode, Int size,
2845 Int off, Int areg, Int reg )
2846{
2847 switch (size) {
2848 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002849 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002850 break;
2851 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002852 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002853 break;
2854 case 1:
2855 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002856 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002857 } else {
njn25e49d8e72002-09-23 09:36:25 +00002858 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002859 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002860 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002861 }
2862 break;
2863 default:
njne427a662002-10-02 11:08:25 +00002864 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002865 }
2866}
2867
2868
sewardjf0f12aa2002-12-28 00:04:08 +00002869static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002870 Opcode opcode, Int size,
2871 UInt lit, Int reg )
2872{
2873 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002874 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002875 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002876 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002877 break;
2878 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002879 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002880 } else {
njn25e49d8e72002-09-23 09:36:25 +00002881 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002882 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002883 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002884 }
2885 break;
njne427a662002-10-02 11:08:25 +00002886 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002887 }
2888}
2889
sewardjf0f12aa2002-12-28 00:04:08 +00002890static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002891 Opcode opcode, Int size,
2892 UInt lit, Int off, Int regmem )
2893{
2894 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002895 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002896 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002897 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002898 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002899 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002900 break;
2901 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2902 }
2903}
2904
sewardjde4a1d02002-03-22 01:27:54 +00002905
jsgf5efa4fd2003-10-14 21:49:11 +00002906static void synth_mul_reg_reg ( Bool upd_cc,
2907 Opcode opcode, Int size,
2908 Int reg1, Int reg2 )
2909{
2910 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2911
2912 switch (size) {
2913 case 2:
2914 VG_(emitB)(0x66);
2915 /* FALLTHROUGH */
2916 case 4:
2917 VG_(emitB)(0x0F);
2918 VG_(emitB)(0xAF);
2919 VG_(emit_amode_ereg_greg)(reg1, reg2);
2920 break;
2921
2922 case 1:
2923 VG_(core_panic)("can't do byte mul");
2924 break;
2925 }
2926 if (dis)
2927 VG_(printf)("\n\t\timul%c\t%s, %s\n",
2928 nameISize(size),
2929 nameIReg(size, reg1),
2930 nameIReg(size, reg2));
2931}
2932
2933static void synth_mul_lit_reg ( Bool upd_cc,
2934 Opcode opcode, Int size,
2935 UInt lit, Int reg )
2936{
2937 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2938
2939 switch (size) {
2940 case 2:
2941 VG_(emitB)(0x66);
2942 /* FALLTHROUGH */
2943 case 4:
2944 VG_(emitB)(0x69);
2945 VG_(emit_amode_ereg_greg)(reg, 0);
2946 if (size == 2)
2947 VG_(emitW)(lit);
2948 else
2949 VG_(emitL)(lit);
2950 break;
2951
2952 case 1:
2953 VG_(core_panic)("can't do byte mul");
2954 break;
2955 }
2956 if (dis)
2957 VG_(printf)("\n\t\timul%c\t%d, %s\n",
2958 nameISize(size),
2959 lit,
2960 nameIReg(size, reg));
2961}
2962
2963static void synth_mul_offregmem_reg (
2964 Bool upd_cc,
2965 Opcode opcode, Int size,
2966 Int off, Int areg, Int reg )
2967{
2968 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2969
2970 switch(size) {
2971 case 2:
2972 VG_(emitB)(0x66);
2973 /* FALLTHROUGH */
2974 case 4:
2975 VG_(emitB)(0x0F);
2976 VG_(emitB)(0xAF);
2977 VG_(emit_amode_offregmem_reg)(off, areg, reg);
2978 break;
2979
2980 case 1:
2981 VG_(core_panic)("can't do byte mul");
2982 }
2983
2984 if (dis)
2985 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
2986 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
2987
2988}
2989
2990
sewardjde4a1d02002-03-22 01:27:54 +00002991static void synth_push_reg ( Int size, Int reg )
2992{
2993 switch (size) {
2994 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002995 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002996 break;
2997 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002998 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002999 break;
3000 /* Pray that we don't have to generate this really cruddy bit of
3001 code very often. Could do better, but can I be bothered? */
3002 case 1:
3003 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003004 VG_(emit_add_lit_to_esp)(-1);
3005 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003006 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00003007 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003008 break;
3009 default:
njne427a662002-10-02 11:08:25 +00003010 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003011 }
3012}
3013
3014
3015static void synth_pop_reg ( Int size, Int reg )
3016{
3017 switch (size) {
3018 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003019 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003020 break;
3021 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003022 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003023 break;
3024 case 1:
3025 /* Same comment as above applies. */
3026 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003027 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003028 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003029 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3030 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003031 break;
njne427a662002-10-02 11:08:25 +00003032 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003033 }
3034}
3035
3036
sewardjf0f12aa2002-12-28 00:04:08 +00003037static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003038 Opcode opcode, Int size,
3039 Int regs, Int regd )
3040{
3041 synth_push_reg ( size, regd );
3042 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003043 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003044 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3045 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3046 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003047 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003048 }
sewardjde4a1d02002-03-22 01:27:54 +00003049 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3050 synth_pop_reg ( size, regd );
3051}
3052
3053
sewardjf0f12aa2002-12-28 00:04:08 +00003054static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003055 Opcode opcode, Int size,
3056 UInt lit, Int reg )
3057{
3058 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003059 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003060 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003061 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003062 break;
3063 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003064 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003065 } else {
njn25e49d8e72002-09-23 09:36:25 +00003066 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003067 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003068 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003069 }
3070 break;
njne427a662002-10-02 11:08:25 +00003071 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003072 }
3073}
3074
3075
sewardjf0f12aa2002-12-28 00:04:08 +00003076static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003077{
sewardjde4a1d02002-03-22 01:27:54 +00003078 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003079 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003080 } else {
njn25e49d8e72002-09-23 09:36:25 +00003081 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003082 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003083 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003084 }
3085}
3086
3087
sewardj3d7c9c82003-03-26 21:08:13 +00003088static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3089 UChar first_byte,
3090 UChar second_byte,
3091 Int ireg )
3092{
3093 emit_MMX2_regmem ( uses_flags, sets_flags,
3094 first_byte, second_byte, ireg );
3095}
3096
3097
sewardjca860012003-03-27 23:52:58 +00003098static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3099 UChar first_byte,
3100 UChar second_byte,
3101 Int ireg )
3102{
3103 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3104 first_byte, second_byte, ireg );
3105}
3106
sewardjd1c9e432003-04-04 20:40:34 +00003107static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3108 UChar first_byte,
3109 UChar second_byte,
3110 Int ireg )
3111{
3112 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3113 first_byte, second_byte, ireg );
3114}
3115
sewardj3d7c9c82003-03-26 21:08:13 +00003116static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3117 UChar first_byte,
3118 UChar second_byte )
3119{
3120 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3121}
3122
3123
sewardjca860012003-03-27 23:52:58 +00003124static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3125 UChar first_byte,
3126 UChar second_byte,
3127 UChar third_byte )
3128{
3129 emit_MMX3_no_mem ( uses_flags, sets_flags,
3130 first_byte, second_byte, third_byte );
3131}
3132
3133
sewardj3d7c9c82003-03-26 21:08:13 +00003134static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3135 UChar first_byte )
3136{
3137 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3138}
3139
3140
sewardjfa492d42002-12-08 18:20:01 +00003141static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3142 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003143 UChar second_byte_masked,
3144 Int reg )
3145{
sewardj3d7c9c82003-03-26 21:08:13 +00003146 emit_fpu_regmem ( uses_flags, sets_flags,
3147 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003148}
3149
3150
sewardjfa492d42002-12-08 18:20:01 +00003151static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3152 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003153 UChar second_byte )
3154{
sewardjfa492d42002-12-08 18:20:01 +00003155 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003156}
3157
3158
3159static void synth_movl_reg_reg ( Int src, Int dst )
3160{
3161 emit_movl_reg_reg ( src, dst );
3162}
3163
3164static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3165{
sewardja2113f92002-12-12 23:42:48 +00003166 Int tgt;
3167
3168 VG_(init_target)(&tgt);
3169
3170 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003171 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003172
3173 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003174}
3175
3176
sewardjde4a1d02002-03-22 01:27:54 +00003177/*----------------------------------------------------*/
3178/*--- Top level of the uinstr -> x86 translation. ---*/
3179/*----------------------------------------------------*/
3180
3181/* Return the byte offset from %ebp (ie, into baseBlock)
3182 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003183static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3184{
3185 if (tag == SpillNo) {
3186 vg_assert(size == 4);
3187 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3188 return 4 * (value + VGOFF_(spillslots));
3189 }
3190 if (tag == ArchReg) {
3191 switch (value) {
3192 case R_EAX: return 4 * VGOFF_(m_eax);
3193 case R_ECX: return 4 * VGOFF_(m_ecx);
3194 case R_EDX: return 4 * VGOFF_(m_edx);
3195 case R_EBX: return 4 * VGOFF_(m_ebx);
3196 case R_ESP:
3197 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3198 else return 4 * VGOFF_(m_esp);
3199 case R_EBP:
3200 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3201 else return 4 * VGOFF_(m_ebp);
3202 case R_ESI:
3203 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3204 else return 4 * VGOFF_(m_esi);
3205 case R_EDI:
3206 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3207 else return 4 * VGOFF_(m_edi);
3208 }
3209 }
njne427a662002-10-02 11:08:25 +00003210 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003211}
3212
sewardjde4a1d02002-03-22 01:27:54 +00003213static Int eflagsOffset ( void )
3214{
3215 return 4 * VGOFF_(m_eflags);
3216}
3217
sewardje1042472002-09-30 12:33:11 +00003218static Int segRegOffset ( UInt archregs )
3219{
3220 switch (archregs) {
3221 case R_CS: return 4 * VGOFF_(m_cs);
3222 case R_SS: return 4 * VGOFF_(m_ss);
3223 case R_DS: return 4 * VGOFF_(m_ds);
3224 case R_ES: return 4 * VGOFF_(m_es);
3225 case R_FS: return 4 * VGOFF_(m_fs);
3226 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003227 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003228 }
3229}
3230
njnf4ce3d32003-02-10 10:17:26 +00003231UInt VG_(get_archreg) ( UInt arch )
3232{
3233 switch (arch) {
3234 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3235 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3236 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3237 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3238 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3239 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3240 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3241 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003242 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003243 }
3244}
3245
3246UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3247{
3248 ThreadState* tst;
3249
3250 vg_assert(VG_(is_valid_tid)(tid));
3251 tst = & VG_(threads)[tid];
3252
3253 switch (arch) {
3254 case R_EAX: return tst->m_eax;
3255 case R_ECX: return tst->m_ecx;
3256 case R_EDX: return tst->m_edx;
3257 case R_EBX: return tst->m_ebx;
3258 case R_ESP: return tst->m_esp;
3259 case R_EBP: return tst->m_ebp;
3260 case R_ESI: return tst->m_esi;
3261 case R_EDI: return tst->m_edi;
3262 default: VG_(core_panic)( "get_thread_archreg");
3263 }
3264}
3265
njnb93d1782003-02-03 12:03:22 +00003266/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003267static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003268{
3269 switch (arch) {
3270 case R_EAX: return VGOFF_(sh_eax);
3271 case R_ECX: return VGOFF_(sh_ecx);
3272 case R_EDX: return VGOFF_(sh_edx);
3273 case R_EBX: return VGOFF_(sh_ebx);
3274 case R_ESP: return VGOFF_(sh_esp);
3275 case R_EBP: return VGOFF_(sh_ebp);
3276 case R_ESI: return VGOFF_(sh_esi);
3277 case R_EDI: return VGOFF_(sh_edi);
3278 default: VG_(core_panic)( "shadow_reg_index");
3279 }
3280}
sewardjde4a1d02002-03-22 01:27:54 +00003281
njn25e49d8e72002-09-23 09:36:25 +00003282/* Return the byte offset from %ebp (ie, into baseBlock)
3283 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003284Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003285{
njnb93d1782003-02-03 12:03:22 +00003286 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003287}
3288
njn4ba5a792002-09-30 10:23:54 +00003289Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003290{
3291 return 4 * VGOFF_(sh_eflags);
3292}
3293
njnb93d1782003-02-03 12:03:22 +00003294/* Accessing shadow arch. registers */
3295UInt VG_(get_shadow_archreg) ( UInt archreg )
3296{
3297 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3298}
3299
3300void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3301{
3302 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3303}
3304
njnd3040452003-05-19 15:04:06 +00003305void VG_(set_shadow_eflags) ( UInt val )
3306{
3307 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3308}
3309
njnf4ce3d32003-02-10 10:17:26 +00003310UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3311{
3312 ThreadState* tst;
3313
3314 vg_assert(VG_(is_valid_tid)(tid));
3315 tst = & VG_(threads)[tid];
3316
3317 switch (archreg) {
3318 case R_EAX: return tst->sh_eax;
3319 case R_ECX: return tst->sh_ecx;
3320 case R_EDX: return tst->sh_edx;
3321 case R_EBX: return tst->sh_ebx;
3322 case R_ESP: return tst->sh_esp;
3323 case R_EBP: return tst->sh_ebp;
3324 case R_ESI: return tst->sh_esi;
3325 case R_EDI: return tst->sh_edi;
3326 default: VG_(core_panic)( "get_thread_shadow_archreg");
3327 }
3328}
3329
3330void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3331{
3332 ThreadState* tst;
3333
3334 vg_assert(VG_(is_valid_tid)(tid));
3335 tst = & VG_(threads)[tid];
3336
3337 switch (archreg) {
3338 case R_EAX: tst->sh_eax = val; break;
3339 case R_ECX: tst->sh_ecx = val; break;
3340 case R_EDX: tst->sh_edx = val; break;
3341 case R_EBX: tst->sh_ebx = val; break;
3342 case R_ESP: tst->sh_esp = val; break;
3343 case R_EBP: tst->sh_ebp = val; break;
3344 case R_ESI: tst->sh_esi = val; break;
3345 case R_EDI: tst->sh_edi = val; break;
3346 default: VG_(core_panic)( "set_thread_shadow_archreg");
3347 }
3348}
3349
njnb93d1782003-02-03 12:03:22 +00003350Addr VG_(shadow_archreg_address) ( UInt archreg )
3351{
3352 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3353}
sewardjde4a1d02002-03-22 01:27:54 +00003354
sewardjde4a1d02002-03-22 01:27:54 +00003355static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3356{
3357 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003358 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3359 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003360 }
3361 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003362 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3363 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003364 }
3365 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003366 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3367 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003368 }
3369 else
njne427a662002-10-02 11:08:25 +00003370 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003371}
3372
3373
sewardjde4a1d02002-03-22 01:27:54 +00003374/*----------------------------------------------------*/
3375/*--- Generate code for a single UInstr. ---*/
3376/*----------------------------------------------------*/
3377
sewardj478335c2002-10-05 02:44:47 +00003378static __inline__
3379Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003380{
3381 return (u->flags_w != FlagsEmpty);
3382}
3383
sewardjfa492d42002-12-08 18:20:01 +00003384static __inline__
3385Bool readFlagUse ( UInstr* u )
3386{
3387 /* If the UInstr writes some flags but not all, then we still need
3388 to consider it as reading flags so that the unchanged values are
3389 passed through properly. (D is special) */
3390 return
3391 (u->flags_r != FlagsEmpty) ||
3392 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3393}
3394
sewardj478335c2002-10-05 02:44:47 +00003395static __inline__
3396Bool anyFlagUse ( UInstr* u )
3397{
sewardjfa492d42002-12-08 18:20:01 +00003398 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003399}
3400
3401
sewardjb91ae7f2003-04-29 23:50:00 +00003402/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3403 the real machine's cpu. If so we need to be very careful not to trash it.
3404 If FPU/SSE state is live and we deem it necessary to copy it back to
3405 the simulated machine's FPU/SSE state, we do so. The final state of
3406 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003407 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003408 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003409*/
sewardjb5ff83e2002-12-01 19:40:49 +00003410static void emitUInstr ( UCodeBlock* cb, Int i,
3411 RRegSet regs_live_before,
3412 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003413 Bool* sselive, /* True<==>FPU/SSE
3414 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003415 Addr* orig_eip, /* previous curr_eip, or zero */
3416 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003417{
njn25e49d8e72002-09-23 09:36:25 +00003418 Int old_emitted_code_used;
3419 UInstr* u = &cb->instrs[i];
3420
sewardjde4a1d02002-03-22 01:27:54 +00003421 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003422 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003423
njn25e49d8e72002-09-23 09:36:25 +00003424 old_emitted_code_used = emitted_code_used;
3425
sewardjde4a1d02002-03-22 01:27:54 +00003426 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003427 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003428
sewardjb5ff83e2002-12-01 19:40:49 +00003429 case INCEIP:
3430 /* Advance %EIP some small amount. */
3431 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003432
sewardjb5ff83e2002-12-01 19:40:49 +00003433 if (*orig_eip == 0 /* we don't know what the old value was */
3434 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3435 /* We have to update all 32 bits of the value. */
3436 VG_(emit_movv_lit_offregmem)(
3437 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3438 } else {
3439 /* Cool! we only need to update lowest 8 bits */
3440 VG_(emit_movb_lit_offregmem)(
3441 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003442 }
njn25e49d8e72002-09-23 09:36:25 +00003443
sewardjb5ff83e2002-12-01 19:40:49 +00003444 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003445 break;
sewardjde4a1d02002-03-22 01:27:54 +00003446
3447 case LEA1: {
3448 vg_assert(u->tag1 == RealReg);
3449 vg_assert(u->tag2 == RealReg);
3450 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3451 break;
3452 }
3453
3454 case LEA2: {
3455 vg_assert(u->tag1 == RealReg);
3456 vg_assert(u->tag2 == RealReg);
3457 vg_assert(u->tag3 == RealReg);
3458 emit_lea_sib_reg ( u->lit32, u->extra4b,
3459 u->val1, u->val2, u->val3 );
3460 break;
3461 }
3462
3463 case WIDEN: {
3464 vg_assert(u->tag1 == RealReg);
3465 if (u->signed_widen) {
3466 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3467 } else {
3468 /* no need to generate any code. */
3469 }
3470 break;
3471 }
3472
sewardjde4a1d02002-03-22 01:27:54 +00003473 case STORE: {
3474 vg_assert(u->tag1 == RealReg);
3475 vg_assert(u->tag2 == RealReg);
3476 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003477 break;
3478 }
3479
3480 case LOAD: {
3481 vg_assert(u->tag1 == RealReg);
3482 vg_assert(u->tag2 == RealReg);
3483 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3484 break;
3485 }
3486
sewardjde4a1d02002-03-22 01:27:54 +00003487 case GET: {
3488 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3489 vg_assert(u->tag2 == RealReg);
3490 synth_mov_offregmem_reg (
3491 u->size,
3492 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3493 R_EBP,
3494 u->val2
3495 );
3496 break;
3497 }
3498
3499 case PUT: {
3500 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3501 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003502 synth_mov_reg_offregmem (
3503 u->size,
3504 u->val1,
3505 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3506 R_EBP
3507 );
sewardjde4a1d02002-03-22 01:27:54 +00003508 break;
3509 }
3510
sewardje1042472002-09-30 12:33:11 +00003511 case GETSEG: {
3512 vg_assert(u->tag1 == ArchRegS);
3513 vg_assert(u->tag2 == RealReg);
3514 vg_assert(u->size == 2);
3515 synth_mov_offregmem_reg (
3516 4,
3517 segRegOffset( u->val1 ),
3518 R_EBP,
3519 u->val2
3520 );
3521 break;
3522 }
3523
3524 case PUTSEG: {
3525 vg_assert(u->tag1 == RealReg);
3526 vg_assert(u->tag2 == ArchRegS);
3527 vg_assert(u->size == 2);
3528 synth_mov_reg_offregmem (
3529 4,
3530 u->val1,
3531 segRegOffset( u->val2 ),
3532 R_EBP
3533 );
3534 break;
3535 }
3536
sewardjde4a1d02002-03-22 01:27:54 +00003537 case GETF: {
3538 vg_assert(u->size == 2 || u->size == 4);
3539 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003540
3541 /* This complexity is because the D(irection) flag is stored
3542 separately from the rest of EFLAGS. */
3543
3544 /* We're only fetching from the Simd state, so make sure it's
3545 up to date. */
3546 maybe_emit_put_eflags();
3547
3548 /* get D in u->val1 (== 1 or -1) */
3549 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3550
3551 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3552 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3553
3554 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3555 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3556 eflagsOffset(), R_EBP);
3557
3558 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3559 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3560 eflagsOffset(), R_EBP);
3561
3562 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3563 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3564 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003565 break;
3566 }
3567
3568 case PUTF: {
3569 vg_assert(u->size == 2 || u->size == 4);
3570 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003571
3572 /* When putting a value into EFLAGS, this generates the
3573 correct value for m_dflag (-1 or 1), and clears the D bit
3574 in EFLAGS. */
3575
3576 /* We're updating the whole flag state, so the old state
3577 doesn't matter; make sure that the new simulated state
3578 will be fetched when needed. */
3579 eflags_state = UPD_Simd;
3580
3581 /* store EFLAGS (with D) */
3582 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3583
3584 /* u->val1 &= EFlagD */
3585 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3586
3587 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3588 synth_unaryop_reg(False, NEG, u->size, u->val1);
3589 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3590 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3591
3592 /* save D */
3593 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3594
3595 /* EFLAGS &= ~EFlagD */
3596 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3597 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003598 break;
3599 }
3600
3601 case MOV: {
3602 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3603 vg_assert(u->tag2 == RealReg);
3604 switch (u->tag1) {
3605 case RealReg: vg_assert(u->size == 4);
3606 if (u->val1 != u->val2)
3607 synth_movl_reg_reg ( u->val1, u->val2 );
3608 break;
3609 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3610 break;
njne427a662002-10-02 11:08:25 +00003611 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003612 }
3613 break;
3614 }
3615
sewardje1042472002-09-30 12:33:11 +00003616 case USESEG: {
3617 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3618 ones. */
sewardjd077f532002-09-30 21:52:50 +00003619 UInt argv[] = { u->val1, u->val2 };
3620 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003621 UInt ret_reg = u->val2;
3622
3623 vg_assert(u->tag1 == RealReg);
3624 vg_assert(u->tag2 == RealReg);
3625 vg_assert(u->size == 0);
3626
sewardjb91ae7f2003-04-29 23:50:00 +00003627 if (*sselive) {
3628 emit_put_sse_state();
3629 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003630 }
3631
sewardje1042472002-09-30 12:33:11 +00003632 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3633 2, /* args */
3634 0, /* regparms_n */
3635 argv, tagv,
3636 ret_reg, regs_live_before, u->regs_live_after );
3637 break;
3638 }
3639
jsgf5efa4fd2003-10-14 21:49:11 +00003640 case MUL: {
3641 vg_assert(u->tag2 == RealReg);
3642
3643 switch(u->tag1) {
3644 case Literal:
3645 synth_mul_lit_reg(anyFlagUse(u),
3646 u->opcode, u->size, u->lit32, u->val2);
3647 break;
3648 case RealReg:
3649 synth_mul_reg_reg(anyFlagUse(u),
3650 u->opcode, u->size, u->val1, u->val2);
3651 break;
3652 case ArchReg:
3653 synth_mul_offregmem_reg(anyFlagUse(u),
3654 u->opcode, u->size,
3655 spillOrArchOffset(u->size, u->tag1, u->val1),
3656 R_EBP, u->val2);
3657 break;
3658
3659 default: VG_(core_panic)("emitUInstr:MUL");
3660 }
3661 break;
3662 }
3663
sewardj478335c2002-10-05 02:44:47 +00003664 case SBB:
3665 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003666 case XOR:
3667 case OR:
3668 case AND:
3669 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003670 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003671 vg_assert(u->tag2 == RealReg);
3672 switch (u->tag1) {
3673 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003674 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003675 u->opcode, u->size, u->lit32, u->val2 );
3676 break;
3677 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003678 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003679 u->opcode, u->size, u->val1, u->val2 );
3680 break;
3681 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003682 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003683 u->opcode, u->size,
3684 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3685 R_EBP,
3686 u->val2 );
3687 break;
njne427a662002-10-02 11:08:25 +00003688 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003689 }
3690 break;
3691 }
3692
sewardj478335c2002-10-05 02:44:47 +00003693 case RCR:
3694 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003695 case ROR:
3696 case ROL:
3697 case SAR:
3698 case SHR:
3699 case SHL: {
3700 vg_assert(u->tag2 == RealReg);
3701 switch (u->tag1) {
3702 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003703 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003704 u->opcode, u->size, u->lit32, u->val2 );
3705 break;
3706 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003707 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003708 u->opcode, u->size, u->val1, u->val2 );
3709 break;
njne427a662002-10-02 11:08:25 +00003710 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003711 }
3712 break;
3713 }
3714
3715 case INC:
3716 case DEC:
3717 case NEG:
3718 case NOT:
3719 vg_assert(u->tag1 == RealReg);
3720 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003721 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003722 break;
3723
3724 case BSWAP:
3725 vg_assert(u->tag1 == RealReg);
3726 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003727 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003728 emit_bswapl_reg ( u->val1 );
3729 break;
3730
3731 case CMOV:
3732 vg_assert(u->tag1 == RealReg);
3733 vg_assert(u->tag2 == RealReg);
3734 vg_assert(u->cond != CondAlways);
3735 vg_assert(u->size == 4);
3736 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3737 break;
3738
3739 case JMP: {
3740 vg_assert(u->tag2 == NoValue);
3741 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003742 if (*sselive) {
3743 emit_put_sse_state();
3744 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003745 }
sewardjde4a1d02002-03-22 01:27:54 +00003746 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003747 switch (u->tag1) {
3748 case RealReg:
3749 synth_jmp_reg ( u->val1, u->jmpkind );
3750 break;
3751 case Literal:
3752 synth_jmp_lit ( u->lit32, u->jmpkind );
3753 break;
3754 default:
njne427a662002-10-02 11:08:25 +00003755 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003756 break;
sewardjde4a1d02002-03-22 01:27:54 +00003757 }
3758 } else {
sewardj2e93c502002-04-12 11:12:52 +00003759 switch (u->tag1) {
3760 case RealReg:
njne427a662002-10-02 11:08:25 +00003761 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003762 break;
3763 case Literal:
3764 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003765 /* %eax had better not be live since synth_jcond_lit
3766 trashes it in some circumstances. If that turns
3767 out to be a problem we can get synth_jcond_lit to
3768 push/pop it when it is live. */
3769 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3770 u->regs_live_after));
3771 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003772 break;
3773 default:
njne427a662002-10-02 11:08:25 +00003774 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003775 break;
sewardjde4a1d02002-03-22 01:27:54 +00003776 }
3777 }
3778 break;
3779 }
3780
3781 case JIFZ:
3782 vg_assert(u->tag1 == RealReg);
3783 vg_assert(u->tag2 == Literal);
3784 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003785 if (*sselive) {
3786 emit_put_sse_state();
3787 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003788 }
sewardjde4a1d02002-03-22 01:27:54 +00003789 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3790 break;
3791
sewardjde4a1d02002-03-22 01:27:54 +00003792 case PUSH:
3793 vg_assert(u->tag1 == RealReg);
3794 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003795 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003796 break;
3797
3798 case POP:
3799 vg_assert(u->tag1 == RealReg);
3800 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003801 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003802 break;
3803
3804 case CALLM:
3805 vg_assert(u->tag1 == Lit16);
3806 vg_assert(u->tag2 == NoValue);
3807 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003808 if (*sselive) {
3809 emit_put_sse_state();
3810 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003811 }
sewardjfa492d42002-12-08 18:20:01 +00003812 /* Call to a helper which is pretending to be a real CPU
3813 instruction (and therefore operates on Real flags and
3814 registers) */
3815 VG_(synth_call) ( False, u->val1,
3816 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003817 break;
3818
njn25e49d8e72002-09-23 09:36:25 +00003819 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003820 /* If you change this, remember to change USESEG above, since
3821 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003822 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3823 ones. */
3824 UInt argv[] = { u->val1, u->val2, u->val3 };
3825 UInt tagv[] = { RealReg, RealReg, RealReg };
3826 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3827
3828 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3829 else vg_assert(u->tag1 == NoValue);
3830 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3831 else vg_assert(u->tag2 == NoValue);
3832 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3833 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003834 vg_assert(u->size == 0);
3835
sewardjb91ae7f2003-04-29 23:50:00 +00003836 if (*sselive) {
3837 emit_put_sse_state();
3838 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003839 }
njn25e49d8e72002-09-23 09:36:25 +00003840 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3841 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003842 break;
njn25e49d8e72002-09-23 09:36:25 +00003843 }
sewardje1042472002-09-30 12:33:11 +00003844
sewardjde4a1d02002-03-22 01:27:54 +00003845 case CLEAR:
3846 vg_assert(u->tag1 == Lit16);
3847 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003848 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003849 break;
3850
3851 case CC2VAL:
3852 vg_assert(u->tag1 == RealReg);
3853 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003854 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003855 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003856 break;
3857
sewardjde4a1d02002-03-22 01:27:54 +00003858 case FPU_R:
3859 case FPU_W:
3860 vg_assert(u->tag1 == Lit16);
3861 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003862 if (!(*sselive)) {
3863 emit_get_sse_state();
3864 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003865 }
sewardjfa492d42002-12-08 18:20:01 +00003866 synth_fpu_regmem ( u->flags_r, u->flags_w,
3867 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003868 u->val1 & 0xFF,
3869 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003870 break;
3871
3872 case FPU:
3873 vg_assert(u->tag1 == Lit16);
3874 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003875 if (!(*sselive)) {
3876 emit_get_sse_state();
3877 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003878 }
sewardjfa492d42002-12-08 18:20:01 +00003879 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3880 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003881 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003882 break;
3883
sewardj3d7c9c82003-03-26 21:08:13 +00003884 case MMX2_MemWr:
3885 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003886 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003887 vg_assert(u->tag1 == Lit16);
3888 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003889 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003890 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003891 if (!(*sselive)) {
3892 emit_get_sse_state();
3893 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003894 }
3895 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3896 (u->val1 >> 8) & 0xFF,
3897 u->val1 & 0xFF,
3898 u->val2 );
3899 break;
3900
sewardj4fbe6e92003-06-15 21:54:34 +00003901 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00003902 vg_assert(u->tag1 == Lit16);
3903 vg_assert(u->tag2 == RealReg);
3904 vg_assert(u->tag3 == NoValue);
3905 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003906 if (!(*sselive)) {
3907 emit_get_sse_state();
3908 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003909 }
3910 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3911 (u->val1 >> 8) & 0xFF,
3912 u->val1 & 0xFF,
3913 u->val2 );
3914 break;
3915
sewardj4fbe6e92003-06-15 21:54:34 +00003916 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00003917 vg_assert(u->tag1 == Lit16);
3918 vg_assert(u->tag2 == RealReg);
3919 vg_assert(u->tag3 == NoValue);
3920 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003921 if (!(*sselive)) {
3922 emit_get_sse_state();
3923 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003924 }
3925 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3926 (u->val1 >> 8) & 0xFF,
3927 u->val1 & 0xFF,
3928 u->val2 );
3929 break;
3930
sewardj3d7c9c82003-03-26 21:08:13 +00003931 case MMX1:
3932 vg_assert(u->tag1 == Lit16);
3933 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003934 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003935 if (!(*sselive)) {
3936 emit_get_sse_state();
3937 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003938 }
3939 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3940 u->val1 & 0xFF );
3941 break;
3942
3943 case MMX2:
3944 vg_assert(u->tag1 == Lit16);
3945 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003946 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003947 if (!(*sselive)) {
3948 emit_get_sse_state();
3949 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003950 }
3951 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3952 (u->val1 >> 8) & 0xFF,
3953 u->val1 & 0xFF );
3954 break;
3955
sewardjca860012003-03-27 23:52:58 +00003956 case MMX3:
3957 vg_assert(u->tag1 == Lit16);
3958 vg_assert(u->tag2 == Lit16);
3959 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003960 if (!(*sselive)) {
3961 emit_get_sse_state();
3962 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003963 }
3964 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3965 (u->val1 >> 8) & 0xFF,
3966 u->val1 & 0xFF,
3967 u->val2 & 0xFF );
3968 break;
3969
sewardjfebaa3b2003-05-25 01:07:34 +00003970 case SSE2a_MemWr:
3971 case SSE2a_MemRd:
3972 vg_assert(u->size == 4 || u->size == 16);
3973 vg_assert(u->tag1 == Lit16);
3974 vg_assert(u->tag2 == Lit16);
3975 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003976 if (!(*sselive)) {
3977 emit_get_sse_state();
3978 *sselive = True;
3979 }
3980 emit_SSE2a ( u->flags_r, u->flags_w,
3981 (u->val1 >> 8) & 0xFF,
3982 u->val1 & 0xFF,
3983 u->val2 & 0xFF,
3984 u->val3 );
3985 break;
3986
sewardj9dd209f2003-06-18 23:30:52 +00003987 case SSE2a1_MemRd:
3988 vg_assert(u->size == 4 || u->size == 16);
3989 vg_assert(u->tag1 == Lit16);
3990 vg_assert(u->tag2 == Lit16);
3991 vg_assert(u->tag3 == RealReg);
3992 vg_assert(!anyFlagUse(u));
3993 if (!(*sselive)) {
3994 emit_get_sse_state();
3995 *sselive = True;
3996 }
3997 emit_SSE2a1 ( u->flags_r, u->flags_w,
3998 (u->val1 >> 8) & 0xFF,
3999 u->val1 & 0xFF,
4000 (u->val2 >> 8) & 0xFF,
4001 u->val2 & 0xFF,
4002 u->val3 );
4003 break;
4004
sewardjfebaa3b2003-05-25 01:07:34 +00004005 case SSE3a_MemWr:
4006 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00004007 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00004008 vg_assert(u->tag1 == Lit16);
4009 vg_assert(u->tag2 == Lit16);
4010 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004011 if (!(*sselive)) {
4012 emit_get_sse_state();
4013 *sselive = True;
4014 }
4015 emit_SSE3a ( u->flags_r, u->flags_w,
4016 (u->val1 >> 8) & 0xFF,
4017 u->val1 & 0xFF,
4018 (u->val2 >> 8) & 0xFF,
4019 u->val2 & 0xFF,
4020 u->val3 );
4021 break;
4022
sewardjabf8bf82003-06-15 22:28:05 +00004023 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004024 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004025 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004026 vg_assert(u->size == 4);
4027 vg_assert(u->tag1 == Lit16);
4028 vg_assert(u->tag2 == Lit16);
4029 vg_assert(u->tag3 == RealReg);
4030 vg_assert(!anyFlagUse(u));
4031 if (!(*sselive)) {
4032 emit_get_sse_state();
4033 *sselive = True;
4034 }
sewardjabf8bf82003-06-15 22:28:05 +00004035 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4036 emit_SSE3e ( u->flags_r, u->flags_w,
4037 (u->val1 >> 8) & 0xFF,
4038 u->val1 & 0xFF,
4039 (u->val2 >> 8) & 0xFF,
4040 u->val2 & 0xFF,
4041 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004042 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004043 emit_SSE3g ( u->flags_r, u->flags_w,
4044 (u->val1 >> 8) & 0xFF,
4045 u->val1 & 0xFF,
4046 (u->val2 >> 8) & 0xFF,
4047 u->val2 & 0xFF,
4048 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004049 }
sewardjfebaa3b2003-05-25 01:07:34 +00004050 break;
4051
sewardjb31b06d2003-06-13 00:26:02 +00004052 case SSE3g1_RegWr:
4053 vg_assert(u->size == 4);
4054 vg_assert(u->tag1 == Lit16);
4055 vg_assert(u->tag2 == Lit16);
4056 vg_assert(u->tag3 == RealReg);
4057 vg_assert(!anyFlagUse(u));
4058 if (!(*sselive)) {
4059 emit_get_sse_state();
4060 *sselive = True;
4061 }
sewardjabf8bf82003-06-15 22:28:05 +00004062 emit_SSE3g1 ( u->flags_r, u->flags_w,
4063 (u->val1 >> 8) & 0xFF,
4064 u->val1 & 0xFF,
4065 (u->val2 >> 8) & 0xFF,
4066 u->val2 & 0xFF,
4067 u->lit32 & 0xFF,
4068 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004069 break;
4070
sewardj4fbe6e92003-06-15 21:54:34 +00004071 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004072 vg_assert(u->size == 2);
4073 vg_assert(u->tag1 == Lit16);
4074 vg_assert(u->tag2 == Lit16);
4075 vg_assert(u->tag3 == RealReg);
4076 vg_assert(!anyFlagUse(u));
4077 if (!(*sselive)) {
4078 emit_get_sse_state();
4079 *sselive = True;
4080 }
sewardjabf8bf82003-06-15 22:28:05 +00004081 emit_SSE3e1 ( u->flags_r, u->flags_w,
4082 (u->val1 >> 8) & 0xFF,
4083 u->val1 & 0xFF,
4084 (u->val2 >> 8) & 0xFF,
4085 u->val2 & 0xFF,
4086 u->lit32 & 0xFF,
4087 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004088 break;
4089
sewardj77d30a22003-10-19 08:18:52 +00004090 case SSE3a1_MemRd:
4091 vg_assert(u->size == 16);
4092 vg_assert(u->tag1 == Lit16);
4093 vg_assert(u->tag2 == Lit16);
4094 vg_assert(u->tag3 == RealReg);
4095 vg_assert(!anyFlagUse(u));
4096 if (!(*sselive)) {
4097 emit_get_sse_state();
4098 *sselive = True;
4099 }
4100 emit_SSE3a1 ( u->flags_r, u->flags_w,
4101 (u->val1 >> 8) & 0xFF,
4102 u->val1 & 0xFF,
4103 (u->val2 >> 8) & 0xFF,
4104 u->val2 & 0xFF,
4105 (u->lit32 >> 8) & 0xFF,
4106 u->val3 );
4107 break;
4108
sewardja453fb02003-06-14 13:22:36 +00004109 case SSE5:
4110 vg_assert(u->size == 0);
4111 vg_assert(u->tag1 == Lit16);
4112 vg_assert(u->tag2 == Lit16);
4113 vg_assert(u->tag3 == Lit16);
4114 vg_assert(!anyFlagUse(u));
4115 if (!(*sselive)) {
4116 emit_get_sse_state();
4117 *sselive = True;
4118 }
4119 emit_SSE5 ( u->flags_r, u->flags_w,
4120 (u->val1 >> 8) & 0xFF,
4121 u->val1 & 0xFF,
4122 (u->val2 >> 8) & 0xFF,
4123 u->val2 & 0xFF,
4124 u->val3 & 0xFF );
4125 break;
4126
sewardjfebaa3b2003-05-25 01:07:34 +00004127 case SSE4:
4128 vg_assert(u->size == 0);
4129 vg_assert(u->tag1 == Lit16);
4130 vg_assert(u->tag2 == Lit16);
4131 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004132 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004133 if (!(*sselive)) {
4134 emit_get_sse_state();
4135 *sselive = True;
4136 }
4137 emit_SSE4 ( u->flags_r, u->flags_w,
4138 (u->val1 >> 8) & 0xFF,
4139 u->val1 & 0xFF,
4140 (u->val2 >> 8) & 0xFF,
4141 u->val2 & 0xFF );
4142 break;
4143
sewardja60be0e2003-05-26 08:47:27 +00004144 case SSE3:
4145 vg_assert(u->size == 0);
4146 vg_assert(u->tag1 == Lit16);
4147 vg_assert(u->tag2 == Lit16);
4148 vg_assert(u->tag3 == NoValue);
sewardj77d30a22003-10-19 08:18:52 +00004149 vg_assert(!readFlagUse(u));
sewardja60be0e2003-05-26 08:47:27 +00004150 if (!(*sselive)) {
4151 emit_get_sse_state();
4152 *sselive = True;
4153 }
4154 emit_SSE3 ( u->flags_r, u->flags_w,
4155 (u->val1 >> 8) & 0xFF,
4156 u->val1 & 0xFF,
4157 u->val2 & 0xFF );
4158 break;
4159
sewardje3891fa2003-06-15 03:13:48 +00004160 case SSE3ag_MemRd_RegWr:
4161 vg_assert(u->size == 4 || u->size == 8);
4162 vg_assert(u->tag1 == RealReg);
4163 vg_assert(u->tag2 == RealReg);
4164 vg_assert(u->tag3 == NoValue);
4165 vg_assert(!anyFlagUse(u));
4166 if (!(*sselive)) {
4167 emit_get_sse_state();
4168 *sselive = True;
4169 }
4170 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4171 (u->lit32 >> 24) & 0xFF,
4172 (u->lit32 >> 16) & 0xFF,
4173 (u->lit32 >> 8) & 0xFF,
4174 u->val1, u->val2 );
4175 break;
4176
sewardjde4a1d02002-03-22 01:27:54 +00004177 default:
sewardj1b7d8022002-11-30 12:35:42 +00004178 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004179 if (*sselive) {
4180 emit_put_sse_state();
4181 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004182 }
njn4ba5a792002-09-30 10:23:54 +00004183 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004184 } else {
njn25e49d8e72002-09-23 09:36:25 +00004185 VG_(printf)("\nError:\n"
4186 " unhandled opcode: %u. Perhaps "
4187 " VG_(needs).extended_UCode should be set?\n",
4188 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004189 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004190 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004191 }
sewardjde4a1d02002-03-22 01:27:54 +00004192 }
4193
sewardjb91ae7f2003-04-29 23:50:00 +00004194 if (0 && (*sselive)) {
4195 emit_put_sse_state();
4196 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004197 }
4198
njn25e49d8e72002-09-23 09:36:25 +00004199 /* Update UInstr histogram */
4200 vg_assert(u->opcode < 100);
4201 histogram[u->opcode].counts++;
4202 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004203}
4204
4205
4206/* Emit x86 for the ucode in cb, returning the address of the
4207 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004208UChar* VG_(emit_code) ( UCodeBlock* cb,
4209 Int* nbytes,
4210 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004211{
4212 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004213 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004214 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004215 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004216 Int tgt;
4217
sewardjfa492d42002-12-08 18:20:01 +00004218 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004219
njn25e49d8e72002-09-23 09:36:25 +00004220 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004221
sewardj22854b92002-11-30 14:00:47 +00004222 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
4223 zero. We have to do this regardless of whether we're t-chaining
4224 or not. */
sewardja2113f92002-12-12 23:42:48 +00004225 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004226 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00004227 VG_(emitB) (0xFF); /* decl */
4228 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
4229 if (dis)
4230 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00004231 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00004232 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4233 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004234 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004235
sewardjb5ff83e2002-12-01 19:40:49 +00004236 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004237 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004238 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004239 curr_eip = cb->orig_eip;
4240 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4241 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004242 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004243 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004244 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004245 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004246
sewardjde4a1d02002-03-22 01:27:54 +00004247 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004248 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004249 if (!sane) {
4250 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004251 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004252 }
4253 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004254 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004255 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004256 }
njn25e49d8e72002-09-23 09:36:25 +00004257 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004258 }
njn25e49d8e72002-09-23 09:36:25 +00004259 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004260 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004261 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004262
sewardj22854b92002-11-30 14:00:47 +00004263 if (j != NULL) {
4264 vg_assert(jumpidx <= VG_MAX_JUMPS);
4265 for(i = 0; i < jumpidx; i++)
4266 j[i] = jumps[i];
4267 }
4268
sewardjde4a1d02002-03-22 01:27:54 +00004269 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004270 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004271 *nbytes = emitted_code_used;
4272 return emitted_code;
4273}
4274
njn25e49d8e72002-09-23 09:36:25 +00004275#undef dis
4276
sewardjde4a1d02002-03-22 01:27:54 +00004277/*--------------------------------------------------------------------*/
4278/*--- end vg_from_ucode.c ---*/
4279/*--------------------------------------------------------------------*/