blob: 859d098a5e77a1f0cb0645ce5a46c45dbc236231 [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
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 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
nethercoteb1affa82004-01-19 19:14:18 +00001521static void emit_SSE2e1 ( 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);
1530 VG_(emitB) ( first_byte );
1531 VG_(emitB) ( second_byte );
1532 third_byte &= 0x38; /* mask out mod and rm fields */
1533 third_byte |= 0xC0; /* set top two bits: mod = 11b */
1534 third_byte |= (ireg & 7); /* patch in our ireg */
1535 VG_(emitB) ( third_byte );
1536 VG_(emitB) ( fourth_byte );
1537 if (dis)
1538 VG_(printf)(
1539 "\n\t\tsse2e1--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}
1545
1546static void emit_SSE2g1 ( FlagSet uses_sflags,
1547 FlagSet sets_sflags,
1548 UChar first_byte,
1549 UChar second_byte,
1550 UChar third_byte,
1551 UChar fourth_byte,
1552 Int ireg )
1553{
1554 VG_(new_emit)(True, uses_sflags, sets_sflags);
1555 VG_(emitB) ( first_byte );
1556 VG_(emitB) ( second_byte );
1557 third_byte &= 0xC7; /* mask out reg field */
1558 third_byte |= 0xC0; /* set top two bits: mod = 11b */
1559 third_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1560 VG_(emitB) ( third_byte );
1561 VG_(emitB) ( fourth_byte );
1562 if (dis)
1563 VG_(printf)(
1564 "\n\t\tsse2g1_reg_wr--0x%x:0x%x:0x%x:0x%x-(%s)\n",
1565 (UInt)first_byte, (UInt)second_byte,
1566 (UInt)third_byte, (UInt)fourth_byte,
1567 nameIReg(4,ireg)
1568 );
1569}
1570
1571static void emit_SSE2g ( FlagSet uses_sflags,
1572 FlagSet sets_sflags,
1573 UChar first_byte,
1574 UChar second_byte,
1575 UChar third_byte,
1576 Int ireg )
1577{
1578 VG_(new_emit)(True, uses_sflags, sets_sflags);
1579 VG_(emitB) ( first_byte );
1580 VG_(emitB) ( second_byte );
1581 third_byte &= 0xC7; /* mask out reg field */
1582 third_byte |= 0xC0; /* set top two bits: mod = 11b */
1583 third_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1584 VG_(emitB) ( third_byte );
1585 if (dis)
1586 VG_(printf)(
1587 "\n\t\tsse2g--0x%x:0x%x:0x%x-(%s)\n",
1588 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte,
1589 nameIReg(4,ireg)
1590 );
1591}
1592
sewardj9dd209f2003-06-18 23:30:52 +00001593static void emit_SSE2a1 ( FlagSet uses_sflags,
1594 FlagSet sets_sflags,
1595 UChar first_byte,
1596 UChar second_byte,
1597 UChar third_byte,
1598 UChar fourth_byte,
1599 Int ireg )
1600{
1601 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001602
1603 boundscheck();
1604
sewardj9dd209f2003-06-18 23:30:52 +00001605 VG_(emitB) ( first_byte );
1606 VG_(emitB) ( second_byte );
1607 third_byte &= 0x38; /* mask out mod and rm fields */
1608 emit_amode_regmem_reg ( ireg, third_byte >> 3 );
1609 VG_(emitB) ( fourth_byte );
1610 if (dis)
1611 VG_(printf)("\n\t\tsse2a1-0x%x:0x%x:0x%x:0x%x-(%s)\n",
1612 (UInt)first_byte, (UInt)second_byte,
1613 (UInt)third_byte, (UInt)fourth_byte,
1614 nameIReg(4,ireg) );
1615}
1616
sewardjfebaa3b2003-05-25 01:07:34 +00001617static void emit_SSE3a ( FlagSet uses_sflags,
1618 FlagSet sets_sflags,
1619 UChar first_byte,
1620 UChar second_byte,
1621 UChar third_byte,
1622 UChar fourth_byte,
1623 Int ireg )
1624{
1625 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001626
1627 boundscheck();
1628
sewardjfebaa3b2003-05-25 01:07:34 +00001629 VG_(emitB) ( first_byte );
1630 VG_(emitB) ( second_byte );
1631 VG_(emitB) ( third_byte );
1632 fourth_byte &= 0x38; /* mask out mod and rm fields */
1633 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1634 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001635 VG_(printf)("\n\t\tsse3a-0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001636 (UInt)first_byte, (UInt)second_byte,
1637 (UInt)third_byte, (UInt)fourth_byte,
1638 nameIReg(4,ireg) );
1639}
1640
sewardjabf8bf82003-06-15 22:28:05 +00001641static void emit_SSE3e ( FlagSet uses_sflags,
1642 FlagSet sets_sflags,
1643 UChar first_byte,
1644 UChar second_byte,
1645 UChar third_byte,
1646 UChar fourth_byte,
1647 Int ireg )
sewardjfebaa3b2003-05-25 01:07:34 +00001648{
1649 VG_(new_emit)(True, uses_sflags, sets_sflags);
1650 VG_(emitB) ( first_byte );
1651 VG_(emitB) ( second_byte );
1652 VG_(emitB) ( third_byte );
1653 fourth_byte &= 0x38; /* mask out mod and rm fields */
1654 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1655 fourth_byte |= (ireg & 7); /* patch in our ireg */
1656 VG_(emitB) ( fourth_byte );
1657 if (dis)
sewardj02af6bc2003-06-12 00:56:06 +00001658 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001659 "\n\t\tsse3e--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj02af6bc2003-06-12 00:56:06 +00001660 (UInt)first_byte, (UInt)second_byte,
1661 (UInt)third_byte, (UInt)fourth_byte,
1662 nameIReg(4,ireg)
1663 );
sewardjfebaa3b2003-05-25 01:07:34 +00001664}
1665
sewardjabf8bf82003-06-15 22:28:05 +00001666static void emit_SSE3e1 ( FlagSet uses_sflags,
1667 FlagSet sets_sflags,
1668 UChar first_byte,
1669 UChar second_byte,
1670 UChar third_byte,
1671 UChar fourth_byte,
1672 UChar fifth_byte,
1673 Int ireg )
sewardj8f33ba62003-06-14 12:00:45 +00001674{
1675 VG_(new_emit)(True, uses_sflags, sets_sflags);
1676 VG_(emitB) ( first_byte );
1677 VG_(emitB) ( second_byte );
1678 VG_(emitB) ( third_byte );
1679 fourth_byte &= 0x38; /* mask out mod and rm fields */
1680 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1681 fourth_byte |= (ireg & 7); /* patch in our ireg */
1682 VG_(emitB) ( fourth_byte );
1683 VG_(emitB) ( fifth_byte );
1684 if (dis)
1685 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001686 "\n\t\tsse3e1--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardj8f33ba62003-06-14 12:00:45 +00001687 (UInt)first_byte, (UInt)second_byte,
1688 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1689 nameIReg(4,ireg)
1690 );
1691}
1692
sewardjabf8bf82003-06-15 22:28:05 +00001693static void emit_SSE3g1 ( FlagSet uses_sflags,
1694 FlagSet sets_sflags,
1695 UChar first_byte,
1696 UChar second_byte,
1697 UChar third_byte,
1698 UChar fourth_byte,
1699 UChar fifth_byte,
1700 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001701{
1702 VG_(new_emit)(True, uses_sflags, sets_sflags);
1703 VG_(emitB) ( first_byte );
1704 VG_(emitB) ( second_byte );
1705 VG_(emitB) ( third_byte );
1706 fourth_byte &= 0xC7; /* mask out reg field */
1707 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
1708 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
1709 VG_(emitB) ( fourth_byte );
1710 VG_(emitB) ( fifth_byte );
1711 if (dis)
1712 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001713 "\n\t\tsse3g1_reg_wr--0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001714 (UInt)first_byte, (UInt)second_byte,
1715 (UInt)third_byte, (UInt)fourth_byte, (UInt)fifth_byte,
1716 nameIReg(4,ireg)
1717 );
1718}
1719
sewardjabf8bf82003-06-15 22:28:05 +00001720static void emit_SSE3g ( FlagSet uses_sflags,
1721 FlagSet sets_sflags,
1722 UChar first_byte,
1723 UChar second_byte,
1724 UChar third_byte,
1725 UChar fourth_byte,
1726 Int ireg )
sewardjb31b06d2003-06-13 00:26:02 +00001727{
1728 VG_(new_emit)(True, uses_sflags, sets_sflags);
1729 VG_(emitB) ( first_byte );
1730 VG_(emitB) ( second_byte );
1731 VG_(emitB) ( third_byte );
sewardj8f33ba62003-06-14 12:00:45 +00001732 fourth_byte &= 0xC7; /* mask out reg field */
sewardjb31b06d2003-06-13 00:26:02 +00001733 fourth_byte |= 0xC0; /* set top two bits: mod = 11b */
sewardj8f33ba62003-06-14 12:00:45 +00001734 fourth_byte |= ((ireg & 7) << 3); /* patch in our ireg */
sewardjb31b06d2003-06-13 00:26:02 +00001735 VG_(emitB) ( fourth_byte );
sewardjb31b06d2003-06-13 00:26:02 +00001736 if (dis)
1737 VG_(printf)(
sewardjabf8bf82003-06-15 22:28:05 +00001738 "\n\t\tsse3g--0x%x:0x%x:0x%x:0x%x-(%s)\n",
sewardjb31b06d2003-06-13 00:26:02 +00001739 (UInt)first_byte, (UInt)second_byte,
sewardj8f33ba62003-06-14 12:00:45 +00001740 (UInt)third_byte, (UInt)fourth_byte,
sewardjb31b06d2003-06-13 00:26:02 +00001741 nameIReg(4,ireg)
1742 );
1743}
1744
sewardj77d30a22003-10-19 08:18:52 +00001745static void emit_SSE3a1 ( FlagSet uses_sflags,
1746 FlagSet sets_sflags,
1747 UChar first_byte,
1748 UChar second_byte,
1749 UChar third_byte,
1750 UChar fourth_byte,
1751 UChar fifth_byte,
1752 Int ireg )
1753{
1754 VG_(new_emit)(True, uses_sflags, sets_sflags);
fitzhardinge98abfc72003-12-16 02:05:15 +00001755
1756 boundscheck();
1757
sewardj77d30a22003-10-19 08:18:52 +00001758 VG_(emitB) ( first_byte );
1759 VG_(emitB) ( second_byte );
1760 VG_(emitB) ( third_byte );
1761 fourth_byte &= 0x38; /* mask out mod and rm fields */
1762 emit_amode_regmem_reg ( ireg, fourth_byte >> 3 );
1763 VG_(emitB) ( fifth_byte );
1764 if (dis)
1765 VG_(printf)("\n\t\tsse3a1-0x%x:0x%x:0x%x:0x%x:0x%x-(%s)\n",
1766 (UInt)first_byte, (UInt)second_byte,
1767 (UInt)third_byte, (UInt)fourth_byte,
1768 (UInt)fifth_byte,
1769 nameIReg(4,ireg) );
1770}
1771
sewardjfebaa3b2003-05-25 01:07:34 +00001772static void emit_SSE4 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001773 FlagSet sets_sflags,
1774 UChar first_byte,
1775 UChar second_byte,
1776 UChar third_byte,
1777 UChar fourth_byte )
sewardjfebaa3b2003-05-25 01:07:34 +00001778{
1779 VG_(new_emit)(True, uses_sflags, sets_sflags);
1780 VG_(emitB) ( first_byte );
1781 VG_(emitB) ( second_byte );
1782 VG_(emitB) ( third_byte );
1783 VG_(emitB) ( fourth_byte );
1784 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001785 VG_(printf)("\n\t\tsse4-0x%x:0x%x:0x%x:0x%x\n",
sewardjfebaa3b2003-05-25 01:07:34 +00001786 (UInt)first_byte, (UInt)second_byte,
1787 (UInt)third_byte, (UInt)fourth_byte );
1788}
1789
sewardja453fb02003-06-14 13:22:36 +00001790static void emit_SSE5 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001791 FlagSet sets_sflags,
1792 UChar first_byte,
1793 UChar second_byte,
1794 UChar third_byte,
1795 UChar fourth_byte,
1796 UChar fifth_byte )
sewardja453fb02003-06-14 13:22:36 +00001797{
1798 VG_(new_emit)(True, uses_sflags, sets_sflags);
1799 VG_(emitB) ( first_byte );
1800 VG_(emitB) ( second_byte );
1801 VG_(emitB) ( third_byte );
1802 VG_(emitB) ( fourth_byte );
1803 VG_(emitB) ( fifth_byte );
1804 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001805 VG_(printf)("\n\t\tsse5-0x%x:0x%x:0x%x:0x%x:0x%x\n",
sewardja453fb02003-06-14 13:22:36 +00001806 (UInt)first_byte, (UInt)second_byte,
1807 (UInt)third_byte, (UInt)fourth_byte,
1808 (UInt)fifth_byte );
1809}
1810
sewardja60be0e2003-05-26 08:47:27 +00001811static void emit_SSE3 ( FlagSet uses_sflags,
sewardje3891fa2003-06-15 03:13:48 +00001812 FlagSet sets_sflags,
1813 UChar first_byte,
1814 UChar second_byte,
1815 UChar third_byte )
sewardja60be0e2003-05-26 08:47:27 +00001816{
1817 VG_(new_emit)(True, uses_sflags, sets_sflags);
1818 VG_(emitB) ( first_byte );
1819 VG_(emitB) ( second_byte );
1820 VG_(emitB) ( third_byte );
1821 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001822 VG_(printf)("\n\t\tsse3-0x%x:0x%x:0x%x\n",
sewardja60be0e2003-05-26 08:47:27 +00001823 (UInt)first_byte, (UInt)second_byte,
1824 (UInt)third_byte );
1825}
1826
sewardje3891fa2003-06-15 03:13:48 +00001827static void emit_SSE3ag_MemRd_RegWr ( FlagSet uses_sflags,
1828 FlagSet sets_sflags,
1829 UChar first_byte,
1830 UChar second_byte,
1831 UChar third_byte,
1832 Int addr_reg,
1833 Int dest_reg )
1834{
1835 VG_(new_emit)(True, uses_sflags, sets_sflags);
1836 VG_(emitB) ( first_byte );
1837 VG_(emitB) ( second_byte );
1838 VG_(emitB) ( third_byte );
1839 /* 4th byte can be completely synthesised from addr_reg and
1840 dest_reg. */
1841 emit_amode_regmem_reg ( addr_reg, dest_reg );
1842 if (dis)
sewardjabf8bf82003-06-15 22:28:05 +00001843 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 +00001844 (UInt)first_byte, (UInt)second_byte,
1845 (UInt)third_byte, nameIReg(4, addr_reg),
1846 nameIReg(4, dest_reg));
1847}
1848
sewardjca860012003-03-27 23:52:58 +00001849static void emit_MMX2_reg_to_mmxreg ( FlagSet uses_sflags,
1850 FlagSet sets_sflags,
1851 UChar first_byte,
1852 UChar second_byte,
1853 Int ireg )
1854{
1855 VG_(new_emit)(True, uses_sflags, sets_sflags);
1856 VG_(emitB) ( 0x0F );
1857 VG_(emitB) ( first_byte );
1858 second_byte &= 0x38; /* mask out mod and rm fields */
1859 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1860 second_byte |= (ireg & 7); /* patch in our ireg */
1861 VG_(emitB) ( second_byte );
1862 if (dis)
sewardjd1c9e432003-04-04 20:40:34 +00001863 VG_(printf)("\n\t\tmmx2:reg-to-mmxreg--0x%x:0x%x-(%s)\n",
1864 (UInt)first_byte, (UInt)second_byte,
1865 nameIReg(4,ireg) );
1866}
1867
1868static void emit_MMX2_mmxreg_to_reg ( FlagSet uses_sflags,
1869 FlagSet sets_sflags,
1870 UChar first_byte,
1871 UChar second_byte,
1872 Int ireg )
1873{
1874 VG_(new_emit)(True, uses_sflags, sets_sflags);
1875 VG_(emitB) ( 0x0F );
1876 VG_(emitB) ( first_byte );
1877 second_byte &= 0x38; /* mask out mod and rm fields */
1878 second_byte |= 0xC0; /* set top two bits: mod = 11b */
1879 second_byte |= (ireg & 7); /* patch in our ireg */
1880 VG_(emitB) ( second_byte );
1881 if (dis)
1882 VG_(printf)("\n\t\tmmx2:mmxreg-to-reg--0x%x:0x%x-(%s)\n",
sewardjca860012003-03-27 23:52:58 +00001883 (UInt)first_byte, (UInt)second_byte,
1884 nameIReg(4,ireg) );
1885}
1886
1887static void emit_MMX3_no_mem ( FlagSet uses_sflags,
1888 FlagSet sets_sflags,
1889 UChar first_byte,
1890 UChar second_byte,
1891 UChar third_byte )
1892{
1893 VG_(new_emit)(True, uses_sflags, sets_sflags);
1894 VG_(emitB) ( 0x0F );
1895 VG_(emitB) ( first_byte );
1896 VG_(emitB) ( second_byte );
1897 VG_(emitB) ( third_byte );
1898 if (dis)
1899 VG_(printf)("\n\t\tmmx3-0x%x:0x%x:0x%x\n",
1900 (UInt)first_byte, (UInt)second_byte, (UInt)third_byte );
1901}
1902
sewardj3d7c9c82003-03-26 21:08:13 +00001903static void emit_MMX2_no_mem ( FlagSet uses_sflags,
1904 FlagSet sets_sflags,
1905 UChar first_byte,
1906 UChar second_byte )
1907{
1908 VG_(new_emit)(True, uses_sflags, sets_sflags);
1909 VG_(emitB) ( 0x0F );
1910 VG_(emitB) ( first_byte );
1911 VG_(emitB) ( second_byte );
1912 if (dis)
1913 VG_(printf)("\n\t\tmmx2-0x%x:0x%x\n",
1914 (UInt)first_byte, (UInt)second_byte );
1915}
1916
1917static void emit_MMX1_no_mem ( FlagSet uses_sflags,
1918 FlagSet sets_sflags,
1919 UChar first_byte )
1920{
1921 VG_(new_emit)(True, uses_sflags, sets_sflags);
1922 VG_(emitB) ( 0x0F );
1923 VG_(emitB) ( first_byte );
1924 if (dis)
1925 VG_(printf)("\n\t\tmmx1-0x%x\n",
1926 (UInt)first_byte );
1927}
1928
sewardjde4a1d02002-03-22 01:27:54 +00001929
1930/*----------------------------------------------------*/
1931/*--- misc instruction emitters ---*/
1932/*----------------------------------------------------*/
1933
njn25e49d8e72002-09-23 09:36:25 +00001934void VG_(emit_call_reg) ( Int reg )
1935{
sewardjfa492d42002-12-08 18:20:01 +00001936 VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP); /* XXX */
njn25e49d8e72002-09-23 09:36:25 +00001937 VG_(emitB) ( 0xFF ); /* Grp5 */
1938 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
1939 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +00001940 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +00001941}
1942
sewardjf0f12aa2002-12-28 00:04:08 +00001943static
1944void emit_call_star_EBP_off ( Bool simd_flags, Int byte_off,
1945 FlagSet use_flag, FlagSet set_flag )
sewardjde4a1d02002-03-22 01:27:54 +00001946{
sewardjfa492d42002-12-08 18:20:01 +00001947 /* Used for helpers which expect to see Simd flags in Real flags */
sewardjf0f12aa2002-12-28 00:04:08 +00001948 VG_(new_emit)(simd_flags, use_flag, set_flag);
sewardjfa492d42002-12-08 18:20:01 +00001949
1950 if (byte_off < -128 || byte_off > 127) {
1951 VG_(emitB) ( 0xFF );
1952 VG_(emitB) ( 0x95 );
1953 VG_(emitL) ( byte_off );
1954 } else {
1955 VG_(emitB) ( 0xFF );
1956 VG_(emitB) ( 0x55 );
1957 VG_(emitB) ( byte_off );
1958 }
1959 if (dis)
1960 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
sewardjde4a1d02002-03-22 01:27:54 +00001961}
1962
sewardja2c5a732002-12-15 03:10:42 +00001963#if 0
1964/* evidently unused */
sewardjde4a1d02002-03-22 01:27:54 +00001965static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
1966{
1967 vg_assert(lit8 >= -128 && lit8 < 128);
sewardjfa492d42002-12-08 18:20:01 +00001968 VG_(new_emit)(True, FlagsEmpty, FlagsOSZACP);
njn25e49d8e72002-09-23 09:36:25 +00001969 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
1970 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +00001971 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +00001972 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001973 if (dis)
1974 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
1975 nameIReg(4,regmem));
1976}
sewardja2c5a732002-12-15 03:10:42 +00001977#endif
sewardjde4a1d02002-03-22 01:27:54 +00001978
njn25e49d8e72002-09-23 09:36:25 +00001979void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +00001980{
njne427a662002-10-02 11:08:25 +00001981 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
sewardjfa492d42002-12-08 18:20:01 +00001982 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
1983 VG_(emitB) ( 0x8D );
1984 VG_(emitB) ( 0x64 );
1985 VG_(emitB) ( 0x24 );
njn25e49d8e72002-09-23 09:36:25 +00001986 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00001987 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00001988 VG_(printf)( "\n\t\tlea\t%d(%%esp), %%esp\n", lit );
sewardjde4a1d02002-03-22 01:27:54 +00001989}
1990
1991
1992static void emit_movb_AL_zeroESPmem ( void )
1993{
1994 /* movb %al, 0(%esp) */
1995 /* 88442400 movb %al, 0(%esp) */
sewardjf0f12aa2002-12-28 00:04:08 +00001996 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00001997 VG_(emitB) ( 0x88 );
1998 VG_(emitB) ( 0x44 );
1999 VG_(emitB) ( 0x24 );
2000 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00002001 if (dis)
2002 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
2003}
2004
2005static void emit_movb_zeroESPmem_AL ( void )
2006{
2007 /* movb 0(%esp), %al */
2008 /* 8A442400 movb 0(%esp), %al */
sewardjf0f12aa2002-12-28 00:04:08 +00002009 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002010 VG_(emitB) ( 0x8A );
2011 VG_(emitB) ( 0x44 );
2012 VG_(emitB) ( 0x24 );
2013 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +00002014 if (dis)
2015 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
2016}
2017
sewardja2113f92002-12-12 23:42:48 +00002018/* Jump target states */
2019#define TGT_UNDEF (1 << 16)
2020#define TGT_FORWARD (2 << 16)
2021#define TGT_BACKWARD (3 << 16)
2022
2023static inline Int tgt_state(Int tgt)
2024{
2025 return tgt & 0xffff0000;
2026}
2027
2028static inline Int tgt_addr(Int tgt)
2029{
2030 return tgt & 0x0000ffff;
2031}
2032
2033static inline Int mk_tgt(Int state, Int addr)
2034{
fitzhardinge462f4f92003-12-18 02:10:54 +00002035 vg_assert(state == TGT_UNDEF ||
2036 state == TGT_FORWARD ||
2037 state == TGT_BACKWARD);
sewardja2113f92002-12-12 23:42:48 +00002038 vg_assert((addr & 0xffff0000) == 0);
2039
2040 return state | addr;
2041}
2042
2043void VG_(init_target) ( Int *tgt )
2044{
2045 *tgt = TGT_UNDEF;
2046}
2047
2048void VG_(target_back) ( Int *tgt )
2049{
2050 vg_assert(tgt_state(*tgt) == TGT_UNDEF);
2051
2052 *tgt = mk_tgt(TGT_BACKWARD, emitted_code_used);
2053}
2054
2055void VG_(target_forward) ( Int *tgt )
2056{
2057 Int delta;
2058
2059 vg_assert(tgt_state(*tgt) == TGT_FORWARD ||
2060 tgt_state(*tgt) == TGT_UNDEF);
2061
2062 if (tgt_state(*tgt) == TGT_UNDEF)
2063 return; /* target not used */
2064
2065 delta = emitted_code_used - (tgt_addr(*tgt) + 1);
2066 vg_assert(delta >= -128 && delta <= 127);
2067 vg_assert(tgt_addr(*tgt) >= 0);
sewardjbd6473c2002-12-12 23:50:22 +00002068 vg_assert(tgt_addr(*tgt) < emitted_code_used);
sewardja2113f92002-12-12 23:42:48 +00002069 emitted_code[tgt_addr(*tgt)] = delta;
2070 if (dis)
2071 VG_(printf)("(target to jump site %d; delta: %d)\n",
2072 tgt_addr(*tgt), delta);
2073}
2074
2075void VG_(emit_target_delta) ( Int *tgt )
2076{
2077 vg_assert(tgt_state(*tgt) == TGT_UNDEF ||
2078 tgt_state(*tgt) == TGT_BACKWARD);
2079
2080 if (tgt_state(*tgt) == TGT_UNDEF) {
2081 /* forward jump */
2082 *tgt = mk_tgt(TGT_FORWARD, emitted_code_used);
2083 VG_(emitB) (0x00);
2084 } else {
2085 /* backward jump */
2086 Int delta = emitted_code_used - (tgt_addr(*tgt) + 1);
2087 vg_assert(delta >= -128 && delta <= 127);
2088 VG_(emitB) (delta);
2089 }
2090}
2091
sewardjde4a1d02002-03-22 01:27:54 +00002092
2093/* Emit a jump short with an 8-bit signed offset. Note that the
2094 offset is that which should be added to %eip once %eip has been
2095 advanced over this insn. */
fitzhardinge462f4f92003-12-18 02:10:54 +00002096void VG_(emit_jcondshort_delta) ( Bool simd_flags, Condcode cond, Int delta, JumpPred pred )
sewardjde4a1d02002-03-22 01:27:54 +00002097{
2098 vg_assert(delta >= -128 && delta <= 127);
sewardjf0f12aa2002-12-28 00:04:08 +00002099 VG_(new_emit)(simd_flags, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002100
2101 if (VG_(clo_branchpred) &&
2102 pred != JP_NONE &&
2103 pred != static_pred(cond, delta > 0))
2104 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2105
njn25e49d8e72002-09-23 09:36:25 +00002106 VG_(emitB) ( 0x70 + (UInt)cond );
2107 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +00002108 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002109 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+%d\n",
2110 VG_(name_UCondcode)(cond), predstr(pred), delta );
sewardjde4a1d02002-03-22 01:27:54 +00002111}
2112
sewardja2113f92002-12-12 23:42:48 +00002113/* Same as above, but defers emitting the delta */
fitzhardinge462f4f92003-12-18 02:10:54 +00002114void VG_(emit_jcondshort_target) ( Bool simd, Condcode cond, Int *tgt, JumpPred pred )
sewardja2113f92002-12-12 23:42:48 +00002115{
sewardj706240d2002-12-26 17:10:12 +00002116 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
fitzhardinge462f4f92003-12-18 02:10:54 +00002117
2118 if (VG_(clo_branchpred) &&
2119 pred != JP_NONE &&
2120 pred != static_pred(cond, tgt_state(*tgt) != TGT_BACKWARD))
2121 VG_(emitB)(pred == JP_TAKEN ? 0x3e : 0x2e);
2122
sewardja2113f92002-12-12 23:42:48 +00002123 VG_(emitB) ( 0x70 + (UInt)cond );
2124 VG_(emit_target_delta) (tgt);
2125 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00002126 VG_(printf)( "\n\t\tj%s-8%s\t%%eip+(%d)\n",
2127 VG_(name_UCondcode)(cond), predstr(pred), tgt_addr(*tgt) );
sewardja2113f92002-12-12 23:42:48 +00002128}
2129
2130
2131
sewardjf0f12aa2002-12-28 00:04:08 +00002132static void emit_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00002133{
sewardjf0f12aa2002-12-28 00:04:08 +00002134 VG_(new_emit)(simd, FlagsOSZCP, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002135 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
2136 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00002137 if (dis)
2138 VG_(printf)("\n\t\tset%s %s\n",
njn563f96f2003-02-03 11:17:46 +00002139 VG_(name_UCondcode)(cond), nameIReg(1,reg));
sewardjde4a1d02002-03-22 01:27:54 +00002140}
2141
2142static void emit_ret ( void )
2143{
sewardjfa492d42002-12-08 18:20:01 +00002144 maybe_emit_put_eflags(); /* make sure flags are stored */
sewardj706240d2002-12-26 17:10:12 +00002145 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002146 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00002147 if (dis)
2148 VG_(printf)("\n\t\tret\n");
2149}
2150
sewardj22854b92002-11-30 14:00:47 +00002151/* Predicate used in sanity checks elsewhere - returns true if any
2152 jump-site is an actual chained jump */
2153Bool VG_(is_chained_jumpsite)(Addr a)
2154{
2155 UChar *cp = (UChar *)a;
2156
2157 return (*cp == 0xE9); /* 0xE9 -- jmp */
2158}
2159
sewardj83f11862002-12-01 02:07:08 +00002160static
2161Bool is_fresh_jumpsite(UChar *cp)
2162{
2163 return
2164 cp[0] == 0x0F && /* UD2 */
2165 cp[1] == 0x0B &&
2166 cp[2] == 0x0F && /* UD2 */
2167 cp[3] == 0x0B &&
2168 cp[4] == 0x90; /* NOP */
2169}
2170
sewardj22854b92002-11-30 14:00:47 +00002171/* Predicate used in sanity checks elsewhere - returns true if all
2172 jump-sites are calls to VG_(patch_me) */
2173Bool VG_(is_unchained_jumpsite)(Addr a)
2174{
2175 UChar *cp = (UChar *)a;
2176 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2177 Int idelta;
2178
2179 if (*cp++ != 0xE8) /* 0xE8 == call */
2180 return False;
2181
2182 idelta = (*cp++) << 0;
2183 idelta |= (*cp++) << 8;
2184 idelta |= (*cp++) << 16;
2185 idelta |= (*cp++) << 24;
2186
2187 return idelta == delta;
2188}
2189
2190/* Return target address for a direct jmp */
2191Addr VG_(get_jmp_dest)(Addr a)
2192{
2193 Int delta;
2194 UChar *cp = (UChar *)a;
2195
2196 if (*cp++ != 0xE9) /* 0xE9 == jmp */
2197 return 0;
2198
2199 delta = (*cp++) << 0;
2200 delta |= (*cp++) << 8;
2201 delta |= (*cp++) << 16;
2202 delta |= (*cp++) << 24;
2203
2204 return a + VG_PATCHME_JMPSZ + delta;
2205}
2206
2207/* unchain a BB by generating a call to VG_(patch_me) */
2208void VG_(unchain_jumpsite)(Addr a)
2209{
2210 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
2211 UChar *cp = (UChar *)a;
2212
2213 if (VG_(is_unchained_jumpsite)(a))
2214 return; /* don't write unnecessarily */
2215
sewardj83f11862002-12-01 02:07:08 +00002216 if (!is_fresh_jumpsite(cp))
2217 VG_(bb_dechain_count)++; /* update stats */
2218
sewardj22854b92002-11-30 14:00:47 +00002219 *cp++ = 0xE8; /* call */
2220 *cp++ = (delta >> 0) & 0xff;
2221 *cp++ = (delta >> 8) & 0xff;
2222 *cp++ = (delta >> 16) & 0xff;
2223 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00002224}
2225
2226/* This doesn't actually generate a call to VG_(patch_me), but
2227 reserves enough space in the instruction stream for it to happen
2228 and records the offset into the jump table. This is because call
2229 is a relative jump, and so will be affected when this code gets
2230 moved about. The translation table will "unchain" this basic block
2231 on insertion (with VG_(unchain_BB)()), and thereby generate a
2232 proper call instruction. */
2233static void emit_call_patchme( void )
2234{
2235 vg_assert(VG_PATCHME_CALLSZ == 5);
2236
sewardjfa492d42002-12-08 18:20:01 +00002237 maybe_emit_put_eflags(); /* save flags before end of BB */
sewardj706240d2002-12-26 17:10:12 +00002238 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
sewardj22854b92002-11-30 14:00:47 +00002239
2240 if (jumpidx >= VG_MAX_JUMPS) {
2241 /* If there too many jumps in this basic block, fall back to
2242 dispatch loop. We still need to keep it the same size as the
2243 call sequence. */
2244 VG_(emitB) ( 0xC3 ); /* ret */
fitzhardinge98abfc72003-12-16 02:05:15 +00002245 VG_(emitB) ( 0x8d ); /* 4 byte nop (lea 0x0(%esi,1),%esi) */
2246 VG_(emitB) ( 0x74 );
2247 VG_(emitB) ( 0x26 );
2248 VG_(emitB) ( 0x00 );
sewardj22854b92002-11-30 14:00:47 +00002249
2250 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002251 VG_(printf)("\n\t\tret; nop4\n");
sewardj22854b92002-11-30 14:00:47 +00002252
2253 if (0 && VG_(clo_verbosity))
2254 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
2255 } else {
2256 jumps[jumpidx++] = emitted_code_used;
2257
2258 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2259 VG_(emitB) ( 0x0B );
2260 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
2261 VG_(emitB) ( 0x0B );
2262 VG_(emitB) ( 0x90 ); /* NOP */
2263
2264 if (dis)
fitzhardinge98abfc72003-12-16 02:05:15 +00002265 VG_(printf)("\n\t\tud2; ud2; nop /* call VG_(patchme) */\n");
sewardj22854b92002-11-30 14:00:47 +00002266 }
2267}
2268
njn25e49d8e72002-09-23 09:36:25 +00002269void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002270{
sewardjf0f12aa2002-12-28 00:04:08 +00002271 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002272 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00002273 if (dis)
2274 VG_(printf)("\n\t\tpushal\n");
2275}
2276
njn25e49d8e72002-09-23 09:36:25 +00002277void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002278{
sewardjf0f12aa2002-12-28 00:04:08 +00002279 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002280 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00002281 if (dis)
2282 VG_(printf)("\n\t\tpopal\n");
2283}
2284
2285static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
2286{
sewardjf0f12aa2002-12-28 00:04:08 +00002287 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002288 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
2289 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002290 if (dis)
2291 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
2292 lit, nameIReg(4,regmem), nameIReg(4,reg) );
2293}
2294
2295static void emit_lea_sib_reg ( UInt lit, Int scale,
2296 Int regbase, Int regindex, Int reg )
2297{
sewardjf0f12aa2002-12-28 00:04:08 +00002298 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002299 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00002300 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
2301 if (dis)
2302 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
2303 lit, nameIReg(4,regbase),
2304 nameIReg(4,regindex), scale,
2305 nameIReg(4,reg) );
2306}
2307
njn25e49d8e72002-09-23 09:36:25 +00002308void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00002309{
sewardjf0f12aa2002-12-28 00:04:08 +00002310 VG_(new_emit)(False, FlagsEmpty, FlagsEmpty);
njn25e49d8e72002-09-23 09:36:25 +00002311 VG_(emitB) ( 0x0F );
2312 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00002313 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
2314 if (dis)
2315 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
2316}
2317
2318/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00002319/*--- Helper offset -> addr translation ---*/
2320/*----------------------------------------------------*/
2321
2322/* Finds the baseBlock offset of a skin-specified helper.
2323 * Searches through compacts first, then non-compacts. */
2324Int VG_(helper_offset)(Addr a)
2325{
sewardj05bcdcb2003-05-18 10:05:38 +00002326 UInt i;
njnf4ce3d32003-02-10 10:17:26 +00002327 Char buf[100];
njn25e49d8e72002-09-23 09:36:25 +00002328
2329 for (i = 0; i < VG_(n_compact_helpers); i++)
2330 if (VG_(compact_helper_addrs)[i] == a)
2331 return VG_(compact_helper_offsets)[i];
2332 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2333 if (VG_(noncompact_helper_addrs)[i] == a)
2334 return VG_(noncompact_helper_offsets)[i];
2335
2336 /* Shouldn't get here */
njnf4ce3d32003-02-10 10:17:26 +00002337 VG_(get_fnname) ( a, buf, 100 );
2338
njn25e49d8e72002-09-23 09:36:25 +00002339 VG_(printf)(
njnf4ce3d32003-02-10 10:17:26 +00002340 "\nCouldn't find offset of helper from its address (%p: %s).\n"
2341 "A helper function probably used hasn't been registered?\n\n", a, buf);
njn25e49d8e72002-09-23 09:36:25 +00002342
2343 VG_(printf)(" compact helpers: ");
2344 for (i = 0; i < VG_(n_compact_helpers); i++)
2345 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
2346
2347 VG_(printf)("\n non-compact helpers: ");
2348 for (i = 0; i < VG_(n_noncompact_helpers); i++)
2349 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
2350
2351 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00002352 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00002353}
2354
2355/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00002356/*--- Instruction synthesisers ---*/
2357/*----------------------------------------------------*/
2358
2359static Condcode invertCondition ( Condcode cond )
2360{
2361 return (Condcode)(1 ^ (UInt)cond);
2362}
2363
2364
2365/* Synthesise a call to *baseBlock[offset], ie,
2366 call * (4 x offset)(%ebp).
2367*/
sewardjfa492d42002-12-08 18:20:01 +00002368void VG_(synth_call) ( Bool ensure_shortform, Int word_offset,
sewardjf0f12aa2002-12-28 00:04:08 +00002369 Bool simd_flags, FlagSet use_flags, FlagSet set_flags )
sewardjde4a1d02002-03-22 01:27:54 +00002370{
2371 vg_assert(word_offset >= 0);
2372 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
sewardjfa492d42002-12-08 18:20:01 +00002373 if (ensure_shortform) {
sewardjde4a1d02002-03-22 01:27:54 +00002374 vg_assert(word_offset < 32);
sewardjfa492d42002-12-08 18:20:01 +00002375 }
sewardjf0f12aa2002-12-28 00:04:08 +00002376 emit_call_star_EBP_off ( simd_flags, 4 * word_offset, use_flags, set_flags );
sewardjde4a1d02002-03-22 01:27:54 +00002377}
2378
njn25e49d8e72002-09-23 09:36:25 +00002379static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00002380{
njn25e49d8e72002-09-23 09:36:25 +00002381 if (src != dst) {
2382 VG_(emit_movv_reg_reg) ( 4, src, dst );
2383 ccall_arg_setup_instrs++;
2384 }
njn6431be72002-07-28 09:53:34 +00002385}
njn25e49d8e72002-09-23 09:36:25 +00002386
2387/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
2388static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
2389{
2390 if (RealReg == tag) {
2391 maybe_emit_movl_reg_reg ( litOrReg, reg );
2392 } else if (Literal == tag) {
2393 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
2394 ccall_arg_setup_instrs++;
2395 }
2396 else
njne427a662002-10-02 11:08:25 +00002397 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00002398}
2399
2400static
2401void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
2402{
2403 if (R_EAX == reg1) {
2404 VG_(emit_swapl_reg_EAX) ( reg2 );
2405 } else if (R_EAX == reg2) {
2406 VG_(emit_swapl_reg_EAX) ( reg1 );
2407 } else {
2408 emit_swapl_reg_reg ( reg1, reg2 );
2409 }
2410 ccall_arg_setup_instrs++;
2411}
2412
2413static
2414void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
2415{
2416 if (dst1 != src2) {
2417 maybe_emit_movl_reg_reg ( src1, dst1 );
2418 maybe_emit_movl_reg_reg ( src2, dst2 );
2419
2420 } else if (dst2 != src1) {
2421 maybe_emit_movl_reg_reg ( src2, dst2 );
2422 maybe_emit_movl_reg_reg ( src1, dst1 );
2423
2424 } else {
2425 /* swap to break cycle */
2426 emit_swapl_arg_regs ( dst1, dst2 );
2427 }
2428}
2429
2430static
2431void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
2432 UInt dst1, UInt dst2, UInt dst3)
2433{
2434 if (dst1 != src2 && dst1 != src3) {
2435 maybe_emit_movl_reg_reg ( src1, dst1 );
2436 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
2437
2438 } else if (dst2 != src1 && dst2 != src3) {
2439 maybe_emit_movl_reg_reg ( src2, dst2 );
2440 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
2441
2442 } else if (dst3 != src1 && dst3 != src2) {
2443 maybe_emit_movl_reg_reg ( src3, dst3 );
2444 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
2445
2446 } else {
2447 /* break cycle */
2448 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
2449 emit_swapl_arg_regs ( dst1, dst2 );
2450 emit_swapl_arg_regs ( dst1, dst3 );
2451
2452 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
2453 emit_swapl_arg_regs ( dst1, dst3 );
2454 emit_swapl_arg_regs ( dst1, dst2 );
2455
2456 } else {
njne427a662002-10-02 11:08:25 +00002457 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00002458 }
2459 }
2460}
2461
2462static
2463void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2464 UInt src1, UInt src2,
2465 UInt dst1, UInt dst2)
2466{
2467 /* If either are lits, order doesn't matter */
2468 if (Literal == tagv[src1] || Literal == tagv[src2]) {
2469 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
2470 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
2471
2472 } else {
2473 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
2474 }
2475}
2476
2477static
2478void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
2479 UInt src1, UInt src2, UInt src3,
2480 UInt dst1, UInt dst2, UInt dst3)
2481{
2482 // SSS: fix this eventually -- make STOREV use two RealRegs?
2483 /* Not supporting literals for 3-arg C functions -- they're only used
2484 by STOREV which has 2 args */
2485 vg_assert(RealReg == tagv[src1] &&
2486 RealReg == tagv[src2] &&
2487 RealReg == tagv[src3]);
2488 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
2489 dst1, dst2, dst3 );
2490}
2491
2492/* Synthesise a call to a C function `fn' (which must be registered in
2493 baseBlock) doing all the reg saving and arg handling work.
2494
2495 WARNING: a UInstr should *not* be translated with synth_ccall followed
2496 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
2497 such behaviour and everything will fall over.
2498 */
2499void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
2500 Tag tagv[], Int ret_reg,
2501 RRegSet regs_live_before, RRegSet regs_live_after )
2502{
2503 Int i;
2504 Int stack_used = 0;
2505 Bool preserve_eax, preserve_ecx, preserve_edx;
2506
2507 vg_assert(0 <= regparms_n && regparms_n <= 3);
2508
2509 ccalls++;
2510
2511 /* If %e[acd]x is live before and after the C call, save/restore it.
2512 Unless the return values clobbers the reg; in this case we must not
2513 save/restore the reg, because the restore would clobber the return
2514 value. (Before and after the UInstr really constitute separate live
2515 ranges, but you miss this if you don't consider what happens during
2516 the UInstr.) */
2517# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00002518 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
2519 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00002520 ret_reg != realReg)
2521
2522 preserve_eax = PRESERVE_REG(R_EAX);
2523 preserve_ecx = PRESERVE_REG(R_ECX);
2524 preserve_edx = PRESERVE_REG(R_EDX);
2525
2526# undef PRESERVE_REG
2527
2528 /* Save caller-save regs as required */
2529 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
2530 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
2531 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
2532
2533 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
2534 is the number of args passed in regs (maximum 3 for GCC on x86). */
2535
2536 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00002537
njn25e49d8e72002-09-23 09:36:25 +00002538 /* First push stack args (RealRegs or Literals) in reverse order. */
2539 for (i = argc-1; i >= regparms_n; i--) {
2540 switch (tagv[i]) {
2541 case RealReg:
2542 VG_(emit_pushv_reg) ( 4, argv[i] );
2543 break;
2544 case Literal:
2545 /* Use short form of pushl if possible. */
2546 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
2547 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
2548 else
2549 VG_(emit_pushl_lit32)( argv[i] );
2550 break;
2551 default:
2552 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00002553 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00002554 }
2555 stack_used += 4;
2556 ccall_arg_setup_instrs++;
2557 }
njn6431be72002-07-28 09:53:34 +00002558
njn25e49d8e72002-09-23 09:36:25 +00002559 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
2560 If moving values between registers, be careful not to clobber any on
2561 the way. Happily we can use xchgl to swap registers.
2562 */
2563 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00002564
njn25e49d8e72002-09-23 09:36:25 +00002565 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
2566 case 3:
2567 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
2568 R_EAX, R_EDX, R_ECX );
2569 break;
njn6431be72002-07-28 09:53:34 +00002570
njn25e49d8e72002-09-23 09:36:25 +00002571 /* Less-tricky. Args passed in %eax and %edx. */
2572 case 2:
2573 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
2574 break;
2575
2576 /* Easy. Just move arg1 into %eax (if not already in there). */
2577 case 1:
2578 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
2579 break;
2580
2581 case 0:
2582 break;
2583
2584 default:
njne427a662002-10-02 11:08:25 +00002585 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00002586 }
2587
sewardjfa492d42002-12-08 18:20:01 +00002588 /* Call the function - may trash all flags */
2589 VG_(synth_call) ( False, VG_(helper_offset) ( fn ), False, FlagsEmpty, FlagsOSZACP );
njn25e49d8e72002-09-23 09:36:25 +00002590
2591 /* Clear any args from stack */
2592 if (0 != stack_used) {
2593 VG_(emit_add_lit_to_esp) ( stack_used );
2594 ccall_stack_clears++;
2595 }
2596
2597 /* Move return value into ret_reg if necessary and not already there */
2598 if (INVALID_REALREG != ret_reg) {
2599 ccall_retvals++;
2600 if (R_EAX != ret_reg) {
2601 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
2602 ccall_retval_movs++;
2603 }
2604 }
2605
2606 /* Restore live caller-save regs as required */
2607 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
2608 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
2609 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00002610}
sewardjde4a1d02002-03-22 01:27:54 +00002611
sewardj2e93c502002-04-12 11:12:52 +00002612static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002613{
sewardj2e93c502002-04-12 11:12:52 +00002614 switch (jmpkind) {
2615 case JmpBoring:
2616 break;
sewardj2e93c502002-04-12 11:12:52 +00002617 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00002618 break;
2619 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00002620 break;
2621 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00002622 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002623 break;
2624 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00002625 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00002626 break;
fitzhardingea02f8812003-12-18 09:06:09 +00002627 case JmpYield:
2628 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_YIELD, R_EBP );
2629 break;
sewardj2e93c502002-04-12 11:12:52 +00002630 default:
njne427a662002-10-02 11:08:25 +00002631 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00002632 }
2633}
2634
2635/* Jump to the next translation, by loading its original addr into
2636 %eax and returning to the scheduler. Signal special requirements
2637 by loading a special value into %ebp first.
2638*/
2639static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
2640{
sewardjfa492d42002-12-08 18:20:01 +00002641 maybe_emit_put_eflags(); /* save flags here */
sewardj2e93c502002-04-12 11:12:52 +00002642 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00002643 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00002644 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00002645 emit_ret();
2646}
2647
sewardj22854b92002-11-30 14:00:47 +00002648static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00002649
2650/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00002651static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00002652{
sewardjfa492d42002-12-08 18:20:01 +00002653 maybe_emit_put_eflags(); /* save flags here */
2654
njn25e49d8e72002-09-23 09:36:25 +00002655 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00002656
2657 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
2658 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
2659 emit_call_patchme();
2660 } else {
2661 load_ebp_from_JmpKind ( jmpkind );
2662 emit_ret();
2663 }
sewardjde4a1d02002-03-22 01:27:54 +00002664}
2665
2666
sewardj2370f3b2002-11-30 15:01:01 +00002667static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002668static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardj2370f3b2002-11-30 15:01:01 +00002669 Opcode opcode, Int size,
2670 UInt lit, Int reg );
2671
sewardjfa492d42002-12-08 18:20:01 +00002672static void synth_jcond_lit ( Condcode cond,
2673 Addr addr,
2674 Bool eax_trashable )
sewardjde4a1d02002-03-22 01:27:54 +00002675{
sewardj2370f3b2002-11-30 15:01:01 +00002676 UInt mask;
sewardjfa492d42002-12-08 18:20:01 +00002677 Bool simd;
sewardjbb6c1182002-12-12 23:54:47 +00002678 Int tgt, tgt2, tgt_jump;
sewardj2370f3b2002-11-30 15:01:01 +00002679
sewardja2113f92002-12-12 23:42:48 +00002680 VG_(init_target)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002681 VG_(init_target)(&tgt2);
2682 VG_(init_target)(&tgt_jump);
sewardjfa492d42002-12-08 18:20:01 +00002683
sewardjfa492d42002-12-08 18:20:01 +00002684 /* Ensure simulated %EFLAGS are up-to-date, by copying back %eflags
2685 if need be */
2686 maybe_emit_put_eflags();
2687 vg_assert(eflags_state == UPD_Both || eflags_state == UPD_Simd);
2688
2689 if (eflags_state == UPD_Both) {
2690 /* The flags are already set up, so we just use them as is. */
2691 simd = True;
sewardj2370f3b2002-11-30 15:01:01 +00002692 cond = invertCondition(cond);
2693 } else {
sewardj75f04932002-12-12 23:13:21 +00002694 Bool parity = False; /* test Z or P */
sewardjfa492d42002-12-08 18:20:01 +00002695
2696 /* The simd state contains the most recent version, so we emit a
2697 sequence to calculate the relevant condition directly out of
2698 the simd flags. This is much cheaper (on P3/P4/Athlon) than
2699 copying them back to the real flags via popf. Notice that
2700 some of these sequences trash %eax, but that should be free
2701 now since this is the end of a bb and therefore all regs are
2702 dead. */
2703 simd = False;
2704
2705 switch (cond) {
2706
sewardjbb6c1182002-12-12 23:54:47 +00002707 case CondLE: /* Z || S != O -> S || !P */
2708 case CondNLE: /* !Z && S == O -> !S && P */
sewardjfa492d42002-12-08 18:20:01 +00002709 vg_assert(eax_trashable);
2710
2711 VG_(emit_movv_offregmem_reg)
2712 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2713 /* eax == %EFLAGS */
2714
sewardjbb6c1182002-12-12 23:54:47 +00002715 VG_(emit_nonshiftopv_lit_reg)
2716 ( False, 4, AND, EFlagO|EFlagS|EFlagZ, R_EAX );
2717 /* eax just contains OF, SF and ZF */
sewardjfa492d42002-12-08 18:20:01 +00002718
sewardjbb6c1182002-12-12 23:54:47 +00002719 VG_(emit_shiftopv_lit_reg)( False, 4, ROR, 7, R_EAX );
2720 /* eax has OF and SF in lower 8 bits, and ZF in MSB */
sewardjfa492d42002-12-08 18:20:01 +00002721
sewardj09736622002-12-28 00:19:00 +00002722 /* actually set the real cpu flags, since ROR changes
2723 neither P nor Z */
2724 VG_(emit_nonshiftopv_reg_reg)( False, 4, OR, R_EAX, R_EAX );
2725
sewardjbb6c1182002-12-12 23:54:47 +00002726 if (cond == CondLE) {
2727 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002728 VG_(emit_jcondshort_target)(False, CondS, &tgt_jump, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002729 /* test OF != SF */
2730 cond = CondP;
2731 } else {
2732 /* test Z */
fitzhardinge462f4f92003-12-18 02:10:54 +00002733 VG_(emit_jcondshort_target)(False, CondS, &tgt2, JP_NONE);
sewardjbb6c1182002-12-12 23:54:47 +00002734 /* test OF == SF */
2735 cond = CondNP;
2736 }
sewardj2370f3b2002-11-30 15:01:01 +00002737 break;
2738
sewardjfa492d42002-12-08 18:20:01 +00002739 case CondL:
2740 case CondNL:
sewardjac3414b2002-12-10 23:44:17 +00002741 vg_assert(eax_trashable);
2742
2743 VG_(emit_movv_offregmem_reg)
2744 ( 4, VGOFF_(m_eflags) * 4, R_EBP, R_EAX );
2745 /* eax == %EFLAGS */
2746
sewardj75f04932002-12-12 23:13:21 +00002747 VG_(emit_shiftopv_lit_reg)( False, 4, SHR, 7, R_EAX );
2748 /* eax has OF and SF in lower byte */
sewardjac3414b2002-12-10 23:44:17 +00002749
sewardj75f04932002-12-12 23:13:21 +00002750 VG_(emit_testb_lit_reg) ( False, 0x11, R_EAX);
2751 /* PF = OF == SF */
sewardjac3414b2002-12-10 23:44:17 +00002752
sewardj09736622002-12-28 00:19:00 +00002753 /* Testing P now is OK since SHR sets it */
sewardj75f04932002-12-12 23:13:21 +00002754 if (cond == CondL) cond = CondP; else cond = CondNP;
2755 break;
sewardjfa492d42002-12-08 18:20:01 +00002756
2757 case CondB:
2758 case CondNB:
2759 mask = EFlagC; goto simple; /* C=1 */
2760
2761 case CondZ:
2762 case CondNZ:
2763 mask = EFlagZ; goto simple; /* Z=1 */
2764
2765 case CondBE:
2766 case CondNBE:
2767 mask = EFlagC | EFlagZ; goto simple; /* C=1 || Z=1 */
2768
2769 case CondS:
2770 case CondNS:
2771 mask = EFlagS; goto simple; /* S=1 */
2772
2773 case CondP:
sewardj06d3f8c2002-12-08 19:50:36 +00002774 case CondNP:
sewardjfa492d42002-12-08 18:20:01 +00002775 mask = EFlagP; goto simple; /* P=1 */
2776
sewardj39542072002-12-09 22:44:00 +00002777 case CondO:
2778 case CondNO:
2779 mask = EFlagO; goto simple; /* O=1 */
2780
sewardjfa492d42002-12-08 18:20:01 +00002781 default:
2782 VG_(printf)("synth_jcond_lit: unhandled simd case %d (%s)\n",
njn563f96f2003-02-03 11:17:46 +00002783 (Int)cond, VG_(name_UCondcode)(cond) );
sewardjfa492d42002-12-08 18:20:01 +00002784 VG_(core_panic)("synth_jcond_lit: unhandled simd case");
2785
2786 simple:
2787 VG_(new_emit)(False, False, FlagsOSZACP);
sewardj2370f3b2002-11-30 15:01:01 +00002788 if ((mask & 0xff) == mask) {
2789 VG_(emitB) ( 0xF6 ); /* Grp3 */
2790 VG_(emit_amode_offregmem_reg)(
2791 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
2792 VG_(emitB) (mask);
2793 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002794 VG_(printf)("\n\t\ttestb $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002795 mask, VGOFF_(m_eflags) * 4);
2796 } else {
sewardjfa492d42002-12-08 18:20:01 +00002797 /* all cond codes are in lower 16 bits */
2798 vg_assert((mask & 0xffff) == mask);
2799
2800 VG_(emitB) ( 0x66 );
sewardj2370f3b2002-11-30 15:01:01 +00002801 VG_(emitB) ( 0xF7 );
2802 VG_(emit_amode_offregmem_reg)(
2803 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
sewardjfa492d42002-12-08 18:20:01 +00002804 VG_(emitW) (mask);
sewardj2370f3b2002-11-30 15:01:01 +00002805 if (dis)
sewardjfa492d42002-12-08 18:20:01 +00002806 VG_(printf)("\n\t\ttestl $0x%x, %d(%%ebp)\n",
sewardj2370f3b2002-11-30 15:01:01 +00002807 mask, VGOFF_(m_eflags) * 4);
2808 }
2809
sewardj75f04932002-12-12 23:13:21 +00002810 cond = (parity ? CondP : CondZ) | (cond & 1);
sewardj2370f3b2002-11-30 15:01:01 +00002811 break;
2812 }
2813 }
2814
fitzhardinge462f4f92003-12-18 02:10:54 +00002815 VG_(emit_jcondshort_target) ( simd, cond, &tgt, JP_NONE );
sewardjbb6c1182002-12-12 23:54:47 +00002816
2817 VG_(target_forward)(&tgt_jump);
sewardj2e93c502002-04-12 11:12:52 +00002818 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002819
2820 VG_(target_forward)(&tgt);
sewardjbb6c1182002-12-12 23:54:47 +00002821 VG_(target_forward)(&tgt2);
sewardjde4a1d02002-03-22 01:27:54 +00002822}
2823
2824
sewardj2370f3b2002-11-30 15:01:01 +00002825
sewardjde4a1d02002-03-22 01:27:54 +00002826static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
2827{
sewardja2113f92002-12-12 23:42:48 +00002828 Int tgt;
2829
2830 VG_(init_target)(&tgt);
2831
sewardjfa492d42002-12-08 18:20:01 +00002832 VG_(emit_cmpl_zero_reg) ( False, reg );
sewardja2113f92002-12-12 23:42:48 +00002833
fitzhardinge462f4f92003-12-18 02:10:54 +00002834 VG_(emit_jcondshort_target) ( False, CondNZ, &tgt, JP_NONE );
sewardj2e93c502002-04-12 11:12:52 +00002835 synth_jmp_lit ( addr, JmpBoring );
sewardja2113f92002-12-12 23:42:48 +00002836
2837 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00002838}
2839
2840
2841static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
2842{
2843 /* Load the zero-extended literal into reg, at size l,
2844 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00002845 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002846}
2847
2848
2849static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
2850{
fitzhardinge98abfc72003-12-16 02:05:15 +00002851 switch (size & ~DO_BOUNDSCHECK) {
2852 case 4: emit_movv_regmem_reg ( size, reg1, reg2 ); break;
2853 case 2: VG_(emit_movzwl_regmem_reg) ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
2854 case 1: emit_movzbl_regmem_reg ( size & DO_BOUNDSCHECK, reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00002855 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002856 }
2857}
2858
2859
2860static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
2861{
fitzhardinge98abfc72003-12-16 02:05:15 +00002862 switch (size & ~DO_BOUNDSCHECK) {
njn25e49d8e72002-09-23 09:36:25 +00002863 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
fitzhardinge98abfc72003-12-16 02:05:15 +00002864 case 2: VG_(emit_movzwl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
2865 case 1: VG_(emit_movzbl_offregmem_reg) ( size & DO_BOUNDSCHECK, off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00002866 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002867 }
2868}
2869
2870
2871static void synth_mov_reg_offregmem ( Int size, Int reg,
2872 Int off, Int areg )
2873{
2874 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00002875 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
2876 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002877 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00002878 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00002879 }
2880 else {
njn25e49d8e72002-09-23 09:36:25 +00002881 VG_(emit_swapl_reg_EAX) ( reg );
2882 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
2883 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002884 }
2885 break;
njne427a662002-10-02 11:08:25 +00002886 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00002887 }
2888}
2889
2890
2891static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
2892{
2893 Int s1;
fitzhardinge98abfc72003-12-16 02:05:15 +00002894 switch (size & ~DO_BOUNDSCHECK) {
2895 case 4:
2896 case 2: emit_movv_reg_regmem ( size, reg1, reg2 ); break;
sewardjde4a1d02002-03-22 01:27:54 +00002897 case 1: if (reg1 < 4) {
fitzhardinge98abfc72003-12-16 02:05:15 +00002898 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002899 }
2900 else {
2901 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
2902 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2903 emit_swapl_reg_reg ( s1, reg1 );
fitzhardinge98abfc72003-12-16 02:05:15 +00002904 emit_movb_reg_regmem ( size & DO_BOUNDSCHECK, s1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002905 emit_swapl_reg_reg ( s1, reg1 );
2906 }
2907 break;
njne427a662002-10-02 11:08:25 +00002908 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00002909 }
2910}
2911
2912
sewardjf0f12aa2002-12-28 00:04:08 +00002913static void synth_unaryop_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002914 Opcode opcode, Int size,
2915 Int reg )
2916{
2917 /* NB! opcode is a uinstr opcode, not an x86 one! */
2918 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002919 case 4: VG_(emit_unaryopv_reg) ( simd_flags, 4, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002920 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002921 case 2: VG_(emit_unaryopv_reg) ( simd_flags, 2, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002922 break;
2923 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002924 VG_(emit_unaryopb_reg) ( simd_flags, opcode, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002925 } else {
njn25e49d8e72002-09-23 09:36:25 +00002926 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00002927 VG_(emit_unaryopb_reg) ( simd_flags, opcode, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00002928 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002929 }
2930 break;
njne427a662002-10-02 11:08:25 +00002931 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002932 }
2933}
2934
2935
2936
sewardjf0f12aa2002-12-28 00:04:08 +00002937static void synth_nonshiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00002938 Opcode opcode, Int size,
2939 Int reg1, Int reg2 )
2940{
2941 /* NB! opcode is a uinstr opcode, not an x86 one! */
2942 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00002943 case 4: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 4, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002944 break;
sewardjf0f12aa2002-12-28 00:04:08 +00002945 case 2: VG_(emit_nonshiftopv_reg_reg) ( simd_flags, 2, opcode, reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +00002946 break;
2947 case 1: { /* Horrible ... */
2948 Int s1, s2;
2949 /* Choose s1 and s2 to be x86 regs which we can talk about the
2950 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
2951 sure s1 != s2 and that neither of them equal either reg1 or
2952 reg2. Then use them as temporaries to make things work. */
2953 if (reg1 < 4 && reg2 < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00002954 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002955 break;
2956 }
2957 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
2958 if (reg1 >= 4 && reg2 < 4) {
2959 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002960 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, reg2);
sewardjde4a1d02002-03-22 01:27:54 +00002961 emit_swapl_reg_reg ( reg1, s1 );
2962 break;
2963 }
2964 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
2965 if (reg1 < 4 && reg2 >= 4) {
2966 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002967 emit_nonshiftopb_reg_reg(simd_flags, opcode, reg1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002968 emit_swapl_reg_reg ( reg2, s2 );
2969 break;
2970 }
2971 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
2972 emit_swapl_reg_reg ( reg1, s1 );
2973 emit_swapl_reg_reg ( reg2, s2 );
sewardjf0f12aa2002-12-28 00:04:08 +00002974 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s2);
sewardjde4a1d02002-03-22 01:27:54 +00002975 emit_swapl_reg_reg ( reg1, s1 );
2976 emit_swapl_reg_reg ( reg2, s2 );
2977 break;
2978 }
2979 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
2980 emit_swapl_reg_reg ( reg1, s1 );
sewardjf0f12aa2002-12-28 00:04:08 +00002981 emit_nonshiftopb_reg_reg(simd_flags, opcode, s1, s1);
sewardjde4a1d02002-03-22 01:27:54 +00002982 emit_swapl_reg_reg ( reg1, s1 );
2983 break;
2984 }
njne427a662002-10-02 11:08:25 +00002985 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002986 }
njne427a662002-10-02 11:08:25 +00002987 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00002988 }
2989}
2990
sewardja2c5a732002-12-15 03:10:42 +00002991#if 0
2992/* evidently unused */
sewardjfa492d42002-12-08 18:20:01 +00002993static void synth_nonshiftop_reg_offregmem (
sewardjf0f12aa2002-12-28 00:04:08 +00002994 Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00002995 Opcode opcode, Int size,
2996 Int off, Int areg, Int reg )
2997{
2998 switch (size) {
2999 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00003000 emit_nonshiftopv_reg_offregmem ( simd_flags, 4, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00003001 break;
3002 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00003003 emit_nonshiftopv_reg_offregmem ( simd_flags, 2, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00003004 break;
3005 case 1:
3006 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003007 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, reg );
sewardjfa492d42002-12-08 18:20:01 +00003008 } else {
3009 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003010 emit_nonshiftopb_reg_offregmem ( simd_flags, opcode, off, areg, R_AL );
sewardjfa492d42002-12-08 18:20:01 +00003011 VG_(emit_swapl_reg_EAX) ( reg );
3012 }
3013 break;
3014 default:
3015 VG_(core_panic)("synth_nonshiftop_reg_offregmem");
3016 }
3017}
sewardja2c5a732002-12-15 03:10:42 +00003018#endif
sewardjfa492d42002-12-08 18:20:01 +00003019
sewardjde4a1d02002-03-22 01:27:54 +00003020static void synth_nonshiftop_offregmem_reg (
sewardjf0f12aa2002-12-28 00:04:08 +00003021 Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003022 Opcode opcode, Int size,
3023 Int off, Int areg, Int reg )
3024{
3025 switch (size) {
3026 case 4:
sewardjf0f12aa2002-12-28 00:04:08 +00003027 emit_nonshiftopv_offregmem_reg ( simd_flags, 4, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003028 break;
3029 case 2:
sewardjf0f12aa2002-12-28 00:04:08 +00003030 emit_nonshiftopv_offregmem_reg ( simd_flags, 2, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003031 break;
3032 case 1:
3033 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003034 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003035 } else {
njn25e49d8e72002-09-23 09:36:25 +00003036 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003037 emit_nonshiftopb_offregmem_reg ( simd_flags, opcode, off, areg, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003038 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003039 }
3040 break;
3041 default:
njne427a662002-10-02 11:08:25 +00003042 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003043 }
3044}
3045
3046
sewardjf0f12aa2002-12-28 00:04:08 +00003047static void synth_nonshiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003048 Opcode opcode, Int size,
3049 UInt lit, Int reg )
3050{
3051 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003052 case 4: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003053 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003054 case 2: VG_(emit_nonshiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003055 break;
3056 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003057 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003058 } else {
njn25e49d8e72002-09-23 09:36:25 +00003059 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003060 emit_nonshiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003061 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003062 }
3063 break;
njne427a662002-10-02 11:08:25 +00003064 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003065 }
3066}
3067
sewardjf0f12aa2002-12-28 00:04:08 +00003068static void synth_nonshiftop_lit_offregmem ( Bool simd_flags,
sewardjfa492d42002-12-08 18:20:01 +00003069 Opcode opcode, Int size,
3070 UInt lit, Int off, Int regmem )
3071{
3072 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003073 case 4: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 4, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003074 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003075 case 2: VG_(emit_nonshiftopv_lit_offregmem) ( simd_flags, 2, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003076 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003077 case 1: emit_nonshiftopb_lit_offregmem ( simd_flags, opcode, lit, off, regmem );
sewardjfa492d42002-12-08 18:20:01 +00003078 break;
3079 default: VG_(core_panic)("synth_nonshiftop_lit_offregmem");
3080 }
3081}
3082
sewardjde4a1d02002-03-22 01:27:54 +00003083
jsgf5efa4fd2003-10-14 21:49:11 +00003084static void synth_mul_reg_reg ( Bool upd_cc,
3085 Opcode opcode, Int size,
3086 Int reg1, Int reg2 )
3087{
3088 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3089
3090 switch (size) {
3091 case 2:
3092 VG_(emitB)(0x66);
3093 /* FALLTHROUGH */
3094 case 4:
3095 VG_(emitB)(0x0F);
3096 VG_(emitB)(0xAF);
3097 VG_(emit_amode_ereg_greg)(reg1, reg2);
3098 break;
3099
3100 case 1:
3101 VG_(core_panic)("can't do byte mul");
3102 break;
3103 }
3104 if (dis)
3105 VG_(printf)("\n\t\timul%c\t%s, %s\n",
3106 nameISize(size),
3107 nameIReg(size, reg1),
3108 nameIReg(size, reg2));
3109}
3110
3111static void synth_mul_lit_reg ( Bool upd_cc,
3112 Opcode opcode, Int size,
3113 UInt lit, Int reg )
3114{
3115 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3116
3117 switch (size) {
3118 case 2:
3119 VG_(emitB)(0x66);
3120 /* FALLTHROUGH */
3121 case 4:
3122 VG_(emitB)(0x69);
3123 VG_(emit_amode_ereg_greg)(reg, 0);
3124 if (size == 2)
3125 VG_(emitW)(lit);
3126 else
3127 VG_(emitL)(lit);
3128 break;
3129
3130 case 1:
3131 VG_(core_panic)("can't do byte mul");
3132 break;
3133 }
3134 if (dis)
3135 VG_(printf)("\n\t\timul%c\t%d, %s\n",
3136 nameISize(size),
3137 lit,
3138 nameIReg(size, reg));
3139}
3140
3141static void synth_mul_offregmem_reg (
3142 Bool upd_cc,
3143 Opcode opcode, Int size,
3144 Int off, Int areg, Int reg )
3145{
3146 VG_(new_emit)(upd_cc, FlagsEmpty, FlagsOSZACP);
3147
3148 switch(size) {
3149 case 2:
3150 VG_(emitB)(0x66);
3151 /* FALLTHROUGH */
3152 case 4:
3153 VG_(emitB)(0x0F);
3154 VG_(emitB)(0xAF);
3155 VG_(emit_amode_offregmem_reg)(off, areg, reg);
3156 break;
3157
3158 case 1:
3159 VG_(core_panic)("can't do byte mul");
3160 }
3161
3162 if (dis)
3163 VG_(printf)("\n\t\timul%c\t0x%x(%s), %s\n",
3164 nameISize(size), off, nameIReg(4,areg),nameIReg(size,reg));
3165
3166}
3167
3168
sewardjde4a1d02002-03-22 01:27:54 +00003169static void synth_push_reg ( Int size, Int reg )
3170{
3171 switch (size) {
3172 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003173 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003174 break;
3175 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003176 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003177 break;
3178 /* Pray that we don't have to generate this really cruddy bit of
3179 code very often. Could do better, but can I be bothered? */
3180 case 1:
3181 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003182 VG_(emit_add_lit_to_esp)(-1);
3183 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003184 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00003185 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003186 break;
3187 default:
njne427a662002-10-02 11:08:25 +00003188 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003189 }
3190}
3191
3192
3193static void synth_pop_reg ( Int size, Int reg )
3194{
3195 switch (size) {
3196 case 4:
njn25e49d8e72002-09-23 09:36:25 +00003197 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003198 break;
3199 case 2:
njn25e49d8e72002-09-23 09:36:25 +00003200 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003201 break;
3202 case 1:
3203 /* Same comment as above applies. */
3204 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00003205 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003206 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00003207 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
3208 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00003209 break;
njne427a662002-10-02 11:08:25 +00003210 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003211 }
3212}
3213
3214
sewardjf0f12aa2002-12-28 00:04:08 +00003215static void synth_shiftop_reg_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003216 Opcode opcode, Int size,
3217 Int regs, Int regd )
3218{
3219 synth_push_reg ( size, regd );
3220 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardjde4a1d02002-03-22 01:27:54 +00003221 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003222 case 4: emit_shiftopv_cl_stack0 ( simd_flags, 4, opcode ); break;
3223 case 2: emit_shiftopv_cl_stack0 ( simd_flags, 2, opcode ); break;
3224 case 1: emit_shiftopb_cl_stack0 ( simd_flags, opcode ); break;
njne427a662002-10-02 11:08:25 +00003225 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003226 }
sewardjde4a1d02002-03-22 01:27:54 +00003227 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
3228 synth_pop_reg ( size, regd );
3229}
3230
3231
sewardjf0f12aa2002-12-28 00:04:08 +00003232static void synth_shiftop_lit_reg ( Bool simd_flags,
sewardjde4a1d02002-03-22 01:27:54 +00003233 Opcode opcode, Int size,
3234 UInt lit, Int reg )
3235{
3236 switch (size) {
sewardjf0f12aa2002-12-28 00:04:08 +00003237 case 4: VG_(emit_shiftopv_lit_reg) ( simd_flags, 4, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003238 break;
sewardjf0f12aa2002-12-28 00:04:08 +00003239 case 2: VG_(emit_shiftopv_lit_reg) ( simd_flags, 2, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003240 break;
3241 case 1: if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003242 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003243 } else {
njn25e49d8e72002-09-23 09:36:25 +00003244 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003245 emit_shiftopb_lit_reg ( simd_flags, opcode, lit, R_AL );
njn25e49d8e72002-09-23 09:36:25 +00003246 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003247 }
3248 break;
njne427a662002-10-02 11:08:25 +00003249 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00003250 }
3251}
3252
3253
sewardjf0f12aa2002-12-28 00:04:08 +00003254static void synth_setb_reg ( Bool simd, Int reg, Condcode cond )
sewardjde4a1d02002-03-22 01:27:54 +00003255{
sewardjde4a1d02002-03-22 01:27:54 +00003256 if (reg < 4) {
sewardjf0f12aa2002-12-28 00:04:08 +00003257 emit_setb_reg ( simd, reg, cond );
sewardjde4a1d02002-03-22 01:27:54 +00003258 } else {
njn25e49d8e72002-09-23 09:36:25 +00003259 VG_(emit_swapl_reg_EAX) ( reg );
sewardjf0f12aa2002-12-28 00:04:08 +00003260 emit_setb_reg ( simd, R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00003261 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00003262 }
3263}
3264
3265
sewardj3d7c9c82003-03-26 21:08:13 +00003266static void synth_MMX2_regmem ( Bool uses_flags, Bool sets_flags,
3267 UChar first_byte,
3268 UChar second_byte,
3269 Int ireg )
3270{
3271 emit_MMX2_regmem ( uses_flags, sets_flags,
3272 first_byte, second_byte, ireg );
3273}
3274
3275
sewardjca860012003-03-27 23:52:58 +00003276static void synth_MMX2_reg_to_mmxreg ( Bool uses_flags, Bool sets_flags,
3277 UChar first_byte,
3278 UChar second_byte,
3279 Int ireg )
3280{
3281 emit_MMX2_reg_to_mmxreg ( uses_flags, sets_flags,
3282 first_byte, second_byte, ireg );
3283}
3284
sewardjd1c9e432003-04-04 20:40:34 +00003285static void synth_MMX2_mmxreg_to_reg ( Bool uses_flags, Bool sets_flags,
3286 UChar first_byte,
3287 UChar second_byte,
3288 Int ireg )
3289{
3290 emit_MMX2_mmxreg_to_reg ( uses_flags, sets_flags,
3291 first_byte, second_byte, ireg );
3292}
3293
sewardj3d7c9c82003-03-26 21:08:13 +00003294static void synth_MMX2_no_mem ( Bool uses_flags, Bool sets_flags,
3295 UChar first_byte,
3296 UChar second_byte )
3297{
3298 emit_MMX2_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
3299}
3300
3301
sewardjca860012003-03-27 23:52:58 +00003302static void synth_MMX3_no_mem ( Bool uses_flags, Bool sets_flags,
3303 UChar first_byte,
3304 UChar second_byte,
3305 UChar third_byte )
3306{
3307 emit_MMX3_no_mem ( uses_flags, sets_flags,
3308 first_byte, second_byte, third_byte );
3309}
3310
3311
sewardj3d7c9c82003-03-26 21:08:13 +00003312static void synth_MMX1_no_mem ( Bool uses_flags, Bool sets_flags,
3313 UChar first_byte )
3314{
3315 emit_MMX1_no_mem ( uses_flags, sets_flags, first_byte );
3316}
3317
3318
sewardjfa492d42002-12-08 18:20:01 +00003319static void synth_fpu_regmem ( Bool uses_flags, Bool sets_flags,
3320 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003321 UChar second_byte_masked,
3322 Int reg )
3323{
sewardj3d7c9c82003-03-26 21:08:13 +00003324 emit_fpu_regmem ( uses_flags, sets_flags,
3325 first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003326}
3327
3328
sewardjfa492d42002-12-08 18:20:01 +00003329static void synth_fpu_no_mem ( Bool uses_flags, Bool sets_flags,
3330 UChar first_byte,
sewardjde4a1d02002-03-22 01:27:54 +00003331 UChar second_byte )
3332{
sewardjfa492d42002-12-08 18:20:01 +00003333 emit_fpu_no_mem ( uses_flags, sets_flags, first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00003334}
3335
3336
3337static void synth_movl_reg_reg ( Int src, Int dst )
3338{
3339 emit_movl_reg_reg ( src, dst );
3340}
3341
3342static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
3343{
sewardja2113f92002-12-12 23:42:48 +00003344 Int tgt;
3345
3346 VG_(init_target)(&tgt);
3347
fitzhardinge462f4f92003-12-18 02:10:54 +00003348 VG_(emit_jcondshort_target) ( True, invertCondition(cond), &tgt, JP_NONE);
sewardjde4a1d02002-03-22 01:27:54 +00003349 emit_movl_reg_reg ( src, dst );
sewardja2113f92002-12-12 23:42:48 +00003350
3351 VG_(target_forward)(&tgt);
sewardjde4a1d02002-03-22 01:27:54 +00003352}
3353
3354
sewardjde4a1d02002-03-22 01:27:54 +00003355/*----------------------------------------------------*/
3356/*--- Top level of the uinstr -> x86 translation. ---*/
3357/*----------------------------------------------------*/
3358
3359/* Return the byte offset from %ebp (ie, into baseBlock)
3360 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00003361static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
3362{
3363 if (tag == SpillNo) {
3364 vg_assert(size == 4);
3365 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
3366 return 4 * (value + VGOFF_(spillslots));
3367 }
3368 if (tag == ArchReg) {
3369 switch (value) {
3370 case R_EAX: return 4 * VGOFF_(m_eax);
3371 case R_ECX: return 4 * VGOFF_(m_ecx);
3372 case R_EDX: return 4 * VGOFF_(m_edx);
3373 case R_EBX: return 4 * VGOFF_(m_ebx);
3374 case R_ESP:
3375 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
3376 else return 4 * VGOFF_(m_esp);
3377 case R_EBP:
3378 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
3379 else return 4 * VGOFF_(m_ebp);
3380 case R_ESI:
3381 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
3382 else return 4 * VGOFF_(m_esi);
3383 case R_EDI:
3384 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
3385 else return 4 * VGOFF_(m_edi);
3386 }
3387 }
njne427a662002-10-02 11:08:25 +00003388 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00003389}
3390
sewardjde4a1d02002-03-22 01:27:54 +00003391static Int eflagsOffset ( void )
3392{
3393 return 4 * VGOFF_(m_eflags);
3394}
3395
sewardje1042472002-09-30 12:33:11 +00003396static Int segRegOffset ( UInt archregs )
3397{
3398 switch (archregs) {
3399 case R_CS: return 4 * VGOFF_(m_cs);
3400 case R_SS: return 4 * VGOFF_(m_ss);
3401 case R_DS: return 4 * VGOFF_(m_ds);
3402 case R_ES: return 4 * VGOFF_(m_es);
3403 case R_FS: return 4 * VGOFF_(m_fs);
3404 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00003405 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00003406 }
3407}
3408
njnf4ce3d32003-02-10 10:17:26 +00003409UInt VG_(get_archreg) ( UInt arch )
3410{
3411 switch (arch) {
3412 case R_EAX: return VG_(baseBlock)[ VGOFF_(m_eax) ];
3413 case R_ECX: return VG_(baseBlock)[ VGOFF_(m_ecx) ];
3414 case R_EDX: return VG_(baseBlock)[ VGOFF_(m_edx) ];
3415 case R_EBX: return VG_(baseBlock)[ VGOFF_(m_ebx) ];
3416 case R_ESP: return VG_(baseBlock)[ VGOFF_(m_esp) ];
3417 case R_EBP: return VG_(baseBlock)[ VGOFF_(m_ebp) ];
3418 case R_ESI: return VG_(baseBlock)[ VGOFF_(m_esi) ];
3419 case R_EDI: return VG_(baseBlock)[ VGOFF_(m_edi) ];
njna7b627d2003-07-22 10:50:41 +00003420 default: VG_(core_panic)( "get_archreg");
njnf4ce3d32003-02-10 10:17:26 +00003421 }
3422}
3423
3424UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch )
3425{
3426 ThreadState* tst;
3427
3428 vg_assert(VG_(is_valid_tid)(tid));
3429 tst = & VG_(threads)[tid];
3430
3431 switch (arch) {
3432 case R_EAX: return tst->m_eax;
3433 case R_ECX: return tst->m_ecx;
3434 case R_EDX: return tst->m_edx;
3435 case R_EBX: return tst->m_ebx;
3436 case R_ESP: return tst->m_esp;
3437 case R_EBP: return tst->m_ebp;
3438 case R_ESI: return tst->m_esi;
3439 case R_EDI: return tst->m_edi;
3440 default: VG_(core_panic)( "get_thread_archreg");
3441 }
3442}
3443
njnb93d1782003-02-03 12:03:22 +00003444/* Return the baseBlock index for the specified shadow register */
njn9b007f62003-04-07 14:40:25 +00003445static Int shadow_reg_index ( Int arch )
njnb93d1782003-02-03 12:03:22 +00003446{
3447 switch (arch) {
3448 case R_EAX: return VGOFF_(sh_eax);
3449 case R_ECX: return VGOFF_(sh_ecx);
3450 case R_EDX: return VGOFF_(sh_edx);
3451 case R_EBX: return VGOFF_(sh_ebx);
3452 case R_ESP: return VGOFF_(sh_esp);
3453 case R_EBP: return VGOFF_(sh_ebp);
3454 case R_ESI: return VGOFF_(sh_esi);
3455 case R_EDI: return VGOFF_(sh_edi);
3456 default: VG_(core_panic)( "shadow_reg_index");
3457 }
3458}
sewardjde4a1d02002-03-22 01:27:54 +00003459
njn25e49d8e72002-09-23 09:36:25 +00003460/* Return the byte offset from %ebp (ie, into baseBlock)
3461 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00003462Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00003463{
njnb93d1782003-02-03 12:03:22 +00003464 return 4 * shadow_reg_index ( arch );
sewardjde4a1d02002-03-22 01:27:54 +00003465}
3466
njn4ba5a792002-09-30 10:23:54 +00003467Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00003468{
3469 return 4 * VGOFF_(sh_eflags);
3470}
3471
njnb93d1782003-02-03 12:03:22 +00003472/* Accessing shadow arch. registers */
3473UInt VG_(get_shadow_archreg) ( UInt archreg )
3474{
3475 return VG_(baseBlock)[ shadow_reg_index(archreg) ];
3476}
3477
3478void VG_(set_shadow_archreg) ( UInt archreg, UInt val )
3479{
3480 VG_(baseBlock)[ shadow_reg_index(archreg) ] = val;
3481}
3482
njnd3040452003-05-19 15:04:06 +00003483void VG_(set_shadow_eflags) ( UInt val )
3484{
3485 VG_(baseBlock)[ VGOFF_(sh_eflags) ] = val;
3486}
3487
njnf4ce3d32003-02-10 10:17:26 +00003488UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg )
3489{
3490 ThreadState* tst;
3491
3492 vg_assert(VG_(is_valid_tid)(tid));
3493 tst = & VG_(threads)[tid];
3494
3495 switch (archreg) {
3496 case R_EAX: return tst->sh_eax;
3497 case R_ECX: return tst->sh_ecx;
3498 case R_EDX: return tst->sh_edx;
3499 case R_EBX: return tst->sh_ebx;
3500 case R_ESP: return tst->sh_esp;
3501 case R_EBP: return tst->sh_ebp;
3502 case R_ESI: return tst->sh_esi;
3503 case R_EDI: return tst->sh_edi;
3504 default: VG_(core_panic)( "get_thread_shadow_archreg");
3505 }
3506}
3507
3508void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val )
3509{
3510 ThreadState* tst;
3511
3512 vg_assert(VG_(is_valid_tid)(tid));
3513 tst = & VG_(threads)[tid];
3514
3515 switch (archreg) {
3516 case R_EAX: tst->sh_eax = val; break;
3517 case R_ECX: tst->sh_ecx = val; break;
3518 case R_EDX: tst->sh_edx = val; break;
3519 case R_EBX: tst->sh_ebx = val; break;
3520 case R_ESP: tst->sh_esp = val; break;
3521 case R_EBP: tst->sh_ebp = val; break;
3522 case R_ESI: tst->sh_esi = val; break;
3523 case R_EDI: tst->sh_edi = val; break;
3524 default: VG_(core_panic)( "set_thread_shadow_archreg");
3525 }
3526}
3527
njnb93d1782003-02-03 12:03:22 +00003528Addr VG_(shadow_archreg_address) ( UInt archreg )
3529{
3530 return (Addr) & VG_(baseBlock)[ shadow_reg_index(archreg) ];
3531}
sewardjde4a1d02002-03-22 01:27:54 +00003532
sewardjde4a1d02002-03-22 01:27:54 +00003533static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
3534{
3535 if (sz_src == 1 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003536 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 24, reg );
3537 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003538 }
3539 else if (sz_src == 2 && sz_dst == 4) {
sewardjfa492d42002-12-08 18:20:01 +00003540 VG_(emit_shiftopv_lit_reg) ( False, 4, SHL, 16, reg );
3541 VG_(emit_shiftopv_lit_reg) ( False, 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003542 }
3543 else if (sz_src == 1 && sz_dst == 2) {
sewardjfa492d42002-12-08 18:20:01 +00003544 VG_(emit_shiftopv_lit_reg) ( False, 2, SHL, 8, reg );
3545 VG_(emit_shiftopv_lit_reg) ( False, 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00003546 }
3547 else
njne427a662002-10-02 11:08:25 +00003548 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00003549}
3550
3551
sewardjde4a1d02002-03-22 01:27:54 +00003552/*----------------------------------------------------*/
3553/*--- Generate code for a single UInstr. ---*/
3554/*----------------------------------------------------*/
3555
sewardj478335c2002-10-05 02:44:47 +00003556static __inline__
3557Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00003558{
3559 return (u->flags_w != FlagsEmpty);
3560}
3561
sewardjfa492d42002-12-08 18:20:01 +00003562static __inline__
3563Bool readFlagUse ( UInstr* u )
3564{
3565 /* If the UInstr writes some flags but not all, then we still need
3566 to consider it as reading flags so that the unchanged values are
3567 passed through properly. (D is special) */
3568 return
3569 (u->flags_r != FlagsEmpty) ||
3570 (u->flags_w != FlagsEmpty && u->flags_w != FlagsOSZACP) ;
3571}
3572
sewardj478335c2002-10-05 02:44:47 +00003573static __inline__
3574Bool anyFlagUse ( UInstr* u )
3575{
sewardjfa492d42002-12-08 18:20:01 +00003576 return readFlagUse(u) || writeFlagUse(u);
sewardj478335c2002-10-05 02:44:47 +00003577}
3578
3579
sewardjb91ae7f2003-04-29 23:50:00 +00003580/* *fplive==True indicates that the simulated machine's FPU/SSE state is in
3581 the real machine's cpu. If so we need to be very careful not to trash it.
3582 If FPU/SSE state is live and we deem it necessary to copy it back to
3583 the simulated machine's FPU/SSE state, we do so. The final state of
3584 fpliveness is returned. In short we _must_ do put_sse_state if
sewardj1b7d8022002-11-30 12:35:42 +00003585 there is any chance at all that the code generated for a UInstr
sewardjb91ae7f2003-04-29 23:50:00 +00003586 will change the real FPU/MMX/SSE/SSE2 state.
sewardj1b7d8022002-11-30 12:35:42 +00003587*/
sewardjb5ff83e2002-12-01 19:40:49 +00003588static void emitUInstr ( UCodeBlock* cb, Int i,
3589 RRegSet regs_live_before,
3590 /* Running state, which we update. */
sewardjb91ae7f2003-04-29 23:50:00 +00003591 Bool* sselive, /* True<==>FPU/SSE
3592 state in real FPU */
sewardjb5ff83e2002-12-01 19:40:49 +00003593 Addr* orig_eip, /* previous curr_eip, or zero */
3594 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00003595{
njn25e49d8e72002-09-23 09:36:25 +00003596 Int old_emitted_code_used;
3597 UInstr* u = &cb->instrs[i];
3598
sewardjde4a1d02002-03-22 01:27:54 +00003599 if (dis)
njn4ba5a792002-09-30 10:23:54 +00003600 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00003601
njn25e49d8e72002-09-23 09:36:25 +00003602 old_emitted_code_used = emitted_code_used;
3603
sewardjde4a1d02002-03-22 01:27:54 +00003604 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00003605 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00003606
sewardjb5ff83e2002-12-01 19:40:49 +00003607 case INCEIP:
3608 /* Advance %EIP some small amount. */
3609 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00003610
sewardjb5ff83e2002-12-01 19:40:49 +00003611 if (*orig_eip == 0 /* we don't know what the old value was */
3612 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
3613 /* We have to update all 32 bits of the value. */
3614 VG_(emit_movv_lit_offregmem)(
3615 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
3616 } else {
3617 /* Cool! we only need to update lowest 8 bits */
3618 VG_(emit_movb_lit_offregmem)(
3619 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00003620 }
njn25e49d8e72002-09-23 09:36:25 +00003621
sewardjb5ff83e2002-12-01 19:40:49 +00003622 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00003623 break;
sewardjde4a1d02002-03-22 01:27:54 +00003624
3625 case LEA1: {
3626 vg_assert(u->tag1 == RealReg);
3627 vg_assert(u->tag2 == RealReg);
3628 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
3629 break;
3630 }
3631
3632 case LEA2: {
3633 vg_assert(u->tag1 == RealReg);
3634 vg_assert(u->tag2 == RealReg);
3635 vg_assert(u->tag3 == RealReg);
3636 emit_lea_sib_reg ( u->lit32, u->extra4b,
3637 u->val1, u->val2, u->val3 );
3638 break;
3639 }
3640
3641 case WIDEN: {
3642 vg_assert(u->tag1 == RealReg);
3643 if (u->signed_widen) {
3644 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
3645 } else {
3646 /* no need to generate any code. */
3647 }
3648 break;
3649 }
3650
sewardjde4a1d02002-03-22 01:27:54 +00003651 case STORE: {
3652 vg_assert(u->tag1 == RealReg);
3653 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003654 synth_mov_reg_memreg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003655 break;
3656 }
3657
3658 case LOAD: {
3659 vg_assert(u->tag1 == RealReg);
3660 vg_assert(u->tag2 == RealReg);
fitzhardinge98abfc72003-12-16 02:05:15 +00003661 synth_mov_regmem_reg ( u->size | DO_BOUNDSCHECK, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00003662 break;
3663 }
3664
sewardjde4a1d02002-03-22 01:27:54 +00003665 case GET: {
3666 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
3667 vg_assert(u->tag2 == RealReg);
3668 synth_mov_offregmem_reg (
3669 u->size,
3670 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3671 R_EBP,
3672 u->val2
3673 );
3674 break;
3675 }
3676
3677 case PUT: {
3678 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
3679 vg_assert(u->tag1 == RealReg);
njn9b007f62003-04-07 14:40:25 +00003680 synth_mov_reg_offregmem (
3681 u->size,
3682 u->val1,
3683 spillOrArchOffset( u->size, u->tag2, u->val2 ),
3684 R_EBP
3685 );
sewardjde4a1d02002-03-22 01:27:54 +00003686 break;
3687 }
3688
sewardje1042472002-09-30 12:33:11 +00003689 case GETSEG: {
3690 vg_assert(u->tag1 == ArchRegS);
3691 vg_assert(u->tag2 == RealReg);
3692 vg_assert(u->size == 2);
3693 synth_mov_offregmem_reg (
3694 4,
3695 segRegOffset( u->val1 ),
3696 R_EBP,
3697 u->val2
3698 );
3699 break;
3700 }
3701
3702 case PUTSEG: {
3703 vg_assert(u->tag1 == RealReg);
3704 vg_assert(u->tag2 == ArchRegS);
3705 vg_assert(u->size == 2);
3706 synth_mov_reg_offregmem (
3707 4,
3708 u->val1,
3709 segRegOffset( u->val2 ),
3710 R_EBP
3711 );
3712 break;
3713 }
3714
sewardjde4a1d02002-03-22 01:27:54 +00003715 case GETF: {
3716 vg_assert(u->size == 2 || u->size == 4);
3717 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003718
3719 /* This complexity is because the D(irection) flag is stored
3720 separately from the rest of EFLAGS. */
3721
3722 /* We're only fetching from the Simd state, so make sure it's
3723 up to date. */
3724 maybe_emit_put_eflags();
3725
3726 /* get D in u->val1 (== 1 or -1) */
3727 synth_mov_offregmem_reg (u->size, 4*VGOFF_(m_dflag), R_EBP, u->val1);
3728
3729 /* u->val1 &= EFlagD (== 0 or EFlagD) */
3730 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3731
3732 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3733 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3734 eflagsOffset(), R_EBP);
3735
3736 /* EFLAGS &= ~EFlagD (make sure there's no surprises) */
3737 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3738 eflagsOffset(), R_EBP);
3739
3740 /* u->val1 |= EFLAGS (EFLAGS & EflagD == 0) */
3741 synth_nonshiftop_offregmem_reg(False, OR, u->size,
3742 eflagsOffset(), R_EBP, u->val1);
sewardjde4a1d02002-03-22 01:27:54 +00003743 break;
3744 }
3745
3746 case PUTF: {
3747 vg_assert(u->size == 2 || u->size == 4);
3748 vg_assert(u->tag1 == RealReg);
sewardjfa492d42002-12-08 18:20:01 +00003749
3750 /* When putting a value into EFLAGS, this generates the
3751 correct value for m_dflag (-1 or 1), and clears the D bit
3752 in EFLAGS. */
3753
3754 /* We're updating the whole flag state, so the old state
3755 doesn't matter; make sure that the new simulated state
3756 will be fetched when needed. */
3757 eflags_state = UPD_Simd;
3758
3759 /* store EFLAGS (with D) */
3760 synth_mov_reg_offregmem (u->size, u->val1, eflagsOffset(), R_EBP);
3761
3762 /* u->val1 &= EFlagD */
3763 synth_nonshiftop_lit_reg(False, AND, u->size, EFlagD, u->val1);
3764
3765 /* computes: u->val1 = (u->val1 == 0) ? 1 : -1 */
3766 synth_unaryop_reg(False, NEG, u->size, u->val1);
3767 synth_nonshiftop_reg_reg(False, SBB, u->size, u->val1, u->val1);
3768 synth_nonshiftop_lit_reg(False, SBB, u->size, -1, u->val1);
3769
3770 /* save D */
3771 synth_mov_reg_offregmem(u->size, u->val1, 4*VGOFF_(m_dflag), R_EBP);
3772
3773 /* EFLAGS &= ~EFlagD */
3774 synth_nonshiftop_lit_offregmem(False, AND, u->size, ~EFlagD,
3775 eflagsOffset(), R_EBP);
sewardjde4a1d02002-03-22 01:27:54 +00003776 break;
3777 }
3778
3779 case MOV: {
3780 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
3781 vg_assert(u->tag2 == RealReg);
3782 switch (u->tag1) {
3783 case RealReg: vg_assert(u->size == 4);
3784 if (u->val1 != u->val2)
3785 synth_movl_reg_reg ( u->val1, u->val2 );
3786 break;
3787 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
3788 break;
njne427a662002-10-02 11:08:25 +00003789 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00003790 }
3791 break;
3792 }
3793
sewardje1042472002-09-30 12:33:11 +00003794 case USESEG: {
3795 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
3796 ones. */
sewardjd077f532002-09-30 21:52:50 +00003797 UInt argv[] = { u->val1, u->val2 };
3798 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00003799 UInt ret_reg = u->val2;
3800
3801 vg_assert(u->tag1 == RealReg);
3802 vg_assert(u->tag2 == RealReg);
3803 vg_assert(u->size == 0);
3804
sewardjb91ae7f2003-04-29 23:50:00 +00003805 if (*sselive) {
3806 emit_put_sse_state();
3807 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003808 }
3809
sewardje1042472002-09-30 12:33:11 +00003810 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
3811 2, /* args */
3812 0, /* regparms_n */
3813 argv, tagv,
3814 ret_reg, regs_live_before, u->regs_live_after );
3815 break;
3816 }
3817
jsgf5efa4fd2003-10-14 21:49:11 +00003818 case MUL: {
3819 vg_assert(u->tag2 == RealReg);
3820
3821 switch(u->tag1) {
3822 case Literal:
3823 synth_mul_lit_reg(anyFlagUse(u),
3824 u->opcode, u->size, u->lit32, u->val2);
3825 break;
3826 case RealReg:
3827 synth_mul_reg_reg(anyFlagUse(u),
3828 u->opcode, u->size, u->val1, u->val2);
3829 break;
3830 case ArchReg:
3831 synth_mul_offregmem_reg(anyFlagUse(u),
3832 u->opcode, u->size,
3833 spillOrArchOffset(u->size, u->tag1, u->val1),
3834 R_EBP, u->val2);
3835 break;
3836
3837 default: VG_(core_panic)("emitUInstr:MUL");
3838 }
3839 break;
3840 }
3841
sewardj478335c2002-10-05 02:44:47 +00003842 case SBB:
3843 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00003844 case XOR:
3845 case OR:
3846 case AND:
3847 case SUB:
sewardj478335c2002-10-05 02:44:47 +00003848 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00003849 vg_assert(u->tag2 == RealReg);
3850 switch (u->tag1) {
3851 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003852 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003853 u->opcode, u->size, u->lit32, u->val2 );
3854 break;
3855 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003856 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003857 u->opcode, u->size, u->val1, u->val2 );
3858 break;
3859 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00003860 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003861 u->opcode, u->size,
3862 spillOrArchOffset( u->size, u->tag1, u->val1 ),
3863 R_EBP,
3864 u->val2 );
3865 break;
njne427a662002-10-02 11:08:25 +00003866 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003867 }
3868 break;
3869 }
3870
sewardj478335c2002-10-05 02:44:47 +00003871 case RCR:
3872 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00003873 case ROR:
3874 case ROL:
3875 case SAR:
3876 case SHR:
3877 case SHL: {
3878 vg_assert(u->tag2 == RealReg);
3879 switch (u->tag1) {
3880 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00003881 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003882 u->opcode, u->size, u->lit32, u->val2 );
3883 break;
3884 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00003885 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00003886 u->opcode, u->size, u->val1, u->val2 );
3887 break;
njne427a662002-10-02 11:08:25 +00003888 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00003889 }
3890 break;
3891 }
3892
3893 case INC:
3894 case DEC:
3895 case NEG:
3896 case NOT:
3897 vg_assert(u->tag1 == RealReg);
3898 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00003899 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003900 break;
3901
3902 case BSWAP:
3903 vg_assert(u->tag1 == RealReg);
3904 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00003905 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00003906 emit_bswapl_reg ( u->val1 );
3907 break;
3908
3909 case CMOV:
3910 vg_assert(u->tag1 == RealReg);
3911 vg_assert(u->tag2 == RealReg);
3912 vg_assert(u->cond != CondAlways);
3913 vg_assert(u->size == 4);
3914 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
3915 break;
3916
3917 case JMP: {
3918 vg_assert(u->tag2 == NoValue);
3919 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb91ae7f2003-04-29 23:50:00 +00003920 if (*sselive) {
3921 emit_put_sse_state();
3922 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003923 }
sewardjde4a1d02002-03-22 01:27:54 +00003924 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00003925 switch (u->tag1) {
3926 case RealReg:
3927 synth_jmp_reg ( u->val1, u->jmpkind );
3928 break;
3929 case Literal:
3930 synth_jmp_lit ( u->lit32, u->jmpkind );
3931 break;
3932 default:
njne427a662002-10-02 11:08:25 +00003933 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003934 break;
sewardjde4a1d02002-03-22 01:27:54 +00003935 }
3936 } else {
sewardj2e93c502002-04-12 11:12:52 +00003937 switch (u->tag1) {
3938 case RealReg:
njne427a662002-10-02 11:08:25 +00003939 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00003940 break;
3941 case Literal:
3942 vg_assert(u->jmpkind == JmpBoring);
sewardjfa492d42002-12-08 18:20:01 +00003943 /* %eax had better not be live since synth_jcond_lit
3944 trashes it in some circumstances. If that turns
3945 out to be a problem we can get synth_jcond_lit to
3946 push/pop it when it is live. */
3947 vg_assert(! IS_RREG_LIVE(VG_(realreg_to_rank)(R_EAX),
3948 u->regs_live_after));
3949 synth_jcond_lit ( u->cond, u->lit32, True );
sewardj2e93c502002-04-12 11:12:52 +00003950 break;
3951 default:
njne427a662002-10-02 11:08:25 +00003952 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00003953 break;
sewardjde4a1d02002-03-22 01:27:54 +00003954 }
3955 }
3956 break;
3957 }
3958
3959 case JIFZ:
3960 vg_assert(u->tag1 == RealReg);
3961 vg_assert(u->tag2 == Literal);
3962 vg_assert(u->size == 4);
sewardjb91ae7f2003-04-29 23:50:00 +00003963 if (*sselive) {
3964 emit_put_sse_state();
3965 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003966 }
sewardjde4a1d02002-03-22 01:27:54 +00003967 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
3968 break;
3969
sewardjde4a1d02002-03-22 01:27:54 +00003970 case PUSH:
3971 vg_assert(u->tag1 == RealReg);
3972 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003973 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003974 break;
3975
3976 case POP:
3977 vg_assert(u->tag1 == RealReg);
3978 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00003979 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00003980 break;
3981
3982 case CALLM:
3983 vg_assert(u->tag1 == Lit16);
3984 vg_assert(u->tag2 == NoValue);
3985 vg_assert(u->size == 0);
sewardjb91ae7f2003-04-29 23:50:00 +00003986 if (*sselive) {
3987 emit_put_sse_state();
3988 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00003989 }
sewardjfa492d42002-12-08 18:20:01 +00003990 /* Call to a helper which is pretending to be a real CPU
3991 instruction (and therefore operates on Real flags and
3992 registers) */
3993 VG_(synth_call) ( False, u->val1,
3994 True, u->flags_r, u->flags_w );
sewardjde4a1d02002-03-22 01:27:54 +00003995 break;
3996
njn25e49d8e72002-09-23 09:36:25 +00003997 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00003998 /* If you change this, remember to change USESEG above, since
3999 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00004000 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
4001 ones. */
4002 UInt argv[] = { u->val1, u->val2, u->val3 };
4003 UInt tagv[] = { RealReg, RealReg, RealReg };
4004 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
4005
4006 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
4007 else vg_assert(u->tag1 == NoValue);
4008 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
4009 else vg_assert(u->tag2 == NoValue);
4010 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
4011 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00004012 vg_assert(u->size == 0);
4013
sewardjb91ae7f2003-04-29 23:50:00 +00004014 if (*sselive) {
4015 emit_put_sse_state();
4016 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004017 }
njn25e49d8e72002-09-23 09:36:25 +00004018 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
4019 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00004020 break;
njn25e49d8e72002-09-23 09:36:25 +00004021 }
sewardje1042472002-09-30 12:33:11 +00004022
sewardjde4a1d02002-03-22 01:27:54 +00004023 case CLEAR:
4024 vg_assert(u->tag1 == Lit16);
4025 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00004026 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00004027 break;
4028
4029 case CC2VAL:
4030 vg_assert(u->tag1 == RealReg);
4031 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00004032 vg_assert(VG_(any_flag_use)(u));
sewardjf0f12aa2002-12-28 00:04:08 +00004033 synth_setb_reg ( True, u->val1, u->cond );
sewardjde4a1d02002-03-22 01:27:54 +00004034 break;
4035
sewardjde4a1d02002-03-22 01:27:54 +00004036 case FPU_R:
4037 case FPU_W:
4038 vg_assert(u->tag1 == Lit16);
4039 vg_assert(u->tag2 == RealReg);
sewardjb91ae7f2003-04-29 23:50:00 +00004040 if (!(*sselive)) {
4041 emit_get_sse_state();
4042 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00004043 }
sewardjfa492d42002-12-08 18:20:01 +00004044 synth_fpu_regmem ( u->flags_r, u->flags_w,
4045 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00004046 u->val1 & 0xFF,
4047 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00004048 break;
4049
4050 case FPU:
4051 vg_assert(u->tag1 == Lit16);
4052 vg_assert(u->tag2 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004053 if (!(*sselive)) {
4054 emit_get_sse_state();
4055 *sselive = True;
sewardj1b7d8022002-11-30 12:35:42 +00004056 }
sewardjfa492d42002-12-08 18:20:01 +00004057 synth_fpu_no_mem ( u->flags_r, u->flags_w,
4058 (u->val1 >> 8) & 0xFF,
sewardjde4a1d02002-03-22 01:27:54 +00004059 u->val1 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +00004060 break;
4061
sewardj3d7c9c82003-03-26 21:08:13 +00004062 case MMX2_MemWr:
4063 case MMX2_MemRd:
sewardjd1c9e432003-04-04 20:40:34 +00004064 vg_assert(u->size == 4 || u->size == 8);
sewardj3d7c9c82003-03-26 21:08:13 +00004065 vg_assert(u->tag1 == Lit16);
4066 vg_assert(u->tag2 == RealReg);
sewardjca860012003-03-27 23:52:58 +00004067 vg_assert(u->tag3 == NoValue);
sewardj3d7c9c82003-03-26 21:08:13 +00004068 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004069 if (!(*sselive)) {
4070 emit_get_sse_state();
4071 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004072 }
4073 synth_MMX2_regmem ( u->flags_r, u->flags_w,
4074 (u->val1 >> 8) & 0xFF,
4075 u->val1 & 0xFF,
4076 u->val2 );
4077 break;
4078
sewardj4fbe6e92003-06-15 21:54:34 +00004079 case MMX2_ERegRd:
sewardjca860012003-03-27 23:52:58 +00004080 vg_assert(u->tag1 == Lit16);
4081 vg_assert(u->tag2 == RealReg);
4082 vg_assert(u->tag3 == NoValue);
4083 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004084 if (!(*sselive)) {
4085 emit_get_sse_state();
4086 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004087 }
4088 synth_MMX2_reg_to_mmxreg ( u->flags_r, u->flags_w,
4089 (u->val1 >> 8) & 0xFF,
4090 u->val1 & 0xFF,
4091 u->val2 );
4092 break;
4093
sewardj4fbe6e92003-06-15 21:54:34 +00004094 case MMX2_ERegWr:
sewardjd1c9e432003-04-04 20:40:34 +00004095 vg_assert(u->tag1 == Lit16);
4096 vg_assert(u->tag2 == RealReg);
4097 vg_assert(u->tag3 == NoValue);
4098 vg_assert(!anyFlagUse(u));
sewardjb91ae7f2003-04-29 23:50:00 +00004099 if (!(*sselive)) {
4100 emit_get_sse_state();
4101 *sselive = True;
sewardjd1c9e432003-04-04 20:40:34 +00004102 }
4103 synth_MMX2_mmxreg_to_reg ( u->flags_r, u->flags_w,
4104 (u->val1 >> 8) & 0xFF,
4105 u->val1 & 0xFF,
4106 u->val2 );
4107 break;
4108
sewardj3d7c9c82003-03-26 21:08:13 +00004109 case MMX1:
4110 vg_assert(u->tag1 == Lit16);
4111 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004112 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004113 if (!(*sselive)) {
4114 emit_get_sse_state();
4115 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004116 }
4117 synth_MMX1_no_mem ( u->flags_r, u->flags_w,
4118 u->val1 & 0xFF );
4119 break;
4120
4121 case MMX2:
4122 vg_assert(u->tag1 == Lit16);
4123 vg_assert(u->tag2 == NoValue);
sewardjca860012003-03-27 23:52:58 +00004124 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004125 if (!(*sselive)) {
4126 emit_get_sse_state();
4127 *sselive = True;
sewardj3d7c9c82003-03-26 21:08:13 +00004128 }
4129 synth_MMX2_no_mem ( u->flags_r, u->flags_w,
4130 (u->val1 >> 8) & 0xFF,
4131 u->val1 & 0xFF );
4132 break;
4133
sewardjca860012003-03-27 23:52:58 +00004134 case MMX3:
4135 vg_assert(u->tag1 == Lit16);
4136 vg_assert(u->tag2 == Lit16);
4137 vg_assert(u->tag3 == NoValue);
sewardjb91ae7f2003-04-29 23:50:00 +00004138 if (!(*sselive)) {
4139 emit_get_sse_state();
4140 *sselive = True;
sewardjca860012003-03-27 23:52:58 +00004141 }
4142 synth_MMX3_no_mem ( u->flags_r, u->flags_w,
4143 (u->val1 >> 8) & 0xFF,
4144 u->val1 & 0xFF,
4145 u->val2 & 0xFF );
4146 break;
4147
sewardjfebaa3b2003-05-25 01:07:34 +00004148 case SSE2a_MemWr:
4149 case SSE2a_MemRd:
nethercoteb1affa82004-01-19 19:14:18 +00004150 vg_assert(u->size == 4 || u->size == 8
4151 || u->size == 16 || u->size == 512);
sewardjfebaa3b2003-05-25 01:07:34 +00004152 vg_assert(u->tag1 == Lit16);
4153 vg_assert(u->tag2 == Lit16);
4154 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004155 if (!(*sselive)) {
4156 emit_get_sse_state();
4157 *sselive = True;
4158 }
4159 emit_SSE2a ( u->flags_r, u->flags_w,
4160 (u->val1 >> 8) & 0xFF,
4161 u->val1 & 0xFF,
4162 u->val2 & 0xFF,
4163 u->val3 );
4164 break;
4165
nethercoteb1affa82004-01-19 19:14:18 +00004166 case SSE2g_RegWr:
4167 vg_assert(u->size == 4);
4168 vg_assert(u->tag1 == Lit16);
4169 vg_assert(u->tag2 == Lit16);
4170 vg_assert(u->tag3 == RealReg);
4171 vg_assert(!anyFlagUse(u));
4172 if (!(*sselive)) {
4173 emit_get_sse_state();
4174 *sselive = True;
4175 }
4176 emit_SSE2g ( u->flags_r, u->flags_w,
4177 (u->val1 >> 8) & 0xFF,
4178 u->val1 & 0xFF,
4179 u->val2 & 0xFF,
4180 u->val3 );
4181 break;
4182
4183 case SSE2g1_RegWr:
4184 vg_assert(u->size == 4);
4185 vg_assert(u->tag1 == Lit16);
4186 vg_assert(u->tag2 == Lit16);
4187 vg_assert(u->tag3 == RealReg);
4188 vg_assert(!anyFlagUse(u));
4189 if (!(*sselive)) {
4190 emit_get_sse_state();
4191 *sselive = True;
4192 }
4193 emit_SSE2g1 ( u->flags_r, u->flags_w,
4194 (u->val1 >> 8) & 0xFF,
4195 u->val1 & 0xFF,
4196 u->val2 & 0xFF,
4197 u->lit32 & 0xFF,
4198 u->val3 );
4199 break;
4200
4201 case SSE2e1_RegRd:
4202 vg_assert(u->size == 2);
4203 vg_assert(u->tag1 == Lit16);
4204 vg_assert(u->tag2 == Lit16);
4205 vg_assert(u->tag3 == RealReg);
4206 vg_assert(!anyFlagUse(u));
4207 if (!(*sselive)) {
4208 emit_get_sse_state();
4209 *sselive = True;
4210 }
4211 emit_SSE2e1 ( u->flags_r, u->flags_w,
4212 (u->val1 >> 8) & 0xFF,
4213 u->val1 & 0xFF,
4214 u->val2 & 0xFF,
4215 u->lit32 & 0xFF,
4216 u->val3 );
4217 break;
4218
sewardj9dd209f2003-06-18 23:30:52 +00004219 case SSE2a1_MemRd:
nethercote1018bdd2004-02-11 23:33:29 +00004220 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardj9dd209f2003-06-18 23:30:52 +00004221 vg_assert(u->tag1 == Lit16);
4222 vg_assert(u->tag2 == Lit16);
4223 vg_assert(u->tag3 == RealReg);
4224 vg_assert(!anyFlagUse(u));
4225 if (!(*sselive)) {
4226 emit_get_sse_state();
4227 *sselive = True;
4228 }
4229 emit_SSE2a1 ( u->flags_r, u->flags_w,
4230 (u->val1 >> 8) & 0xFF,
4231 u->val1 & 0xFF,
4232 (u->val2 >> 8) & 0xFF,
4233 u->val2 & 0xFF,
4234 u->val3 );
4235 break;
4236
sewardjfebaa3b2003-05-25 01:07:34 +00004237 case SSE3a_MemWr:
4238 case SSE3a_MemRd:
sewardjde8aecf2003-05-27 00:46:28 +00004239 vg_assert(u->size == 4 || u->size == 8 || u->size == 16);
sewardjfebaa3b2003-05-25 01:07:34 +00004240 vg_assert(u->tag1 == Lit16);
4241 vg_assert(u->tag2 == Lit16);
4242 vg_assert(u->tag3 == RealReg);
sewardjfebaa3b2003-05-25 01:07:34 +00004243 if (!(*sselive)) {
4244 emit_get_sse_state();
4245 *sselive = True;
4246 }
4247 emit_SSE3a ( u->flags_r, u->flags_w,
4248 (u->val1 >> 8) & 0xFF,
4249 u->val1 & 0xFF,
4250 (u->val2 >> 8) & 0xFF,
4251 u->val2 & 0xFF,
4252 u->val3 );
4253 break;
4254
sewardjabf8bf82003-06-15 22:28:05 +00004255 case SSE3e_RegWr:
sewardj4fbe6e92003-06-15 21:54:34 +00004256 case SSE3e_RegRd:
sewardj02af6bc2003-06-12 00:56:06 +00004257 case SSE3g_RegWr:
sewardjfebaa3b2003-05-25 01:07:34 +00004258 vg_assert(u->size == 4);
4259 vg_assert(u->tag1 == Lit16);
4260 vg_assert(u->tag2 == Lit16);
4261 vg_assert(u->tag3 == RealReg);
4262 vg_assert(!anyFlagUse(u));
4263 if (!(*sselive)) {
4264 emit_get_sse_state();
4265 *sselive = True;
4266 }
sewardjabf8bf82003-06-15 22:28:05 +00004267 if (u->opcode==SSE3e_RegRd || u->opcode==SSE3e_RegWr) {
4268 emit_SSE3e ( u->flags_r, u->flags_w,
4269 (u->val1 >> 8) & 0xFF,
4270 u->val1 & 0xFF,
4271 (u->val2 >> 8) & 0xFF,
4272 u->val2 & 0xFF,
4273 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004274 } else {
sewardjabf8bf82003-06-15 22:28:05 +00004275 emit_SSE3g ( u->flags_r, u->flags_w,
4276 (u->val1 >> 8) & 0xFF,
4277 u->val1 & 0xFF,
4278 (u->val2 >> 8) & 0xFF,
4279 u->val2 & 0xFF,
4280 u->val3 );
sewardj8f33ba62003-06-14 12:00:45 +00004281 }
sewardjfebaa3b2003-05-25 01:07:34 +00004282 break;
4283
sewardjb31b06d2003-06-13 00:26:02 +00004284 case SSE3g1_RegWr:
4285 vg_assert(u->size == 4);
4286 vg_assert(u->tag1 == Lit16);
4287 vg_assert(u->tag2 == Lit16);
4288 vg_assert(u->tag3 == RealReg);
4289 vg_assert(!anyFlagUse(u));
4290 if (!(*sselive)) {
4291 emit_get_sse_state();
4292 *sselive = True;
4293 }
sewardjabf8bf82003-06-15 22:28:05 +00004294 emit_SSE3g1 ( u->flags_r, u->flags_w,
4295 (u->val1 >> 8) & 0xFF,
4296 u->val1 & 0xFF,
4297 (u->val2 >> 8) & 0xFF,
4298 u->val2 & 0xFF,
4299 u->lit32 & 0xFF,
4300 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004301 break;
4302
sewardj4fbe6e92003-06-15 21:54:34 +00004303 case SSE3e1_RegRd:
sewardjb31b06d2003-06-13 00:26:02 +00004304 vg_assert(u->size == 2);
4305 vg_assert(u->tag1 == Lit16);
4306 vg_assert(u->tag2 == Lit16);
4307 vg_assert(u->tag3 == RealReg);
4308 vg_assert(!anyFlagUse(u));
4309 if (!(*sselive)) {
4310 emit_get_sse_state();
4311 *sselive = True;
4312 }
sewardjabf8bf82003-06-15 22:28:05 +00004313 emit_SSE3e1 ( u->flags_r, u->flags_w,
4314 (u->val1 >> 8) & 0xFF,
4315 u->val1 & 0xFF,
4316 (u->val2 >> 8) & 0xFF,
4317 u->val2 & 0xFF,
4318 u->lit32 & 0xFF,
4319 u->val3 );
sewardjb31b06d2003-06-13 00:26:02 +00004320 break;
4321
sewardj77d30a22003-10-19 08:18:52 +00004322 case SSE3a1_MemRd:
nethercoteb1affa82004-01-19 19:14:18 +00004323 vg_assert(u->size == 8 || u->size == 16);
sewardj77d30a22003-10-19 08:18:52 +00004324 vg_assert(u->tag1 == Lit16);
4325 vg_assert(u->tag2 == Lit16);
4326 vg_assert(u->tag3 == RealReg);
4327 vg_assert(!anyFlagUse(u));
4328 if (!(*sselive)) {
4329 emit_get_sse_state();
4330 *sselive = True;
4331 }
4332 emit_SSE3a1 ( u->flags_r, u->flags_w,
4333 (u->val1 >> 8) & 0xFF,
4334 u->val1 & 0xFF,
4335 (u->val2 >> 8) & 0xFF,
4336 u->val2 & 0xFF,
nethercoteb1affa82004-01-19 19:14:18 +00004337 u->lit32 & 0xFF,
sewardj77d30a22003-10-19 08:18:52 +00004338 u->val3 );
4339 break;
4340
sewardja453fb02003-06-14 13:22:36 +00004341 case SSE5:
4342 vg_assert(u->size == 0);
4343 vg_assert(u->tag1 == Lit16);
4344 vg_assert(u->tag2 == Lit16);
4345 vg_assert(u->tag3 == Lit16);
4346 vg_assert(!anyFlagUse(u));
4347 if (!(*sselive)) {
4348 emit_get_sse_state();
4349 *sselive = True;
4350 }
4351 emit_SSE5 ( u->flags_r, u->flags_w,
4352 (u->val1 >> 8) & 0xFF,
4353 u->val1 & 0xFF,
4354 (u->val2 >> 8) & 0xFF,
4355 u->val2 & 0xFF,
4356 u->val3 & 0xFF );
4357 break;
4358
sewardjfebaa3b2003-05-25 01:07:34 +00004359 case SSE4:
4360 vg_assert(u->size == 0);
4361 vg_assert(u->tag1 == Lit16);
4362 vg_assert(u->tag2 == Lit16);
4363 vg_assert(u->tag3 == NoValue);
sewardj8f33ba62003-06-14 12:00:45 +00004364 vg_assert(u->flags_r == FlagsEmpty);
sewardjfebaa3b2003-05-25 01:07:34 +00004365 if (!(*sselive)) {
4366 emit_get_sse_state();
4367 *sselive = True;
4368 }
4369 emit_SSE4 ( u->flags_r, u->flags_w,
4370 (u->val1 >> 8) & 0xFF,
4371 u->val1 & 0xFF,
4372 (u->val2 >> 8) & 0xFF,
4373 u->val2 & 0xFF );
4374 break;
4375
sewardja60be0e2003-05-26 08:47:27 +00004376 case SSE3:
4377 vg_assert(u->size == 0);
4378 vg_assert(u->tag1 == Lit16);
4379 vg_assert(u->tag2 == Lit16);
4380 vg_assert(u->tag3 == NoValue);
sewardj77d30a22003-10-19 08:18:52 +00004381 vg_assert(!readFlagUse(u));
sewardja60be0e2003-05-26 08:47:27 +00004382 if (!(*sselive)) {
4383 emit_get_sse_state();
4384 *sselive = True;
4385 }
4386 emit_SSE3 ( u->flags_r, u->flags_w,
4387 (u->val1 >> 8) & 0xFF,
4388 u->val1 & 0xFF,
4389 u->val2 & 0xFF );
4390 break;
4391
sewardje3891fa2003-06-15 03:13:48 +00004392 case SSE3ag_MemRd_RegWr:
4393 vg_assert(u->size == 4 || u->size == 8);
4394 vg_assert(u->tag1 == RealReg);
4395 vg_assert(u->tag2 == RealReg);
4396 vg_assert(u->tag3 == NoValue);
4397 vg_assert(!anyFlagUse(u));
4398 if (!(*sselive)) {
4399 emit_get_sse_state();
4400 *sselive = True;
4401 }
4402 emit_SSE3ag_MemRd_RegWr ( u->flags_r, u->flags_w,
4403 (u->lit32 >> 24) & 0xFF,
4404 (u->lit32 >> 16) & 0xFF,
4405 (u->lit32 >> 8) & 0xFF,
4406 u->val1, u->val2 );
4407 break;
4408
sewardjde4a1d02002-03-22 01:27:54 +00004409 default:
sewardj1b7d8022002-11-30 12:35:42 +00004410 if (VG_(needs).extended_UCode) {
sewardjb91ae7f2003-04-29 23:50:00 +00004411 if (*sselive) {
4412 emit_put_sse_state();
4413 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004414 }
njn4ba5a792002-09-30 10:23:54 +00004415 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00004416 } else {
njn25e49d8e72002-09-23 09:36:25 +00004417 VG_(printf)("\nError:\n"
4418 " unhandled opcode: %u. Perhaps "
4419 " VG_(needs).extended_UCode should be set?\n",
4420 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00004421 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00004422 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00004423 }
sewardjde4a1d02002-03-22 01:27:54 +00004424 }
4425
sewardjb91ae7f2003-04-29 23:50:00 +00004426 if (0 && (*sselive)) {
4427 emit_put_sse_state();
4428 *sselive = False;
sewardj1b7d8022002-11-30 12:35:42 +00004429 }
4430
njn25e49d8e72002-09-23 09:36:25 +00004431 /* Update UInstr histogram */
4432 vg_assert(u->opcode < 100);
4433 histogram[u->opcode].counts++;
4434 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00004435}
4436
4437
4438/* Emit x86 for the ucode in cb, returning the address of the
4439 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00004440UChar* VG_(emit_code) ( UCodeBlock* cb,
4441 Int* nbytes,
4442 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00004443{
4444 Int i;
njn25e49d8e72002-09-23 09:36:25 +00004445 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb91ae7f2003-04-29 23:50:00 +00004446 Bool sselive;
sewardjb5ff83e2002-12-01 19:40:49 +00004447 Addr orig_eip, curr_eip;
sewardja2113f92002-12-12 23:42:48 +00004448 Int tgt;
4449
sewardjfa492d42002-12-08 18:20:01 +00004450 reset_state();
sewardjde4a1d02002-03-22 01:27:54 +00004451
njn25e49d8e72002-09-23 09:36:25 +00004452 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00004453
fitzhardinge462f4f92003-12-18 02:10:54 +00004454 /* Generate subl $1, VG_(dispatch_ctr) and drop into dispatch if we hit
sewardj22854b92002-11-30 14:00:47 +00004455 zero. We have to do this regardless of whether we're t-chaining
fitzhardinge462f4f92003-12-18 02:10:54 +00004456 or not. (The ia32 optimisation guide recommends sub over dec.) */
sewardja2113f92002-12-12 23:42:48 +00004457 VG_(init_target)(&tgt);
sewardjfa492d42002-12-08 18:20:01 +00004458 VG_(new_emit)(False, FlagsEmpty, FlagsOSZAP);
fitzhardinge462f4f92003-12-18 02:10:54 +00004459 VG_(emitB) (0x83); /* subl */
4460 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 5);
4461 VG_(emitB) (0x01);
4462
sewardj22854b92002-11-30 14:00:47 +00004463 if (dis)
fitzhardinge462f4f92003-12-18 02:10:54 +00004464 VG_(printf)("\n\t\tsubl $1, (%p)\n", &VG_(dispatch_ctr));
4465
4466 VG_(emit_jcondshort_target)(False, CondNZ, &tgt, JP_TAKEN);
sewardj22854b92002-11-30 14:00:47 +00004467 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
4468 emit_ret();
sewardja2113f92002-12-12 23:42:48 +00004469 VG_(target_forward)(&tgt);
sewardj22854b92002-11-30 14:00:47 +00004470
sewardjb5ff83e2002-12-01 19:40:49 +00004471 /* Set up running state. */
sewardjb91ae7f2003-04-29 23:50:00 +00004472 sselive = False;
sewardjfa492d42002-12-08 18:20:01 +00004473 orig_eip = cb->orig_eip; /* we know EIP is up to date on BB entry */
sewardjb5ff83e2002-12-01 19:40:49 +00004474 curr_eip = cb->orig_eip;
4475 vg_assert(curr_eip != 0); /* otherwise the incremental updating
4476 algorithm gets messed up. */
sewardjb5ff83e2002-12-01 19:40:49 +00004477 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00004478 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00004479 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00004480 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00004481
sewardjde4a1d02002-03-22 01:27:54 +00004482 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00004483 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00004484 if (!sane) {
4485 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00004486 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00004487 }
4488 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00004489 emitUInstr( cb, i, regs_live_before,
sewardjb91ae7f2003-04-29 23:50:00 +00004490 &sselive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00004491 }
njn25e49d8e72002-09-23 09:36:25 +00004492 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00004493 }
njn25e49d8e72002-09-23 09:36:25 +00004494 if (dis) VG_(printf)("\n");
sewardjb91ae7f2003-04-29 23:50:00 +00004495 vg_assert(!sselive); /* SSE state must be saved by end of BB */
sewardjfa492d42002-12-08 18:20:01 +00004496 vg_assert(eflags_state != UPD_Real); /* flags can't just be in CPU */
sewardjde4a1d02002-03-22 01:27:54 +00004497
sewardj22854b92002-11-30 14:00:47 +00004498 if (j != NULL) {
4499 vg_assert(jumpidx <= VG_MAX_JUMPS);
4500 for(i = 0; i < jumpidx; i++)
4501 j[i] = jumps[i];
4502 }
4503
sewardjde4a1d02002-03-22 01:27:54 +00004504 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00004505 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00004506 *nbytes = emitted_code_used;
4507 return emitted_code;
4508}
4509
njn25e49d8e72002-09-23 09:36:25 +00004510#undef dis
4511
sewardjde4a1d02002-03-22 01:27:54 +00004512/*--------------------------------------------------------------------*/
4513/*--- end vg_from_ucode.c ---*/
4514/*--------------------------------------------------------------------*/