blob: 94fd72810b9bfe94a196df892228ccdba4028d83 [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
sewardjfebaa3b2003-05-25 01:07:34 +00001586static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001587 FlagSet sets_sflags,
1588 UChar first_byte,
1589 UChar second_byte,
1590 UChar third_byte,
1591 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001592{
1593 VG_(new_emit)(True, uses_sflags, sets_sflags);
1594 VG_(emitB) ( first_byte );
1595 VG_(emitB) ( second_byte );
1596 VG_(emitB) ( third_byte );
1597 VG_(emitB) ( fourth_byte );
1598 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001599 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001600 (UInt)first_byte, (UInt)second_byte,
1601 (UInt)third_byte, (UInt)fourth_byte );
1602}
1603
sewardja453fb02003-06-14 13:22:36 +00001604static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001605 FlagSet sets_sflags,
1606 UChar first_byte,
1607 UChar second_byte,
1608 UChar third_byte,
1609 UChar fourth_byte,
1610 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001611{
1612 VG_(new_emit)(True, uses_sflags, sets_sflags);
1613 VG_(emitB) ( first_byte );
1614 VG_(emitB) ( second_byte );
1615 VG_(emitB) ( third_byte );
1616 VG_(emitB) ( fourth_byte );
1617 VG_(emitB) ( fifth_byte );
1618 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001619 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001620 (UInt)first_byte, (UInt)second_byte,
1621 (UInt)third_byte, (UInt)fourth_byte,
1622 (UInt)fifth_byte );
1623}
1624
sewardja60be0e2003-05-26 08:47:27 +00001625static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001626 FlagSet sets_sflags,
1627 UChar first_byte,
1628 UChar second_byte,
1629 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001630{
1631 VG_(new_emit)(True, uses_sflags, sets_sflags);
1632 VG_(emitB) ( first_byte );
1633 VG_(emitB) ( second_byte );
1634 VG_(emitB) ( third_byte );
1635 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001636 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001637 (UInt)first_byte, (UInt)second_byte,
1638 (UInt)third_byte );
1639}
1640
sewardje3891fa2003-06-15 03:13:48 +00001641static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1642 FlagSet sets_sflags,
1643 UChar first_byte,
1644 UChar second_byte,
1645 UChar third_byte,
1646 Int addr_reg,
1647 Int dest_reg )
1648{
1649 VG_(new_emit)(True, uses_sflags, sets_sflags);
1650 VG_(emitB) ( first_byte );
1651 VG_(emitB) ( second_byte );
1652 VG_(emitB) ( third_byte );
1653 /* 4th byte can be completely synthesised from addr_reg and
1654 dest_reg. */
1655 emit_amode_regmem_reg ( addr_reg, dest_reg );
1656 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001657 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 +00001658 (UInt)first_byte, (UInt)second_byte,
1659 (UInt)third_byte, nameIReg(4, addr_reg),
1660 nameIReg(4, dest_reg));
1661}
1662
sewardjca860012003-03-27 23:52:58 +00001663static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1664 FlagSet sets_sflags,
1665 UChar first_byte,
1666 UChar second_byte,
1667 Int ireg )
1668{
1669 VG_(new_emit)(True, uses_sflags, sets_sflags);
1670 VG_(emitB) ( 0x0F );
1671 VG_(emitB) ( first_byte );
1672 second_byte &= 0x38; /* mask out mod and rm fields */
1673 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1674 second_byte |= (ireg & 7); /* patch in our ireg */
1675 VG_(emitB) ( second_byte );
1676 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001677 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1678 (UInt)first_byte, (UInt)second_byte,
1679 nameIReg(4,ireg) );
1680}
1681
1682static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1683 FlagSet sets_sflags,
1684 UChar first_byte,
1685 UChar second_byte,
1686 Int ireg )
1687{
1688 VG_(new_emit)(True, uses_sflags, sets_sflags);
1689 VG_(emitB) ( 0x0F );
1690 VG_(emitB) ( first_byte );
1691 second_byte &= 0x38; /* mask out mod and rm fields */
1692 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1693 second_byte |= (ireg & 7); /* patch in our ireg */
1694 VG_(emitB) ( second_byte );
1695 if (dis)
1696 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001697 (UInt)first_byte, (UInt)second_byte,
1698 nameIReg(4,ireg) );
1699}
1700
1701static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1702 FlagSet sets_sflags,
1703 UChar first_byte,
1704 UChar second_byte,
1705 UChar third_byte )
1706{
1707 VG_(new_emit)(True, uses_sflags, sets_sflags);
1708 VG_(emitB) ( 0x0F );
1709 VG_(emitB) ( first_byte );
1710 VG_(emitB) ( second_byte );
1711 VG_(emitB) ( third_byte );
1712 if (dis)
1713 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1714 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1715}
1716
sewardj3d7c9c82003-03-26 21:08:13 +00001717static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1718 FlagSet sets_sflags,
1719 UChar first_byte,
1720 UChar second_byte )
1721{
1722 VG_(new_emit)(True, uses_sflags, sets_sflags);
1723 VG_(emitB) ( 0x0F );
1724 VG_(emitB) ( first_byte );
1725 VG_(emitB) ( second_byte );
1726 if (dis)
1727 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1728 (UInt)first_byte, (UInt)second_byte );
1729}
1730
1731static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1732 FlagSet sets_sflags,
1733 UChar first_byte )
1734{
1735 VG_(new_emit)(True, uses_sflags, sets_sflags);
1736 VG_(emitB) ( 0x0F );
1737 VG_(emitB) ( first_byte );
1738 if (dis)
1739 VG_(printf)("\n\t\tmmx1-0x%x\n",
1740 (UInt)first_byte );
1741}
1742
sewardjde4a1d02002-03-22 01:27:54 +00001743
1744/*----------------------------------------------------*/
1745/*--- misc instruction emitters ---*/
1746/*----------------------------------------------------*/
1747
njn25e49d8e72002-09-23 09:36:25 +00001748void VG_(emit_call_reg) ( Int reg )
1749{
sewardjfa492d42002-12-08 18:20:01 +00001750 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001751 VG_(emitB) ( 0xFF ); /* Grp5 */
1752 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1753 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001754 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001755}
1756
sewardjf0f12aa2002-12-28 00:04:08 +00001757static
1758void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1759 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001760{
sewardjfa492d42002-12-08 18:20:01 +00001761 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001762 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001763
1764 if (byte_off < -128 || byte_off > 127) {
1765 VG_(emitB) ( 0xFF );
1766 VG_(emitB) ( 0x95 );
1767 VG_(emitL) ( byte_off );
1768 } else {
1769 VG_(emitB) ( 0xFF );
1770 VG_(emitB) ( 0x55 );
1771 VG_(emitB) ( byte_off );
1772 }
1773 if (dis)
1774 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001775}
1776
sewardja2c5a732002-12-15 03:10:42 +00001777#if 0
1778/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001779static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1780{
1781 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001782 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001783 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1784 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001785 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001786 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001787 if (dis)
1788 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1789 nameIReg(4,regmem));
1790}
sewardja2c5a732002-12-15 03:10:42 +00001791#endif
sewardjde4a1d02002-03-22 01:27:54 +00001792
njn25e49d8e72002-09-23 09:36:25 +00001793void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001794{
njne427a662002-10-02 11:08:25 +00001795 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001796 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1797 VG_(emitB) ( 0x8D );
1798 VG_(emitB) ( 0x64 );
1799 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001800 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001801 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001802 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001803}
1804
1805
1806static void emit_movb_AL_zeroESPmem ( void )
1807{
1808 /* movb %al, 0(%esp) */
1809 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001810 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001811 VG_(emitB) ( 0x88 );
1812 VG_(emitB) ( 0x44 );
1813 VG_(emitB) ( 0x24 );
1814 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001815 if (dis)
1816 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1817}
1818
1819static void emit_movb_zeroESPmem_AL ( void )
1820{
1821 /* movb 0(%esp), %al */
1822 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001823 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001824 VG_(emitB) ( 0x8A );
1825 VG_(emitB) ( 0x44 );
1826 VG_(emitB) ( 0x24 );
1827 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001828 if (dis)
1829 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1830}
1831
sewardja2113f92002-12-12 23:42:48 +00001832/* Jump target states */
1833#define TGT_UNDEF (1 << 16)
1834#define TGT_FORWARD (2 << 16)
1835#define TGT_BACKWARD (3 << 16)
1836
1837static inline Int tgt_state(Int tgt)
1838{
1839 return tgt & 0xffff0000;
1840}
1841
1842static inline Int tgt_addr(Int tgt)
1843{
1844 return tgt & 0x0000ffff;
1845}
1846
1847static inline Int mk_tgt(Int state, Int addr)
1848{
1849 vg_assert(state == TGT_UNDEF
1850 || state == TGT_FORWARD || state == TGT_BACKWARD);
1851 vg_assert((addr & 0xffff0000) == 0);
1852
1853 return state | addr;
1854}
1855
1856void VG_(init_target) ( Int *tgt )
1857{
1858 *tgt = TGT_UNDEF;
1859}
1860
1861void VG_(target_back) ( Int *tgt )
1862{
1863 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1864
1865 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1866}
1867
1868void VG_(target_forward) ( Int *tgt )
1869{
1870 Int delta;
1871
1872 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1873 tgt_state(*tgt) == TGT_UNDEF);
1874
1875 if (tgt_state(*tgt) == TGT_UNDEF)
1876 return; /* target not used */
1877
1878 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1879 vg_assert(delta >= -128 && delta <= 127);
1880 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001881 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001882 emitted_code[tgt_addr(*tgt)] = delta;
1883 if (dis)
1884 VG_(printf)("(target to jump site %d; delta: %d)\n",
1885 tgt_addr(*tgt), delta);
1886}
1887
1888void VG_(emit_target_delta) ( Int *tgt )
1889{
1890 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
1891 tgt_state(*tgt) == TGT_BACKWARD);
1892
1893 if (tgt_state(*tgt) == TGT_UNDEF) {
1894 /* forward jump */
1895 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
1896 VG_(emitB) (0x00);
1897 } else {
1898 /* backward jump */
1899 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1900 vg_assert(delta >= -128 && delta <= 127);
1901 VG_(emitB) (delta);
1902 }
1903}
1904
sewardjde4a1d02002-03-22 01:27:54 +00001905
1906/* Emit a jump short with an 8-bit signed offset. Note that the
1907 offset is that which should be added to %eip once %eip has been
1908 advanced over this insn. */
sewardjf0f12aa2002-12-28 00:04:08 +00001909void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +00001910{
1911 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00001912 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001913 VG_(emitB) ( 0x70 + (UInt)cond );
1914 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00001915 if (dis)
1916 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
njn563f96f2003-02-03 11:17:46 +00001917 VG_(name_UCondcode)(cond), delta );
sewardjde4a1d02002-03-22 01:27:54 +00001918}
1919
sewardja2113f92002-12-12 23:42:48 +00001920/* Same as above, but defers emitting the delta */
1921void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt )
1922{
sewardj706240d2002-12-26 17:10:12 +00001923 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
sewardja2113f92002-12-12 23:42:48 +00001924 VG_(emitB) ( 0x70 + (UInt)cond );
1925 VG_(emit_target_delta) (tgt);
1926 if (dis)
1927 VG_(printf)( "\n\t\tj%s-8\t%%eip+(%d)\n",
njn563f96f2003-02-03 11:17:46 +00001928 VG_(name_UCondcode)(cond), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00001929}
1930
1931
1932
sewardjf0f12aa2002-12-28 00:04:08 +00001933static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00001934{
sewardjf0f12aa2002-12-28 00:04:08 +00001935 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001936 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1937 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001938 if (dis)
1939 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00001940 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00001941}
1942
1943static void emit_ret ( void )
1944{
sewardjfa492d42002-12-08 18:20:01 +00001945 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00001946 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001947 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001948 if (dis)
1949 VG_(printf)("\n\t\tret\n");
1950}
1951
sewardj22854b92002-11-30 14:00:47 +00001952/* Predicate used in sanity checks elsewhere - returns true if any
1953 jump-site is an actual chained jump */
1954Bool VG_(is_chained_jumpsite)(Addr a)
1955{
1956 UChar *cp = (UChar *)a;
1957
1958 return (*cp == 0xE9); /* 0xE9 -- jmp */
1959}
1960
sewardj83f11862002-12-01 02:07:08 +00001961static
1962Bool is_fresh_jumpsite(UChar *cp)
1963{
1964 return
1965 cp[0] == 0x0F && /* UD2 */
1966 cp[1] == 0x0B &&
1967 cp[2] == 0x0F && /* UD2 */
1968 cp[3] == 0x0B &&
1969 cp[4] == 0x90; /* NOP */
1970}
1971
sewardj22854b92002-11-30 14:00:47 +00001972/* Predicate used in sanity checks elsewhere - returns true if all
1973 jump-sites are calls to VG_(patch_me) */
1974Bool VG_(is_unchained_jumpsite)(Addr a)
1975{
1976 UChar *cp = (UChar *)a;
1977 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1978 Int idelta;
1979
1980 if (*cp++ != 0xE8) /* 0xE8 == call */
1981 return False;
1982
1983 idelta = (*cp++) << 0;
1984 idelta |= (*cp++) << 8;
1985 idelta |= (*cp++) << 16;
1986 idelta |= (*cp++) << 24;
1987
1988 return idelta == delta;
1989}
1990
1991/* Return target address for a direct jmp */
1992Addr VG_(get_jmp_dest)(Addr a)
1993{
1994 Int delta;
1995 UChar *cp = (UChar *)a;
1996
1997 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1998 return 0;
1999
2000 delta = (*cp++) << 0;
2001 delta |= (*cp++) << 8;
2002 delta |= (*cp++) << 16;
2003 delta |= (*cp++) << 24;
2004
2005 return a + VG_PATCHME_JMPSZ + delta;
2006}
2007
2008/* unchain a BB by generating a call to VG_(patch_me) */
2009void VG_(unchain_jumpsite)(Addr a)
2010{
2011 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2012 UChar *cp = (UChar *)a;
2013
2014 if (VG_(is_unchained_jumpsite)(a))
2015 return; /* don't write unnecessarily */
2016
sewardj83f11862002-12-01 02:07:08 +00002017 if (!is_fresh_jumpsite(cp))
2018 VG_(bb_dechain_count)++; /* update stats */
2019
sewardj22854b92002-11-30 14:00:47 +00002020 *cp++ = 0xE8; /* call */
2021 *cp++ = (delta >> 0) & 0xff;
2022 *cp++ = (delta >> 8) & 0xff;
2023 *cp++ = (delta >> 16) & 0xff;
2024 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002025}
2026
2027/* This doesn't actually generate a call to VG_(patch_me), but
2028 reserves enough space in the instruction stream for it to happen
2029 and records the offset into the jump table. This is because call
2030 is a relative jump, and so will be affected when this code gets
2031 moved about. The translation table will "unchain" this basic block
2032 on insertion (with VG_(unchain_BB)()), and thereby generate a
2033 proper call instruction. */
2034static void emit_call_patchme( void )
2035{
2036 vg_assert(VG_PATCHME_CALLSZ == 5);
2037
sewardjfa492d42002-12-08 18:20:01 +00002038 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002039 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002040
2041 if (jumpidx >= VG_MAX_JUMPS) {
2042 /* If there too many jumps in this basic block, fall back to
2043 dispatch loop. We still need to keep it the same size as the
2044 call sequence. */
2045 VG_(emitB) ( 0xC3 ); /* ret */
2046 VG_(emitB) ( 0x90 ); /* nop */
2047 VG_(emitB) ( 0x90 ); /* nop */
2048 VG_(emitB) ( 0x90 ); /* nop */
2049 VG_(emitB) ( 0x90 ); /* nop */
2050
2051 if (dis)
2052 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
2053
2054 if (0 && VG_(clo_verbosity))
2055 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2056 } else {
2057 jumps[jumpidx++] = emitted_code_used;
2058
2059 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2060 VG_(emitB) ( 0x0B );
2061 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2062 VG_(emitB) ( 0x0B );
2063 VG_(emitB) ( 0x90 ); /* NOP */
2064
2065 if (dis)
2066 VG_(printf)("\n\t\tud2; ud2; nop\n");
2067 }
2068}
2069
njn25e49d8e72002-09-23 09:36:25 +00002070void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002071{
sewardjf0f12aa2002-12-28 00:04:08 +00002072 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002073 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002074 if (dis)
2075 VG_(printf)("\n\t\tpushal\n");
2076}
2077
njn25e49d8e72002-09-23 09:36:25 +00002078void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002079{
sewardjf0f12aa2002-12-28 00:04:08 +00002080 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002081 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002082 if (dis)
2083 VG_(printf)("\n\t\tpopal\n");
2084}
2085
2086static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2087{
sewardjf0f12aa2002-12-28 00:04:08 +00002088 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002089 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2090 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002091 if (dis)
2092 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2093 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2094}
2095
2096static void emit_lea_sib_reg ( UInt lit, Int scale,
2097 Int regbase, Int regindex, Int reg )
2098{
sewardjf0f12aa2002-12-28 00:04:08 +00002099 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002100 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002101 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2102 if (dis)
2103 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2104 lit, nameIReg(4,regbase),
2105 nameIReg(4,regindex), scale,
2106 nameIReg(4,reg) );
2107}
2108
njn25e49d8e72002-09-23 09:36:25 +00002109void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002110{
sewardjf0f12aa2002-12-28 00:04:08 +00002111 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002112 VG_(emitB) ( 0x0F );
2113 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002114 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2115 if (dis)
2116 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2117}
2118
2119/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002120/*--- Helper offset -> addr translation ---*/
2121/*----------------------------------------------------*/
2122
2123/* Finds the baseBlock offset of a skin-specified helper.
2124 * Searches through compacts first, then non-compacts. */
2125Int VG_(helper_offset)(Addr a)
2126{
sewardj05bcdcb2003-05-18 10:05:38 +00002127 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002128 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002129
2130 for (i = 0; i < VG_(n_compact_helpers); i++)
2131 if (VG_(compact_helper_addrs)[i] == a)
2132 return VG_(compact_helper_offsets)[i];
2133 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2134 if (VG_(noncompact_helper_addrs)[i] == a)
2135 return VG_(noncompact_helper_offsets)[i];
2136
2137 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002138 VG_(get_fnname) ( a, buf, 100 );
2139
njn25e49d8e72002-09-23 09:36:25 +00002140 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002141 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2142 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002143
2144 VG_(printf)(" compact helpers: ");
2145 for (i = 0; i < VG_(n_compact_helpers); i++)
2146 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2147
2148 VG_(printf)("\n non-compact helpers: ");
2149 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2150 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2151
2152 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002153 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002154}
2155
2156/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002157/*--- Instruction synthesisers ---*/
2158/*----------------------------------------------------*/
2159
2160static Condcode invertCondition ( Condcode cond )
2161{
2162 return (Condcode)(1 ^ (UInt)cond);
2163}
2164
2165
2166/* Synthesise a call to *baseBlock[offset], ie,
2167 call * (4 x offset)(%ebp).
2168*/
sewardjfa492d42002-12-08 18:20:01 +00002169void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002170 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002171{
2172 vg_assert(word_offset >= 0);
2173 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002174 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002175 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002176 }
sewardjf0f12aa2002-12-28 00:04:08 +00002177 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002178}
2179
njn25e49d8e72002-09-23 09:36:25 +00002180static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002181{
njn25e49d8e72002-09-23 09:36:25 +00002182 if (src != dst) {
2183 VG_(emit_movv_reg_reg) ( 4, src, dst );
2184 ccall_arg_setup_instrs++;
2185 }
njn6431be72002-07-28 09:53:34 +00002186}
njn25e49d8e72002-09-23 09:36:25 +00002187
2188/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2189static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2190{
2191 if (RealReg == tag) {
2192 maybe_emit_movl_reg_reg ( litOrReg, reg );
2193 } else if (Literal == tag) {
2194 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2195 ccall_arg_setup_instrs++;
2196 }
2197 else
njne427a662002-10-02 11:08:25 +00002198 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002199}
2200
2201static
2202void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2203{
2204 if (R_EAX == reg1) {
2205 VG_(emit_swapl_reg_EAX) ( reg2 );
2206 } else if (R_EAX == reg2) {
2207 VG_(emit_swapl_reg_EAX) ( reg1 );
2208 } else {
2209 emit_swapl_reg_reg ( reg1, reg2 );
2210 }
2211 ccall_arg_setup_instrs++;
2212}
2213
2214static
2215void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2216{
2217 if (dst1 != src2) {
2218 maybe_emit_movl_reg_reg ( src1, dst1 );
2219 maybe_emit_movl_reg_reg ( src2, dst2 );
2220
2221 } else if (dst2 != src1) {
2222 maybe_emit_movl_reg_reg ( src2, dst2 );
2223 maybe_emit_movl_reg_reg ( src1, dst1 );
2224
2225 } else {
2226 /* swap to break cycle */
2227 emit_swapl_arg_regs ( dst1, dst2 );
2228 }
2229}
2230
2231static
2232void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2233 UInt dst1, UInt dst2, UInt dst3)
2234{
2235 if (dst1 != src2 && dst1 != src3) {
2236 maybe_emit_movl_reg_reg ( src1, dst1 );
2237 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2238
2239 } else if (dst2 != src1 && dst2 != src3) {
2240 maybe_emit_movl_reg_reg ( src2, dst2 );
2241 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2242
2243 } else if (dst3 != src1 && dst3 != src2) {
2244 maybe_emit_movl_reg_reg ( src3, dst3 );
2245 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2246
2247 } else {
2248 /* break cycle */
2249 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2250 emit_swapl_arg_regs ( dst1, dst2 );
2251 emit_swapl_arg_regs ( dst1, dst3 );
2252
2253 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2254 emit_swapl_arg_regs ( dst1, dst3 );
2255 emit_swapl_arg_regs ( dst1, dst2 );
2256
2257 } else {
njne427a662002-10-02 11:08:25 +00002258 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002259 }
2260 }
2261}
2262
2263static
2264void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2265 UInt src1, UInt src2,
2266 UInt dst1, UInt dst2)
2267{
2268 /* If either are lits, order doesn't matter */
2269 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2270 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2271 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2272
2273 } else {
2274 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2275 }
2276}
2277
2278static
2279void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2280 UInt src1, UInt src2, UInt src3,
2281 UInt dst1, UInt dst2, UInt dst3)
2282{
2283 // SSS: fix this eventually -- make STOREV use two RealRegs?
2284 /* Not supporting literals for 3-arg C functions -- they're only used
2285 by STOREV which has 2 args */
2286 vg_assert(RealReg == tagv[src1] &&
2287 RealReg == tagv[src2] &&
2288 RealReg == tagv[src3]);
2289 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2290 dst1, dst2, dst3 );
2291}
2292
2293/* Synthesise a call to a C function `fn' (which must be registered in
2294 baseBlock) doing all the reg saving and arg handling work.
2295
2296 WARNING: a UInstr should *not* be translated with synth_ccall followed
2297 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2298 such behaviour and everything will fall over.
2299 */
2300void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2301 Tag tagv[], Int ret_reg,
2302 RRegSet regs_live_before, RRegSet regs_live_after )
2303{
2304 Int i;
2305 Int stack_used = 0;
2306 Bool preserve_eax, preserve_ecx, preserve_edx;
2307
2308 vg_assert(0 <= regparms_n && regparms_n <= 3);
2309
2310 ccalls++;
2311
2312 /* If %e[acd]x is live before and after the C call, save/restore it.
2313 Unless the return values clobbers the reg; in this case we must not
2314 save/restore the reg, because the restore would clobber the return
2315 value. (Before and after the UInstr really constitute separate live
2316 ranges, but you miss this if you don't consider what happens during
2317 the UInstr.) */
2318# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002319 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2320 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002321 ret_reg != realReg)
2322
2323 preserve_eax = PRESERVE_REG(R_EAX);
2324 preserve_ecx = PRESERVE_REG(R_ECX);
2325 preserve_edx = PRESERVE_REG(R_EDX);
2326
2327# undef PRESERVE_REG
2328
2329 /* Save caller-save regs as required */
2330 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2331 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2332 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2333
2334 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2335 is the number of args passed in regs (maximum 3 for GCC on x86). */
2336
2337 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002338
njn25e49d8e72002-09-23 09:36:25 +00002339 /* First push stack args (RealRegs or Literals) in reverse order. */
2340 for (i = argc-1; i >= regparms_n; i--) {
2341 switch (tagv[i]) {
2342 case RealReg:
2343 VG_(emit_pushv_reg) ( 4, argv[i] );
2344 break;
2345 case Literal:
2346 /* Use short form of pushl if possible. */
2347 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2348 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2349 else
2350 VG_(emit_pushl_lit32)( argv[i] );
2351 break;
2352 default:
2353 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002354 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002355 }
2356 stack_used += 4;
2357 ccall_arg_setup_instrs++;
2358 }
njn6431be72002-07-28 09:53:34 +00002359
njn25e49d8e72002-09-23 09:36:25 +00002360 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2361 If moving values between registers, be careful not to clobber any on
2362 the way. Happily we can use xchgl to swap registers.
2363 */
2364 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002365
njn25e49d8e72002-09-23 09:36:25 +00002366 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2367 case 3:
2368 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2369 R_EAX, R_EDX, R_ECX );
2370 break;
njn6431be72002-07-28 09:53:34 +00002371
njn25e49d8e72002-09-23 09:36:25 +00002372 /* Less-tricky. Args passed in %eax and %edx. */
2373 case 2:
2374 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2375 break;
2376
2377 /* Easy. Just move arg1 into %eax (if not already in there). */
2378 case 1:
2379 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2380 break;
2381
2382 case 0:
2383 break;
2384
2385 default:
njne427a662002-10-02 11:08:25 +00002386 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002387 }
2388
sewardjfa492d42002-12-08 18:20:01 +00002389 /* Call the function - may trash all flags */
2390 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002391
2392 /* Clear any args from stack */
2393 if (0 != stack_used) {
2394 VG_(emit_add_lit_to_esp) ( stack_used );
2395 ccall_stack_clears++;
2396 }
2397
2398 /* Move return value into ret_reg if necessary and not already there */
2399 if (INVALID_REALREG != ret_reg) {
2400 ccall_retvals++;
2401 if (R_EAX != ret_reg) {
2402 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2403 ccall_retval_movs++;
2404 }
2405 }
2406
2407 /* Restore live caller-save regs as required */
2408 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2409 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2410 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002411}
sewardjde4a1d02002-03-22 01:27:54 +00002412
sewardj2e93c502002-04-12 11:12:52 +00002413static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002414{
sewardj2e93c502002-04-12 11:12:52 +00002415 switch (jmpkind) {
2416 case JmpBoring:
2417 break;
sewardj2e93c502002-04-12 11:12:52 +00002418 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002419 break;
2420 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002421 break;
2422 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002423 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002424 break;
2425 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002426 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002427 break;
2428 default:
njne427a662002-10-02 11:08:25 +00002429 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002430 }
2431}
2432
2433/* Jump to the next translation, by loading its original addr into
2434 %eax and returning to the scheduler. Signal special requirements
2435 by loading a special value into %ebp first.
2436*/
2437static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2438{
sewardjfa492d42002-12-08 18:20:01 +00002439 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002440 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002441 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002442 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002443 emit_ret();
2444}
2445
sewardj22854b92002-11-30 14:00:47 +00002446static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002447
2448/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002449static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002450{
sewardjfa492d42002-12-08 18:20:01 +00002451 maybe_emit_put_eflags(); /* save flags here */
2452
njn25e49d8e72002-09-23 09:36:25 +00002453 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002454
2455 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2456 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2457 emit_call_patchme();
2458 } else {
2459 load_ebp_from_JmpKind ( jmpkind );
2460 emit_ret();
2461 }
sewardjde4a1d02002-03-22 01:27:54 +00002462}
2463
2464
sewardj2370f3b2002-11-30 15:01:01 +00002465static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002466static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002467 Opcode opcode, Int size,
2468 UInt lit, Int reg );
2469
sewardjfa492d42002-12-08 18:20:01 +00002470static void synth_jcond_lit ( Condcode cond,
2471 Addr addr,
2472 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002473{
sewardj2370f3b2002-11-30 15:01:01 +00002474 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002475 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002476 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002477
sewardja2113f92002-12-12 23:42:48 +00002478 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002479 VG_(init_target)(&tgt2);
2480 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002481
sewardjfa492d42002-12-08 18:20:01 +00002482 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2483 if need be */
2484 maybe_emit_put_eflags();
2485 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2486
2487 if (eflags_state == UPD_Both) {
2488 /* The flags are already set up, so we just use them as is. */
2489 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002490 cond = invertCondition(cond);
2491 } else {
sewardj75f04932002-12-12 23:13:21 +00002492 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002493
2494 /* The simd state contains the most recent version, so we emit a
2495 sequence to calculate the relevant condition directly out of
2496 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2497 copying them back to the real flags via popf. Notice that
2498 some of these sequences trash %eax, but that should be free
2499 now since this is the end of a bb and therefore all regs are
2500 dead. */
2501 simd = False;
2502
2503 switch (cond) {
2504
sewardjbb6c1182002-12-12 23:54:47 +00002505 case CondLE: /* Z || S != O -> S || !P */
2506 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002507 vg_assert(eax_trashable);
2508
2509 VG_(emit_movv_offregmem_reg)
2510 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2511 /* eax == %EFLAGS */
2512
sewardjbb6c1182002-12-12 23:54:47 +00002513 VG_(emit_nonshiftopv_lit_reg)
2514 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2515 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002516
sewardjbb6c1182002-12-12 23:54:47 +00002517 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2518 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002519
sewardj09736622002-12-28 00:19:00 +00002520 /* actually set the real cpu flags, since ROR changes
2521 neither P nor Z */
2522 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2523
sewardjbb6c1182002-12-12 23:54:47 +00002524 if (cond == CondLE) {
2525 /* test Z */
2526 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump);
2527 /* test OF != SF */
2528 cond = CondP;
2529 } else {
2530 /* test Z */
2531 VG_(emit_jcondshort_target)(False, CondS, &tgt2);
2532 /* test OF == SF */
2533 cond = CondNP;
2534 }
sewardj2370f3b2002-11-30 15:01:01 +00002535 break;
2536
sewardjfa492d42002-12-08 18:20:01 +00002537 case CondL:
2538 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002539 vg_assert(eax_trashable);
2540
2541 VG_(emit_movv_offregmem_reg)
2542 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2543 /* eax == %EFLAGS */
2544
sewardj75f04932002-12-12 23:13:21 +00002545 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2546 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002547
sewardj75f04932002-12-12 23:13:21 +00002548 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2549 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002550
sewardj09736622002-12-28 00:19:00 +00002551 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002552 if (cond == CondL) cond = CondP; else cond = CondNP;
2553 break;
sewardjfa492d42002-12-08 18:20:01 +00002554
2555 case CondB:
2556 case CondNB:
2557 mask = EFlagC; goto simple; /* C=1 */
2558
2559 case CondZ:
2560 case CondNZ:
2561 mask = EFlagZ; goto simple; /* Z=1 */
2562
2563 case CondBE:
2564 case CondNBE:
2565 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2566
2567 case CondS:
2568 case CondNS:
2569 mask = EFlagS; goto simple; /* S=1 */
2570
2571 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002572 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002573 mask = EFlagP; goto simple; /* P=1 */
2574
sewardj39542072002-12-09 22:44:00 +00002575 case CondO:
2576 case CondNO:
2577 mask = EFlagO; goto simple; /* O=1 */
2578
sewardjfa492d42002-12-08 18:20:01 +00002579 default:
2580 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002581 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002582 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2583
2584 simple:
2585 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002586 if ((mask & 0xff) == mask) {
2587 VG_(emitB) ( 0xF6 ); /* Grp3 */
2588 VG_(emit_amode_offregmem_reg)(
2589 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2590 VG_(emitB) (mask);
2591 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002592 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002593 mask, VGOFF_(m_eflags) * 4);
2594 } else {
sewardjfa492d42002-12-08 18:20:01 +00002595 /* all cond codes are in lower 16 bits */
2596 vg_assert((mask & 0xffff) == mask);
2597
2598 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002599 VG_(emitB) ( 0xF7 );
2600 VG_(emit_amode_offregmem_reg)(
2601 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002602 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002603 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002604 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002605 mask, VGOFF_(m_eflags) * 4);
2606 }
2607
sewardj75f04932002-12-12 23:13:21 +00002608 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002609 break;
2610 }
2611 }
2612
sewardja2113f92002-12-12 23:42:48 +00002613 VG_(emit_jcondshort_target) ( simd, cond, &tgt );
sewardjbb6c1182002-12-12 23:54:47 +00002614
2615 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002616 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002617
2618 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002619 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002620}
2621
2622
sewardj2370f3b2002-11-30 15:01:01 +00002623
sewardjde4a1d02002-03-22 01:27:54 +00002624static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2625{
sewardja2113f92002-12-12 23:42:48 +00002626 Int tgt;
2627
2628 VG_(init_target)(&tgt);
2629
sewardjfa492d42002-12-08 18:20:01 +00002630 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002631
2632 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt );
sewardj2e93c502002-04-12 11:12:52 +00002633 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002634
2635 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002636}
2637
2638
2639static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2640{
2641 /* Load the zero-extended literal into reg, at size l,
2642 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002643 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002644}
2645
2646
2647static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2648{
2649 switch (size) {
2650 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
daywalkerf26b2162003-09-30 23:01:50 +00002651 case 2: VG_(emit_movzwl_regmem_reg) ( reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002652 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002653 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002654 }
2655}
2656
2657
2658static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2659{
2660 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002661 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
2662 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
2663 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002664 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002665 }
2666}
2667
2668
2669static void synth_mov_reg_offregmem ( Int size, Int reg,
2670 Int off, Int areg )
2671{
2672 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002673 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2674 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002675 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002676 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002677 }
2678 else {
njn25e49d8e72002-09-23 09:36:25 +00002679 VG_(emit_swapl_reg_EAX) ( reg );
2680 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2681 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002682 }
2683 break;
njne427a662002-10-02 11:08:25 +00002684 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002685 }
2686}
2687
2688
2689static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2690{
2691 Int s1;
2692 switch (size) {
2693 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
2694 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
2695 case 1: if (reg1 < 4) {
2696 emit_movb_reg_regmem ( reg1, reg2 );
2697 }
2698 else {
2699 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2700 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2701 emit_swapl_reg_reg ( s1, reg1 );
2702 emit_movb_reg_regmem ( s1, reg2 );
2703 emit_swapl_reg_reg ( s1, reg1 );
2704 }
2705 break;
njne427a662002-10-02 11:08:25 +00002706 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002707 }
2708}
2709
2710
sewardjf0f12aa2002-12-28 00:04:08 +00002711static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002712 Opcode opcode, Int size,
2713 Int reg )
2714{
2715 /* NB! opcode is a uinstr opcode, not an x86 one! */
2716 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002717 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002718 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002719 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002720 break;
2721 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002722 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002723 } else {
njn25e49d8e72002-09-23 09:36:25 +00002724 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002725 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002726 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002727 }
2728 break;
njne427a662002-10-02 11:08:25 +00002729 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002730 }
2731}
2732
2733
2734
sewardjf0f12aa2002-12-28 00:04:08 +00002735static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002736 Opcode opcode, Int size,
2737 Int reg1, Int reg2 )
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_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002742 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002743 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002744 break;
2745 case 1: { /* Horrible ... */
2746 Int s1, s2;
2747 /* Choose s1 and s2 to be x86 regs which we can talk about the
2748 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2749 sure s1 != s2 and that neither of them equal either reg1 or
2750 reg2. Then use them as temporaries to make things work. */
2751 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002752 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002753 break;
2754 }
2755 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2756 if (reg1 >= 4 && reg2 < 4) {
2757 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002758 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002759 emit_swapl_reg_reg ( reg1, s1 );
2760 break;
2761 }
2762 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2763 if (reg1 < 4 && reg2 >= 4) {
2764 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002765 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002766 emit_swapl_reg_reg ( reg2, s2 );
2767 break;
2768 }
2769 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2770 emit_swapl_reg_reg ( reg1, s1 );
2771 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002772 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002773 emit_swapl_reg_reg ( reg1, s1 );
2774 emit_swapl_reg_reg ( reg2, s2 );
2775 break;
2776 }
2777 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2778 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002779 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002780 emit_swapl_reg_reg ( reg1, s1 );
2781 break;
2782 }
njne427a662002-10-02 11:08:25 +00002783 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002784 }
njne427a662002-10-02 11:08:25 +00002785 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002786 }
2787}
2788
sewardja2c5a732002-12-15 03:10:42 +00002789#if 0
2790/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002791static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002792 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002793 Opcode opcode, Int size,
2794 Int off, Int areg, Int reg )
2795{
2796 switch (size) {
2797 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002798 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002799 break;
2800 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002801 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002802 break;
2803 case 1:
2804 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002805 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002806 } else {
2807 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002808 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002809 VG_(emit_swapl_reg_EAX) ( reg );
2810 }
2811 break;
2812 default:
2813 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2814 }
2815}
sewardja2c5a732002-12-15 03:10:42 +00002816#endif
sewardjfa492d42002-12-08 18:20:01 +00002817
sewardjde4a1d02002-03-22 01:27:54 +00002818static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002819 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002820 Opcode opcode, Int size,
2821 Int off, Int areg, Int reg )
2822{
2823 switch (size) {
2824 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002825 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002826 break;
2827 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002828 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002829 break;
2830 case 1:
2831 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002832 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002833 } else {
njn25e49d8e72002-09-23 09:36:25 +00002834 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002835 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002836 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002837 }
2838 break;
2839 default:
njne427a662002-10-02 11:08:25 +00002840 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002841 }
2842}
2843
2844
sewardjf0f12aa2002-12-28 00:04:08 +00002845static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002846 Opcode opcode, Int size,
2847 UInt lit, Int reg )
2848{
2849 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002850 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002851 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002852 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002853 break;
2854 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002855 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002856 } else {
njn25e49d8e72002-09-23 09:36:25 +00002857 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002858 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002859 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002860 }
2861 break;
njne427a662002-10-02 11:08:25 +00002862 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002863 }
2864}
2865
sewardjf0f12aa2002-12-28 00:04:08 +00002866static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002867 Opcode opcode, Int size,
2868 UInt lit, Int off, Int regmem )
2869{
2870 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002871 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002872 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002873 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002874 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002875 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00002876 break;
2877 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
2878 }
2879}
2880
sewardjde4a1d02002-03-22 01:27:54 +00002881
jsgf5efa4fd2003-10-14 21:49:11 +00002882static void synth_mul_reg_reg ( Bool upd_cc,
2883 Opcode opcode, Int size,
2884 Int reg1, Int reg2 )
2885{
2886 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2887
2888 switch (size) {
2889 case 2:
2890 VG_(emitB)(0x66);
2891 /* FALLTHROUGH */
2892 case 4:
2893 VG_(emitB)(0x0F);
2894 VG_(emitB)(0xAF);
2895 VG_(emit_amode_ereg_greg)(reg1, reg2);
2896 break;
2897
2898 case 1:
2899 VG_(core_panic)("can't do byte mul");
2900 break;
2901 }
2902 if (dis)
2903 VG_(printf)("\n\t\timul%c\t%s, %s\n",
2904 nameISize(size),
2905 nameIReg(size, reg1),
2906 nameIReg(size, reg2));
2907}
2908
2909static void synth_mul_lit_reg ( Bool upd_cc,
2910 Opcode opcode, Int size,
2911 UInt lit, Int reg )
2912{
2913 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2914
2915 switch (size) {
2916 case 2:
2917 VG_(emitB)(0x66);
2918 /* FALLTHROUGH */
2919 case 4:
2920 VG_(emitB)(0x69);
2921 VG_(emit_amode_ereg_greg)(reg, 0);
2922 if (size == 2)
2923 VG_(emitW)(lit);
2924 else
2925 VG_(emitL)(lit);
2926 break;
2927
2928 case 1:
2929 VG_(core_panic)("can't do byte mul");
2930 break;
2931 }
2932 if (dis)
2933 VG_(printf)("\n\t\timul%c\t%d, %s\n",
2934 nameISize(size),
2935 lit,
2936 nameIReg(size, reg));
2937}
2938
2939static void synth_mul_offregmem_reg (
2940 Bool upd_cc,
2941 Opcode opcode, Int size,
2942 Int off, Int areg, Int reg )
2943{
2944 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
2945
2946 switch(size) {
2947 case 2:
2948 VG_(emitB)(0x66);
2949 /* FALLTHROUGH */
2950 case 4:
2951 VG_(emitB)(0x0F);
2952 VG_(emitB)(0xAF);
2953 VG_(emit_amode_offregmem_reg)(off, areg, reg);
2954 break;
2955
2956 case 1:
2957 VG_(core_panic)("can't do byte mul");
2958 }
2959
2960 if (dis)
2961 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
2962 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
2963
2964}
2965
2966
sewardjde4a1d02002-03-22 01:27:54 +00002967static void synth_push_reg ( Int size, Int reg )
2968{
2969 switch (size) {
2970 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002971 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002972 break;
2973 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002974 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002975 break;
2976 /* Pray that we don't have to generate this really cruddy bit of
2977 code very often. Could do better, but can I be bothered? */
2978 case 1:
2979 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00002980 VG_(emit_add_lit_to_esp)(-1);
2981 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002982 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00002983 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002984 break;
2985 default:
njne427a662002-10-02 11:08:25 +00002986 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002987 }
2988}
2989
2990
2991static void synth_pop_reg ( Int size, Int reg )
2992{
2993 switch (size) {
2994 case 4:
njn25e49d8e72002-09-23 09:36:25 +00002995 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002996 break;
2997 case 2:
njn25e49d8e72002-09-23 09:36:25 +00002998 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002999 break;
3000 case 1:
3001 /* Same comment as above applies. */
3002 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003003 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003004 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003005 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3006 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003007 break;
njne427a662002-10-02 11:08:25 +00003008 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003009 }
3010}
3011
3012
sewardjf0f12aa2002-12-28 00:04:08 +00003013static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003014 Opcode opcode, Int size,
3015 Int regs, Int regd )
3016{
3017 synth_push_reg ( size, regd );
3018 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003019 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003020 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3021 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3022 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003023 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003024 }
sewardjde4a1d02002-03-22 01:27:54 +00003025 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3026 synth_pop_reg ( size, regd );
3027}
3028
3029
sewardjf0f12aa2002-12-28 00:04:08 +00003030static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003031 Opcode opcode, Int size,
3032 UInt lit, Int reg )
3033{
3034 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003035 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003036 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003037 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003038 break;
3039 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003040 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003041 } else {
njn25e49d8e72002-09-23 09:36:25 +00003042 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003043 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003044 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003045 }
3046 break;
njne427a662002-10-02 11:08:25 +00003047 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003048 }
3049}
3050
3051
sewardjf0f12aa2002-12-28 00:04:08 +00003052static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003053{
sewardjde4a1d02002-03-22 01:27:54 +00003054 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003055 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003056 } else {
njn25e49d8e72002-09-23 09:36:25 +00003057 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003058 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003059 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003060 }
3061}
3062
3063
sewardj3d7c9c82003-03-26 21:08:13 +00003064static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3065 UChar first_byte,
3066 UChar second_byte,
3067 Int ireg )
3068{
3069 emit_MMX2_regmem ( uses_flags, sets_flags,
3070 first_byte, second_byte, ireg );
3071}
3072
3073
sewardjca860012003-03-27 23:52:58 +00003074static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3075 UChar first_byte,
3076 UChar second_byte,
3077 Int ireg )
3078{
3079 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3080 first_byte, second_byte, ireg );
3081}
3082
sewardjd1c9e432003-04-04 20:40:34 +00003083static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3084 UChar first_byte,
3085 UChar second_byte,
3086 Int ireg )
3087{
3088 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3089 first_byte, second_byte, ireg );
3090}
3091
sewardj3d7c9c82003-03-26 21:08:13 +00003092static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3093 UChar first_byte,
3094 UChar second_byte )
3095{
3096 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3097}
3098
3099
sewardjca860012003-03-27 23:52:58 +00003100static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3101 UChar first_byte,
3102 UChar second_byte,
3103 UChar third_byte )
3104{
3105 emit_MMX3_no_mem ( uses_flags, sets_flags,
3106 first_byte, second_byte, third_byte );
3107}
3108
3109
sewardj3d7c9c82003-03-26 21:08:13 +00003110static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3111 UChar first_byte )
3112{
3113 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3114}
3115
3116
sewardjfa492d42002-12-08 18:20:01 +00003117static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3118 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003119 UChar second_byte_masked,
3120 Int reg )
3121{
sewardj3d7c9c82003-03-26 21:08:13 +00003122 emit_fpu_regmem ( uses_flags, sets_flags,
3123 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003124}
3125
3126
sewardjfa492d42002-12-08 18:20:01 +00003127static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3128 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003129 UChar second_byte )
3130{
sewardjfa492d42002-12-08 18:20:01 +00003131 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003132}
3133
3134
3135static void synth_movl_reg_reg ( Int src, Int dst )
3136{
3137 emit_movl_reg_reg ( src, dst );
3138}
3139
3140static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3141{
sewardja2113f92002-12-12 23:42:48 +00003142 Int tgt;
3143
3144 VG_(init_target)(&tgt);
3145
3146 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003147 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003148
3149 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003150}
3151
3152
sewardjde4a1d02002-03-22 01:27:54 +00003153/*----------------------------------------------------*/
3154/*--- Top level of the uinstr -> x86 translation. ---*/
3155/*----------------------------------------------------*/
3156
3157/* Return the byte offset from %ebp (ie, into baseBlock)
3158 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003159static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3160{
3161 if (tag == SpillNo) {
3162 vg_assert(size == 4);
3163 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3164 return 4 * (value + VGOFF_(spillslots));
3165 }
3166 if (tag == ArchReg) {
3167 switch (value) {
3168 case R_EAX: return 4 * VGOFF_(m_eax);
3169 case R_ECX: return 4 * VGOFF_(m_ecx);
3170 case R_EDX: return 4 * VGOFF_(m_edx);
3171 case R_EBX: return 4 * VGOFF_(m_ebx);
3172 case R_ESP:
3173 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3174 else return 4 * VGOFF_(m_esp);
3175 case R_EBP:
3176 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3177 else return 4 * VGOFF_(m_ebp);
3178 case R_ESI:
3179 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3180 else return 4 * VGOFF_(m_esi);
3181 case R_EDI:
3182 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3183 else return 4 * VGOFF_(m_edi);
3184 }
3185 }
njne427a662002-10-02 11:08:25 +00003186 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003187}
3188
sewardjde4a1d02002-03-22 01:27:54 +00003189static Int eflagsOffset ( void )
3190{
3191 return 4 * VGOFF_(m_eflags);
3192}
3193
sewardje1042472002-09-30 12:33:11 +00003194static Int segRegOffset ( UInt archregs )
3195{
3196 switch (archregs) {
3197 case R_CS: return 4 * VGOFF_(m_cs);
3198 case R_SS: return 4 * VGOFF_(m_ss);
3199 case R_DS: return 4 * VGOFF_(m_ds);
3200 case R_ES: return 4 * VGOFF_(m_es);
3201 case R_FS: return 4 * VGOFF_(m_fs);
3202 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003203 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003204 }
3205}
3206
njnf4ce3d32003-02-10 10:17:26 +00003207UInt VG_(get_archreg) ( UInt arch )
3208{
3209 switch (arch) {
3210 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3211 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3212 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3213 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3214 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3215 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3216 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3217 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003218 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003219 }
3220}
3221
3222UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3223{
3224 ThreadState* tst;
3225
3226 vg_assert(VG_(is_valid_tid)(tid));
3227 tst = & VG_(threads)[tid];
3228
3229 switch (arch) {
3230 case R_EAX: return tst->m_eax;
3231 case R_ECX: return tst->m_ecx;
3232 case R_EDX: return tst->m_edx;
3233 case R_EBX: return tst->m_ebx;
3234 case R_ESP: return tst->m_esp;
3235 case R_EBP: return tst->m_ebp;
3236 case R_ESI: return tst->m_esi;
3237 case R_EDI: return tst->m_edi;
3238 default: VG_(core_panic)( "get_thread_archreg");
3239 }
3240}
3241
njnb93d1782003-02-03 12:03:22 +00003242/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003243static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003244{
3245 switch (arch) {
3246 case R_EAX: return VGOFF_(sh_eax);
3247 case R_ECX: return VGOFF_(sh_ecx);
3248 case R_EDX: return VGOFF_(sh_edx);
3249 case R_EBX: return VGOFF_(sh_ebx);
3250 case R_ESP: return VGOFF_(sh_esp);
3251 case R_EBP: return VGOFF_(sh_ebp);
3252 case R_ESI: return VGOFF_(sh_esi);
3253 case R_EDI: return VGOFF_(sh_edi);
3254 default: VG_(core_panic)( "shadow_reg_index");
3255 }
3256}
sewardjde4a1d02002-03-22 01:27:54 +00003257
njn25e49d8e72002-09-23 09:36:25 +00003258/* Return the byte offset from %ebp (ie, into baseBlock)
3259 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003260Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003261{
njnb93d1782003-02-03 12:03:22 +00003262 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003263}
3264
njn4ba5a792002-09-30 10:23:54 +00003265Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003266{
3267 return 4 * VGOFF_(sh_eflags);
3268}
3269
njnb93d1782003-02-03 12:03:22 +00003270/* Accessing shadow arch. registers */
3271UInt VG_(get_shadow_archreg) ( UInt archreg )
3272{
3273 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3274}
3275
3276void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3277{
3278 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3279}
3280
njnd3040452003-05-19 15:04:06 +00003281void VG_(set_shadow_eflags) ( UInt val )
3282{
3283 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3284}
3285
njnf4ce3d32003-02-10 10:17:26 +00003286UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3287{
3288 ThreadState* tst;
3289
3290 vg_assert(VG_(is_valid_tid)(tid));
3291 tst = & VG_(threads)[tid];
3292
3293 switch (archreg) {
3294 case R_EAX: return tst->sh_eax;
3295 case R_ECX: return tst->sh_ecx;
3296 case R_EDX: return tst->sh_edx;
3297 case R_EBX: return tst->sh_ebx;
3298 case R_ESP: return tst->sh_esp;
3299 case R_EBP: return tst->sh_ebp;
3300 case R_ESI: return tst->sh_esi;
3301 case R_EDI: return tst->sh_edi;
3302 default: VG_(core_panic)( "get_thread_shadow_archreg");
3303 }
3304}
3305
3306void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3307{
3308 ThreadState* tst;
3309
3310 vg_assert(VG_(is_valid_tid)(tid));
3311 tst = & VG_(threads)[tid];
3312
3313 switch (archreg) {
3314 case R_EAX: tst->sh_eax = val; break;
3315 case R_ECX: tst->sh_ecx = val; break;
3316 case R_EDX: tst->sh_edx = val; break;
3317 case R_EBX: tst->sh_ebx = val; break;
3318 case R_ESP: tst->sh_esp = val; break;
3319 case R_EBP: tst->sh_ebp = val; break;
3320 case R_ESI: tst->sh_esi = val; break;
3321 case R_EDI: tst->sh_edi = val; break;
3322 default: VG_(core_panic)( "set_thread_shadow_archreg");
3323 }
3324}
3325
njnb93d1782003-02-03 12:03:22 +00003326Addr VG_(shadow_archreg_address) ( UInt archreg )
3327{
3328 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3329}
sewardjde4a1d02002-03-22 01:27:54 +00003330
sewardjde4a1d02002-03-22 01:27:54 +00003331static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3332{
3333 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003334 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3335 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003336 }
3337 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003338 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3339 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003340 }
3341 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003342 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3343 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003344 }
3345 else
njne427a662002-10-02 11:08:25 +00003346 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003347}
3348
3349
sewardjde4a1d02002-03-22 01:27:54 +00003350/*----------------------------------------------------*/
3351/*--- Generate code for a single UInstr. ---*/
3352/*----------------------------------------------------*/
3353
sewardj478335c2002-10-05 02:44:47 +00003354static __inline__
3355Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003356{
3357 return (u->flags_w != FlagsEmpty);
3358}
3359
sewardjfa492d42002-12-08 18:20:01 +00003360static __inline__
3361Bool readFlagUse ( UInstr* u )
3362{
3363 /* If the UInstr writes some flags but not all, then we still need
3364 to consider it as reading flags so that the unchanged values are
3365 passed through properly. (D is special) */
3366 return
3367 (u->flags_r != FlagsEmpty) ||
3368 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3369}
3370
sewardj478335c2002-10-05 02:44:47 +00003371static __inline__
3372Bool anyFlagUse ( UInstr* u )
3373{
sewardjfa492d42002-12-08 18:20:01 +00003374 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003375}
3376
3377
sewardjb91ae7f2003-04-29 23:50:00 +00003378/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3379 the real machine's cpu. If so we need to be very careful not to trash it.
3380 If FPU/SSE state is live and we deem it necessary to copy it back to
3381 the simulated machine's FPU/SSE state, we do so. The final state of
3382 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003383 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003384 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003385*/
sewardjb5ff83e2002-12-01 19:40:49 +00003386static void emitUInstr ( UCodeBlock* cb, Int i,
3387 RRegSet regs_live_before,
3388 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003389 Bool* sselive, /* True<==>FPU/SSE
3390 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003391 Addr* orig_eip, /* previous curr_eip, or zero */
3392 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003393{
njn25e49d8e72002-09-23 09:36:25 +00003394 Int old_emitted_code_used;
3395 UInstr* u = &cb->instrs[i];
3396
sewardjde4a1d02002-03-22 01:27:54 +00003397 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003398 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003399
njn25e49d8e72002-09-23 09:36:25 +00003400 old_emitted_code_used = emitted_code_used;
3401
sewardjde4a1d02002-03-22 01:27:54 +00003402 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003403 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003404
sewardjb5ff83e2002-12-01 19:40:49 +00003405 case INCEIP:
3406 /* Advance %EIP some small amount. */
3407 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003408
sewardjb5ff83e2002-12-01 19:40:49 +00003409 if (*orig_eip == 0 /* we don't know what the old value was */
3410 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3411 /* We have to update all 32 bits of the value. */
3412 VG_(emit_movv_lit_offregmem)(
3413 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3414 } else {
3415 /* Cool! we only need to update lowest 8 bits */
3416 VG_(emit_movb_lit_offregmem)(
3417 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003418 }
njn25e49d8e72002-09-23 09:36:25 +00003419
sewardjb5ff83e2002-12-01 19:40:49 +00003420 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003421 break;
sewardjde4a1d02002-03-22 01:27:54 +00003422
3423 case LEA1: {
3424 vg_assert(u->tag1 == RealReg);
3425 vg_assert(u->tag2 == RealReg);
3426 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3427 break;
3428 }
3429
3430 case LEA2: {
3431 vg_assert(u->tag1 == RealReg);
3432 vg_assert(u->tag2 == RealReg);
3433 vg_assert(u->tag3 == RealReg);
3434 emit_lea_sib_reg ( u->lit32, u->extra4b,
3435 u->val1, u->val2, u->val3 );
3436 break;
3437 }
3438
3439 case WIDEN: {
3440 vg_assert(u->tag1 == RealReg);
3441 if (u->signed_widen) {
3442 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3443 } else {
3444 /* no need to generate any code. */
3445 }
3446 break;
3447 }
3448
sewardjde4a1d02002-03-22 01:27:54 +00003449 case STORE: {
3450 vg_assert(u->tag1 == RealReg);
3451 vg_assert(u->tag2 == RealReg);
3452 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003453 break;
3454 }
3455
3456 case LOAD: {
3457 vg_assert(u->tag1 == RealReg);
3458 vg_assert(u->tag2 == RealReg);
3459 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
3460 break;
3461 }
3462
sewardjde4a1d02002-03-22 01:27:54 +00003463 case GET: {
3464 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3465 vg_assert(u->tag2 == RealReg);
3466 synth_mov_offregmem_reg (
3467 u->size,
3468 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3469 R_EBP,
3470 u->val2
3471 );
3472 break;
3473 }
3474
3475 case PUT: {
3476 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3477 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003478 synth_mov_reg_offregmem (
3479 u->size,
3480 u->val1,
3481 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3482 R_EBP
3483 );
sewardjde4a1d02002-03-22 01:27:54 +00003484 break;
3485 }
3486
sewardje1042472002-09-30 12:33:11 +00003487 case GETSEG: {
3488 vg_assert(u->tag1 == ArchRegS);
3489 vg_assert(u->tag2 == RealReg);
3490 vg_assert(u->size == 2);
3491 synth_mov_offregmem_reg (
3492 4,
3493 segRegOffset( u->val1 ),
3494 R_EBP,
3495 u->val2
3496 );
3497 break;
3498 }
3499
3500 case PUTSEG: {
3501 vg_assert(u->tag1 == RealReg);
3502 vg_assert(u->tag2 == ArchRegS);
3503 vg_assert(u->size == 2);
3504 synth_mov_reg_offregmem (
3505 4,
3506 u->val1,
3507 segRegOffset( u->val2 ),
3508 R_EBP
3509 );
3510 break;
3511 }
3512
sewardjde4a1d02002-03-22 01:27:54 +00003513 case GETF: {
3514 vg_assert(u->size == 2 || u->size == 4);
3515 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003516
3517 /* This complexity is because the D(irection) flag is stored
3518 separately from the rest of EFLAGS. */
3519
3520 /* We're only fetching from the Simd state, so make sure it's
3521 up to date. */
3522 maybe_emit_put_eflags();
3523
3524 /* get D in u->val1 (== 1 or -1) */
3525 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3526
3527 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3528 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3529
3530 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3531 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3532 eflagsOffset(), R_EBP);
3533
3534 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3535 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3536 eflagsOffset(), R_EBP);
3537
3538 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3539 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3540 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003541 break;
3542 }
3543
3544 case PUTF: {
3545 vg_assert(u->size == 2 || u->size == 4);
3546 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003547
3548 /* When putting a value into EFLAGS, this generates the
3549 correct value for m_dflag (-1 or 1), and clears the D bit
3550 in EFLAGS. */
3551
3552 /* We're updating the whole flag state, so the old state
3553 doesn't matter; make sure that the new simulated state
3554 will be fetched when needed. */
3555 eflags_state = UPD_Simd;
3556
3557 /* store EFLAGS (with D) */
3558 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3559
3560 /* u->val1 &= EFlagD */
3561 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3562
3563 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3564 synth_unaryop_reg(False, NEG, u->size, u->val1);
3565 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3566 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3567
3568 /* save D */
3569 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3570
3571 /* EFLAGS &= ~EFlagD */
3572 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3573 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003574 break;
3575 }
3576
3577 case MOV: {
3578 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3579 vg_assert(u->tag2 == RealReg);
3580 switch (u->tag1) {
3581 case RealReg: vg_assert(u->size == 4);
3582 if (u->val1 != u->val2)
3583 synth_movl_reg_reg ( u->val1, u->val2 );
3584 break;
3585 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3586 break;
njne427a662002-10-02 11:08:25 +00003587 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003588 }
3589 break;
3590 }
3591
sewardje1042472002-09-30 12:33:11 +00003592 case USESEG: {
3593 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3594 ones. */
sewardjd077f532002-09-30 21:52:50 +00003595 UInt argv[] = { u->val1, u->val2 };
3596 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003597 UInt ret_reg = u->val2;
3598
3599 vg_assert(u->tag1 == RealReg);
3600 vg_assert(u->tag2 == RealReg);
3601 vg_assert(u->size == 0);
3602
sewardjb91ae7f2003-04-29 23:50:00 +00003603 if (*sselive) {
3604 emit_put_sse_state();
3605 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003606 }
3607
sewardje1042472002-09-30 12:33:11 +00003608 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3609 2, /* args */
3610 0, /* regparms_n */
3611 argv, tagv,
3612 ret_reg, regs_live_before, u->regs_live_after );
3613 break;
3614 }
3615
jsgf5efa4fd2003-10-14 21:49:11 +00003616 case MUL: {
3617 vg_assert(u->tag2 == RealReg);
3618
3619 switch(u->tag1) {
3620 case Literal:
3621 synth_mul_lit_reg(anyFlagUse(u),
3622 u->opcode, u->size, u->lit32, u->val2);
3623 break;
3624 case RealReg:
3625 synth_mul_reg_reg(anyFlagUse(u),
3626 u->opcode, u->size, u->val1, u->val2);
3627 break;
3628 case ArchReg:
3629 synth_mul_offregmem_reg(anyFlagUse(u),
3630 u->opcode, u->size,
3631 spillOrArchOffset(u->size, u->tag1, u->val1),
3632 R_EBP, u->val2);
3633 break;
3634
3635 default: VG_(core_panic)("emitUInstr:MUL");
3636 }
3637 break;
3638 }
3639
sewardj478335c2002-10-05 02:44:47 +00003640 case SBB:
3641 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003642 case XOR:
3643 case OR:
3644 case AND:
3645 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003646 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003647 vg_assert(u->tag2 == RealReg);
3648 switch (u->tag1) {
3649 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003650 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003651 u->opcode, u->size, u->lit32, u->val2 );
3652 break;
3653 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003654 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003655 u->opcode, u->size, u->val1, u->val2 );
3656 break;
3657 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003658 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003659 u->opcode, u->size,
3660 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3661 R_EBP,
3662 u->val2 );
3663 break;
njne427a662002-10-02 11:08:25 +00003664 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003665 }
3666 break;
3667 }
3668
sewardj478335c2002-10-05 02:44:47 +00003669 case RCR:
3670 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003671 case ROR:
3672 case ROL:
3673 case SAR:
3674 case SHR:
3675 case SHL: {
3676 vg_assert(u->tag2 == RealReg);
3677 switch (u->tag1) {
3678 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003679 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003680 u->opcode, u->size, u->lit32, u->val2 );
3681 break;
3682 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003683 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003684 u->opcode, u->size, u->val1, u->val2 );
3685 break;
njne427a662002-10-02 11:08:25 +00003686 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003687 }
3688 break;
3689 }
3690
3691 case INC:
3692 case DEC:
3693 case NEG:
3694 case NOT:
3695 vg_assert(u->tag1 == RealReg);
3696 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003697 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003698 break;
3699
3700 case BSWAP:
3701 vg_assert(u->tag1 == RealReg);
3702 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003703 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003704 emit_bswapl_reg ( u->val1 );
3705 break;
3706
3707 case CMOV:
3708 vg_assert(u->tag1 == RealReg);
3709 vg_assert(u->tag2 == RealReg);
3710 vg_assert(u->cond != CondAlways);
3711 vg_assert(u->size == 4);
3712 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3713 break;
3714
3715 case JMP: {
3716 vg_assert(u->tag2 == NoValue);
3717 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003718 if (*sselive) {
3719 emit_put_sse_state();
3720 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003721 }
sewardjde4a1d02002-03-22 01:27:54 +00003722 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003723 switch (u->tag1) {
3724 case RealReg:
3725 synth_jmp_reg ( u->val1, u->jmpkind );
3726 break;
3727 case Literal:
3728 synth_jmp_lit ( u->lit32, u->jmpkind );
3729 break;
3730 default:
njne427a662002-10-02 11:08:25 +00003731 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003732 break;
sewardjde4a1d02002-03-22 01:27:54 +00003733 }
3734 } else {
sewardj2e93c502002-04-12 11:12:52 +00003735 switch (u->tag1) {
3736 case RealReg:
njne427a662002-10-02 11:08:25 +00003737 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003738 break;
3739 case Literal:
3740 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003741 /* %eax had better not be live since synth_jcond_lit
3742 trashes it in some circumstances. If that turns
3743 out to be a problem we can get synth_jcond_lit to
3744 push/pop it when it is live. */
3745 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3746 u->regs_live_after));
3747 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003748 break;
3749 default:
njne427a662002-10-02 11:08:25 +00003750 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003751 break;
sewardjde4a1d02002-03-22 01:27:54 +00003752 }
3753 }
3754 break;
3755 }
3756
3757 case JIFZ:
3758 vg_assert(u->tag1 == RealReg);
3759 vg_assert(u->tag2 == Literal);
3760 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003761 if (*sselive) {
3762 emit_put_sse_state();
3763 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003764 }
sewardjde4a1d02002-03-22 01:27:54 +00003765 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3766 break;
3767
sewardjde4a1d02002-03-22 01:27:54 +00003768 case PUSH:
3769 vg_assert(u->tag1 == RealReg);
3770 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003771 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003772 break;
3773
3774 case POP:
3775 vg_assert(u->tag1 == RealReg);
3776 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003777 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003778 break;
3779
3780 case CALLM:
3781 vg_assert(u->tag1 == Lit16);
3782 vg_assert(u->tag2 == NoValue);
3783 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003784 if (*sselive) {
3785 emit_put_sse_state();
3786 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003787 }
sewardjfa492d42002-12-08 18:20:01 +00003788 /* Call to a helper which is pretending to be a real CPU
3789 instruction (and therefore operates on Real flags and
3790 registers) */
3791 VG_(synth_call) ( False, u->val1,
3792 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003793 break;
3794
njn25e49d8e72002-09-23 09:36:25 +00003795 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003796 /* If you change this, remember to change USESEG above, since
3797 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003798 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3799 ones. */
3800 UInt argv[] = { u->val1, u->val2, u->val3 };
3801 UInt tagv[] = { RealReg, RealReg, RealReg };
3802 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3803
3804 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3805 else vg_assert(u->tag1 == NoValue);
3806 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3807 else vg_assert(u->tag2 == NoValue);
3808 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3809 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003810 vg_assert(u->size == 0);
3811
sewardjb91ae7f2003-04-29 23:50:00 +00003812 if (*sselive) {
3813 emit_put_sse_state();
3814 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003815 }
njn25e49d8e72002-09-23 09:36:25 +00003816 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3817 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003818 break;
njn25e49d8e72002-09-23 09:36:25 +00003819 }
sewardje1042472002-09-30 12:33:11 +00003820
sewardjde4a1d02002-03-22 01:27:54 +00003821 case CLEAR:
3822 vg_assert(u->tag1 == Lit16);
3823 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003824 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003825 break;
3826
3827 case CC2VAL:
3828 vg_assert(u->tag1 == RealReg);
3829 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003830 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003831 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003832 break;
3833
sewardjde4a1d02002-03-22 01:27:54 +00003834 case FPU_R:
3835 case FPU_W:
3836 vg_assert(u->tag1 == Lit16);
3837 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003838 if (!(*sselive)) {
3839 emit_get_sse_state();
3840 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003841 }
sewardjfa492d42002-12-08 18:20:01 +00003842 synth_fpu_regmem ( u->flags_r, u->flags_w,
3843 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003844 u->val1 & 0xFF,
3845 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003846 break;
3847
3848 case FPU:
3849 vg_assert(u->tag1 == Lit16);
3850 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003851 if (!(*sselive)) {
3852 emit_get_sse_state();
3853 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003854 }
sewardjfa492d42002-12-08 18:20:01 +00003855 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3856 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003857 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003858 break;
3859
sewardj3d7c9c82003-03-26 21:08:13 +00003860 case MMX2_MemWr:
3861 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003862 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003863 vg_assert(u->tag1 == Lit16);
3864 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003865 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003866 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003867 if (!(*sselive)) {
3868 emit_get_sse_state();
3869 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003870 }
3871 synth_MMX2_regmem ( u->flags_r, u->flags_w,
3872 (u->val1 >> 8) & 0xFF,
3873 u->val1 & 0xFF,
3874 u->val2 );
3875 break;
3876
sewardj4fbe6e92003-06-15 21:54:34 +00003877 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00003878 vg_assert(u->tag1 == Lit16);
3879 vg_assert(u->tag2 == RealReg);
3880 vg_assert(u->tag3 == NoValue);
3881 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003882 if (!(*sselive)) {
3883 emit_get_sse_state();
3884 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003885 }
3886 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
3887 (u->val1 >> 8) & 0xFF,
3888 u->val1 & 0xFF,
3889 u->val2 );
3890 break;
3891
sewardj4fbe6e92003-06-15 21:54:34 +00003892 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00003893 vg_assert(u->tag1 == Lit16);
3894 vg_assert(u->tag2 == RealReg);
3895 vg_assert(u->tag3 == NoValue);
3896 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003897 if (!(*sselive)) {
3898 emit_get_sse_state();
3899 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00003900 }
3901 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
3902 (u->val1 >> 8) & 0xFF,
3903 u->val1 & 0xFF,
3904 u->val2 );
3905 break;
3906
sewardj3d7c9c82003-03-26 21:08:13 +00003907 case MMX1:
3908 vg_assert(u->tag1 == Lit16);
3909 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003910 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003911 if (!(*sselive)) {
3912 emit_get_sse_state();
3913 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003914 }
3915 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
3916 u->val1 & 0xFF );
3917 break;
3918
3919 case MMX2:
3920 vg_assert(u->tag1 == Lit16);
3921 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00003922 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003923 if (!(*sselive)) {
3924 emit_get_sse_state();
3925 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00003926 }
3927 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
3928 (u->val1 >> 8) & 0xFF,
3929 u->val1 & 0xFF );
3930 break;
3931
sewardjca860012003-03-27 23:52:58 +00003932 case MMX3:
3933 vg_assert(u->tag1 == Lit16);
3934 vg_assert(u->tag2 == Lit16);
3935 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003936 if (!(*sselive)) {
3937 emit_get_sse_state();
3938 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00003939 }
3940 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
3941 (u->val1 >> 8) & 0xFF,
3942 u->val1 & 0xFF,
3943 u->val2 & 0xFF );
3944 break;
3945
sewardjfebaa3b2003-05-25 01:07:34 +00003946 case SSE2a_MemWr:
3947 case SSE2a_MemRd:
3948 vg_assert(u->size == 4 || u->size == 16);
3949 vg_assert(u->tag1 == Lit16);
3950 vg_assert(u->tag2 == Lit16);
3951 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003952 if (!(*sselive)) {
3953 emit_get_sse_state();
3954 *sselive = True;
3955 }
3956 emit_SSE2a ( u->flags_r, u->flags_w,
3957 (u->val1 >> 8) & 0xFF,
3958 u->val1 & 0xFF,
3959 u->val2 & 0xFF,
3960 u->val3 );
3961 break;
3962
sewardj9dd209f2003-06-18 23:30:52 +00003963 case SSE2a1_MemRd:
3964 vg_assert(u->size == 4 || u->size == 16);
3965 vg_assert(u->tag1 == Lit16);
3966 vg_assert(u->tag2 == Lit16);
3967 vg_assert(u->tag3 == RealReg);
3968 vg_assert(!anyFlagUse(u));
3969 if (!(*sselive)) {
3970 emit_get_sse_state();
3971 *sselive = True;
3972 }
3973 emit_SSE2a1 ( u->flags_r, u->flags_w,
3974 (u->val1 >> 8) & 0xFF,
3975 u->val1 & 0xFF,
3976 (u->val2 >> 8) & 0xFF,
3977 u->val2 & 0xFF,
3978 u->val3 );
3979 break;
3980
sewardjfebaa3b2003-05-25 01:07:34 +00003981 case SSE3a_MemWr:
3982 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00003983 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00003984 vg_assert(u->tag1 == Lit16);
3985 vg_assert(u->tag2 == Lit16);
3986 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00003987 if (!(*sselive)) {
3988 emit_get_sse_state();
3989 *sselive = True;
3990 }
3991 emit_SSE3a ( u->flags_r, u->flags_w,
3992 (u->val1 >> 8) & 0xFF,
3993 u->val1 & 0xFF,
3994 (u->val2 >> 8) & 0xFF,
3995 u->val2 & 0xFF,
3996 u->val3 );
3997 break;
3998
sewardjabf8bf82003-06-15 22:28:05 +00003999 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004000 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004001 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004002 vg_assert(u->size == 4);
4003 vg_assert(u->tag1 == Lit16);
4004 vg_assert(u->tag2 == Lit16);
4005 vg_assert(u->tag3 == RealReg);
4006 vg_assert(!anyFlagUse(u));
4007 if (!(*sselive)) {
4008 emit_get_sse_state();
4009 *sselive = True;
4010 }
sewardjabf8bf82003-06-15 22:28:05 +00004011 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4012 emit_SSE3e ( u->flags_r, u->flags_w,
4013 (u->val1 >> 8) & 0xFF,
4014 u->val1 & 0xFF,
4015 (u->val2 >> 8) & 0xFF,
4016 u->val2 & 0xFF,
4017 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004018 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004019 emit_SSE3g ( u->flags_r, u->flags_w,
4020 (u->val1 >> 8) & 0xFF,
4021 u->val1 & 0xFF,
4022 (u->val2 >> 8) & 0xFF,
4023 u->val2 & 0xFF,
4024 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004025 }
sewardjfebaa3b2003-05-25 01:07:34 +00004026 break;
4027
sewardjb31b06d2003-06-13 00:26:02 +00004028 case SSE3g1_RegWr:
4029 vg_assert(u->size == 4);
4030 vg_assert(u->tag1 == Lit16);
4031 vg_assert(u->tag2 == Lit16);
4032 vg_assert(u->tag3 == RealReg);
4033 vg_assert(!anyFlagUse(u));
4034 if (!(*sselive)) {
4035 emit_get_sse_state();
4036 *sselive = True;
4037 }
sewardjabf8bf82003-06-15 22:28:05 +00004038 emit_SSE3g1 ( u->flags_r, u->flags_w,
4039 (u->val1 >> 8) & 0xFF,
4040 u->val1 & 0xFF,
4041 (u->val2 >> 8) & 0xFF,
4042 u->val2 & 0xFF,
4043 u->lit32 & 0xFF,
4044 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004045 break;
4046
sewardj4fbe6e92003-06-15 21:54:34 +00004047 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004048 vg_assert(u->size == 2);
4049 vg_assert(u->tag1 == Lit16);
4050 vg_assert(u->tag2 == Lit16);
4051 vg_assert(u->tag3 == RealReg);
4052 vg_assert(!anyFlagUse(u));
4053 if (!(*sselive)) {
4054 emit_get_sse_state();
4055 *sselive = True;
4056 }
sewardjabf8bf82003-06-15 22:28:05 +00004057 emit_SSE3e1 ( u->flags_r, u->flags_w,
4058 (u->val1 >> 8) & 0xFF,
4059 u->val1 & 0xFF,
4060 (u->val2 >> 8) & 0xFF,
4061 u->val2 & 0xFF,
4062 u->lit32 & 0xFF,
4063 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004064 break;
4065
sewardja453fb02003-06-14 13:22:36 +00004066 case SSE5:
4067 vg_assert(u->size == 0);
4068 vg_assert(u->tag1 == Lit16);
4069 vg_assert(u->tag2 == Lit16);
4070 vg_assert(u->tag3 == Lit16);
4071 vg_assert(!anyFlagUse(u));
4072 if (!(*sselive)) {
4073 emit_get_sse_state();
4074 *sselive = True;
4075 }
4076 emit_SSE5 ( u->flags_r, u->flags_w,
4077 (u->val1 >> 8) & 0xFF,
4078 u->val1 & 0xFF,
4079 (u->val2 >> 8) & 0xFF,
4080 u->val2 & 0xFF,
4081 u->val3 & 0xFF );
4082 break;
4083
sewardjfebaa3b2003-05-25 01:07:34 +00004084 case SSE4:
4085 vg_assert(u->size == 0);
4086 vg_assert(u->tag1 == Lit16);
4087 vg_assert(u->tag2 == Lit16);
4088 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004089 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004090 if (!(*sselive)) {
4091 emit_get_sse_state();
4092 *sselive = True;
4093 }
4094 emit_SSE4 ( u->flags_r, u->flags_w,
4095 (u->val1 >> 8) & 0xFF,
4096 u->val1 & 0xFF,
4097 (u->val2 >> 8) & 0xFF,
4098 u->val2 & 0xFF );
4099 break;
4100
sewardja60be0e2003-05-26 08:47:27 +00004101 case SSE3:
4102 vg_assert(u->size == 0);
4103 vg_assert(u->tag1 == Lit16);
4104 vg_assert(u->tag2 == Lit16);
4105 vg_assert(u->tag3 == NoValue);
4106 vg_assert(!anyFlagUse(u));
4107 if (!(*sselive)) {
4108 emit_get_sse_state();
4109 *sselive = True;
4110 }
4111 emit_SSE3 ( u->flags_r, u->flags_w,
4112 (u->val1 >> 8) & 0xFF,
4113 u->val1 & 0xFF,
4114 u->val2 & 0xFF );
4115 break;
4116
sewardje3891fa2003-06-15 03:13:48 +00004117 case SSE3ag_MemRd_RegWr:
4118 vg_assert(u->size == 4 || u->size == 8);
4119 vg_assert(u->tag1 == RealReg);
4120 vg_assert(u->tag2 == RealReg);
4121 vg_assert(u->tag3 == NoValue);
4122 vg_assert(!anyFlagUse(u));
4123 if (!(*sselive)) {
4124 emit_get_sse_state();
4125 *sselive = True;
4126 }
4127 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4128 (u->lit32 >> 24) & 0xFF,
4129 (u->lit32 >> 16) & 0xFF,
4130 (u->lit32 >> 8) & 0xFF,
4131 u->val1, u->val2 );
4132 break;
4133
sewardjde4a1d02002-03-22 01:27:54 +00004134 default:
sewardj1b7d8022002-11-30 12:35:42 +00004135 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004136 if (*sselive) {
4137 emit_put_sse_state();
4138 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004139 }
njn4ba5a792002-09-30 10:23:54 +00004140 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004141 } else {
njn25e49d8e72002-09-23 09:36:25 +00004142 VG_(printf)("\nError:\n"
4143 " unhandled opcode: %u. Perhaps "
4144 " VG_(needs).extended_UCode should be set?\n",
4145 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004146 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004147 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004148 }
sewardjde4a1d02002-03-22 01:27:54 +00004149 }
4150
sewardjb91ae7f2003-04-29 23:50:00 +00004151 if (0 && (*sselive)) {
4152 emit_put_sse_state();
4153 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004154 }
4155
njn25e49d8e72002-09-23 09:36:25 +00004156 /* Update UInstr histogram */
4157 vg_assert(u->opcode < 100);
4158 histogram[u->opcode].counts++;
4159 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004160}
4161
4162
4163/* Emit x86 for the ucode in cb, returning the address of the
4164 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004165UChar* VG_(emit_code) ( UCodeBlock* cb,
4166 Int* nbytes,
4167 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004168{
4169 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004170 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004171 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004172 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004173 Int tgt;
4174
sewardjfa492d42002-12-08 18:20:01 +00004175 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004176
njn25e49d8e72002-09-23 09:36:25 +00004177 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004178
sewardj22854b92002-11-30 14:00:47 +00004179 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
4180 zero. We have to do this regardless of whether we're t-chaining
4181 or not. */
sewardja2113f92002-12-12 23:42:48 +00004182 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004183 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
sewardj22854b92002-11-30 14:00:47 +00004184 VG_(emitB) (0xFF); /* decl */
4185 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
4186 if (dis)
4187 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
sewardja2113f92002-12-12 23:42:48 +00004188 VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
sewardj22854b92002-11-30 14:00:47 +00004189 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4190 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004191 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004192
sewardjb5ff83e2002-12-01 19:40:49 +00004193 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004194 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004195 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004196 curr_eip = cb->orig_eip;
4197 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4198 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004199 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004200 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004201 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004202 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004203
sewardjde4a1d02002-03-22 01:27:54 +00004204 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004205 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004206 if (!sane) {
4207 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004208 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004209 }
4210 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004211 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004212 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004213 }
njn25e49d8e72002-09-23 09:36:25 +00004214 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004215 }
njn25e49d8e72002-09-23 09:36:25 +00004216 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004217 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004218 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004219
sewardj22854b92002-11-30 14:00:47 +00004220 if (j != NULL) {
4221 vg_assert(jumpidx <= VG_MAX_JUMPS);
4222 for(i = 0; i < jumpidx; i++)
4223 j[i] = jumps[i];
4224 }
4225
sewardjde4a1d02002-03-22 01:27:54 +00004226 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004227 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004228 *nbytes = emitted_code_used;
4229 return emitted_code;
4230}
4231
njn25e49d8e72002-09-23 09:36:25 +00004232#undef dis
4233
sewardjde4a1d02002-03-22 01:27:54 +00004234/*--------------------------------------------------------------------*/
4235/*--- end vg_from_ucode.c ---*/
4236/*--------------------------------------------------------------------*/