blob: d371f1480376fe3d0110c1f78b7ae544b94e9019 [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
fitzhardinge462f4f92003-12-18 02:10:54 +000083/* ia32 static prediction is very simple. Other implementations are
84 more complex, so we get the condition anyway. */
85static JumpPred static_pred(Condcode cond, Int forward)
86{
87 if (cond == CondAlways)
88 return JP_TAKEN;
89
90 return forward ? JP_NOT_TAKEN : JP_TAKEN;
91}
92
93static const Char *predstr(JumpPred p)
94{
fitzhardinge66ee7502003-12-19 23:47:24 +000095 if (!VG_(clo_branchpred))
96 return "";
97
fitzhardinge462f4f92003-12-18 02:10:54 +000098 switch(p) {
99 default:
100 case JP_NONE: return "";
101 case JP_TAKEN: return ",pt";
102 case JP_NOT_TAKEN: return ",pn";
103 }
104}
105
sewardjfa492d42002-12-08 18:20:01 +0000106/* single site for resetting state */
107static void reset_state(void)
108{
109 emitted_code_used = 0;
110 emitted_code_size = 500; /* reasonable initial size */
111 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
112 jumpidx = 0;
113 eflags_state = UPD_Simd;
114}
115
116
njn25e49d8e72002-09-23 09:36:25 +0000117/* Statistics about C functions called from generated code. */
118static UInt ccalls = 0;
119static UInt ccall_reg_saves = 0;
120static UInt ccall_args = 0;
121static UInt ccall_arg_setup_instrs = 0;
122static UInt ccall_stack_clears = 0;
123static UInt ccall_retvals = 0;
124static UInt ccall_retval_movs = 0;
125
126/* Statistics about frequency of each UInstr */
127typedef
128 struct {
129 UInt counts;
130 UInt size;
131 } Histogram;
132
133/* Automatically zeroed because it's static. */
134static Histogram histogram[100];
135
136void VG_(print_ccall_stats)(void)
137{
138 VG_(message)(Vg_DebugMsg,
139 " ccalls: %u C calls, %u%% saves+restores avoided"
140 " (%d bytes)",
141 ccalls,
142 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
143 ((ccalls*3) - ccall_reg_saves)*2);
144 VG_(message)(Vg_DebugMsg,
145 " %u args, avg 0.%d setup instrs each (%d bytes)",
146 ccall_args,
147 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
148 (ccall_args - ccall_arg_setup_instrs)*2);
149 VG_(message)(Vg_DebugMsg,
150 " %d%% clear the stack (%d bytes)",
151 (UInt)(ccall_stack_clears/(double)ccalls*100),
152 (ccalls - ccall_stack_clears)*3);
153 VG_(message)(Vg_DebugMsg,
154 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
155 ccall_retvals,
156 ( ccall_retvals == 0
157 ? 100
158 : 100-(UInt)(ccall_retval_movs /
159 (double)ccall_retvals*100)),
160 (ccall_retvals-ccall_retval_movs)*2);
161}
162
163void VG_(print_UInstr_histogram)(void)
164{
165 Int i, j;
166 UInt total_counts = 0;
167 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000168
njn25e49d8e72002-09-23 09:36:25 +0000169 for (i = 0; i < 100; i++) {
170 total_counts += histogram[i].counts;
171 total_size += histogram[i].size;
172 }
173
174 VG_(printf)("-- UInstr frequencies -----------\n");
175 for (i = 0; i < 100; i++) {
176 if (0 != histogram[i].counts) {
177
178 UInt count_pc =
179 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
180 UInt size_pc =
181 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
182 UInt avg_size =
183 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
184
185 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000186 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000187 histogram[i].counts, count_pc,
188 avg_size, size_pc);
189
sewardj05bcdcb2003-05-18 10:05:38 +0000190 for (j = 0; j < (Int)size_pc; j++) VG_(printf)("O");
njn25e49d8e72002-09-23 09:36:25 +0000191 VG_(printf)("\n");
192
193 } else {
194 vg_assert(0 == histogram[i].size);
195 }
196 }
197
198 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
199}
200
sewardjde4a1d02002-03-22 01:27:54 +0000201static void expandEmittedCode ( void )
202{
203 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000204 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000205 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
206 for (i = 0; i < emitted_code_size; i++)
207 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000208 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000209 emitted_code = tmp;
210 emitted_code_size *= 2;
211}
212
njn25e49d8e72002-09-23 09:36:25 +0000213/* Local calls will be inlined, cross-module ones not */
214__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000215{
216 if (dis) {
217 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
218 }
219 if (emitted_code_used == emitted_code_size)
220 expandEmittedCode();
221
222 emitted_code[emitted_code_used] = (UChar)b;
223 emitted_code_used++;
224}
225
njn25e49d8e72002-09-23 09:36:25 +0000226__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000227{
njn25e49d8e72002-09-23 09:36:25 +0000228 VG_(emitB) ( (l) & 0x000000FF );
229 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000230}
231
sewardj56867352003-10-12 10:27:06 +0000232/* __inline__ */
233void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000234{
njn25e49d8e72002-09-23 09:36:25 +0000235 VG_(emitB) ( (l) & 0x000000FF );
236 VG_(emitB) ( (l >> 8) & 0x000000FF );
237 VG_(emitB) ( (l >> 16) & 0x000000FF );
238 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000239}
240
fitzhardinge98abfc72003-12-16 02:05:15 +0000241/* This bit is ORd onto the size to indicate that it's a client
242 pointer which needs bounds checking. */
243#define DO_BOUNDSCHECK (1<<8)
244
245/* If the user asks for it, generate bounds checks on application
246 pointer dereferences, in the form of a segment override. */
247static __inline__ void boundscheck()
248{
249 if (VG_(clo_pointercheck))
250 VG_(emitB)(0x64); /* %fs prefix - see vg_dispatch.S */
251}
252
253
sewardjfa492d42002-12-08 18:20:01 +0000254static void emit_get_eflags ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000255{
sewardjfa492d42002-12-08 18:20:01 +0000256 Int off = 4 * VGOFF_(m_eflags);
257 vg_assert(off >= 0 && off < 128);
258
259 if (dis)
260 VG_(printf)("\t %4d: ", emitted_code_used );
261
262 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
263 VG_(emitB) ( 0x75 );
264 VG_(emitB) ( off );
265 VG_(emitB) ( 0x9D ); /* POPFL */
266 if (dis)
267 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
268}
269
270static void emit_put_eflags ( void )
271{
272 Int off = 4 * VGOFF_(m_eflags);
273 vg_assert(off >= 0 && off < 128);
274
275 if (dis)
276 VG_(printf)("\t %4d: ", emitted_code_used );
277
278 VG_(emitB) ( 0x9C ); /* PUSHFL */
279 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
280 VG_(emitB) ( 0x45 );
281 VG_(emitB) ( off );
282 if (dis)
283 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
284}
285
286static void maybe_emit_put_eflags( void )
287{
288 if (eflags_state == UPD_Real) {
289 eflags_state = UPD_Both;
290 emit_put_eflags();
291 }
292}
293
sewardja2c5a732002-12-15 03:10:42 +0000294
295/* evidently unused */
296#if 0
sewardjfa492d42002-12-08 18:20:01 +0000297static void maybe_emit_get_eflags( void )
298{
299 if (eflags_state == UPD_Simd) {
300 eflags_state = UPD_Both;
301 emit_get_eflags();
302 }
303}
sewardja2c5a732002-12-15 03:10:42 +0000304#endif
sewardjfa492d42002-12-08 18:20:01 +0000305
sewardjf0f12aa2002-12-28 00:04:08 +0000306
307#if 0
308/* begin UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
309/* An alternative implementation of new_emit in which the
310 state space is explicitly enumerated. */
311__inline__
312void VG_(new_emit) ( Bool upds_simd_flags,
313 FlagSet use_flags, FlagSet set_flags )
314{
315 Bool simd = upds_simd_flags;
316 enum _eflags_state where = eflags_state;
317
318 enum { WNone, WSome, WAll } ww;
319 Bool rr;
320
321#define DIS_HEADER \
322 if (dis) \
323 VG_(printf)("\t %4d: ", emitted_code_used );
324
325 if (use_flags == FlagsEmpty) {
326 rr = False;
327 } else {
328 rr = True;
329 }
330
331 if (set_flags == FlagsEmpty) {
332 ww = WNone;
333 } else
334 if (set_flags == FlagsOSZACP) {
335 ww = WAll;
336 } else {
337 ww = WSome;
338 }
339
340 /* If we're not wanting to interact with simd flags, and the simd
341 flags are not in the real flags, then do nothing. */
342 if (simd == False && where == UPD_Simd)
343 goto noaction;
344
345 if (simd == True && where == UPD_Simd && rr == False && ww == WAll) {
346 /* We're going to generate a complete new simd flag state without
347 consulting the old one first, so just deem this insn to create
348 the state in the real flags. */
349 eflags_state = UPD_Real;
350 DIS_HEADER;
351 return;
352 }
353
354 if (simd == True && where == UPD_Simd && rr == False && ww == WSome) {
355 /* Want to partially update the flags state, but is in simd. So
356 fetch it first, then declare that the real state is the most
357 recent. */
358 emit_get_eflags();
359 eflags_state = UPD_Real;
360 DIS_HEADER;
361 return;
362 }
363
364 if (simd == True && where == UPD_Simd && rr == True && ww == WNone) {
365 /* want to read simd flags, but not in real -> copy to real. */
366 emit_get_eflags();
367 eflags_state = UPD_Both;
368 DIS_HEADER;
369 return;
370 }
371
372 if (simd == True && where == UPD_Simd && rr == True && ww == WAll) {
373 /* want to read and write simd flags, but not in real -> copy to
374 real. State is then Real since they get updated. */
375 emit_get_eflags();
376 eflags_state = UPD_Real;
377 DIS_HEADER;
378 return;
379 }
380
381 if (simd == True && where == UPD_Simd && rr == False && ww == WNone) {
382 /* Doesn't really make sense. Want to interact with simd flags,
383 but insn doesn't modify them. So don't do anything. ??? */
384 goto noaction;
385 }
386
387 if (simd == True && where == UPD_Real && rr == False && ww == WNone) {
388 /* Doesn't really make sense. Want to interact with simd flags,
389 but insn doesn't modify them. So don't do anything. ??? */
390 goto noaction;
391 }
392
393 if (simd == True && where == UPD_Real && rr == True && ww == WNone) {
394 /* simd is in real. Insn reads real but does not change. --> do
395 nothing. */
396 goto noaction;
397 }
398
399 if (simd == True && where == UPD_Real && rr == True && ww == WAll) {
400 /* simd is in real. we want to capture changes made by it. -->
401 do nothing */
402 goto noaction;
403 }
404
405 if (simd == True && where == UPD_Real && rr == False && ww == WAll) {
406 /* simd is in real. Insn creates new simd state. --> leave in
407 real */
408 goto noaction;
409 }
410
411 if (simd == True && where == UPD_Both && rr == False && ww == WAll) {
412 /* simd is in both. Insn creates new simd state. --> change
413 state to Real. */
414 narrow_Both_to_Real:
415 eflags_state = UPD_Real;
416 DIS_HEADER;
417 return;
418 }
419
420 if (simd == True && where == UPD_Both && rr == False && ww == WSome) {
421 /* simd is in both. Insn creates partial new simd state. -->
422 change state to Real. No need to get, since Both holds. */
423 goto narrow_Both_to_Real;
424 }
425
426 if (simd == True && where == UPD_Real && rr == False && ww == WSome) {
427 /* simd is in real. Insn creates new simd state. --> leave in
428 real */
429 goto noaction;
430 }
431
432 if (simd == True && where == UPD_Both && rr == True && ww == WNone)
433 /* want to read the simd flags, but already have a copy in real,
434 and not planning to modify it --> do nothing. */
435 goto noaction;
436
437 ////////////////
438
439 if (simd == False && where == UPD_Real && rr == False && ww == WNone)
440 /* simd state is in real, but insn doesn't touch it --> do nothing */
441 goto noaction;
442
443 if (simd == False && where == UPD_Both && rr == False && ww == WNone)
444 /* simd state is in both, insn doesn't touch it --> do nothing */
445 goto noaction;
446
447 if (simd == False && where == UPD_Both && rr == False && ww == WAll) {
448 /* simd state is in both. insn trashes real, therefore declare
449 simd state only in simd. */
450 narrow_Both_to_Simd:
451 eflags_state = UPD_Simd;
452 DIS_HEADER;
453 return;
454 }
455
456 if (simd == False && where == UPD_Both && rr == False && ww == WSome) {
457 /* simd state is in both. insn trashes real, therefore declare
458 simd state only in simd. */
459 goto narrow_Both_to_Simd;
460 }
461
462 if (simd == False && where == UPD_Real && rr == False && ww == WAll) {
463 /* simd state is in real; we don't want simd state changed, but
464 insn writes the flags. Therefore have to copy back first. */
465 put_flags_and_continue:
466 emit_put_eflags();
467 eflags_state = UPD_Simd;
468 DIS_HEADER;
469 return;
470 }
471
472 if (simd == False && where == UPD_Real && rr == False && ww == WSome) {
473 /* simd state is in real; we don't want simd state changed, but
474 insn writes the flags. Therefore have to copy back first. */
475 goto put_flags_and_continue;
476 }
477
478 goto unhandled;
479
480 noaction:
481 DIS_HEADER;
482 return;
483
484 // if (simd == False && where == UPD_Simd && FL_NONE(rrr) && FL_SOME(www)) {
485 // return;
486 //}
487
488 unhandled:
489 VG_(printf)("simd %s, where %s, read %s, write %s\n",
490 simd ? "True " : "False",
491 (eflags_state == UPD_Simd ? "Simd" : (eflags_state == UPD_Real
492 ? "Real" : "Both")),
493 rr ? "True " : "False",
494 ww == WNone ? "None" : ww == WSome ? "Some" : "All "
495 );
496
497 VG_(core_panic)("new_emit");
498}
499/* end UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED UNUSED */
500#endif
501
502
sewardjfa492d42002-12-08 18:20:01 +0000503/* Call this before emitting each instruction.
504
505 Arguments are:
sewardjf0f12aa2002-12-28 00:04:08 +0000506 interacts_with_simd_flags:
507 if true, this instruction wants to interact (read and/or write)
508 the simulated %EFLAGS state,
509 otherwise it doesn't want to.
sewardjfa492d42002-12-08 18:20:01 +0000510 use_flags: set of (real) flags the instruction uses
511 set_flags: set of (real) flags the instruction sets
sewardjf0f12aa2002-12-28 00:04:08 +0000512*/
sewardjf0f12aa2002-12-28 00:04:08 +0000513void VG_(new_emit) ( Bool interacts_with_simd_flags,
sewardjfa492d42002-12-08 18:20:01 +0000514 FlagSet use_flags, FlagSet set_flags )
515{
516 Bool use, set;
517
518 use = use_flags != FlagsEmpty
519 || (set_flags != FlagsEmpty && set_flags != FlagsOSZACP);
520 set = set_flags != FlagsEmpty;
521
522 if (0)
523 VG_(printf)(
sewardjf0f12aa2002-12-28 00:04:08 +0000524 "new_emit: state=%d interacts_with_simd_flags=%d "
525 "use_flags=%x set_flags=%x\n",
526 eflags_state, interacts_with_simd_flags, use_flags, set_flags);
sewardjfa492d42002-12-08 18:20:01 +0000527
sewardjf0f12aa2002-12-28 00:04:08 +0000528 if (interacts_with_simd_flags) {
sewardjfa492d42002-12-08 18:20:01 +0000529 if (use && eflags_state == UPD_Simd) {
530 /* we need the CPU flags set, but they're not already */
531 eflags_state = UPD_Both;
532 emit_get_eflags();
533 }
534 if (set) {
535 /* if we're setting the flags, then the CPU will have the
536 only good copy */
537 eflags_state = UPD_Real;
538 }
539 } else {
540 /* presume that if non-simd code is using flags, it knows what
541 it's doing (ie, it just set up the flags). */
542 if (set) {
543 /* This instruction is going to trash the flags, so we'd
544 better save them away and say that they're only in the
545 simulated state. */
546 maybe_emit_put_eflags();
547 eflags_state = UPD_Simd;
548 }
549 }
550
sewardjde4a1d02002-03-22 01:27:54 +0000551 if (dis)
552 VG_(printf)("\t %4d: ", emitted_code_used );
553}
554
sewardjde4a1d02002-03-22 01:27:54 +0000555
556/*----------------------------------------------------*/
557/*--- Addressing modes ---*/
558/*----------------------------------------------------*/
559
560static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
561{
562 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
563}
564
565static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
566{
567 Int shift;
568 switch (scale) {
569 case 1: shift = 0; break;
570 case 2: shift = 1; break;
571 case 4: shift = 2; break;
572 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000573 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000574 }
575 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
576}
577
578static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
579{
580 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000581 VG_(emitB) ( mkModRegRM(0, reg, 5) );
582 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000583}
584
585static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
586{
587 /* (regmem), reg */
588 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000589 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000590 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000591 VG_(emitB) ( mkModRegRM(1, reg, 5) );
592 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000593 } else {
njn25e49d8e72002-09-23 09:36:25 +0000594 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000595 }
596}
597
njn25e49d8e72002-09-23 09:36:25 +0000598void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000599{
600 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000601 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000602 if (off < -128 || off > 127) {
603 /* Use a large offset */
604 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000605 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
606 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000607 } else {
608 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000609 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
610 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000611 }
612}
613
614static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
615 Int regindex, Int reg )
616{
617 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000618 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000619 if (off < -128 || off > 127) {
620 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000621 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
622 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
623 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000624 } else {
625 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000626 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
627 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
628 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000629 }
630}
631
njn25e49d8e72002-09-23 09:36:25 +0000632void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000633{
634 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000635 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000636}
637
638static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
639{
640 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000641 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000642}
643
644
645/*----------------------------------------------------*/
646/*--- Opcode translation ---*/
647/*----------------------------------------------------*/
648
649static __inline__ Int mkGrp1opcode ( Opcode opc )
650{
651 switch (opc) {
652 case ADD: return 0;
653 case OR: return 1;
654 case ADC: return 2;
655 case SBB: return 3;
656 case AND: return 4;
657 case SUB: return 5;
658 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000659 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000660 }
661}
662
sewardjfa492d42002-12-08 18:20:01 +0000663static __inline__ FlagSet nonshiftop_use(Opcode opc)
664{
665 switch(opc) {
666 case ADC:
667 case SBB:
668 return FlagC;
669
670 case ADD:
671 case OR:
672 case AND:
673 case SUB:
674 case XOR:
675 return FlagsEmpty;
676
677 default:
678 VG_(core_panic)("nonshiftop_use");
679 }
680}
681
682static __inline__ FlagSet nonshiftop_set(Opcode opc)
683{
684 switch(opc) {
685 case ADC:
686 case SBB:
687 case ADD:
688 case OR:
689 case AND:
690 case SUB:
691 case XOR:
692 return FlagsOSZACP;
693
694 default:
695 VG_(core_panic)("nonshiftop_set");
696 }
697}
698
sewardjde4a1d02002-03-22 01:27:54 +0000699static __inline__ Int mkGrp2opcode ( Opcode opc )
700{
701 switch (opc) {
702 case ROL: return 0;
703 case ROR: return 1;
704 case RCL: return 2;
705 case RCR: return 3;
706 case SHL: return 4;
707 case SHR: return 5;
708 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000709 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000710 }
711}
712
sewardjfa492d42002-12-08 18:20:01 +0000713static __inline__ FlagSet shiftop_use(Opcode opc)
714{
715 switch(opc) {
716 case ROR:
717 case ROL:
718 case SHL:
719 case SHR:
720 case SAR:
721 return FlagsEmpty;
722
723 case RCL:
724 case RCR:
725 return FlagC;
726
727 default:
728 VG_(core_panic)("shiftop_use");
729 }
730}
731
732static __inline__ FlagSet shiftop_set(Opcode opc)
733{
734 switch(opc) {
735 case ROR:
736 case ROL:
737 case RCL:
738 case RCR:
739 return FlagsOC;
740
741 case SHL:
742 case SHR:
743 case SAR:
744 return FlagsOSZACP;
745
746 default:
747 VG_(core_panic)("shiftop_set");
748 }
749}
750
sewardjde4a1d02002-03-22 01:27:54 +0000751static __inline__ Int mkGrp3opcode ( Opcode opc )
752{
753 switch (opc) {
754 case NOT: return 2;
755 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000756 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000757 }
758}
759
760static __inline__ Int mkGrp4opcode ( Opcode opc )
761{
762 switch (opc) {
763 case INC: return 0;
764 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000765 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000766 }
767}
768
769static __inline__ Int mkGrp5opcode ( Opcode opc )
770{
771 switch (opc) {
772 case CALLM: return 2;
773 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000774 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000775 }
776}
777
778static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
779{
780 switch (opc) {
781 case ADD: return 0x00;
782 case ADC: return 0x10;
783 case AND: return 0x20;
784 case XOR: return 0x30;
785 case OR: return 0x08;
786 case SBB: return 0x18;
787 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000788 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000789 }
790}
791
792/*----------------------------------------------------*/
793/*--- v-size (4, or 2 with OSO) insn emitters ---*/
794/*----------------------------------------------------*/
795
njn25e49d8e72002-09-23 09:36:25 +0000796void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000797{
sewardjf0f12aa2002-12-28 00:04:08 +0000798 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000799 if (sz == 2) VG_(emitB) ( 0x66 );
800 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
801 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000802 if (dis)
803 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
804 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
805}
806
njn25e49d8e72002-09-23 09:36:25 +0000807void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000808{
sewardjf0f12aa2002-12-28 00:04:08 +0000809 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000810
811 if (sz & DO_BOUNDSCHECK) {
812 boundscheck();
813 sz &= ~DO_BOUNDSCHECK;
814 }
815
njn25e49d8e72002-09-23 09:36:25 +0000816 if (sz == 2) VG_(emitB) ( 0x66 );
817 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
818 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000819 if (dis)
820 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
821 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
822}
823
824static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
825{
sewardjf0f12aa2002-12-28 00:04:08 +0000826 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000827
828 if (sz & DO_BOUNDSCHECK) {
829 boundscheck();
830 sz &= ~DO_BOUNDSCHECK;
831 }
832
njn25e49d8e72002-09-23 09:36:25 +0000833 if (sz == 2) VG_(emitB) ( 0x66 );
834 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000835 emit_amode_regmem_reg ( reg1, reg2 );
836 if (dis)
837 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
838 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
839}
840
841static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
842{
sewardjf0f12aa2002-12-28 00:04:08 +0000843 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +0000844
845 if (sz & DO_BOUNDSCHECK) {
846 boundscheck();
847 sz &= ~DO_BOUNDSCHECK;
848 }
849
njn25e49d8e72002-09-23 09:36:25 +0000850 if (sz == 2) VG_(emitB) ( 0x66 );
851 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000852 emit_amode_regmem_reg ( reg2, reg1 );
853 if (dis)
854 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
855 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
856}
857
njn25e49d8e72002-09-23 09:36:25 +0000858void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000859{
sewardjf0f12aa2002-12-28 00:04:08 +0000860 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +0000861 if (sz == 2) VG_(emitB) ( 0x66 );
862 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
863 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000864 if (dis)
865 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
866 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
867}
868
sewardjf0f12aa2002-12-28 00:04:08 +0000869void VG_(emit_nonshiftopv_lit_reg) ( Bool simd_flags,
870 Int sz, Opcode opc,
871 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000872{
sewardjf0f12aa2002-12-28 00:04:08 +0000873 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000874
njn25e49d8e72002-09-23 09:36:25 +0000875 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000876 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
877 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000878 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
879 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
880 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000881 } else {
njn25e49d8e72002-09-23 09:36:25 +0000882 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
883 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
884 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000885 }
886 if (dis)
887 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000888 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000889 lit, nameIReg(sz,reg));
890}
891
sewardjf0f12aa2002-12-28 00:04:08 +0000892void VG_(emit_nonshiftopv_lit_offregmem) ( Bool simd_flags, Int sz,
893 Opcode opc, UInt lit,
sewardjfa492d42002-12-08 18:20:01 +0000894 Int off, Int regmem )
sewardjde4a1d02002-03-22 01:27:54 +0000895{
sewardjf0f12aa2002-12-28 00:04:08 +0000896 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000897 if (sz == 2) VG_(emitB) ( 0x66 );
898 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
899 /* short form OK */
900 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
901 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
902 VG_(emitB) ( lit & 0x000000FF );
903 } else {
904 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
905 VG_(emit_amode_offregmem_reg) ( off, regmem, mkGrp1opcode(opc) );
906 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
907 }
908 if (dis)
909 VG_(printf)( "\n\t\t%s%c\t$0x%x, 0x%x(%s)\n",
910 VG_(name_UOpcode)(False,opc), nameISize(sz),
911 lit, off, nameIReg(sz,regmem));
912}
913
sewardjf0f12aa2002-12-28 00:04:08 +0000914void VG_(emit_shiftopv_lit_reg) ( Bool simd_flags,
915 Int sz, Opcode opc,
916 UInt lit, Int reg )
sewardjfa492d42002-12-08 18:20:01 +0000917{
sewardjf0f12aa2002-12-28 00:04:08 +0000918 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000919
njn25e49d8e72002-09-23 09:36:25 +0000920 if (sz == 2) VG_(emitB) ( 0x66 );
921 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
922 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
923 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000924 if (dis)
925 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000926 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000927 lit, nameIReg(sz,reg));
928}
929
sewardjf0f12aa2002-12-28 00:04:08 +0000930static void emit_shiftopv_cl_stack0 ( Bool simd_flags, Int sz, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000931{
sewardjf0f12aa2002-12-28 00:04:08 +0000932 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000933 if (sz == 2) VG_(emitB) ( 0x66 );
934 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
935 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
936 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
937 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000938 if (dis)
939 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000940 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000941}
942
sewardjf0f12aa2002-12-28 00:04:08 +0000943static void emit_shiftopb_cl_stack0 ( Bool simd_flags, Opcode opc )
sewardjde4a1d02002-03-22 01:27:54 +0000944{
sewardjf0f12aa2002-12-28 00:04:08 +0000945 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000946 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
947 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
948 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
949 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000950 if (dis)
951 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000952 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000953}
954
sewardjf0f12aa2002-12-28 00:04:08 +0000955static void emit_nonshiftopv_offregmem_reg ( Bool simd_flags, Int sz,
956 Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000957 Int off, Int areg, Int reg )
958{
sewardjf0f12aa2002-12-28 00:04:08 +0000959 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000960 if (sz == 2) VG_(emitB) ( 0x66 );
961 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
962 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000963 if (dis)
964 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000965 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000966 off, nameIReg(4,areg), nameIReg(sz,reg));
967}
968
sewardja2c5a732002-12-15 03:10:42 +0000969#if 0
970/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +0000971static void emit_nonshiftopv_reg_offregmem ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000972 Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000973{
sewardjf0f12aa2002-12-28 00:04:08 +0000974 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +0000975 if (sz == 2) VG_(emitB) ( 0x66 );
976 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
977 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
978 if (dis)
979 VG_(printf)( "\n\t\t%s%c\t0x%s, %x(%s),\n",
980 VG_(name_UOpcode)(False,opc), nameISize(sz),
981 nameIReg(sz,reg), off, nameIReg(4,areg));
982}
sewardja2c5a732002-12-15 03:10:42 +0000983#endif
sewardjfa492d42002-12-08 18:20:01 +0000984
sewardjf0f12aa2002-12-28 00:04:08 +0000985void VG_(emit_nonshiftopv_reg_reg) ( Bool simd_flags, Int sz, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +0000986 Int reg1, Int reg2 )
987{
sewardjf0f12aa2002-12-28 00:04:08 +0000988 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +0000989 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000990# if 0
991 /* Perfectly correct, but the GNU assembler uses the other form.
992 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000993 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
994 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000995# else
njn25e49d8e72002-09-23 09:36:25 +0000996 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000997 emit_amode_greg_ereg ( reg1, reg2 );
998# endif
999 if (dis)
1000 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001001 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +00001002 nameIReg(sz,reg1), nameIReg(sz,reg2));
1003}
1004
njn25e49d8e72002-09-23 09:36:25 +00001005void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001006{
sewardjf0f12aa2002-12-28 00:04:08 +00001007#if 0
sewardjfa492d42002-12-08 18:20:01 +00001008 if (lit == 0 && eflags_state != UPD_Real) {
1009 /* Only emit this for zeroing if it won't stomp flags */
1010 VG_(emit_nonshiftopv_reg_reg) ( False, sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001011 return;
1012 }
sewardjf0f12aa2002-12-28 00:04:08 +00001013#endif
1014 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001015 if (sz == 2) VG_(emitB) ( 0x66 );
1016 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
1017 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001018 if (dis)
1019 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
1020 nameISize(sz), lit, nameIReg(sz,reg));
1021}
1022
sewardjf0f12aa2002-12-28 00:04:08 +00001023void VG_(emit_unaryopv_reg) ( Bool simd_flags, Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001024{
sewardjde4a1d02002-03-22 01:27:54 +00001025 switch (opc) {
1026 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001027 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
sewardjfa492d42002-12-08 18:20:01 +00001028 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001029 VG_(emitB) ( 0xF7 );
1030 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001031 if (dis)
1032 VG_(printf)( "\n\t\tneg%c\t%s\n",
1033 nameISize(sz), nameIReg(sz,reg));
1034 break;
1035 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001036 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
sewardjfa492d42002-12-08 18:20:01 +00001037 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001038 VG_(emitB) ( 0xF7 );
1039 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001040 if (dis)
1041 VG_(printf)( "\n\t\tnot%c\t%s\n",
1042 nameISize(sz), nameIReg(sz,reg));
1043 break;
1044 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001045 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001046 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001047 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001048 if (dis)
1049 VG_(printf)( "\n\t\tdec%c\t%s\n",
1050 nameISize(sz), nameIReg(sz,reg));
1051 break;
1052 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001053 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
sewardjfa492d42002-12-08 18:20:01 +00001054 if (sz == 2) VG_(emitB) ( 0x66 );
njn25e49d8e72002-09-23 09:36:25 +00001055 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001056 if (dis)
1057 VG_(printf)( "\n\t\tinc%c\t%s\n",
1058 nameISize(sz), nameIReg(sz,reg));
1059 break;
1060 default:
njne427a662002-10-02 11:08:25 +00001061 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001062 }
1063}
1064
njn25e49d8e72002-09-23 09:36:25 +00001065void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001066{
sewardjf0f12aa2002-12-28 00:04:08 +00001067 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001068 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001069 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001070 } else {
1071 vg_assert(sz == 4);
1072 }
njn25e49d8e72002-09-23 09:36:25 +00001073 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001074 if (dis)
1075 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
1076}
1077
njn25e49d8e72002-09-23 09:36:25 +00001078void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001079{
sewardjf0f12aa2002-12-28 00:04:08 +00001080 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001081 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001082 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001083 } else {
1084 vg_assert(sz == 4);
1085 }
njn25e49d8e72002-09-23 09:36:25 +00001086 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +00001087 if (dis)
1088 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
1089}
1090
njn25e49d8e72002-09-23 09:36:25 +00001091void VG_(emit_pushl_lit32) ( UInt int32 )
1092{
sewardjf0f12aa2002-12-28 00:04:08 +00001093 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001094 VG_(emitB) ( 0x68 );
1095 VG_(emitL) ( int32 );
1096 if (dis)
1097 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
1098}
1099
1100void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +00001101{
1102 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjf0f12aa2002-12-28 00:04:08 +00001103 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001104 VG_(emitB) ( 0x6A );
1105 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +00001106 if (dis)
1107 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
1108}
1109
sewardjf0f12aa2002-12-28 00:04:08 +00001110void VG_(emit_cmpl_zero_reg) ( Bool simd_flags, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001111{
sewardjf0f12aa2002-12-28 00:04:08 +00001112 VG_(new_emit)(simd_flags, False, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001113 VG_(emitB) ( 0x83 );
1114 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
1115 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001116 if (dis)
1117 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
1118}
1119
1120static void emit_swapl_reg_ECX ( Int reg )
1121{
sewardjf0f12aa2002-12-28 00:04:08 +00001122 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001123 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1124 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +00001125 if (dis)
1126 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
1127}
1128
njn25e49d8e72002-09-23 09:36:25 +00001129void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001130{
sewardjf0f12aa2002-12-28 00:04:08 +00001131 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001132 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +00001133 if (dis)
1134 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
1135}
1136
1137static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
1138{
sewardjf0f12aa2002-12-28 00:04:08 +00001139 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001140 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
1141 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001142 if (dis)
1143 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
1144 nameIReg(4,reg2));
1145}
1146
1147static void emit_bswapl_reg ( Int reg )
1148{
sewardjf0f12aa2002-12-28 00:04:08 +00001149 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001150 VG_(emitB) ( 0x0F );
1151 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +00001152 if (dis)
1153 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
1154}
1155
1156static void emit_movl_reg_reg ( Int regs, Int regd )
1157{
sewardjf0f12aa2002-12-28 00:04:08 +00001158 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001159 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
1160 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +00001161 if (dis)
1162 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
1163}
1164
njn25e49d8e72002-09-23 09:36:25 +00001165void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +00001166{
sewardjf0f12aa2002-12-28 00:04:08 +00001167 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardjde4a1d02002-03-22 01:27:54 +00001168 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001169 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +00001170 } else {
1171 vg_assert(sz == 4);
1172 }
njn25e49d8e72002-09-23 09:36:25 +00001173 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
1174 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1175 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001176 if (dis)
1177 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
1178 nameISize(sz), lit, off, nameIReg(4,memreg) );
1179}
1180
1181
1182/*----------------------------------------------------*/
1183/*--- b-size (1 byte) instruction emitters ---*/
1184/*----------------------------------------------------*/
1185
1186/* There is some doubt as to whether C6 (Grp 11) is in the
1187 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +00001188void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
1189{
sewardjf0f12aa2002-12-28 00:04:08 +00001190 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001191 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
1192 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
1193 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001194 if (dis)
1195 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
1196 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +00001197}
1198
sewardjf0f12aa2002-12-28 00:04:08 +00001199static void emit_nonshiftopb_offregmem_reg ( Bool simd_flags, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +00001200 Int off, Int areg, Int reg )
1201{
sewardjf0f12aa2002-12-28 00:04:08 +00001202 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001203 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1204 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001205 if (dis)
1206 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +00001207 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +00001208 nameIReg(1,reg));
1209}
1210
sewardjf0f12aa2002-12-28 00:04:08 +00001211static void emit_nonshiftopb_lit_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001212 UInt lit, Int off, Int areg )
1213{
sewardjf0f12aa2002-12-28 00:04:08 +00001214 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001215 VG_(emitB) ( 0x80 );
1216 VG_(emit_amode_offregmem_reg) ( off, areg, mkGrp1opcode(opc) );
1217 VG_(emitB) ( lit );
1218 if (dis)
1219 VG_(printf)( "\n\t\t%sb\t$0x%x, 0x%x(%s)\n",
1220 VG_(name_UOpcode)(False,opc), lit, off, nameIReg(4,areg));
1221}
1222
sewardja2c5a732002-12-15 03:10:42 +00001223#if 0
1224/* evidently unused */
sewardjf0f12aa2002-12-28 00:04:08 +00001225static void emit_nonshiftopb_reg_offregmem ( Bool simd_flags, Opcode opc,
sewardjfa492d42002-12-08 18:20:01 +00001226 Int off, Int areg, Int reg )
1227{
sewardjf0f12aa2002-12-28 00:04:08 +00001228 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
sewardjfa492d42002-12-08 18:20:01 +00001229 VG_(emitB) ( 0 + mkPrimaryOpcode(opc) ); /* op Gb, Eb */
1230 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
1231 if (dis)
1232 VG_(printf)( "\n\t\t%sb\t0x%s , %x(%s)\n",
1233 VG_(name_UOpcode)(False,opc),
1234 nameIReg(1,reg),
1235 off, nameIReg(4,areg));
1236}
sewardja2c5a732002-12-15 03:10:42 +00001237#endif
sewardjfa492d42002-12-08 18:20:01 +00001238
njn25e49d8e72002-09-23 09:36:25 +00001239void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +00001240{
1241 /* Could do better when reg == %al. */
sewardjf0f12aa2002-12-28 00:04:08 +00001242 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001243 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
1244 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001245 if (dis)
1246 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
1247 nameIReg(1,reg), off, nameIReg(4,areg));
1248}
1249
sewardjf0f12aa2002-12-28 00:04:08 +00001250static void emit_nonshiftopb_reg_reg ( Bool simd_flags, Opcode opc,
1251 Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001252{
sewardjf0f12aa2002-12-28 00:04:08 +00001253 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001254 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
1255 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00001256 if (dis)
1257 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001258 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001259 nameIReg(1,reg1), nameIReg(1,reg2));
1260}
1261
fitzhardinge98abfc72003-12-16 02:05:15 +00001262static void emit_movb_reg_regmem ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001263{
sewardjf0f12aa2002-12-28 00:04:08 +00001264 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001265
1266 if (bounds)
1267 boundscheck();
1268
njn25e49d8e72002-09-23 09:36:25 +00001269 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +00001270 emit_amode_regmem_reg ( reg2, reg1 );
1271 if (dis)
1272 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
1273 nameIReg(4,reg2));
1274}
1275
sewardjf0f12aa2002-12-28 00:04:08 +00001276static void emit_nonshiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1277 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001278{
sewardjf0f12aa2002-12-28 00:04:08 +00001279 VG_(new_emit)(simd_flags, nonshiftop_use(opc), nonshiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001280 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
1281 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
1282 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +00001283 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001284 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001285 lit, nameIReg(1,reg));
1286}
1287
sewardjf0f12aa2002-12-28 00:04:08 +00001288static void emit_shiftopb_lit_reg ( Bool simd_flags, Opcode opc,
1289 UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001290{
sewardjf0f12aa2002-12-28 00:04:08 +00001291 VG_(new_emit)(simd_flags, shiftop_use(opc), shiftop_set(opc));
njn25e49d8e72002-09-23 09:36:25 +00001292 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
1293 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
1294 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001295 if (dis)
1296 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +00001297 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +00001298 lit, nameIReg(1,reg));
1299}
1300
sewardjf0f12aa2002-12-28 00:04:08 +00001301void VG_(emit_unaryopb_reg) ( Bool simd_flags, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001302{
sewardjde4a1d02002-03-22 01:27:54 +00001303 switch (opc) {
1304 case INC:
sewardjf0f12aa2002-12-28 00:04:08 +00001305 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001306 VG_(emitB) ( 0xFE );
1307 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +00001308 if (dis)
1309 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
1310 break;
1311 case DEC:
sewardjf0f12aa2002-12-28 00:04:08 +00001312 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZAP);
njn25e49d8e72002-09-23 09:36:25 +00001313 VG_(emitB) ( 0xFE );
1314 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +00001315 if (dis)
1316 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
1317 break;
1318 case NOT:
sewardjf0f12aa2002-12-28 00:04:08 +00001319 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001320 VG_(emitB) ( 0xF6 );
1321 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +00001322 if (dis)
1323 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
1324 break;
1325 case NEG:
sewardjf0f12aa2002-12-28 00:04:08 +00001326 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001327 VG_(emitB) ( 0xF6 );
1328 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +00001329 if (dis)
1330 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
1331 break;
1332 default:
njne427a662002-10-02 11:08:25 +00001333 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +00001334 }
1335}
1336
sewardjf0f12aa2002-12-28 00:04:08 +00001337void VG_(emit_testb_lit_reg) ( Bool simd_flags, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001338{
sewardjf0f12aa2002-12-28 00:04:08 +00001339 VG_(new_emit)(simd_flags, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001340 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
1341 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
1342 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +00001343 if (dis)
1344 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
1345}
1346
sewardjde4a1d02002-03-22 01:27:54 +00001347/*----------------------------------------------------*/
1348/*--- zero-extended load emitters ---*/
1349/*----------------------------------------------------*/
1350
fitzhardinge98abfc72003-12-16 02:05:15 +00001351void VG_(emit_movzbl_offregmem_reg) ( Bool bounds, Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001352{
sewardjf0f12aa2002-12-28 00:04:08 +00001353 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001354 if (bounds)
1355 boundscheck();
njn25e49d8e72002-09-23 09:36:25 +00001356 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
1357 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001358 if (dis)
1359 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
1360 off, nameIReg(4,regmem), nameIReg(4,reg));
1361}
1362
fitzhardinge98abfc72003-12-16 02:05:15 +00001363static void emit_movzbl_regmem_reg ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001364{
sewardjf0f12aa2002-12-28 00:04:08 +00001365 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001366
1367 if (bounds)
1368 boundscheck();
1369
njn25e49d8e72002-09-23 09:36:25 +00001370 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +00001371 emit_amode_regmem_reg ( reg1, reg2 );
1372 if (dis)
1373 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
1374 nameIReg(4,reg2));
1375}
1376
fitzhardinge98abfc72003-12-16 02:05:15 +00001377void VG_(emit_movzwl_offregmem_reg) ( Bool bounds, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001378{
sewardjf0f12aa2002-12-28 00:04:08 +00001379 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001380
1381 if (bounds)
1382 boundscheck();
1383
njn25e49d8e72002-09-23 09:36:25 +00001384 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
1385 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001386 if (dis)
1387 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
1388 off, nameIReg(4,areg), nameIReg(4,reg));
1389}
1390
fitzhardinge98abfc72003-12-16 02:05:15 +00001391void VG_( emit_movzwl_regmem_reg ) ( Bool bounds, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +00001392{
sewardjf0f12aa2002-12-28 00:04:08 +00001393 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
fitzhardinge98abfc72003-12-16 02:05:15 +00001394
1395 if (bounds)
1396 boundscheck();
1397
njn25e49d8e72002-09-23 09:36:25 +00001398 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +00001399 emit_amode_regmem_reg ( reg1, reg2 );
1400 if (dis)
1401 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
1402 nameIReg(4,reg2));
1403}
1404
1405/*----------------------------------------------------*/
1406/*--- FPU instruction emitters ---*/
1407/*----------------------------------------------------*/
1408
sewardjb91ae7f2003-04-29 23:50:00 +00001409static void emit_get_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001410{
sewardjb91ae7f2003-04-29 23:50:00 +00001411 Int off = 4 * VGOFF_(m_ssestate);
1412 if (VG_(have_ssestate)) {
1413 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1414 VG_(emitB) ( 0x0F );
1415 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x8D ); /* fxrstor d32(%ebp) */
1416 VG_(emitL) ( off );
1417 if (dis)
1418 VG_(printf)("\n\t\tfxrstor\t%d(%%ebp)\n", off );
1419 } else {
1420 /* Not a SSE-capable CPU. Just do frstor. */
1421 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1422 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
1423 VG_(emitL) ( off );
1424 if (dis)
1425 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
1426 }
sewardjde4a1d02002-03-22 01:27:54 +00001427}
1428
sewardjb91ae7f2003-04-29 23:50:00 +00001429static void emit_put_sse_state ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001430{
sewardjb91ae7f2003-04-29 23:50:00 +00001431 Int off = 4 * VGOFF_(m_ssestate);
1432 if (VG_(have_ssestate)) {
1433 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1434 VG_(emitB) ( 0x0F );
1435 VG_(emitB) ( 0xAE ); VG_(emitB) ( 0x85 ); /* fxsave d32(%ebp) */
1436 VG_(emitL) ( off );
1437 if (dis)
1438 VG_(printf)("\n\t\tfxsave\t%d(%%ebp)\n", off );
1439 } else {
1440 /* Not a SSE-capable CPU. Just do fnsave. */
1441 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1442 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
1443 VG_(emitL) ( off );
1444 if (dis)
1445 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
1446 }
sewardjde4a1d02002-03-22 01:27:54 +00001447}
1448
sewardjf0f12aa2002-12-28 00:04:08 +00001449static void emit_fpu_no_mem ( FlagSet uses_sflags,
1450 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001451 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001452 UChar second_byte )
1453{
sewardjf0f12aa2002-12-28 00:04:08 +00001454 VG_(new_emit)(True, uses_sflags, sets_sflags);
njn25e49d8e72002-09-23 09:36:25 +00001455 VG_(emitB) ( first_byte );
1456 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001457 if (dis)
1458 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
1459 (UInt)first_byte, (UInt)second_byte );
1460}
1461
sewardjf0f12aa2002-12-28 00:04:08 +00001462static void emit_fpu_regmem ( FlagSet uses_sflags,
1463 FlagSet sets_sflags,
sewardjfa492d42002-12-08 18:20:01 +00001464 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00001465 UChar second_byte_masked,
1466 Int reg )
1467{
sewardjf0f12aa2002-12-28 00:04:08 +00001468 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001469
1470 boundscheck(); /* assume all FPU ops are the client's */
1471
njn25e49d8e72002-09-23 09:36:25 +00001472 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001473 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
1474 if (dis)
1475 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
1476 (UInt)first_byte, (UInt)second_byte_masked,
1477 nameIReg(4,reg) );
1478}
1479
sewardj3d7c9c82003-03-26 21:08:13 +00001480static void emit_MMX2_regmem ( FlagSet uses_sflags,
1481 FlagSet sets_sflags,
1482 UChar first_byte,
1483 UChar second_byte,
1484 Int ireg )
1485{
1486 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001487
1488 boundscheck();
1489
sewardj3d7c9c82003-03-26 21:08:13 +00001490 VG_(emitB) ( 0x0F );
1491 VG_(emitB) ( first_byte );
1492 second_byte &= 0x38; /* mask out mod and rm fields */
1493 emit_amode_regmem_reg ( ireg, second_byte >> 3 );
1494 if (dis)
1495 VG_(printf)("\n\t\tmmx2-0x%x:0x%x-(%s)\n",
1496 (UInt)first_byte, (UInt)second_byte,
1497 nameIReg(4,ireg) );
1498}
1499
sewardjfebaa3b2003-05-25 01:07:34 +00001500static void emit_SSE2a ( FlagSet uses_sflags,
1501 FlagSet sets_sflags,
1502 UChar first_byte,
1503 UChar second_byte,
1504 UChar third_byte,
1505 Int ireg )
1506{
1507 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001508
1509 boundscheck();
1510
sewardjfebaa3b2003-05-25 01:07:34 +00001511 VG_(emitB) ( first_byte );
1512 VG_(emitB) ( second_byte );
1513 third_byte &= 0x38; /* mask out mod and rm fields */
1514 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1515 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001516 VG_(printf)("\n\t\tsse2a-0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001517 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1518 nameIReg(4,ireg) );
1519}
1520
sewardj9dd209f2003-06-18 23:30:52 +00001521static void emit_SSE2a1 ( FlagSet uses_sflags,
1522 FlagSet sets_sflags,
1523 UChar first_byte,
1524 UChar second_byte,
1525 UChar third_byte,
1526 UChar fourth_byte,
1527 Int ireg )
1528{
1529 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001530
1531 boundscheck();
1532
sewardj9dd209f2003-06-18 23:30:52 +00001533 VG_(emitB) ( first_byte );
1534 VG_(emitB) ( second_byte );
1535 third_byte &= 0x38; /* mask out mod and rm fields */
1536 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1537 VG_(emitB) ( fourth_byte );
1538 if (dis)
1539 VG_(printf)("\n\t\tsse2a1-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1540 (UInt)first_byte, (UInt)second_byte,
1541 (UInt)third_byte, (UInt)fourth_byte,
1542 nameIReg(4,ireg) );
1543}
1544
sewardjfebaa3b2003-05-25 01:07:34 +00001545static void emit_SSE3a ( FlagSet uses_sflags,
1546 FlagSet sets_sflags,
1547 UChar first_byte,
1548 UChar second_byte,
1549 UChar third_byte,
1550 UChar fourth_byte,
1551 Int ireg )
1552{
1553 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001554
1555 boundscheck();
1556
sewardjfebaa3b2003-05-25 01:07:34 +00001557 VG_(emitB) ( first_byte );
1558 VG_(emitB) ( second_byte );
1559 VG_(emitB) ( third_byte );
1560 fourth_byte &= 0x38; /* mask out mod and rm fields */
1561 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1562 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001563 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001564 (UInt)first_byte, (UInt)second_byte,
1565 (UInt)third_byte, (UInt)fourth_byte,
1566 nameIReg(4,ireg) );
1567}
1568
sewardjabf8bf82003-06-15 22:28:05 +00001569static void emit_SSE3e ( FlagSet uses_sflags,
1570 FlagSet sets_sflags,
1571 UChar first_byte,
1572 UChar second_byte,
1573 UChar third_byte,
1574 UChar fourth_byte,
1575 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001576{
1577 VG_(new_emit)(True, uses_sflags, sets_sflags);
1578 VG_(emitB) ( first_byte );
1579 VG_(emitB) ( second_byte );
1580 VG_(emitB) ( third_byte );
1581 fourth_byte &= 0x38; /* mask out mod and rm fields */
1582 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1583 fourth_byte |= (ireg & 7); /* patch in our ireg */
1584 VG_(emitB) ( fourth_byte );
1585 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001586 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001587 "\n\t\tsse3e--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001588 (UInt)first_byte, (UInt)second_byte,
1589 (UInt)third_byte, (UInt)fourth_byte,
1590 nameIReg(4,ireg)
1591 );
sewardjfebaa3b2003-05-25 01:07:34 +00001592}
1593
sewardjabf8bf82003-06-15 22:28:05 +00001594static void emit_SSE3e1 ( FlagSet uses_sflags,
1595 FlagSet sets_sflags,
1596 UChar first_byte,
1597 UChar second_byte,
1598 UChar third_byte,
1599 UChar fourth_byte,
1600 UChar fifth_byte,
1601 Int ireg )
sewardj8f33ba62003-06-14 12:00:45 +00001602{
1603 VG_(new_emit)(True, uses_sflags, sets_sflags);
1604 VG_(emitB) ( first_byte );
1605 VG_(emitB) ( second_byte );
1606 VG_(emitB) ( third_byte );
1607 fourth_byte &= 0x38; /* mask out mod and rm fields */
1608 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1609 fourth_byte |= (ireg & 7); /* patch in our ireg */
1610 VG_(emitB) ( fourth_byte );
1611 VG_(emitB) ( fifth_byte );
1612 if (dis)
1613 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001614 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001615 (UInt)first_byte, (UInt)second_byte,
1616 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1617 nameIReg(4,ireg)
1618 );
1619}
1620
sewardjabf8bf82003-06-15 22:28:05 +00001621static void emit_SSE3g1 ( FlagSet uses_sflags,
1622 FlagSet sets_sflags,
1623 UChar first_byte,
1624 UChar second_byte,
1625 UChar third_byte,
1626 UChar fourth_byte,
1627 UChar fifth_byte,
1628 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001629{
1630 VG_(new_emit)(True, uses_sflags, sets_sflags);
1631 VG_(emitB) ( first_byte );
1632 VG_(emitB) ( second_byte );
1633 VG_(emitB) ( third_byte );
1634 fourth_byte &= 0xC7; /* mask out reg field */
1635 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1636 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1637 VG_(emitB) ( fourth_byte );
1638 VG_(emitB) ( fifth_byte );
1639 if (dis)
1640 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001641 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001642 (UInt)first_byte, (UInt)second_byte,
1643 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1644 nameIReg(4,ireg)
1645 );
1646}
1647
sewardjabf8bf82003-06-15 22:28:05 +00001648static void emit_SSE3g ( FlagSet uses_sflags,
1649 FlagSet sets_sflags,
1650 UChar first_byte,
1651 UChar second_byte,
1652 UChar third_byte,
1653 UChar fourth_byte,
1654 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001655{
1656 VG_(new_emit)(True, uses_sflags, sets_sflags);
1657 VG_(emitB) ( first_byte );
1658 VG_(emitB) ( second_byte );
1659 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001660 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001661 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001662 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001663 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001664 if (dis)
1665 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001666 "\n\t\tsse3g--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001667 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001668 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001669 nameIReg(4,ireg)
1670 );
1671}
1672
sewardj77d30a22003-10-19 08:18:52 +00001673static void emit_SSE3a1 ( FlagSet uses_sflags,
1674 FlagSet sets_sflags,
1675 UChar first_byte,
1676 UChar second_byte,
1677 UChar third_byte,
1678 UChar fourth_byte,
1679 UChar fifth_byte,
1680 Int ireg )
1681{
1682 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001683
1684 boundscheck();
1685
sewardj77d30a22003-10-19 08:18:52 +00001686 VG_(emitB) ( first_byte );
1687 VG_(emitB) ( second_byte );
1688 VG_(emitB) ( third_byte );
1689 fourth_byte &= 0x38; /* mask out mod and rm fields */
1690 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1691 VG_(emitB) ( fifth_byte );
1692 if (dis)
1693 VG_(printf)("\n\t\tsse3a1-0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1694 (UInt)first_byte, (UInt)second_byte,
1695 (UInt)third_byte, (UInt)fourth_byte,
1696 (UInt)fifth_byte,
1697 nameIReg(4,ireg) );
1698}
1699
sewardjfebaa3b2003-05-25 01:07:34 +00001700static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001701 FlagSet sets_sflags,
1702 UChar first_byte,
1703 UChar second_byte,
1704 UChar third_byte,
1705 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001706{
1707 VG_(new_emit)(True, uses_sflags, sets_sflags);
1708 VG_(emitB) ( first_byte );
1709 VG_(emitB) ( second_byte );
1710 VG_(emitB) ( third_byte );
1711 VG_(emitB) ( fourth_byte );
1712 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001713 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001714 (UInt)first_byte, (UInt)second_byte,
1715 (UInt)third_byte, (UInt)fourth_byte );
1716}
1717
sewardja453fb02003-06-14 13:22:36 +00001718static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001719 FlagSet sets_sflags,
1720 UChar first_byte,
1721 UChar second_byte,
1722 UChar third_byte,
1723 UChar fourth_byte,
1724 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001725{
1726 VG_(new_emit)(True, uses_sflags, sets_sflags);
1727 VG_(emitB) ( first_byte );
1728 VG_(emitB) ( second_byte );
1729 VG_(emitB) ( third_byte );
1730 VG_(emitB) ( fourth_byte );
1731 VG_(emitB) ( fifth_byte );
1732 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001733 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001734 (UInt)first_byte, (UInt)second_byte,
1735 (UInt)third_byte, (UInt)fourth_byte,
1736 (UInt)fifth_byte );
1737}
1738
sewardja60be0e2003-05-26 08:47:27 +00001739static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001740 FlagSet sets_sflags,
1741 UChar first_byte,
1742 UChar second_byte,
1743 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001744{
1745 VG_(new_emit)(True, uses_sflags, sets_sflags);
1746 VG_(emitB) ( first_byte );
1747 VG_(emitB) ( second_byte );
1748 VG_(emitB) ( third_byte );
1749 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001750 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001751 (UInt)first_byte, (UInt)second_byte,
1752 (UInt)third_byte );
1753}
1754
sewardje3891fa2003-06-15 03:13:48 +00001755static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1756 FlagSet sets_sflags,
1757 UChar first_byte,
1758 UChar second_byte,
1759 UChar third_byte,
1760 Int addr_reg,
1761 Int dest_reg )
1762{
1763 VG_(new_emit)(True, uses_sflags, sets_sflags);
1764 VG_(emitB) ( first_byte );
1765 VG_(emitB) ( second_byte );
1766 VG_(emitB) ( third_byte );
1767 /* 4th byte can be completely synthesised from addr_reg and
1768 dest_reg. */
1769 emit_amode_regmem_reg ( addr_reg, dest_reg );
1770 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001771 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 +00001772 (UInt)first_byte, (UInt)second_byte,
1773 (UInt)third_byte, nameIReg(4, addr_reg),
1774 nameIReg(4, dest_reg));
1775}
1776
sewardjca860012003-03-27 23:52:58 +00001777static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1778 FlagSet sets_sflags,
1779 UChar first_byte,
1780 UChar second_byte,
1781 Int ireg )
1782{
1783 VG_(new_emit)(True, uses_sflags, sets_sflags);
1784 VG_(emitB) ( 0x0F );
1785 VG_(emitB) ( first_byte );
1786 second_byte &= 0x38; /* mask out mod and rm fields */
1787 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1788 second_byte |= (ireg & 7); /* patch in our ireg */
1789 VG_(emitB) ( second_byte );
1790 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001791 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1792 (UInt)first_byte, (UInt)second_byte,
1793 nameIReg(4,ireg) );
1794}
1795
1796static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1797 FlagSet sets_sflags,
1798 UChar first_byte,
1799 UChar second_byte,
1800 Int ireg )
1801{
1802 VG_(new_emit)(True, uses_sflags, sets_sflags);
1803 VG_(emitB) ( 0x0F );
1804 VG_(emitB) ( first_byte );
1805 second_byte &= 0x38; /* mask out mod and rm fields */
1806 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1807 second_byte |= (ireg & 7); /* patch in our ireg */
1808 VG_(emitB) ( second_byte );
1809 if (dis)
1810 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001811 (UInt)first_byte, (UInt)second_byte,
1812 nameIReg(4,ireg) );
1813}
1814
1815static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1816 FlagSet sets_sflags,
1817 UChar first_byte,
1818 UChar second_byte,
1819 UChar third_byte )
1820{
1821 VG_(new_emit)(True, uses_sflags, sets_sflags);
1822 VG_(emitB) ( 0x0F );
1823 VG_(emitB) ( first_byte );
1824 VG_(emitB) ( second_byte );
1825 VG_(emitB) ( third_byte );
1826 if (dis)
1827 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1828 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1829}
1830
sewardj3d7c9c82003-03-26 21:08:13 +00001831static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1832 FlagSet sets_sflags,
1833 UChar first_byte,
1834 UChar second_byte )
1835{
1836 VG_(new_emit)(True, uses_sflags, sets_sflags);
1837 VG_(emitB) ( 0x0F );
1838 VG_(emitB) ( first_byte );
1839 VG_(emitB) ( second_byte );
1840 if (dis)
1841 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1842 (UInt)first_byte, (UInt)second_byte );
1843}
1844
1845static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1846 FlagSet sets_sflags,
1847 UChar first_byte )
1848{
1849 VG_(new_emit)(True, uses_sflags, sets_sflags);
1850 VG_(emitB) ( 0x0F );
1851 VG_(emitB) ( first_byte );
1852 if (dis)
1853 VG_(printf)("\n\t\tmmx1-0x%x\n",
1854 (UInt)first_byte );
1855}
1856
sewardjde4a1d02002-03-22 01:27:54 +00001857
1858/*----------------------------------------------------*/
1859/*--- misc instruction emitters ---*/
1860/*----------------------------------------------------*/
1861
njn25e49d8e72002-09-23 09:36:25 +00001862void VG_(emit_call_reg) ( Int reg )
1863{
sewardjfa492d42002-12-08 18:20:01 +00001864 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001865 VG_(emitB) ( 0xFF ); /* Grp5 */
1866 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1867 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001868 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001869}
1870
sewardjf0f12aa2002-12-28 00:04:08 +00001871static
1872void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1873 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001874{
sewardjfa492d42002-12-08 18:20:01 +00001875 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001876 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001877
1878 if (byte_off < -128 || byte_off > 127) {
1879 VG_(emitB) ( 0xFF );
1880 VG_(emitB) ( 0x95 );
1881 VG_(emitL) ( byte_off );
1882 } else {
1883 VG_(emitB) ( 0xFF );
1884 VG_(emitB) ( 0x55 );
1885 VG_(emitB) ( byte_off );
1886 }
1887 if (dis)
1888 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001889}
1890
sewardja2c5a732002-12-15 03:10:42 +00001891#if 0
1892/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001893static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1894{
1895 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001896 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001897 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1898 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001899 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001900 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001901 if (dis)
1902 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1903 nameIReg(4,regmem));
1904}
sewardja2c5a732002-12-15 03:10:42 +00001905#endif
sewardjde4a1d02002-03-22 01:27:54 +00001906
njn25e49d8e72002-09-23 09:36:25 +00001907void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001908{
njne427a662002-10-02 11:08:25 +00001909 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001910 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1911 VG_(emitB) ( 0x8D );
1912 VG_(emitB) ( 0x64 );
1913 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001914 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001915 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001916 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001917}
1918
1919
1920static void emit_movb_AL_zeroESPmem ( void )
1921{
1922 /* movb %al, 0(%esp) */
1923 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001924 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001925 VG_(emitB) ( 0x88 );
1926 VG_(emitB) ( 0x44 );
1927 VG_(emitB) ( 0x24 );
1928 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001929 if (dis)
1930 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
1931}
1932
1933static void emit_movb_zeroESPmem_AL ( void )
1934{
1935 /* movb 0(%esp), %al */
1936 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00001937 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001938 VG_(emitB) ( 0x8A );
1939 VG_(emitB) ( 0x44 );
1940 VG_(emitB) ( 0x24 );
1941 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00001942 if (dis)
1943 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
1944}
1945
sewardja2113f92002-12-12 23:42:48 +00001946/* Jump target states */
1947#define TGT_UNDEF (1 << 16)
1948#define TGT_FORWARD (2 << 16)
1949#define TGT_BACKWARD (3 << 16)
1950
1951static inline Int tgt_state(Int tgt)
1952{
1953 return tgt & 0xffff0000;
1954}
1955
1956static inline Int tgt_addr(Int tgt)
1957{
1958 return tgt & 0x0000ffff;
1959}
1960
1961static inline Int mk_tgt(Int state, Int addr)
1962{
fitzhardinge462f4f92003-12-18 02:10:54 +00001963 vg_assert(state == TGT_UNDEF ||
1964 state == TGT_FORWARD ||
1965 state == TGT_BACKWARD);
sewardja2113f92002-12-12 23:42:48 +00001966 vg_assert((addr & 0xffff0000) == 0);
1967
1968 return state | addr;
1969}
1970
1971void VG_(init_target) ( Int *tgt )
1972{
1973 *tgt = TGT_UNDEF;
1974}
1975
1976void VG_(target_back) ( Int *tgt )
1977{
1978 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
1979
1980 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
1981}
1982
1983void VG_(target_forward) ( Int *tgt )
1984{
1985 Int delta;
1986
1987 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
1988 tgt_state(*tgt) == TGT_UNDEF);
1989
1990 if (tgt_state(*tgt) == TGT_UNDEF)
1991 return; /* target not used */
1992
1993 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
1994 vg_assert(delta >= -128 && delta <= 127);
1995 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00001996 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00001997 emitted_code[tgt_addr(*tgt)] = delta;
1998 if (dis)
1999 VG_(printf)("(target to jump site %d; delta: %d)\n",
2000 tgt_addr(*tgt), delta);
2001}
2002
2003void VG_(emit_target_delta) ( Int *tgt )
2004{
2005 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
2006 tgt_state(*tgt) == TGT_BACKWARD);
2007
2008 if (tgt_state(*tgt) == TGT_UNDEF) {
2009 /* forward jump */
2010 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
2011 VG_(emitB) (0x00);
2012 } else {
2013 /* backward jump */
2014 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
2015 vg_assert(delta >= -128 && delta <= 127);
2016 VG_(emitB) (delta);
2017 }
2018}
2019
sewardjde4a1d02002-03-22 01:27:54 +00002020
2021/* Emit a jump short with an 8-bit signed offset. Note that the
2022 offset is that which should be added to %eip once %eip has been
2023 advanced over this insn. */
fitzhardinge462f4f92003-12-18 02:10:54 +00002024void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta, JumpPred pred )
sewardjde4a1d02002-03-22 01:27:54 +00002025{
2026 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00002027 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002028
2029 if (VG_(clo_branchpred) &&
2030 pred != JP_NONE &&
2031 pred != static_pred(cond, delta > 0))
2032 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2033
njn25e49d8e72002-09-23 09:36:25 +00002034 VG_(emitB) ( 0x70 + (UInt)cond );
2035 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00002036 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002037 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+%d\n",
2038 VG_(name_UCondcode)(cond), predstr(pred), delta );
sewardjde4a1d02002-03-22 01:27:54 +00002039}
2040
sewardja2113f92002-12-12 23:42:48 +00002041/* Same as above, but defers emitting the delta */
fitzhardinge462f4f92003-12-18 02:10:54 +00002042void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt, JumpPred pred )
sewardja2113f92002-12-12 23:42:48 +00002043{
sewardj706240d2002-12-26 17:10:12 +00002044 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002045
2046 if (VG_(clo_branchpred) &&
2047 pred != JP_NONE &&
2048 pred != static_pred(cond, tgt_state(*tgt) != TGT_BACKWARD))
2049 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2050
sewardja2113f92002-12-12 23:42:48 +00002051 VG_(emitB) ( 0x70 + (UInt)cond );
2052 VG_(emit_target_delta) (tgt);
2053 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002054 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+(%d)\n",
2055 VG_(name_UCondcode)(cond), predstr(pred), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00002056}
2057
2058
2059
sewardjf0f12aa2002-12-28 00:04:08 +00002060static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002061{
sewardjf0f12aa2002-12-28 00:04:08 +00002062 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002063 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
2064 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00002065 if (dis)
2066 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00002067 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00002068}
2069
2070static void emit_ret ( void )
2071{
sewardjfa492d42002-12-08 18:20:01 +00002072 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00002073 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002074 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00002075 if (dis)
2076 VG_(printf)("\n\t\tret\n");
2077}
2078
sewardj22854b92002-11-30 14:00:47 +00002079/* Predicate used in sanity checks elsewhere - returns true if any
2080 jump-site is an actual chained jump */
2081Bool VG_(is_chained_jumpsite)(Addr a)
2082{
2083 UChar *cp = (UChar *)a;
2084
2085 return (*cp == 0xE9); /* 0xE9 -- jmp */
2086}
2087
sewardj83f11862002-12-01 02:07:08 +00002088static
2089Bool is_fresh_jumpsite(UChar *cp)
2090{
2091 return
2092 cp[0] == 0x0F && /* UD2 */
2093 cp[1] == 0x0B &&
2094 cp[2] == 0x0F && /* UD2 */
2095 cp[3] == 0x0B &&
2096 cp[4] == 0x90; /* NOP */
2097}
2098
sewardj22854b92002-11-30 14:00:47 +00002099/* Predicate used in sanity checks elsewhere - returns true if all
2100 jump-sites are calls to VG_(patch_me) */
2101Bool VG_(is_unchained_jumpsite)(Addr a)
2102{
2103 UChar *cp = (UChar *)a;
2104 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2105 Int idelta;
2106
2107 if (*cp++ != 0xE8) /* 0xE8 == call */
2108 return False;
2109
2110 idelta = (*cp++) << 0;
2111 idelta |= (*cp++) << 8;
2112 idelta |= (*cp++) << 16;
2113 idelta |= (*cp++) << 24;
2114
2115 return idelta == delta;
2116}
2117
2118/* Return target address for a direct jmp */
2119Addr VG_(get_jmp_dest)(Addr a)
2120{
2121 Int delta;
2122 UChar *cp = (UChar *)a;
2123
2124 if (*cp++ != 0xE9) /* 0xE9 == jmp */
2125 return 0;
2126
2127 delta = (*cp++) << 0;
2128 delta |= (*cp++) << 8;
2129 delta |= (*cp++) << 16;
2130 delta |= (*cp++) << 24;
2131
2132 return a + VG_PATCHME_JMPSZ + delta;
2133}
2134
2135/* unchain a BB by generating a call to VG_(patch_me) */
2136void VG_(unchain_jumpsite)(Addr a)
2137{
2138 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2139 UChar *cp = (UChar *)a;
2140
2141 if (VG_(is_unchained_jumpsite)(a))
2142 return; /* don't write unnecessarily */
2143
sewardj83f11862002-12-01 02:07:08 +00002144 if (!is_fresh_jumpsite(cp))
2145 VG_(bb_dechain_count)++; /* update stats */
2146
sewardj22854b92002-11-30 14:00:47 +00002147 *cp++ = 0xE8; /* call */
2148 *cp++ = (delta >> 0) & 0xff;
2149 *cp++ = (delta >> 8) & 0xff;
2150 *cp++ = (delta >> 16) & 0xff;
2151 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002152}
2153
2154/* This doesn't actually generate a call to VG_(patch_me), but
2155 reserves enough space in the instruction stream for it to happen
2156 and records the offset into the jump table. This is because call
2157 is a relative jump, and so will be affected when this code gets
2158 moved about. The translation table will "unchain" this basic block
2159 on insertion (with VG_(unchain_BB)()), and thereby generate a
2160 proper call instruction. */
2161static void emit_call_patchme( void )
2162{
2163 vg_assert(VG_PATCHME_CALLSZ == 5);
2164
sewardjfa492d42002-12-08 18:20:01 +00002165 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002166 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002167
2168 if (jumpidx >= VG_MAX_JUMPS) {
2169 /* If there too many jumps in this basic block, fall back to
2170 dispatch loop. We still need to keep it the same size as the
2171 call sequence. */
2172 VG_(emitB) ( 0xC3 ); /* ret */
fitzhardinge98abfc72003-12-16 02:05:15 +00002173 VG_(emitB) ( 0x8d ); /* 4 byte nop (lea 0x0(%esi,1),%esi) */
2174 VG_(emitB) ( 0x74 );
2175 VG_(emitB) ( 0x26 );
2176 VG_(emitB) ( 0x00 );
sewardj22854b92002-11-30 14:00:47 +00002177
2178 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002179 VG_(printf)("\n\t\tret; nop4\n");
sewardj22854b92002-11-30 14:00:47 +00002180
2181 if (0 && VG_(clo_verbosity))
2182 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2183 } else {
2184 jumps[jumpidx++] = emitted_code_used;
2185
2186 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2187 VG_(emitB) ( 0x0B );
2188 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2189 VG_(emitB) ( 0x0B );
2190 VG_(emitB) ( 0x90 ); /* NOP */
2191
2192 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002193 VG_(printf)("\n\t\tud2; ud2; nop /* call VG_(patchme) */\n");
sewardj22854b92002-11-30 14:00:47 +00002194 }
2195}
2196
njn25e49d8e72002-09-23 09:36:25 +00002197void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002198{
sewardjf0f12aa2002-12-28 00:04:08 +00002199 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002200 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002201 if (dis)
2202 VG_(printf)("\n\t\tpushal\n");
2203}
2204
njn25e49d8e72002-09-23 09:36:25 +00002205void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002206{
sewardjf0f12aa2002-12-28 00:04:08 +00002207 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002208 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002209 if (dis)
2210 VG_(printf)("\n\t\tpopal\n");
2211}
2212
2213static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2214{
sewardjf0f12aa2002-12-28 00:04:08 +00002215 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002216 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2217 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002218 if (dis)
2219 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2220 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2221}
2222
2223static void emit_lea_sib_reg ( UInt lit, Int scale,
2224 Int regbase, Int regindex, Int reg )
2225{
sewardjf0f12aa2002-12-28 00:04:08 +00002226 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002227 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002228 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2229 if (dis)
2230 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2231 lit, nameIReg(4,regbase),
2232 nameIReg(4,regindex), scale,
2233 nameIReg(4,reg) );
2234}
2235
njn25e49d8e72002-09-23 09:36:25 +00002236void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002237{
sewardjf0f12aa2002-12-28 00:04:08 +00002238 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002239 VG_(emitB) ( 0x0F );
2240 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002241 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2242 if (dis)
2243 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2244}
2245
2246/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002247/*--- Helper offset -> addr translation ---*/
2248/*----------------------------------------------------*/
2249
2250/* Finds the baseBlock offset of a skin-specified helper.
2251 * Searches through compacts first, then non-compacts. */
2252Int VG_(helper_offset)(Addr a)
2253{
sewardj05bcdcb2003-05-18 10:05:38 +00002254 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002255 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002256
2257 for (i = 0; i < VG_(n_compact_helpers); i++)
2258 if (VG_(compact_helper_addrs)[i] == a)
2259 return VG_(compact_helper_offsets)[i];
2260 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2261 if (VG_(noncompact_helper_addrs)[i] == a)
2262 return VG_(noncompact_helper_offsets)[i];
2263
2264 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002265 VG_(get_fnname) ( a, buf, 100 );
2266
njn25e49d8e72002-09-23 09:36:25 +00002267 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002268 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2269 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002270
2271 VG_(printf)(" compact helpers: ");
2272 for (i = 0; i < VG_(n_compact_helpers); i++)
2273 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2274
2275 VG_(printf)("\n non-compact helpers: ");
2276 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2277 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2278
2279 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002280 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002281}
2282
2283/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002284/*--- Instruction synthesisers ---*/
2285/*----------------------------------------------------*/
2286
2287static Condcode invertCondition ( Condcode cond )
2288{
2289 return (Condcode)(1 ^ (UInt)cond);
2290}
2291
2292
2293/* Synthesise a call to *baseBlock[offset], ie,
2294 call * (4 x offset)(%ebp).
2295*/
sewardjfa492d42002-12-08 18:20:01 +00002296void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002297 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002298{
2299 vg_assert(word_offset >= 0);
2300 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002301 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002302 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002303 }
sewardjf0f12aa2002-12-28 00:04:08 +00002304 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002305}
2306
njn25e49d8e72002-09-23 09:36:25 +00002307static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002308{
njn25e49d8e72002-09-23 09:36:25 +00002309 if (src != dst) {
2310 VG_(emit_movv_reg_reg) ( 4, src, dst );
2311 ccall_arg_setup_instrs++;
2312 }
njn6431be72002-07-28 09:53:34 +00002313}
njn25e49d8e72002-09-23 09:36:25 +00002314
2315/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2316static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2317{
2318 if (RealReg == tag) {
2319 maybe_emit_movl_reg_reg ( litOrReg, reg );
2320 } else if (Literal == tag) {
2321 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2322 ccall_arg_setup_instrs++;
2323 }
2324 else
njne427a662002-10-02 11:08:25 +00002325 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002326}
2327
2328static
2329void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2330{
2331 if (R_EAX == reg1) {
2332 VG_(emit_swapl_reg_EAX) ( reg2 );
2333 } else if (R_EAX == reg2) {
2334 VG_(emit_swapl_reg_EAX) ( reg1 );
2335 } else {
2336 emit_swapl_reg_reg ( reg1, reg2 );
2337 }
2338 ccall_arg_setup_instrs++;
2339}
2340
2341static
2342void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2343{
2344 if (dst1 != src2) {
2345 maybe_emit_movl_reg_reg ( src1, dst1 );
2346 maybe_emit_movl_reg_reg ( src2, dst2 );
2347
2348 } else if (dst2 != src1) {
2349 maybe_emit_movl_reg_reg ( src2, dst2 );
2350 maybe_emit_movl_reg_reg ( src1, dst1 );
2351
2352 } else {
2353 /* swap to break cycle */
2354 emit_swapl_arg_regs ( dst1, dst2 );
2355 }
2356}
2357
2358static
2359void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2360 UInt dst1, UInt dst2, UInt dst3)
2361{
2362 if (dst1 != src2 && dst1 != src3) {
2363 maybe_emit_movl_reg_reg ( src1, dst1 );
2364 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2365
2366 } else if (dst2 != src1 && dst2 != src3) {
2367 maybe_emit_movl_reg_reg ( src2, dst2 );
2368 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2369
2370 } else if (dst3 != src1 && dst3 != src2) {
2371 maybe_emit_movl_reg_reg ( src3, dst3 );
2372 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2373
2374 } else {
2375 /* break cycle */
2376 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2377 emit_swapl_arg_regs ( dst1, dst2 );
2378 emit_swapl_arg_regs ( dst1, dst3 );
2379
2380 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2381 emit_swapl_arg_regs ( dst1, dst3 );
2382 emit_swapl_arg_regs ( dst1, dst2 );
2383
2384 } else {
njne427a662002-10-02 11:08:25 +00002385 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002386 }
2387 }
2388}
2389
2390static
2391void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2392 UInt src1, UInt src2,
2393 UInt dst1, UInt dst2)
2394{
2395 /* If either are lits, order doesn't matter */
2396 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2397 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2398 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2399
2400 } else {
2401 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2402 }
2403}
2404
2405static
2406void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2407 UInt src1, UInt src2, UInt src3,
2408 UInt dst1, UInt dst2, UInt dst3)
2409{
2410 // SSS: fix this eventually -- make STOREV use two RealRegs?
2411 /* Not supporting literals for 3-arg C functions -- they're only used
2412 by STOREV which has 2 args */
2413 vg_assert(RealReg == tagv[src1] &&
2414 RealReg == tagv[src2] &&
2415 RealReg == tagv[src3]);
2416 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2417 dst1, dst2, dst3 );
2418}
2419
2420/* Synthesise a call to a C function `fn' (which must be registered in
2421 baseBlock) doing all the reg saving and arg handling work.
2422
2423 WARNING: a UInstr should *not* be translated with synth_ccall followed
2424 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2425 such behaviour and everything will fall over.
2426 */
2427void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2428 Tag tagv[], Int ret_reg,
2429 RRegSet regs_live_before, RRegSet regs_live_after )
2430{
2431 Int i;
2432 Int stack_used = 0;
2433 Bool preserve_eax, preserve_ecx, preserve_edx;
2434
2435 vg_assert(0 <= regparms_n && regparms_n <= 3);
2436
2437 ccalls++;
2438
2439 /* If %e[acd]x is live before and after the C call, save/restore it.
2440 Unless the return values clobbers the reg; in this case we must not
2441 save/restore the reg, because the restore would clobber the return
2442 value. (Before and after the UInstr really constitute separate live
2443 ranges, but you miss this if you don't consider what happens during
2444 the UInstr.) */
2445# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002446 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2447 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002448 ret_reg != realReg)
2449
2450 preserve_eax = PRESERVE_REG(R_EAX);
2451 preserve_ecx = PRESERVE_REG(R_ECX);
2452 preserve_edx = PRESERVE_REG(R_EDX);
2453
2454# undef PRESERVE_REG
2455
2456 /* Save caller-save regs as required */
2457 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2458 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2459 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2460
2461 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2462 is the number of args passed in regs (maximum 3 for GCC on x86). */
2463
2464 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002465
njn25e49d8e72002-09-23 09:36:25 +00002466 /* First push stack args (RealRegs or Literals) in reverse order. */
2467 for (i = argc-1; i >= regparms_n; i--) {
2468 switch (tagv[i]) {
2469 case RealReg:
2470 VG_(emit_pushv_reg) ( 4, argv[i] );
2471 break;
2472 case Literal:
2473 /* Use short form of pushl if possible. */
2474 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2475 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2476 else
2477 VG_(emit_pushl_lit32)( argv[i] );
2478 break;
2479 default:
2480 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002481 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002482 }
2483 stack_used += 4;
2484 ccall_arg_setup_instrs++;
2485 }
njn6431be72002-07-28 09:53:34 +00002486
njn25e49d8e72002-09-23 09:36:25 +00002487 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2488 If moving values between registers, be careful not to clobber any on
2489 the way. Happily we can use xchgl to swap registers.
2490 */
2491 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002492
njn25e49d8e72002-09-23 09:36:25 +00002493 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2494 case 3:
2495 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2496 R_EAX, R_EDX, R_ECX );
2497 break;
njn6431be72002-07-28 09:53:34 +00002498
njn25e49d8e72002-09-23 09:36:25 +00002499 /* Less-tricky. Args passed in %eax and %edx. */
2500 case 2:
2501 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2502 break;
2503
2504 /* Easy. Just move arg1 into %eax (if not already in there). */
2505 case 1:
2506 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2507 break;
2508
2509 case 0:
2510 break;
2511
2512 default:
njne427a662002-10-02 11:08:25 +00002513 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002514 }
2515
sewardjfa492d42002-12-08 18:20:01 +00002516 /* Call the function - may trash all flags */
2517 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002518
2519 /* Clear any args from stack */
2520 if (0 != stack_used) {
2521 VG_(emit_add_lit_to_esp) ( stack_used );
2522 ccall_stack_clears++;
2523 }
2524
2525 /* Move return value into ret_reg if necessary and not already there */
2526 if (INVALID_REALREG != ret_reg) {
2527 ccall_retvals++;
2528 if (R_EAX != ret_reg) {
2529 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2530 ccall_retval_movs++;
2531 }
2532 }
2533
2534 /* Restore live caller-save regs as required */
2535 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2536 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2537 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002538}
sewardjde4a1d02002-03-22 01:27:54 +00002539
sewardj2e93c502002-04-12 11:12:52 +00002540static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002541{
sewardj2e93c502002-04-12 11:12:52 +00002542 switch (jmpkind) {
2543 case JmpBoring:
2544 break;
sewardj2e93c502002-04-12 11:12:52 +00002545 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002546 break;
2547 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002548 break;
2549 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002550 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002551 break;
2552 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002553 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002554 break;
fitzhardingea02f8812003-12-18 09:06:09 +00002555 case JmpYield:
2556 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_YIELD, R_EBP );
2557 break;
sewardj2e93c502002-04-12 11:12:52 +00002558 default:
njne427a662002-10-02 11:08:25 +00002559 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002560 }
2561}
2562
2563/* Jump to the next translation, by loading its original addr into
2564 %eax and returning to the scheduler. Signal special requirements
2565 by loading a special value into %ebp first.
2566*/
2567static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2568{
sewardjfa492d42002-12-08 18:20:01 +00002569 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002570 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002571 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002572 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002573 emit_ret();
2574}
2575
sewardj22854b92002-11-30 14:00:47 +00002576static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002577
2578/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002579static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002580{
sewardjfa492d42002-12-08 18:20:01 +00002581 maybe_emit_put_eflags(); /* save flags here */
2582
njn25e49d8e72002-09-23 09:36:25 +00002583 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002584
2585 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2586 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2587 emit_call_patchme();
2588 } else {
2589 load_ebp_from_JmpKind ( jmpkind );
2590 emit_ret();
2591 }
sewardjde4a1d02002-03-22 01:27:54 +00002592}
2593
2594
sewardj2370f3b2002-11-30 15:01:01 +00002595static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002596static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002597 Opcode opcode, Int size,
2598 UInt lit, Int reg );
2599
sewardjfa492d42002-12-08 18:20:01 +00002600static void synth_jcond_lit ( Condcode cond,
2601 Addr addr,
2602 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002603{
sewardj2370f3b2002-11-30 15:01:01 +00002604 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002605 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002606 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002607
sewardja2113f92002-12-12 23:42:48 +00002608 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002609 VG_(init_target)(&tgt2);
2610 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002611
sewardjfa492d42002-12-08 18:20:01 +00002612 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2613 if need be */
2614 maybe_emit_put_eflags();
2615 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2616
2617 if (eflags_state == UPD_Both) {
2618 /* The flags are already set up, so we just use them as is. */
2619 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002620 cond = invertCondition(cond);
2621 } else {
sewardj75f04932002-12-12 23:13:21 +00002622 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002623
2624 /* The simd state contains the most recent version, so we emit a
2625 sequence to calculate the relevant condition directly out of
2626 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2627 copying them back to the real flags via popf. Notice that
2628 some of these sequences trash %eax, but that should be free
2629 now since this is the end of a bb and therefore all regs are
2630 dead. */
2631 simd = False;
2632
2633 switch (cond) {
2634
sewardjbb6c1182002-12-12 23:54:47 +00002635 case CondLE: /* Z || S != O -> S || !P */
2636 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002637 vg_assert(eax_trashable);
2638
2639 VG_(emit_movv_offregmem_reg)
2640 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2641 /* eax == %EFLAGS */
2642
sewardjbb6c1182002-12-12 23:54:47 +00002643 VG_(emit_nonshiftopv_lit_reg)
2644 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2645 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002646
sewardjbb6c1182002-12-12 23:54:47 +00002647 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2648 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002649
sewardj09736622002-12-28 00:19:00 +00002650 /* actually set the real cpu flags, since ROR changes
2651 neither P nor Z */
2652 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2653
sewardjbb6c1182002-12-12 23:54:47 +00002654 if (cond == CondLE) {
2655 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002656 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002657 /* test OF != SF */
2658 cond = CondP;
2659 } else {
2660 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002661 VG_(emit_jcondshort_target)(False, CondS, &tgt2, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002662 /* test OF == SF */
2663 cond = CondNP;
2664 }
sewardj2370f3b2002-11-30 15:01:01 +00002665 break;
2666
sewardjfa492d42002-12-08 18:20:01 +00002667 case CondL:
2668 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002669 vg_assert(eax_trashable);
2670
2671 VG_(emit_movv_offregmem_reg)
2672 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2673 /* eax == %EFLAGS */
2674
sewardj75f04932002-12-12 23:13:21 +00002675 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2676 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002677
sewardj75f04932002-12-12 23:13:21 +00002678 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2679 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002680
sewardj09736622002-12-28 00:19:00 +00002681 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002682 if (cond == CondL) cond = CondP; else cond = CondNP;
2683 break;
sewardjfa492d42002-12-08 18:20:01 +00002684
2685 case CondB:
2686 case CondNB:
2687 mask = EFlagC; goto simple; /* C=1 */
2688
2689 case CondZ:
2690 case CondNZ:
2691 mask = EFlagZ; goto simple; /* Z=1 */
2692
2693 case CondBE:
2694 case CondNBE:
2695 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2696
2697 case CondS:
2698 case CondNS:
2699 mask = EFlagS; goto simple; /* S=1 */
2700
2701 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002702 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002703 mask = EFlagP; goto simple; /* P=1 */
2704
sewardj39542072002-12-09 22:44:00 +00002705 case CondO:
2706 case CondNO:
2707 mask = EFlagO; goto simple; /* O=1 */
2708
sewardjfa492d42002-12-08 18:20:01 +00002709 default:
2710 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002711 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002712 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2713
2714 simple:
2715 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002716 if ((mask & 0xff) == mask) {
2717 VG_(emitB) ( 0xF6 ); /* Grp3 */
2718 VG_(emit_amode_offregmem_reg)(
2719 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2720 VG_(emitB) (mask);
2721 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002722 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002723 mask, VGOFF_(m_eflags) * 4);
2724 } else {
sewardjfa492d42002-12-08 18:20:01 +00002725 /* all cond codes are in lower 16 bits */
2726 vg_assert((mask & 0xffff) == mask);
2727
2728 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002729 VG_(emitB) ( 0xF7 );
2730 VG_(emit_amode_offregmem_reg)(
2731 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002732 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002733 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002734 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002735 mask, VGOFF_(m_eflags) * 4);
2736 }
2737
sewardj75f04932002-12-12 23:13:21 +00002738 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002739 break;
2740 }
2741 }
2742
fitzhardinge462f4f92003-12-18 02:10:54 +00002743 VG_(emit_jcondshort_target) ( simd, cond, &tgt, JP_NONE );
sewardjbb6c1182002-12-12 23:54:47 +00002744
2745 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002746 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002747
2748 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002749 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002750}
2751
2752
sewardj2370f3b2002-11-30 15:01:01 +00002753
sewardjde4a1d02002-03-22 01:27:54 +00002754static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2755{
sewardja2113f92002-12-12 23:42:48 +00002756 Int tgt;
2757
2758 VG_(init_target)(&tgt);
2759
sewardjfa492d42002-12-08 18:20:01 +00002760 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002761
fitzhardinge462f4f92003-12-18 02:10:54 +00002762 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt, JP_NONE );
sewardj2e93c502002-04-12 11:12:52 +00002763 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002764
2765 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002766}
2767
2768
2769static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2770{
2771 /* Load the zero-extended literal into reg, at size l,
2772 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002773 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002774}
2775
2776
2777static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2778{
fitzhardinge98abfc72003-12-16 02:05:15 +00002779 switch (size & ~DO_BOUNDSCHECK) {
2780 case 4: emit_movv_regmem_reg ( size, reg1, reg2 ); break;
2781 case 2: VG_(emit_movzwl_regmem_reg) ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
2782 case 1: emit_movzbl_regmem_reg ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002783 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002784 }
2785}
2786
2787
2788static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2789{
fitzhardinge98abfc72003-12-16 02:05:15 +00002790 switch (size & ~DO_BOUNDSCHECK) {
njn25e49d8e72002-09-23 09:36:25 +00002791 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
fitzhardinge98abfc72003-12-16 02:05:15 +00002792 case 2: VG_(emit_movzwl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
2793 case 1: VG_(emit_movzbl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002794 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002795 }
2796}
2797
2798
2799static void synth_mov_reg_offregmem ( Int size, Int reg,
2800 Int off, Int areg )
2801{
2802 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002803 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2804 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002805 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002806 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002807 }
2808 else {
njn25e49d8e72002-09-23 09:36:25 +00002809 VG_(emit_swapl_reg_EAX) ( reg );
2810 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2811 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002812 }
2813 break;
njne427a662002-10-02 11:08:25 +00002814 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002815 }
2816}
2817
2818
2819static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2820{
2821 Int s1;
fitzhardinge98abfc72003-12-16 02:05:15 +00002822 switch (size & ~DO_BOUNDSCHECK) {
2823 case 4:
2824 case 2: emit_movv_reg_regmem ( size, reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002825 case 1: if (reg1 < 4) {
fitzhardinge98abfc72003-12-16 02:05:15 +00002826 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002827 }
2828 else {
2829 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2830 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2831 emit_swapl_reg_reg ( s1, reg1 );
fitzhardinge98abfc72003-12-16 02:05:15 +00002832 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, s1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002833 emit_swapl_reg_reg ( s1, reg1 );
2834 }
2835 break;
njne427a662002-10-02 11:08:25 +00002836 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002837 }
2838}
2839
2840
sewardjf0f12aa2002-12-28 00:04:08 +00002841static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002842 Opcode opcode, Int size,
2843 Int reg )
2844{
2845 /* NB! opcode is a uinstr opcode, not an x86 one! */
2846 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002847 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002848 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002849 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002850 break;
2851 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002852 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002853 } else {
njn25e49d8e72002-09-23 09:36:25 +00002854 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002855 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002856 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002857 }
2858 break;
njne427a662002-10-02 11:08:25 +00002859 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002860 }
2861}
2862
2863
2864
sewardjf0f12aa2002-12-28 00:04:08 +00002865static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002866 Opcode opcode, Int size,
2867 Int reg1, Int reg2 )
2868{
2869 /* NB! opcode is a uinstr opcode, not an x86 one! */
2870 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002871 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002872 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002873 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002874 break;
2875 case 1: { /* Horrible ... */
2876 Int s1, s2;
2877 /* Choose s1 and s2 to be x86 regs which we can talk about the
2878 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2879 sure s1 != s2 and that neither of them equal either reg1 or
2880 reg2. Then use them as temporaries to make things work. */
2881 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002882 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002883 break;
2884 }
2885 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2886 if (reg1 >= 4 && reg2 < 4) {
2887 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002888 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002889 emit_swapl_reg_reg ( reg1, s1 );
2890 break;
2891 }
2892 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2893 if (reg1 < 4 && reg2 >= 4) {
2894 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002895 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002896 emit_swapl_reg_reg ( reg2, s2 );
2897 break;
2898 }
2899 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2900 emit_swapl_reg_reg ( reg1, s1 );
2901 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002902 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002903 emit_swapl_reg_reg ( reg1, s1 );
2904 emit_swapl_reg_reg ( reg2, s2 );
2905 break;
2906 }
2907 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2908 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002909 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002910 emit_swapl_reg_reg ( reg1, s1 );
2911 break;
2912 }
njne427a662002-10-02 11:08:25 +00002913 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002914 }
njne427a662002-10-02 11:08:25 +00002915 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002916 }
2917}
2918
sewardja2c5a732002-12-15 03:10:42 +00002919#if 0
2920/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002921static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002922 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002923 Opcode opcode, Int size,
2924 Int off, Int areg, Int reg )
2925{
2926 switch (size) {
2927 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002928 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002929 break;
2930 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002931 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002932 break;
2933 case 1:
2934 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002935 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00002936 } else {
2937 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002938 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00002939 VG_(emit_swapl_reg_EAX) ( reg );
2940 }
2941 break;
2942 default:
2943 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
2944 }
2945}
sewardja2c5a732002-12-15 03:10:42 +00002946#endif
sewardjfa492d42002-12-08 18:20:01 +00002947
sewardjde4a1d02002-03-22 01:27:54 +00002948static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00002949 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002950 Opcode opcode, Int size,
2951 Int off, Int areg, Int reg )
2952{
2953 switch (size) {
2954 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00002955 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002956 break;
2957 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00002958 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002959 break;
2960 case 1:
2961 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002962 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002963 } else {
njn25e49d8e72002-09-23 09:36:25 +00002964 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002965 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002966 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002967 }
2968 break;
2969 default:
njne427a662002-10-02 11:08:25 +00002970 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002971 }
2972}
2973
2974
sewardjf0f12aa2002-12-28 00:04:08 +00002975static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002976 Opcode opcode, Int size,
2977 UInt lit, Int reg )
2978{
2979 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002980 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002981 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002982 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002983 break;
2984 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002985 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002986 } else {
njn25e49d8e72002-09-23 09:36:25 +00002987 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002988 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002989 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002990 }
2991 break;
njne427a662002-10-02 11:08:25 +00002992 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002993 }
2994}
2995
sewardjf0f12aa2002-12-28 00:04:08 +00002996static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002997 Opcode opcode, Int size,
2998 UInt lit, Int off, Int regmem )
2999{
3000 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003001 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003002 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003003 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003004 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003005 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003006 break;
3007 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
3008 }
3009}
3010
sewardjde4a1d02002-03-22 01:27:54 +00003011
jsgf5efa4fd2003-10-14 21:49:11 +00003012static void synth_mul_reg_reg ( Bool upd_cc,
3013 Opcode opcode, Int size,
3014 Int reg1, Int reg2 )
3015{
3016 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3017
3018 switch (size) {
3019 case 2:
3020 VG_(emitB)(0x66);
3021 /* FALLTHROUGH */
3022 case 4:
3023 VG_(emitB)(0x0F);
3024 VG_(emitB)(0xAF);
3025 VG_(emit_amode_ereg_greg)(reg1, reg2);
3026 break;
3027
3028 case 1:
3029 VG_(core_panic)("can't do byte mul");
3030 break;
3031 }
3032 if (dis)
3033 VG_(printf)("\n\t\timul%c\t%s, %s\n",
3034 nameISize(size),
3035 nameIReg(size, reg1),
3036 nameIReg(size, reg2));
3037}
3038
3039static void synth_mul_lit_reg ( Bool upd_cc,
3040 Opcode opcode, Int size,
3041 UInt lit, Int reg )
3042{
3043 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3044
3045 switch (size) {
3046 case 2:
3047 VG_(emitB)(0x66);
3048 /* FALLTHROUGH */
3049 case 4:
3050 VG_(emitB)(0x69);
3051 VG_(emit_amode_ereg_greg)(reg, 0);
3052 if (size == 2)
3053 VG_(emitW)(lit);
3054 else
3055 VG_(emitL)(lit);
3056 break;
3057
3058 case 1:
3059 VG_(core_panic)("can't do byte mul");
3060 break;
3061 }
3062 if (dis)
3063 VG_(printf)("\n\t\timul%c\t%d, %s\n",
3064 nameISize(size),
3065 lit,
3066 nameIReg(size, reg));
3067}
3068
3069static void synth_mul_offregmem_reg (
3070 Bool upd_cc,
3071 Opcode opcode, Int size,
3072 Int off, Int areg, Int reg )
3073{
3074 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3075
3076 switch(size) {
3077 case 2:
3078 VG_(emitB)(0x66);
3079 /* FALLTHROUGH */
3080 case 4:
3081 VG_(emitB)(0x0F);
3082 VG_(emitB)(0xAF);
3083 VG_(emit_amode_offregmem_reg)(off, areg, reg);
3084 break;
3085
3086 case 1:
3087 VG_(core_panic)("can't do byte mul");
3088 }
3089
3090 if (dis)
3091 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
3092 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
3093
3094}
3095
3096
sewardjde4a1d02002-03-22 01:27:54 +00003097static void synth_push_reg ( Int size, Int reg )
3098{
3099 switch (size) {
3100 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003101 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003102 break;
3103 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003104 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003105 break;
3106 /* Pray that we don't have to generate this really cruddy bit of
3107 code very often. Could do better, but can I be bothered? */
3108 case 1:
3109 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003110 VG_(emit_add_lit_to_esp)(-1);
3111 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003112 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00003113 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003114 break;
3115 default:
njne427a662002-10-02 11:08:25 +00003116 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003117 }
3118}
3119
3120
3121static void synth_pop_reg ( Int size, Int reg )
3122{
3123 switch (size) {
3124 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003125 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003126 break;
3127 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003128 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003129 break;
3130 case 1:
3131 /* Same comment as above applies. */
3132 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003133 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003134 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003135 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3136 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003137 break;
njne427a662002-10-02 11:08:25 +00003138 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003139 }
3140}
3141
3142
sewardjf0f12aa2002-12-28 00:04:08 +00003143static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003144 Opcode opcode, Int size,
3145 Int regs, Int regd )
3146{
3147 synth_push_reg ( size, regd );
3148 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003149 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003150 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3151 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3152 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003153 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003154 }
sewardjde4a1d02002-03-22 01:27:54 +00003155 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3156 synth_pop_reg ( size, regd );
3157}
3158
3159
sewardjf0f12aa2002-12-28 00:04:08 +00003160static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003161 Opcode opcode, Int size,
3162 UInt lit, Int reg )
3163{
3164 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003165 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003166 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003167 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003168 break;
3169 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003170 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003171 } else {
njn25e49d8e72002-09-23 09:36:25 +00003172 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003173 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003174 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003175 }
3176 break;
njne427a662002-10-02 11:08:25 +00003177 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003178 }
3179}
3180
3181
sewardjf0f12aa2002-12-28 00:04:08 +00003182static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003183{
sewardjde4a1d02002-03-22 01:27:54 +00003184 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003185 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003186 } else {
njn25e49d8e72002-09-23 09:36:25 +00003187 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003188 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003189 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003190 }
3191}
3192
3193
sewardj3d7c9c82003-03-26 21:08:13 +00003194static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3195 UChar first_byte,
3196 UChar second_byte,
3197 Int ireg )
3198{
3199 emit_MMX2_regmem ( uses_flags, sets_flags,
3200 first_byte, second_byte, ireg );
3201}
3202
3203
sewardjca860012003-03-27 23:52:58 +00003204static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3205 UChar first_byte,
3206 UChar second_byte,
3207 Int ireg )
3208{
3209 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3210 first_byte, second_byte, ireg );
3211}
3212
sewardjd1c9e432003-04-04 20:40:34 +00003213static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3214 UChar first_byte,
3215 UChar second_byte,
3216 Int ireg )
3217{
3218 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3219 first_byte, second_byte, ireg );
3220}
3221
sewardj3d7c9c82003-03-26 21:08:13 +00003222static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3223 UChar first_byte,
3224 UChar second_byte )
3225{
3226 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3227}
3228
3229
sewardjca860012003-03-27 23:52:58 +00003230static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3231 UChar first_byte,
3232 UChar second_byte,
3233 UChar third_byte )
3234{
3235 emit_MMX3_no_mem ( uses_flags, sets_flags,
3236 first_byte, second_byte, third_byte );
3237}
3238
3239
sewardj3d7c9c82003-03-26 21:08:13 +00003240static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3241 UChar first_byte )
3242{
3243 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3244}
3245
3246
sewardjfa492d42002-12-08 18:20:01 +00003247static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3248 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003249 UChar second_byte_masked,
3250 Int reg )
3251{
sewardj3d7c9c82003-03-26 21:08:13 +00003252 emit_fpu_regmem ( uses_flags, sets_flags,
3253 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003254}
3255
3256
sewardjfa492d42002-12-08 18:20:01 +00003257static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3258 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003259 UChar second_byte )
3260{
sewardjfa492d42002-12-08 18:20:01 +00003261 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003262}
3263
3264
3265static void synth_movl_reg_reg ( Int src, Int dst )
3266{
3267 emit_movl_reg_reg ( src, dst );
3268}
3269
3270static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3271{
sewardja2113f92002-12-12 23:42:48 +00003272 Int tgt;
3273
3274 VG_(init_target)(&tgt);
3275
fitzhardinge462f4f92003-12-18 02:10:54 +00003276 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt, JP_NONE);
sewardjde4a1d02002-03-22 01:27:54 +00003277 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003278
3279 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003280}
3281
3282
sewardjde4a1d02002-03-22 01:27:54 +00003283/*----------------------------------------------------*/
3284/*--- Top level of the uinstr -> x86 translation. ---*/
3285/*----------------------------------------------------*/
3286
3287/* Return the byte offset from %ebp (ie, into baseBlock)
3288 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003289static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3290{
3291 if (tag == SpillNo) {
3292 vg_assert(size == 4);
3293 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3294 return 4 * (value + VGOFF_(spillslots));
3295 }
3296 if (tag == ArchReg) {
3297 switch (value) {
3298 case R_EAX: return 4 * VGOFF_(m_eax);
3299 case R_ECX: return 4 * VGOFF_(m_ecx);
3300 case R_EDX: return 4 * VGOFF_(m_edx);
3301 case R_EBX: return 4 * VGOFF_(m_ebx);
3302 case R_ESP:
3303 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3304 else return 4 * VGOFF_(m_esp);
3305 case R_EBP:
3306 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3307 else return 4 * VGOFF_(m_ebp);
3308 case R_ESI:
3309 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3310 else return 4 * VGOFF_(m_esi);
3311 case R_EDI:
3312 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3313 else return 4 * VGOFF_(m_edi);
3314 }
3315 }
njne427a662002-10-02 11:08:25 +00003316 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003317}
3318
sewardjde4a1d02002-03-22 01:27:54 +00003319static Int eflagsOffset ( void )
3320{
3321 return 4 * VGOFF_(m_eflags);
3322}
3323
sewardje1042472002-09-30 12:33:11 +00003324static Int segRegOffset ( UInt archregs )
3325{
3326 switch (archregs) {
3327 case R_CS: return 4 * VGOFF_(m_cs);
3328 case R_SS: return 4 * VGOFF_(m_ss);
3329 case R_DS: return 4 * VGOFF_(m_ds);
3330 case R_ES: return 4 * VGOFF_(m_es);
3331 case R_FS: return 4 * VGOFF_(m_fs);
3332 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003333 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003334 }
3335}
3336
njnf4ce3d32003-02-10 10:17:26 +00003337UInt VG_(get_archreg) ( UInt arch )
3338{
3339 switch (arch) {
3340 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3341 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3342 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3343 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3344 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3345 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3346 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3347 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003348 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003349 }
3350}
3351
3352UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3353{
3354 ThreadState* tst;
3355
3356 vg_assert(VG_(is_valid_tid)(tid));
3357 tst = & VG_(threads)[tid];
3358
3359 switch (arch) {
3360 case R_EAX: return tst->m_eax;
3361 case R_ECX: return tst->m_ecx;
3362 case R_EDX: return tst->m_edx;
3363 case R_EBX: return tst->m_ebx;
3364 case R_ESP: return tst->m_esp;
3365 case R_EBP: return tst->m_ebp;
3366 case R_ESI: return tst->m_esi;
3367 case R_EDI: return tst->m_edi;
3368 default: VG_(core_panic)( "get_thread_archreg");
3369 }
3370}
3371
njnb93d1782003-02-03 12:03:22 +00003372/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003373static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003374{
3375 switch (arch) {
3376 case R_EAX: return VGOFF_(sh_eax);
3377 case R_ECX: return VGOFF_(sh_ecx);
3378 case R_EDX: return VGOFF_(sh_edx);
3379 case R_EBX: return VGOFF_(sh_ebx);
3380 case R_ESP: return VGOFF_(sh_esp);
3381 case R_EBP: return VGOFF_(sh_ebp);
3382 case R_ESI: return VGOFF_(sh_esi);
3383 case R_EDI: return VGOFF_(sh_edi);
3384 default: VG_(core_panic)( "shadow_reg_index");
3385 }
3386}
sewardjde4a1d02002-03-22 01:27:54 +00003387
njn25e49d8e72002-09-23 09:36:25 +00003388/* Return the byte offset from %ebp (ie, into baseBlock)
3389 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003390Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003391{
njnb93d1782003-02-03 12:03:22 +00003392 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003393}
3394
njn4ba5a792002-09-30 10:23:54 +00003395Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003396{
3397 return 4 * VGOFF_(sh_eflags);
3398}
3399
njnb93d1782003-02-03 12:03:22 +00003400/* Accessing shadow arch. registers */
3401UInt VG_(get_shadow_archreg) ( UInt archreg )
3402{
3403 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3404}
3405
3406void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3407{
3408 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3409}
3410
njnd3040452003-05-19 15:04:06 +00003411void VG_(set_shadow_eflags) ( UInt val )
3412{
3413 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3414}
3415
njnf4ce3d32003-02-10 10:17:26 +00003416UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3417{
3418 ThreadState* tst;
3419
3420 vg_assert(VG_(is_valid_tid)(tid));
3421 tst = & VG_(threads)[tid];
3422
3423 switch (archreg) {
3424 case R_EAX: return tst->sh_eax;
3425 case R_ECX: return tst->sh_ecx;
3426 case R_EDX: return tst->sh_edx;
3427 case R_EBX: return tst->sh_ebx;
3428 case R_ESP: return tst->sh_esp;
3429 case R_EBP: return tst->sh_ebp;
3430 case R_ESI: return tst->sh_esi;
3431 case R_EDI: return tst->sh_edi;
3432 default: VG_(core_panic)( "get_thread_shadow_archreg");
3433 }
3434}
3435
3436void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3437{
3438 ThreadState* tst;
3439
3440 vg_assert(VG_(is_valid_tid)(tid));
3441 tst = & VG_(threads)[tid];
3442
3443 switch (archreg) {
3444 case R_EAX: tst->sh_eax = val; break;
3445 case R_ECX: tst->sh_ecx = val; break;
3446 case R_EDX: tst->sh_edx = val; break;
3447 case R_EBX: tst->sh_ebx = val; break;
3448 case R_ESP: tst->sh_esp = val; break;
3449 case R_EBP: tst->sh_ebp = val; break;
3450 case R_ESI: tst->sh_esi = val; break;
3451 case R_EDI: tst->sh_edi = val; break;
3452 default: VG_(core_panic)( "set_thread_shadow_archreg");
3453 }
3454}
3455
njnb93d1782003-02-03 12:03:22 +00003456Addr VG_(shadow_archreg_address) ( UInt archreg )
3457{
3458 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3459}
sewardjde4a1d02002-03-22 01:27:54 +00003460
sewardjde4a1d02002-03-22 01:27:54 +00003461static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3462{
3463 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003464 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3465 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003466 }
3467 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003468 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3469 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003470 }
3471 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003472 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3473 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003474 }
3475 else
njne427a662002-10-02 11:08:25 +00003476 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003477}
3478
3479
sewardjde4a1d02002-03-22 01:27:54 +00003480/*----------------------------------------------------*/
3481/*--- Generate code for a single UInstr. ---*/
3482/*----------------------------------------------------*/
3483
sewardj478335c2002-10-05 02:44:47 +00003484static __inline__
3485Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003486{
3487 return (u->flags_w != FlagsEmpty);
3488}
3489
sewardjfa492d42002-12-08 18:20:01 +00003490static __inline__
3491Bool readFlagUse ( UInstr* u )
3492{
3493 /* If the UInstr writes some flags but not all, then we still need
3494 to consider it as reading flags so that the unchanged values are
3495 passed through properly. (D is special) */
3496 return
3497 (u->flags_r != FlagsEmpty) ||
3498 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3499}
3500
sewardj478335c2002-10-05 02:44:47 +00003501static __inline__
3502Bool anyFlagUse ( UInstr* u )
3503{
sewardjfa492d42002-12-08 18:20:01 +00003504 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003505}
3506
3507
sewardjb91ae7f2003-04-29 23:50:00 +00003508/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3509 the real machine's cpu. If so we need to be very careful not to trash it.
3510 If FPU/SSE state is live and we deem it necessary to copy it back to
3511 the simulated machine's FPU/SSE state, we do so. The final state of
3512 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003513 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003514 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003515*/
sewardjb5ff83e2002-12-01 19:40:49 +00003516static void emitUInstr ( UCodeBlock* cb, Int i,
3517 RRegSet regs_live_before,
3518 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003519 Bool* sselive, /* True<==>FPU/SSE
3520 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003521 Addr* orig_eip, /* previous curr_eip, or zero */
3522 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003523{
njn25e49d8e72002-09-23 09:36:25 +00003524 Int old_emitted_code_used;
3525 UInstr* u = &cb->instrs[i];
3526
sewardjde4a1d02002-03-22 01:27:54 +00003527 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003528 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003529
njn25e49d8e72002-09-23 09:36:25 +00003530 old_emitted_code_used = emitted_code_used;
3531
sewardjde4a1d02002-03-22 01:27:54 +00003532 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003533 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003534
sewardjb5ff83e2002-12-01 19:40:49 +00003535 case INCEIP:
3536 /* Advance %EIP some small amount. */
3537 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003538
sewardjb5ff83e2002-12-01 19:40:49 +00003539 if (*orig_eip == 0 /* we don't know what the old value was */
3540 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3541 /* We have to update all 32 bits of the value. */
3542 VG_(emit_movv_lit_offregmem)(
3543 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3544 } else {
3545 /* Cool! we only need to update lowest 8 bits */
3546 VG_(emit_movb_lit_offregmem)(
3547 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003548 }
njn25e49d8e72002-09-23 09:36:25 +00003549
sewardjb5ff83e2002-12-01 19:40:49 +00003550 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003551 break;
sewardjde4a1d02002-03-22 01:27:54 +00003552
3553 case LEA1: {
3554 vg_assert(u->tag1 == RealReg);
3555 vg_assert(u->tag2 == RealReg);
3556 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3557 break;
3558 }
3559
3560 case LEA2: {
3561 vg_assert(u->tag1 == RealReg);
3562 vg_assert(u->tag2 == RealReg);
3563 vg_assert(u->tag3 == RealReg);
3564 emit_lea_sib_reg ( u->lit32, u->extra4b,
3565 u->val1, u->val2, u->val3 );
3566 break;
3567 }
3568
3569 case WIDEN: {
3570 vg_assert(u->tag1 == RealReg);
3571 if (u->signed_widen) {
3572 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3573 } else {
3574 /* no need to generate any code. */
3575 }
3576 break;
3577 }
3578
sewardjde4a1d02002-03-22 01:27:54 +00003579 case STORE: {
3580 vg_assert(u->tag1 == RealReg);
3581 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003582 synth_mov_reg_memreg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003583 break;
3584 }
3585
3586 case LOAD: {
3587 vg_assert(u->tag1 == RealReg);
3588 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003589 synth_mov_regmem_reg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003590 break;
3591 }
3592
sewardjde4a1d02002-03-22 01:27:54 +00003593 case GET: {
3594 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3595 vg_assert(u->tag2 == RealReg);
3596 synth_mov_offregmem_reg (
3597 u->size,
3598 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3599 R_EBP,
3600 u->val2
3601 );
3602 break;
3603 }
3604
3605 case PUT: {
3606 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3607 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003608 synth_mov_reg_offregmem (
3609 u->size,
3610 u->val1,
3611 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3612 R_EBP
3613 );
sewardjde4a1d02002-03-22 01:27:54 +00003614 break;
3615 }
3616
sewardje1042472002-09-30 12:33:11 +00003617 case GETSEG: {
3618 vg_assert(u->tag1 == ArchRegS);
3619 vg_assert(u->tag2 == RealReg);
3620 vg_assert(u->size == 2);
3621 synth_mov_offregmem_reg (
3622 4,
3623 segRegOffset( u->val1 ),
3624 R_EBP,
3625 u->val2
3626 );
3627 break;
3628 }
3629
3630 case PUTSEG: {
3631 vg_assert(u->tag1 == RealReg);
3632 vg_assert(u->tag2 == ArchRegS);
3633 vg_assert(u->size == 2);
3634 synth_mov_reg_offregmem (
3635 4,
3636 u->val1,
3637 segRegOffset( u->val2 ),
3638 R_EBP
3639 );
3640 break;
3641 }
3642
sewardjde4a1d02002-03-22 01:27:54 +00003643 case GETF: {
3644 vg_assert(u->size == 2 || u->size == 4);
3645 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003646
3647 /* This complexity is because the D(irection) flag is stored
3648 separately from the rest of EFLAGS. */
3649
3650 /* We're only fetching from the Simd state, so make sure it's
3651 up to date. */
3652 maybe_emit_put_eflags();
3653
3654 /* get D in u->val1 (== 1 or -1) */
3655 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3656
3657 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3658 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3659
3660 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3661 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3662 eflagsOffset(), R_EBP);
3663
3664 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3665 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3666 eflagsOffset(), R_EBP);
3667
3668 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3669 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3670 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003671 break;
3672 }
3673
3674 case PUTF: {
3675 vg_assert(u->size == 2 || u->size == 4);
3676 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003677
3678 /* When putting a value into EFLAGS, this generates the
3679 correct value for m_dflag (-1 or 1), and clears the D bit
3680 in EFLAGS. */
3681
3682 /* We're updating the whole flag state, so the old state
3683 doesn't matter; make sure that the new simulated state
3684 will be fetched when needed. */
3685 eflags_state = UPD_Simd;
3686
3687 /* store EFLAGS (with D) */
3688 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3689
3690 /* u->val1 &= EFlagD */
3691 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3692
3693 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3694 synth_unaryop_reg(False, NEG, u->size, u->val1);
3695 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3696 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3697
3698 /* save D */
3699 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3700
3701 /* EFLAGS &= ~EFlagD */
3702 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3703 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003704 break;
3705 }
3706
3707 case MOV: {
3708 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3709 vg_assert(u->tag2 == RealReg);
3710 switch (u->tag1) {
3711 case RealReg: vg_assert(u->size == 4);
3712 if (u->val1 != u->val2)
3713 synth_movl_reg_reg ( u->val1, u->val2 );
3714 break;
3715 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3716 break;
njne427a662002-10-02 11:08:25 +00003717 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003718 }
3719 break;
3720 }
3721
sewardje1042472002-09-30 12:33:11 +00003722 case USESEG: {
3723 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3724 ones. */
sewardjd077f532002-09-30 21:52:50 +00003725 UInt argv[] = { u->val1, u->val2 };
3726 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003727 UInt ret_reg = u->val2;
3728
3729 vg_assert(u->tag1 == RealReg);
3730 vg_assert(u->tag2 == RealReg);
3731 vg_assert(u->size == 0);
3732
sewardjb91ae7f2003-04-29 23:50:00 +00003733 if (*sselive) {
3734 emit_put_sse_state();
3735 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003736 }
3737
sewardje1042472002-09-30 12:33:11 +00003738 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3739 2, /* args */
3740 0, /* regparms_n */
3741 argv, tagv,
3742 ret_reg, regs_live_before, u->regs_live_after );
3743 break;
3744 }
3745
jsgf5efa4fd2003-10-14 21:49:11 +00003746 case MUL: {
3747 vg_assert(u->tag2 == RealReg);
3748
3749 switch(u->tag1) {
3750 case Literal:
3751 synth_mul_lit_reg(anyFlagUse(u),
3752 u->opcode, u->size, u->lit32, u->val2);
3753 break;
3754 case RealReg:
3755 synth_mul_reg_reg(anyFlagUse(u),
3756 u->opcode, u->size, u->val1, u->val2);
3757 break;
3758 case ArchReg:
3759 synth_mul_offregmem_reg(anyFlagUse(u),
3760 u->opcode, u->size,
3761 spillOrArchOffset(u->size, u->tag1, u->val1),
3762 R_EBP, u->val2);
3763 break;
3764
3765 default: VG_(core_panic)("emitUInstr:MUL");
3766 }
3767 break;
3768 }
3769
sewardj478335c2002-10-05 02:44:47 +00003770 case SBB:
3771 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003772 case XOR:
3773 case OR:
3774 case AND:
3775 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003776 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003777 vg_assert(u->tag2 == RealReg);
3778 switch (u->tag1) {
3779 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003780 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003781 u->opcode, u->size, u->lit32, u->val2 );
3782 break;
3783 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003784 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003785 u->opcode, u->size, u->val1, u->val2 );
3786 break;
3787 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003788 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003789 u->opcode, u->size,
3790 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3791 R_EBP,
3792 u->val2 );
3793 break;
njne427a662002-10-02 11:08:25 +00003794 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003795 }
3796 break;
3797 }
3798
sewardj478335c2002-10-05 02:44:47 +00003799 case RCR:
3800 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003801 case ROR:
3802 case ROL:
3803 case SAR:
3804 case SHR:
3805 case SHL: {
3806 vg_assert(u->tag2 == RealReg);
3807 switch (u->tag1) {
3808 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003809 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003810 u->opcode, u->size, u->lit32, u->val2 );
3811 break;
3812 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003813 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003814 u->opcode, u->size, u->val1, u->val2 );
3815 break;
njne427a662002-10-02 11:08:25 +00003816 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003817 }
3818 break;
3819 }
3820
3821 case INC:
3822 case DEC:
3823 case NEG:
3824 case NOT:
3825 vg_assert(u->tag1 == RealReg);
3826 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003827 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003828 break;
3829
3830 case BSWAP:
3831 vg_assert(u->tag1 == RealReg);
3832 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003833 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003834 emit_bswapl_reg ( u->val1 );
3835 break;
3836
3837 case CMOV:
3838 vg_assert(u->tag1 == RealReg);
3839 vg_assert(u->tag2 == RealReg);
3840 vg_assert(u->cond != CondAlways);
3841 vg_assert(u->size == 4);
3842 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3843 break;
3844
3845 case JMP: {
3846 vg_assert(u->tag2 == NoValue);
3847 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003848 if (*sselive) {
3849 emit_put_sse_state();
3850 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003851 }
sewardjde4a1d02002-03-22 01:27:54 +00003852 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003853 switch (u->tag1) {
3854 case RealReg:
3855 synth_jmp_reg ( u->val1, u->jmpkind );
3856 break;
3857 case Literal:
3858 synth_jmp_lit ( u->lit32, u->jmpkind );
3859 break;
3860 default:
njne427a662002-10-02 11:08:25 +00003861 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003862 break;
sewardjde4a1d02002-03-22 01:27:54 +00003863 }
3864 } else {
sewardj2e93c502002-04-12 11:12:52 +00003865 switch (u->tag1) {
3866 case RealReg:
njne427a662002-10-02 11:08:25 +00003867 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003868 break;
3869 case Literal:
3870 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003871 /* %eax had better not be live since synth_jcond_lit
3872 trashes it in some circumstances. If that turns
3873 out to be a problem we can get synth_jcond_lit to
3874 push/pop it when it is live. */
3875 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3876 u->regs_live_after));
3877 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003878 break;
3879 default:
njne427a662002-10-02 11:08:25 +00003880 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003881 break;
sewardjde4a1d02002-03-22 01:27:54 +00003882 }
3883 }
3884 break;
3885 }
3886
3887 case JIFZ:
3888 vg_assert(u->tag1 == RealReg);
3889 vg_assert(u->tag2 == Literal);
3890 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003891 if (*sselive) {
3892 emit_put_sse_state();
3893 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003894 }
sewardjde4a1d02002-03-22 01:27:54 +00003895 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3896 break;
3897
sewardjde4a1d02002-03-22 01:27:54 +00003898 case PUSH:
3899 vg_assert(u->tag1 == RealReg);
3900 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003901 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003902 break;
3903
3904 case POP:
3905 vg_assert(u->tag1 == RealReg);
3906 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003907 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003908 break;
3909
3910 case CALLM:
3911 vg_assert(u->tag1 == Lit16);
3912 vg_assert(u->tag2 == NoValue);
3913 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003914 if (*sselive) {
3915 emit_put_sse_state();
3916 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003917 }
sewardjfa492d42002-12-08 18:20:01 +00003918 /* Call to a helper which is pretending to be a real CPU
3919 instruction (and therefore operates on Real flags and
3920 registers) */
3921 VG_(synth_call) ( False, u->val1,
3922 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003923 break;
3924
njn25e49d8e72002-09-23 09:36:25 +00003925 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003926 /* If you change this, remember to change USESEG above, since
3927 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00003928 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3929 ones. */
3930 UInt argv[] = { u->val1, u->val2, u->val3 };
3931 UInt tagv[] = { RealReg, RealReg, RealReg };
3932 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
3933
3934 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
3935 else vg_assert(u->tag1 == NoValue);
3936 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
3937 else vg_assert(u->tag2 == NoValue);
3938 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
3939 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00003940 vg_assert(u->size == 0);
3941
sewardjb91ae7f2003-04-29 23:50:00 +00003942 if (*sselive) {
3943 emit_put_sse_state();
3944 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003945 }
njn25e49d8e72002-09-23 09:36:25 +00003946 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
3947 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00003948 break;
njn25e49d8e72002-09-23 09:36:25 +00003949 }
sewardje1042472002-09-30 12:33:11 +00003950
sewardjde4a1d02002-03-22 01:27:54 +00003951 case CLEAR:
3952 vg_assert(u->tag1 == Lit16);
3953 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003954 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003955 break;
3956
3957 case CC2VAL:
3958 vg_assert(u->tag1 == RealReg);
3959 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00003960 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00003961 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00003962 break;
3963
sewardjde4a1d02002-03-22 01:27:54 +00003964 case FPU_R:
3965 case FPU_W:
3966 vg_assert(u->tag1 == Lit16);
3967 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00003968 if (!(*sselive)) {
3969 emit_get_sse_state();
3970 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003971 }
sewardjfa492d42002-12-08 18:20:01 +00003972 synth_fpu_regmem ( u->flags_r, u->flags_w,
3973 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003974 u->val1 & 0xFF,
3975 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003976 break;
3977
3978 case FPU:
3979 vg_assert(u->tag1 == Lit16);
3980 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00003981 if (!(*sselive)) {
3982 emit_get_sse_state();
3983 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00003984 }
sewardjfa492d42002-12-08 18:20:01 +00003985 synth_fpu_no_mem ( u->flags_r, u->flags_w,
3986 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00003987 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00003988 break;
3989
sewardj3d7c9c82003-03-26 21:08:13 +00003990 case MMX2_MemWr:
3991 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00003992 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00003993 vg_assert(u->tag1 == Lit16);
3994 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00003995 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00003996 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00003997 if (!(*sselive)) {
3998 emit_get_sse_state();
3999 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004000 }
4001 synth_MMX2_regmem ( u->flags_r, u->flags_w,
4002 (u->val1 >> 8) & 0xFF,
4003 u->val1 & 0xFF,
4004 u->val2 );
4005 break;
4006
sewardj4fbe6e92003-06-15 21:54:34 +00004007 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00004008 vg_assert(u->tag1 == Lit16);
4009 vg_assert(u->tag2 == RealReg);
4010 vg_assert(u->tag3 == NoValue);
4011 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004012 if (!(*sselive)) {
4013 emit_get_sse_state();
4014 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004015 }
4016 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
4017 (u->val1 >> 8) & 0xFF,
4018 u->val1 & 0xFF,
4019 u->val2 );
4020 break;
4021
sewardj4fbe6e92003-06-15 21:54:34 +00004022 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00004023 vg_assert(u->tag1 == Lit16);
4024 vg_assert(u->tag2 == RealReg);
4025 vg_assert(u->tag3 == NoValue);
4026 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004027 if (!(*sselive)) {
4028 emit_get_sse_state();
4029 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00004030 }
4031 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
4032 (u->val1 >> 8) & 0xFF,
4033 u->val1 & 0xFF,
4034 u->val2 );
4035 break;
4036
sewardj3d7c9c82003-03-26 21:08:13 +00004037 case MMX1:
4038 vg_assert(u->tag1 == Lit16);
4039 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004040 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004041 if (!(*sselive)) {
4042 emit_get_sse_state();
4043 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004044 }
4045 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
4046 u->val1 & 0xFF );
4047 break;
4048
4049 case MMX2:
4050 vg_assert(u->tag1 == Lit16);
4051 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004052 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004053 if (!(*sselive)) {
4054 emit_get_sse_state();
4055 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004056 }
4057 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
4058 (u->val1 >> 8) & 0xFF,
4059 u->val1 & 0xFF );
4060 break;
4061
sewardjca860012003-03-27 23:52:58 +00004062 case MMX3:
4063 vg_assert(u->tag1 == Lit16);
4064 vg_assert(u->tag2 == Lit16);
4065 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004066 if (!(*sselive)) {
4067 emit_get_sse_state();
4068 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004069 }
4070 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
4071 (u->val1 >> 8) & 0xFF,
4072 u->val1 & 0xFF,
4073 u->val2 & 0xFF );
4074 break;
4075
sewardjfebaa3b2003-05-25 01:07:34 +00004076 case SSE2a_MemWr:
4077 case SSE2a_MemRd:
4078 vg_assert(u->size == 4 || u->size == 16);
4079 vg_assert(u->tag1 == Lit16);
4080 vg_assert(u->tag2 == Lit16);
4081 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004082 if (!(*sselive)) {
4083 emit_get_sse_state();
4084 *sselive = True;
4085 }
4086 emit_SSE2a ( u->flags_r, u->flags_w,
4087 (u->val1 >> 8) & 0xFF,
4088 u->val1 & 0xFF,
4089 u->val2 & 0xFF,
4090 u->val3 );
4091 break;
4092
sewardj9dd209f2003-06-18 23:30:52 +00004093 case SSE2a1_MemRd:
4094 vg_assert(u->size == 4 || u->size == 16);
4095 vg_assert(u->tag1 == Lit16);
4096 vg_assert(u->tag2 == Lit16);
4097 vg_assert(u->tag3 == RealReg);
4098 vg_assert(!anyFlagUse(u));
4099 if (!(*sselive)) {
4100 emit_get_sse_state();
4101 *sselive = True;
4102 }
4103 emit_SSE2a1 ( u->flags_r, u->flags_w,
4104 (u->val1 >> 8) & 0xFF,
4105 u->val1 & 0xFF,
4106 (u->val2 >> 8) & 0xFF,
4107 u->val2 & 0xFF,
4108 u->val3 );
4109 break;
4110
sewardjfebaa3b2003-05-25 01:07:34 +00004111 case SSE3a_MemWr:
4112 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00004113 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00004114 vg_assert(u->tag1 == Lit16);
4115 vg_assert(u->tag2 == Lit16);
4116 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004117 if (!(*sselive)) {
4118 emit_get_sse_state();
4119 *sselive = True;
4120 }
4121 emit_SSE3a ( u->flags_r, u->flags_w,
4122 (u->val1 >> 8) & 0xFF,
4123 u->val1 & 0xFF,
4124 (u->val2 >> 8) & 0xFF,
4125 u->val2 & 0xFF,
4126 u->val3 );
4127 break;
4128
sewardjabf8bf82003-06-15 22:28:05 +00004129 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004130 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004131 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004132 vg_assert(u->size == 4);
4133 vg_assert(u->tag1 == Lit16);
4134 vg_assert(u->tag2 == Lit16);
4135 vg_assert(u->tag3 == RealReg);
4136 vg_assert(!anyFlagUse(u));
4137 if (!(*sselive)) {
4138 emit_get_sse_state();
4139 *sselive = True;
4140 }
sewardjabf8bf82003-06-15 22:28:05 +00004141 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4142 emit_SSE3e ( u->flags_r, u->flags_w,
4143 (u->val1 >> 8) & 0xFF,
4144 u->val1 & 0xFF,
4145 (u->val2 >> 8) & 0xFF,
4146 u->val2 & 0xFF,
4147 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004148 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004149 emit_SSE3g ( u->flags_r, u->flags_w,
4150 (u->val1 >> 8) & 0xFF,
4151 u->val1 & 0xFF,
4152 (u->val2 >> 8) & 0xFF,
4153 u->val2 & 0xFF,
4154 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004155 }
sewardjfebaa3b2003-05-25 01:07:34 +00004156 break;
4157
sewardjb31b06d2003-06-13 00:26:02 +00004158 case SSE3g1_RegWr:
4159 vg_assert(u->size == 4);
4160 vg_assert(u->tag1 == Lit16);
4161 vg_assert(u->tag2 == Lit16);
4162 vg_assert(u->tag3 == RealReg);
4163 vg_assert(!anyFlagUse(u));
4164 if (!(*sselive)) {
4165 emit_get_sse_state();
4166 *sselive = True;
4167 }
sewardjabf8bf82003-06-15 22:28:05 +00004168 emit_SSE3g1 ( u->flags_r, u->flags_w,
4169 (u->val1 >> 8) & 0xFF,
4170 u->val1 & 0xFF,
4171 (u->val2 >> 8) & 0xFF,
4172 u->val2 & 0xFF,
4173 u->lit32 & 0xFF,
4174 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004175 break;
4176
sewardj4fbe6e92003-06-15 21:54:34 +00004177 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004178 vg_assert(u->size == 2);
4179 vg_assert(u->tag1 == Lit16);
4180 vg_assert(u->tag2 == Lit16);
4181 vg_assert(u->tag3 == RealReg);
4182 vg_assert(!anyFlagUse(u));
4183 if (!(*sselive)) {
4184 emit_get_sse_state();
4185 *sselive = True;
4186 }
sewardjabf8bf82003-06-15 22:28:05 +00004187 emit_SSE3e1 ( u->flags_r, u->flags_w,
4188 (u->val1 >> 8) & 0xFF,
4189 u->val1 & 0xFF,
4190 (u->val2 >> 8) & 0xFF,
4191 u->val2 & 0xFF,
4192 u->lit32 & 0xFF,
4193 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004194 break;
4195
sewardj77d30a22003-10-19 08:18:52 +00004196 case SSE3a1_MemRd:
4197 vg_assert(u->size == 16);
4198 vg_assert(u->tag1 == Lit16);
4199 vg_assert(u->tag2 == Lit16);
4200 vg_assert(u->tag3 == RealReg);
4201 vg_assert(!anyFlagUse(u));
4202 if (!(*sselive)) {
4203 emit_get_sse_state();
4204 *sselive = True;
4205 }
4206 emit_SSE3a1 ( u->flags_r, u->flags_w,
4207 (u->val1 >> 8) & 0xFF,
4208 u->val1 & 0xFF,
4209 (u->val2 >> 8) & 0xFF,
4210 u->val2 & 0xFF,
4211 (u->lit32 >> 8) & 0xFF,
4212 u->val3 );
4213 break;
4214
sewardja453fb02003-06-14 13:22:36 +00004215 case SSE5:
4216 vg_assert(u->size == 0);
4217 vg_assert(u->tag1 == Lit16);
4218 vg_assert(u->tag2 == Lit16);
4219 vg_assert(u->tag3 == Lit16);
4220 vg_assert(!anyFlagUse(u));
4221 if (!(*sselive)) {
4222 emit_get_sse_state();
4223 *sselive = True;
4224 }
4225 emit_SSE5 ( u->flags_r, u->flags_w,
4226 (u->val1 >> 8) & 0xFF,
4227 u->val1 & 0xFF,
4228 (u->val2 >> 8) & 0xFF,
4229 u->val2 & 0xFF,
4230 u->val3 & 0xFF );
4231 break;
4232
sewardjfebaa3b2003-05-25 01:07:34 +00004233 case SSE4:
4234 vg_assert(u->size == 0);
4235 vg_assert(u->tag1 == Lit16);
4236 vg_assert(u->tag2 == Lit16);
4237 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004238 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004239 if (!(*sselive)) {
4240 emit_get_sse_state();
4241 *sselive = True;
4242 }
4243 emit_SSE4 ( u->flags_r, u->flags_w,
4244 (u->val1 >> 8) & 0xFF,
4245 u->val1 & 0xFF,
4246 (u->val2 >> 8) & 0xFF,
4247 u->val2 & 0xFF );
4248 break;
4249
sewardja60be0e2003-05-26 08:47:27 +00004250 case SSE3:
4251 vg_assert(u->size == 0);
4252 vg_assert(u->tag1 == Lit16);
4253 vg_assert(u->tag2 == Lit16);
4254 vg_assert(u->tag3 == NoValue);
sewardj77d30a22003-10-19 08:18:52 +00004255 vg_assert(!readFlagUse(u));
sewardja60be0e2003-05-26 08:47:27 +00004256 if (!(*sselive)) {
4257 emit_get_sse_state();
4258 *sselive = True;
4259 }
4260 emit_SSE3 ( u->flags_r, u->flags_w,
4261 (u->val1 >> 8) & 0xFF,
4262 u->val1 & 0xFF,
4263 u->val2 & 0xFF );
4264 break;
4265
sewardje3891fa2003-06-15 03:13:48 +00004266 case SSE3ag_MemRd_RegWr:
4267 vg_assert(u->size == 4 || u->size == 8);
4268 vg_assert(u->tag1 == RealReg);
4269 vg_assert(u->tag2 == RealReg);
4270 vg_assert(u->tag3 == NoValue);
4271 vg_assert(!anyFlagUse(u));
4272 if (!(*sselive)) {
4273 emit_get_sse_state();
4274 *sselive = True;
4275 }
4276 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4277 (u->lit32 >> 24) & 0xFF,
4278 (u->lit32 >> 16) & 0xFF,
4279 (u->lit32 >> 8) & 0xFF,
4280 u->val1, u->val2 );
4281 break;
4282
sewardjde4a1d02002-03-22 01:27:54 +00004283 default:
sewardj1b7d8022002-11-30 12:35:42 +00004284 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004285 if (*sselive) {
4286 emit_put_sse_state();
4287 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004288 }
njn4ba5a792002-09-30 10:23:54 +00004289 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004290 } else {
njn25e49d8e72002-09-23 09:36:25 +00004291 VG_(printf)("\nError:\n"
4292 " unhandled opcode: %u. Perhaps "
4293 " VG_(needs).extended_UCode should be set?\n",
4294 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004295 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004296 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004297 }
sewardjde4a1d02002-03-22 01:27:54 +00004298 }
4299
sewardjb91ae7f2003-04-29 23:50:00 +00004300 if (0 && (*sselive)) {
4301 emit_put_sse_state();
4302 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004303 }
4304
njn25e49d8e72002-09-23 09:36:25 +00004305 /* Update UInstr histogram */
4306 vg_assert(u->opcode < 100);
4307 histogram[u->opcode].counts++;
4308 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004309}
4310
4311
4312/* Emit x86 for the ucode in cb, returning the address of the
4313 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004314UChar* VG_(emit_code) ( UCodeBlock* cb,
4315 Int* nbytes,
4316 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004317{
4318 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004319 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004320 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004321 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004322 Int tgt;
4323
sewardjfa492d42002-12-08 18:20:01 +00004324 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004325
njn25e49d8e72002-09-23 09:36:25 +00004326 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004327
fitzhardinge462f4f92003-12-18 02:10:54 +00004328 /* Generate subl $1, VG_(dispatch_ctr) and drop into dispatch if we hit
sewardj22854b92002-11-30 14:00:47 +00004329 zero. We have to do this regardless of whether we're t-chaining
fitzhardinge462f4f92003-12-18 02:10:54 +00004330 or not. (The ia32 optimisation guide recommends sub over dec.) */
sewardja2113f92002-12-12 23:42:48 +00004331 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004332 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
fitzhardinge462f4f92003-12-18 02:10:54 +00004333 VG_(emitB) (0x83); /* subl */
4334 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 5);
4335 VG_(emitB) (0x01);
4336
sewardj22854b92002-11-30 14:00:47 +00004337 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00004338 VG_(printf)("\n\t\tsubl $1, (%p)\n", &VG_(dispatch_ctr));
4339
4340 VG_(emit_jcondshort_target)(False, CondNZ, &tgt, JP_TAKEN);
sewardj22854b92002-11-30 14:00:47 +00004341 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4342 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004343 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004344
sewardjb5ff83e2002-12-01 19:40:49 +00004345 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004346 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004347 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004348 curr_eip = cb->orig_eip;
4349 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4350 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004351 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004352 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004353 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004354 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004355
sewardjde4a1d02002-03-22 01:27:54 +00004356 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004357 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004358 if (!sane) {
4359 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004360 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004361 }
4362 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004363 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004364 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004365 }
njn25e49d8e72002-09-23 09:36:25 +00004366 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004367 }
njn25e49d8e72002-09-23 09:36:25 +00004368 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004369 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004370 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004371
sewardj22854b92002-11-30 14:00:47 +00004372 if (j != NULL) {
4373 vg_assert(jumpidx <= VG_MAX_JUMPS);
4374 for(i = 0; i < jumpidx; i++)
4375 j[i] = jumps[i];
4376 }
4377
sewardjde4a1d02002-03-22 01:27:54 +00004378 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004379 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004380 *nbytes = emitted_code_used;
4381 return emitted_code;
4382}
4383
njn25e49d8e72002-09-23 09:36:25 +00004384#undef dis
4385
sewardjde4a1d02002-03-22 01:27:54 +00004386/*--------------------------------------------------------------------*/
4387/*--- end vg_from_ucode.c ---*/
4388/*--------------------------------------------------------------------*/