blob: 242de5a93d72cb50c11df4db13cdd2e68a54b7d4 [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
11 Copyright (C) 2000-2002 Julian Seward
12 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
68static UChar* emitted_code;
69static Int emitted_code_used;
70static Int emitted_code_size;
71
sewardj22854b92002-11-30 14:00:47 +000072/* offset (in bytes into the basic block) */
73static UShort jumps[VG_MAX_JUMPS];
74static Int jumpidx;
75
njn25e49d8e72002-09-23 09:36:25 +000076/* Statistics about C functions called from generated code. */
77static UInt ccalls = 0;
78static UInt ccall_reg_saves = 0;
79static UInt ccall_args = 0;
80static UInt ccall_arg_setup_instrs = 0;
81static UInt ccall_stack_clears = 0;
82static UInt ccall_retvals = 0;
83static UInt ccall_retval_movs = 0;
84
85/* Statistics about frequency of each UInstr */
86typedef
87 struct {
88 UInt counts;
89 UInt size;
90 } Histogram;
91
92/* Automatically zeroed because it's static. */
93static Histogram histogram[100];
94
95void VG_(print_ccall_stats)(void)
96{
97 VG_(message)(Vg_DebugMsg,
98 " ccalls: %u C calls, %u%% saves+restores avoided"
99 " (%d bytes)",
100 ccalls,
101 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
102 ((ccalls*3) - ccall_reg_saves)*2);
103 VG_(message)(Vg_DebugMsg,
104 " %u args, avg 0.%d setup instrs each (%d bytes)",
105 ccall_args,
106 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
107 (ccall_args - ccall_arg_setup_instrs)*2);
108 VG_(message)(Vg_DebugMsg,
109 " %d%% clear the stack (%d bytes)",
110 (UInt)(ccall_stack_clears/(double)ccalls*100),
111 (ccalls - ccall_stack_clears)*3);
112 VG_(message)(Vg_DebugMsg,
113 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
114 ccall_retvals,
115 ( ccall_retvals == 0
116 ? 100
117 : 100-(UInt)(ccall_retval_movs /
118 (double)ccall_retvals*100)),
119 (ccall_retvals-ccall_retval_movs)*2);
120}
121
122void VG_(print_UInstr_histogram)(void)
123{
124 Int i, j;
125 UInt total_counts = 0;
126 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000127
njn25e49d8e72002-09-23 09:36:25 +0000128 for (i = 0; i < 100; i++) {
129 total_counts += histogram[i].counts;
130 total_size += histogram[i].size;
131 }
132
133 VG_(printf)("-- UInstr frequencies -----------\n");
134 for (i = 0; i < 100; i++) {
135 if (0 != histogram[i].counts) {
136
137 UInt count_pc =
138 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
139 UInt size_pc =
140 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
141 UInt avg_size =
142 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
143
144 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000145 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000146 histogram[i].counts, count_pc,
147 avg_size, size_pc);
148
149 for (j = 0; j < size_pc; j++) VG_(printf)("O");
150 VG_(printf)("\n");
151
152 } else {
153 vg_assert(0 == histogram[i].size);
154 }
155 }
156
157 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
158}
159
sewardjde4a1d02002-03-22 01:27:54 +0000160static void expandEmittedCode ( void )
161{
162 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000163 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000164 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
165 for (i = 0; i < emitted_code_size; i++)
166 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000167 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000168 emitted_code = tmp;
169 emitted_code_size *= 2;
170}
171
njn25e49d8e72002-09-23 09:36:25 +0000172/* Local calls will be inlined, cross-module ones not */
173__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000174{
175 if (dis) {
176 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
177 }
178 if (emitted_code_used == emitted_code_size)
179 expandEmittedCode();
180
181 emitted_code[emitted_code_used] = (UChar)b;
182 emitted_code_used++;
183}
184
njn25e49d8e72002-09-23 09:36:25 +0000185__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000186{
njn25e49d8e72002-09-23 09:36:25 +0000187 VG_(emitB) ( (l) & 0x000000FF );
188 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000189}
190
njn25e49d8e72002-09-23 09:36:25 +0000191__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000192{
njn25e49d8e72002-09-23 09:36:25 +0000193 VG_(emitB) ( (l) & 0x000000FF );
194 VG_(emitB) ( (l >> 8) & 0x000000FF );
195 VG_(emitB) ( (l >> 16) & 0x000000FF );
196 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000197}
198
njn4ba5a792002-09-30 10:23:54 +0000199__inline__ void VG_(new_emit) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000200{
201 if (dis)
202 VG_(printf)("\t %4d: ", emitted_code_used );
203}
204
sewardjde4a1d02002-03-22 01:27:54 +0000205
206/*----------------------------------------------------*/
207/*--- Addressing modes ---*/
208/*----------------------------------------------------*/
209
210static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
211{
212 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
213}
214
215static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
216{
217 Int shift;
218 switch (scale) {
219 case 1: shift = 0; break;
220 case 2: shift = 1; break;
221 case 4: shift = 2; break;
222 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000223 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000224 }
225 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
226}
227
228static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
229{
230 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000231 VG_(emitB) ( mkModRegRM(0, reg, 5) );
232 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000233}
234
235static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
236{
237 /* (regmem), reg */
238 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000239 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000240 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000241 VG_(emitB) ( mkModRegRM(1, reg, 5) );
242 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000243 } else {
njn25e49d8e72002-09-23 09:36:25 +0000244 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000245 }
246}
247
njn25e49d8e72002-09-23 09:36:25 +0000248void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000249{
250 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000251 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000252 if (off < -128 || off > 127) {
253 /* Use a large offset */
254 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000255 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
256 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000257 } else {
258 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000259 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
260 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000261 }
262}
263
264static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
265 Int regindex, Int reg )
266{
267 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000268 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000269 if (off < -128 || off > 127) {
270 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000271 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
272 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
273 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000274 } else {
275 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000276 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
277 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
278 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000279 }
280}
281
njn25e49d8e72002-09-23 09:36:25 +0000282void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000283{
284 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000285 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000286}
287
288static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
289{
290 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000291 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000292}
293
294
295/*----------------------------------------------------*/
296/*--- Opcode translation ---*/
297/*----------------------------------------------------*/
298
299static __inline__ Int mkGrp1opcode ( Opcode opc )
300{
301 switch (opc) {
302 case ADD: return 0;
303 case OR: return 1;
304 case ADC: return 2;
305 case SBB: return 3;
306 case AND: return 4;
307 case SUB: return 5;
308 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000309 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000310 }
311}
312
313static __inline__ Int mkGrp2opcode ( Opcode opc )
314{
315 switch (opc) {
316 case ROL: return 0;
317 case ROR: return 1;
318 case RCL: return 2;
319 case RCR: return 3;
320 case SHL: return 4;
321 case SHR: return 5;
322 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000323 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000324 }
325}
326
327static __inline__ Int mkGrp3opcode ( Opcode opc )
328{
329 switch (opc) {
330 case NOT: return 2;
331 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000332 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000333 }
334}
335
336static __inline__ Int mkGrp4opcode ( Opcode opc )
337{
338 switch (opc) {
339 case INC: return 0;
340 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000341 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000342 }
343}
344
345static __inline__ Int mkGrp5opcode ( Opcode opc )
346{
347 switch (opc) {
348 case CALLM: return 2;
349 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000350 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000351 }
352}
353
354static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
355{
356 switch (opc) {
357 case ADD: return 0x00;
358 case ADC: return 0x10;
359 case AND: return 0x20;
360 case XOR: return 0x30;
361 case OR: return 0x08;
362 case SBB: return 0x18;
363 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000364 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000365 }
366}
367
368/*----------------------------------------------------*/
369/*--- v-size (4, or 2 with OSO) insn emitters ---*/
370/*----------------------------------------------------*/
371
njn25e49d8e72002-09-23 09:36:25 +0000372void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000373{
njn4ba5a792002-09-30 10:23:54 +0000374 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000375 if (sz == 2) VG_(emitB) ( 0x66 );
376 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
377 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000378 if (dis)
379 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
380 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
381}
382
njn25e49d8e72002-09-23 09:36:25 +0000383void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000384{
njn4ba5a792002-09-30 10:23:54 +0000385 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000386 if (sz == 2) VG_(emitB) ( 0x66 );
387 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
388 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000389 if (dis)
390 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
391 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
392}
393
394static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
395{
njn4ba5a792002-09-30 10:23:54 +0000396 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000397 if (sz == 2) VG_(emitB) ( 0x66 );
398 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000399 emit_amode_regmem_reg ( reg1, reg2 );
400 if (dis)
401 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
402 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
403}
404
405static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
406{
njn4ba5a792002-09-30 10:23:54 +0000407 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000408 if (sz == 2) VG_(emitB) ( 0x66 );
409 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000410 emit_amode_regmem_reg ( reg2, reg1 );
411 if (dis)
412 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
413 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
414}
415
njn25e49d8e72002-09-23 09:36:25 +0000416void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000417{
njn4ba5a792002-09-30 10:23:54 +0000418 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000419 if (sz == 2) VG_(emitB) ( 0x66 );
420 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
421 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000422 if (dis)
423 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
424 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
425}
426
njn25e49d8e72002-09-23 09:36:25 +0000427void VG_(emit_nonshiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000428{
njn4ba5a792002-09-30 10:23:54 +0000429 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000430 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000431 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
432 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000433 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
434 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
435 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000436 } else {
njn25e49d8e72002-09-23 09:36:25 +0000437 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
438 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
439 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000440 }
441 if (dis)
442 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000443 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000444 lit, nameIReg(sz,reg));
445}
446
njn25e49d8e72002-09-23 09:36:25 +0000447void VG_(emit_shiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000448{
njn4ba5a792002-09-30 10:23:54 +0000449 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000450 if (sz == 2) VG_(emitB) ( 0x66 );
451 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
452 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
453 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000454 if (dis)
455 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000456 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000457 lit, nameIReg(sz,reg));
458}
459
460static void emit_shiftopv_cl_stack0 ( Int sz, Opcode opc )
461{
njn4ba5a792002-09-30 10:23:54 +0000462 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000463 if (sz == 2) VG_(emitB) ( 0x66 );
464 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
465 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
466 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
467 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000468 if (dis)
469 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000470 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000471}
472
473static void emit_shiftopb_cl_stack0 ( Opcode opc )
474{
njn4ba5a792002-09-30 10:23:54 +0000475 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000476 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
477 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
478 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
479 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000480 if (dis)
481 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000482 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000483}
484
485static void emit_nonshiftopv_offregmem_reg ( Int sz, Opcode opc,
486 Int off, Int areg, Int reg )
487{
njn4ba5a792002-09-30 10:23:54 +0000488 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000489 if (sz == 2) VG_(emitB) ( 0x66 );
490 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
491 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000492 if (dis)
493 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000494 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000495 off, nameIReg(4,areg), nameIReg(sz,reg));
496}
497
njn25e49d8e72002-09-23 09:36:25 +0000498void VG_(emit_nonshiftopv_reg_reg) ( Int sz, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000499 Int reg1, Int reg2 )
500{
njn4ba5a792002-09-30 10:23:54 +0000501 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000502 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000503# if 0
504 /* Perfectly correct, but the GNU assembler uses the other form.
505 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000506 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
507 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000508# else
njn25e49d8e72002-09-23 09:36:25 +0000509 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000510 emit_amode_greg_ereg ( reg1, reg2 );
511# endif
512 if (dis)
513 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000514 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000515 nameIReg(sz,reg1), nameIReg(sz,reg2));
516}
517
njn25e49d8e72002-09-23 09:36:25 +0000518void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000519{
520 if (lit == 0) {
njn25e49d8e72002-09-23 09:36:25 +0000521 VG_(emit_nonshiftopv_reg_reg) ( sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000522 return;
523 }
njn4ba5a792002-09-30 10:23:54 +0000524 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000525 if (sz == 2) VG_(emitB) ( 0x66 );
526 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
527 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000528 if (dis)
529 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
530 nameISize(sz), lit, nameIReg(sz,reg));
531}
532
njn25e49d8e72002-09-23 09:36:25 +0000533void VG_(emit_unaryopv_reg) ( Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000534{
njn4ba5a792002-09-30 10:23:54 +0000535 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000536 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000537 switch (opc) {
538 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000539 VG_(emitB) ( 0xF7 );
540 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000541 if (dis)
542 VG_(printf)( "\n\t\tneg%c\t%s\n",
543 nameISize(sz), nameIReg(sz,reg));
544 break;
545 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000546 VG_(emitB) ( 0xF7 );
547 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000548 if (dis)
549 VG_(printf)( "\n\t\tnot%c\t%s\n",
550 nameISize(sz), nameIReg(sz,reg));
551 break;
552 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000553 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000554 if (dis)
555 VG_(printf)( "\n\t\tdec%c\t%s\n",
556 nameISize(sz), nameIReg(sz,reg));
557 break;
558 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000559 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000560 if (dis)
561 VG_(printf)( "\n\t\tinc%c\t%s\n",
562 nameISize(sz), nameIReg(sz,reg));
563 break;
564 default:
njne427a662002-10-02 11:08:25 +0000565 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000566 }
567}
568
njn25e49d8e72002-09-23 09:36:25 +0000569void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000570{
njn4ba5a792002-09-30 10:23:54 +0000571 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000572 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000574 } else {
575 vg_assert(sz == 4);
576 }
njn25e49d8e72002-09-23 09:36:25 +0000577 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000578 if (dis)
579 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
580}
581
njn25e49d8e72002-09-23 09:36:25 +0000582void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000583{
njn4ba5a792002-09-30 10:23:54 +0000584 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000585 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000586 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000587 } else {
588 vg_assert(sz == 4);
589 }
njn25e49d8e72002-09-23 09:36:25 +0000590 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000591 if (dis)
592 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
593}
594
njn25e49d8e72002-09-23 09:36:25 +0000595void VG_(emit_pushl_lit32) ( UInt int32 )
596{
njn4ba5a792002-09-30 10:23:54 +0000597 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000598 VG_(emitB) ( 0x68 );
599 VG_(emitL) ( int32 );
600 if (dis)
601 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
602}
603
604void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +0000605{
606 vg_assert(lit8 >= -128 && lit8 < 128);
njn4ba5a792002-09-30 10:23:54 +0000607 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000608 VG_(emitB) ( 0x6A );
609 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +0000610 if (dis)
611 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
612}
613
njn25e49d8e72002-09-23 09:36:25 +0000614void VG_(emit_cmpl_zero_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000615{
njn4ba5a792002-09-30 10:23:54 +0000616 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000617 VG_(emitB) ( 0x83 );
618 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
619 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000620 if (dis)
621 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
622}
623
624static void emit_swapl_reg_ECX ( Int reg )
625{
njn4ba5a792002-09-30 10:23:54 +0000626 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000627 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
628 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +0000629 if (dis)
630 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
631}
632
njn25e49d8e72002-09-23 09:36:25 +0000633void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000634{
njn4ba5a792002-09-30 10:23:54 +0000635 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000636 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +0000637 if (dis)
638 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
639}
640
641static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
642{
njn4ba5a792002-09-30 10:23:54 +0000643 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000644 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
645 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000646 if (dis)
647 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
648 nameIReg(4,reg2));
649}
650
651static void emit_bswapl_reg ( Int reg )
652{
njn4ba5a792002-09-30 10:23:54 +0000653 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000654 VG_(emitB) ( 0x0F );
655 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +0000656 if (dis)
657 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
658}
659
660static void emit_movl_reg_reg ( Int regs, Int regd )
661{
njn4ba5a792002-09-30 10:23:54 +0000662 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000663 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
664 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +0000665 if (dis)
666 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
667}
668
njn25e49d8e72002-09-23 09:36:25 +0000669void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +0000670{
njn4ba5a792002-09-30 10:23:54 +0000671 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000672 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000673 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000674 } else {
675 vg_assert(sz == 4);
676 }
njn25e49d8e72002-09-23 09:36:25 +0000677 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
678 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
679 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000680 if (dis)
681 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
682 nameISize(sz), lit, off, nameIReg(4,memreg) );
683}
684
685
686/*----------------------------------------------------*/
687/*--- b-size (1 byte) instruction emitters ---*/
688/*----------------------------------------------------*/
689
690/* There is some doubt as to whether C6 (Grp 11) is in the
691 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +0000692void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
693{
njn4ba5a792002-09-30 10:23:54 +0000694 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000695 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
696 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
697 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000698 if (dis)
699 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
700 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +0000701}
702
sewardjde4a1d02002-03-22 01:27:54 +0000703static void emit_nonshiftopb_offregmem_reg ( Opcode opc,
704 Int off, Int areg, Int reg )
705{
njn4ba5a792002-09-30 10:23:54 +0000706 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000707 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
708 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000709 if (dis)
710 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000711 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +0000712 nameIReg(1,reg));
713}
714
njn25e49d8e72002-09-23 09:36:25 +0000715void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000716{
717 /* Could do better when reg == %al. */
njn4ba5a792002-09-30 10:23:54 +0000718 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000719 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
720 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000721 if (dis)
722 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
723 nameIReg(1,reg), off, nameIReg(4,areg));
724}
725
726static void emit_nonshiftopb_reg_reg ( Opcode opc, Int reg1, Int reg2 )
727{
njn4ba5a792002-09-30 10:23:54 +0000728 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000729 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
730 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000731 if (dis)
732 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000733 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000734 nameIReg(1,reg1), nameIReg(1,reg2));
735}
736
737static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
738{
njn4ba5a792002-09-30 10:23:54 +0000739 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000740 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +0000741 emit_amode_regmem_reg ( reg2, reg1 );
742 if (dis)
743 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
744 nameIReg(4,reg2));
745}
746
747static void emit_nonshiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
748{
njn4ba5a792002-09-30 10:23:54 +0000749 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000750 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
751 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
752 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000753 if (dis)
njn4ba5a792002-09-30 10:23:54 +0000754 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000755 lit, nameIReg(1,reg));
756}
757
758static void emit_shiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
759{
njn4ba5a792002-09-30 10:23:54 +0000760 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000761 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
762 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
763 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000764 if (dis)
765 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000766 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000767 lit, nameIReg(1,reg));
768}
769
njn25e49d8e72002-09-23 09:36:25 +0000770void VG_(emit_unaryopb_reg) ( Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000771{
njn4ba5a792002-09-30 10:23:54 +0000772 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000773 switch (opc) {
774 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000775 VG_(emitB) ( 0xFE );
776 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +0000777 if (dis)
778 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
779 break;
780 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000781 VG_(emitB) ( 0xFE );
782 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +0000783 if (dis)
784 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
785 break;
786 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000787 VG_(emitB) ( 0xF6 );
788 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000789 if (dis)
790 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
791 break;
792 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000793 VG_(emitB) ( 0xF6 );
794 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000795 if (dis)
796 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
797 break;
798 default:
njne427a662002-10-02 11:08:25 +0000799 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000800 }
801}
802
njn25e49d8e72002-09-23 09:36:25 +0000803void VG_(emit_testb_lit_reg) ( UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000804{
njn4ba5a792002-09-30 10:23:54 +0000805 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000806 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
807 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
808 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000809 if (dis)
810 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
811}
812
sewardjde4a1d02002-03-22 01:27:54 +0000813/*----------------------------------------------------*/
814/*--- zero-extended load emitters ---*/
815/*----------------------------------------------------*/
816
njn25e49d8e72002-09-23 09:36:25 +0000817void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000818{
njn4ba5a792002-09-30 10:23:54 +0000819 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000820 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
821 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000822 if (dis)
823 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
824 off, nameIReg(4,regmem), nameIReg(4,reg));
825}
826
827static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
828{
njn4ba5a792002-09-30 10:23:54 +0000829 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000830 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +0000831 emit_amode_regmem_reg ( reg1, reg2 );
832 if (dis)
833 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
834 nameIReg(4,reg2));
835}
836
njn25e49d8e72002-09-23 09:36:25 +0000837void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000838{
njn4ba5a792002-09-30 10:23:54 +0000839 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000840 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
841 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000842 if (dis)
843 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
844 off, nameIReg(4,areg), nameIReg(4,reg));
845}
846
847static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
848{
njn4ba5a792002-09-30 10:23:54 +0000849 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000850 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +0000851 emit_amode_regmem_reg ( reg1, reg2 );
852 if (dis)
853 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
854 nameIReg(4,reg2));
855}
856
857/*----------------------------------------------------*/
858/*--- FPU instruction emitters ---*/
859/*----------------------------------------------------*/
860
861static void emit_get_fpu_state ( void )
862{
863 Int off = 4 * VGOFF_(m_fpustate);
njn4ba5a792002-09-30 10:23:54 +0000864 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000865 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
866 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000867 if (dis)
868 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
869}
870
871static void emit_put_fpu_state ( void )
872{
873 Int off = 4 * VGOFF_(m_fpustate);
njn4ba5a792002-09-30 10:23:54 +0000874 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000875 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
876 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000877 if (dis)
878 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
879}
880
881static void emit_fpu_no_mem ( UChar first_byte,
882 UChar second_byte )
883{
njn4ba5a792002-09-30 10:23:54 +0000884 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000885 VG_(emitB) ( first_byte );
886 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000887 if (dis)
888 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
889 (UInt)first_byte, (UInt)second_byte );
890}
891
892static void emit_fpu_regmem ( UChar first_byte,
893 UChar second_byte_masked,
894 Int reg )
895{
njn4ba5a792002-09-30 10:23:54 +0000896 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000897 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000898 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
899 if (dis)
900 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
901 (UInt)first_byte, (UInt)second_byte_masked,
902 nameIReg(4,reg) );
903}
904
905
906/*----------------------------------------------------*/
907/*--- misc instruction emitters ---*/
908/*----------------------------------------------------*/
909
njn25e49d8e72002-09-23 09:36:25 +0000910void VG_(emit_call_reg) ( Int reg )
911{
njn4ba5a792002-09-30 10:23:54 +0000912 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000913 VG_(emitB) ( 0xFF ); /* Grp5 */
914 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
915 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +0000916 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +0000917}
918
sewardjde4a1d02002-03-22 01:27:54 +0000919static void emit_call_star_EBP_off ( Int byte_off )
920{
njn4ba5a792002-09-30 10:23:54 +0000921 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000922 if (byte_off < -128 || byte_off > 127) {
njn25e49d8e72002-09-23 09:36:25 +0000923 VG_(emitB) ( 0xFF );
924 VG_(emitB) ( 0x95 );
925 VG_(emitL) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000926 } else {
njn25e49d8e72002-09-23 09:36:25 +0000927 VG_(emitB) ( 0xFF );
928 VG_(emitB) ( 0x55 );
929 VG_(emitB) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000930 }
931 if (dis)
932 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
933}
934
935
936static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
937{
938 vg_assert(lit8 >= -128 && lit8 < 128);
njn4ba5a792002-09-30 10:23:54 +0000939 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000940 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
941 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +0000942 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +0000943 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000944 if (dis)
945 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
946 nameIReg(4,regmem));
947}
948
949
njn25e49d8e72002-09-23 09:36:25 +0000950void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +0000951{
njne427a662002-10-02 11:08:25 +0000952 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
njn4ba5a792002-09-30 10:23:54 +0000953 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000954 VG_(emitB) ( 0x83 );
955 VG_(emitB) ( 0xC4 );
956 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000957 if (dis)
958 VG_(printf)( "\n\t\taddl $%d, %%esp\n", lit );
959}
960
961
962static void emit_movb_AL_zeroESPmem ( void )
963{
964 /* movb %al, 0(%esp) */
965 /* 88442400 movb %al, 0(%esp) */
njn4ba5a792002-09-30 10:23:54 +0000966 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000967 VG_(emitB) ( 0x88 );
968 VG_(emitB) ( 0x44 );
969 VG_(emitB) ( 0x24 );
970 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000971 if (dis)
972 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
973}
974
975static void emit_movb_zeroESPmem_AL ( void )
976{
977 /* movb 0(%esp), %al */
978 /* 8A442400 movb 0(%esp), %al */
njn4ba5a792002-09-30 10:23:54 +0000979 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000980 VG_(emitB) ( 0x8A );
981 VG_(emitB) ( 0x44 );
982 VG_(emitB) ( 0x24 );
983 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000984 if (dis)
985 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
986}
987
988
989/* Emit a jump short with an 8-bit signed offset. Note that the
990 offset is that which should be added to %eip once %eip has been
991 advanced over this insn. */
njn25e49d8e72002-09-23 09:36:25 +0000992void VG_(emit_jcondshort_delta) ( Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +0000993{
994 vg_assert(delta >= -128 && delta <= 127);
njn4ba5a792002-09-30 10:23:54 +0000995 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000996 VG_(emitB) ( 0x70 + (UInt)cond );
997 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +0000998 if (dis)
999 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
1000 VG_(nameCondcode)(cond), delta );
1001}
1002
1003static void emit_get_eflags ( void )
1004{
1005 Int off = 4 * VGOFF_(m_eflags);
1006 vg_assert(off >= 0 && off < 128);
njn4ba5a792002-09-30 10:23:54 +00001007 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001008 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
1009 VG_(emitB) ( 0x75 );
1010 VG_(emitB) ( off );
1011 VG_(emitB) ( 0x9D ); /* POPFL */
sewardjde4a1d02002-03-22 01:27:54 +00001012 if (dis)
1013 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
1014}
1015
1016static void emit_put_eflags ( void )
1017{
1018 Int off = 4 * VGOFF_(m_eflags);
1019 vg_assert(off >= 0 && off < 128);
njn4ba5a792002-09-30 10:23:54 +00001020 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001021 VG_(emitB) ( 0x9C ); /* PUSHFL */
1022 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
1023 VG_(emitB) ( 0x45 );
1024 VG_(emitB) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001025 if (dis)
1026 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
1027}
1028
1029static void emit_setb_reg ( Int reg, Condcode cond )
1030{
njn4ba5a792002-09-30 10:23:54 +00001031 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001032 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1033 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001034 if (dis)
1035 VG_(printf)("\n\t\tset%s %s\n",
1036 VG_(nameCondcode)(cond), nameIReg(1,reg));
1037}
1038
1039static void emit_ret ( void )
1040{
njn4ba5a792002-09-30 10:23:54 +00001041 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001042 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001043 if (dis)
1044 VG_(printf)("\n\t\tret\n");
1045}
1046
sewardj22854b92002-11-30 14:00:47 +00001047/* Predicate used in sanity checks elsewhere - returns true if any
1048 jump-site is an actual chained jump */
1049Bool VG_(is_chained_jumpsite)(Addr a)
1050{
1051 UChar *cp = (UChar *)a;
1052
1053 return (*cp == 0xE9); /* 0xE9 -- jmp */
1054}
1055
sewardj83f11862002-12-01 02:07:08 +00001056static
1057Bool is_fresh_jumpsite(UChar *cp)
1058{
1059 return
1060 cp[0] == 0x0F && /* UD2 */
1061 cp[1] == 0x0B &&
1062 cp[2] == 0x0F && /* UD2 */
1063 cp[3] == 0x0B &&
1064 cp[4] == 0x90; /* NOP */
1065}
1066
sewardj22854b92002-11-30 14:00:47 +00001067/* Predicate used in sanity checks elsewhere - returns true if all
1068 jump-sites are calls to VG_(patch_me) */
1069Bool VG_(is_unchained_jumpsite)(Addr a)
1070{
1071 UChar *cp = (UChar *)a;
1072 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1073 Int idelta;
1074
1075 if (*cp++ != 0xE8) /* 0xE8 == call */
1076 return False;
1077
1078 idelta = (*cp++) << 0;
1079 idelta |= (*cp++) << 8;
1080 idelta |= (*cp++) << 16;
1081 idelta |= (*cp++) << 24;
1082
1083 return idelta == delta;
1084}
1085
1086/* Return target address for a direct jmp */
1087Addr VG_(get_jmp_dest)(Addr a)
1088{
1089 Int delta;
1090 UChar *cp = (UChar *)a;
1091
1092 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1093 return 0;
1094
1095 delta = (*cp++) << 0;
1096 delta |= (*cp++) << 8;
1097 delta |= (*cp++) << 16;
1098 delta |= (*cp++) << 24;
1099
1100 return a + VG_PATCHME_JMPSZ + delta;
1101}
1102
1103/* unchain a BB by generating a call to VG_(patch_me) */
1104void VG_(unchain_jumpsite)(Addr a)
1105{
1106 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1107 UChar *cp = (UChar *)a;
1108
1109 if (VG_(is_unchained_jumpsite)(a))
1110 return; /* don't write unnecessarily */
1111
sewardj83f11862002-12-01 02:07:08 +00001112 if (!is_fresh_jumpsite(cp))
1113 VG_(bb_dechain_count)++; /* update stats */
1114
sewardj22854b92002-11-30 14:00:47 +00001115 *cp++ = 0xE8; /* call */
1116 *cp++ = (delta >> 0) & 0xff;
1117 *cp++ = (delta >> 8) & 0xff;
1118 *cp++ = (delta >> 16) & 0xff;
1119 *cp++ = (delta >> 24) & 0xff;
sewardj22854b92002-11-30 14:00:47 +00001120}
1121
1122/* This doesn't actually generate a call to VG_(patch_me), but
1123 reserves enough space in the instruction stream for it to happen
1124 and records the offset into the jump table. This is because call
1125 is a relative jump, and so will be affected when this code gets
1126 moved about. The translation table will "unchain" this basic block
1127 on insertion (with VG_(unchain_BB)()), and thereby generate a
1128 proper call instruction. */
1129static void emit_call_patchme( void )
1130{
1131 vg_assert(VG_PATCHME_CALLSZ == 5);
1132
1133 VG_(new_emit)();
1134
1135 if (jumpidx >= VG_MAX_JUMPS) {
1136 /* If there too many jumps in this basic block, fall back to
1137 dispatch loop. We still need to keep it the same size as the
1138 call sequence. */
1139 VG_(emitB) ( 0xC3 ); /* ret */
1140 VG_(emitB) ( 0x90 ); /* nop */
1141 VG_(emitB) ( 0x90 ); /* nop */
1142 VG_(emitB) ( 0x90 ); /* nop */
1143 VG_(emitB) ( 0x90 ); /* nop */
1144
1145 if (dis)
1146 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1147
1148 if (0 && VG_(clo_verbosity))
1149 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1150 } else {
1151 jumps[jumpidx++] = emitted_code_used;
1152
1153 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1154 VG_(emitB) ( 0x0B );
1155 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1156 VG_(emitB) ( 0x0B );
1157 VG_(emitB) ( 0x90 ); /* NOP */
1158
1159 if (dis)
1160 VG_(printf)("\n\t\tud2; ud2; nop\n");
1161 }
1162}
1163
njn25e49d8e72002-09-23 09:36:25 +00001164void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001165{
njn4ba5a792002-09-30 10:23:54 +00001166 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001167 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001168 if (dis)
1169 VG_(printf)("\n\t\tpushal\n");
1170}
1171
njn25e49d8e72002-09-23 09:36:25 +00001172void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001173{
njn4ba5a792002-09-30 10:23:54 +00001174 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001175 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001176 if (dis)
1177 VG_(printf)("\n\t\tpopal\n");
1178}
1179
1180static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1181{
njn4ba5a792002-09-30 10:23:54 +00001182 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001183 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1184 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001185 if (dis)
1186 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1187 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1188}
1189
1190static void emit_lea_sib_reg ( UInt lit, Int scale,
1191 Int regbase, Int regindex, Int reg )
1192{
njn4ba5a792002-09-30 10:23:54 +00001193 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001194 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001195 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1196 if (dis)
1197 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1198 lit, nameIReg(4,regbase),
1199 nameIReg(4,regindex), scale,
1200 nameIReg(4,reg) );
1201}
1202
njn25e49d8e72002-09-23 09:36:25 +00001203void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001204{
njn4ba5a792002-09-30 10:23:54 +00001205 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001206 VG_(emitB) ( 0x0F );
1207 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001208 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1209 if (dis)
1210 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1211}
1212
1213/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001214/*--- Helper offset -> addr translation ---*/
1215/*----------------------------------------------------*/
1216
1217/* Finds the baseBlock offset of a skin-specified helper.
1218 * Searches through compacts first, then non-compacts. */
1219Int VG_(helper_offset)(Addr a)
1220{
1221 Int i;
1222
1223 for (i = 0; i < VG_(n_compact_helpers); i++)
1224 if (VG_(compact_helper_addrs)[i] == a)
1225 return VG_(compact_helper_offsets)[i];
1226 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1227 if (VG_(noncompact_helper_addrs)[i] == a)
1228 return VG_(noncompact_helper_offsets)[i];
1229
1230 /* Shouldn't get here */
1231 VG_(printf)(
1232 "\nCouldn't find offset of helper from its address (%p).\n"
1233 "A helper function probably used hasn't been registered?\n\n", a);
1234
1235 VG_(printf)(" compact helpers: ");
1236 for (i = 0; i < VG_(n_compact_helpers); i++)
1237 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1238
1239 VG_(printf)("\n non-compact helpers: ");
1240 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1241 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1242
1243 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001244 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001245}
1246
1247/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001248/*--- Instruction synthesisers ---*/
1249/*----------------------------------------------------*/
1250
1251static Condcode invertCondition ( Condcode cond )
1252{
1253 return (Condcode)(1 ^ (UInt)cond);
1254}
1255
1256
1257/* Synthesise a call to *baseBlock[offset], ie,
1258 call * (4 x offset)(%ebp).
1259*/
njn25e49d8e72002-09-23 09:36:25 +00001260void VG_(synth_call) ( Bool ensure_shortform, Int word_offset )
sewardjde4a1d02002-03-22 01:27:54 +00001261{
1262 vg_assert(word_offset >= 0);
1263 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1264 if (ensure_shortform)
1265 vg_assert(word_offset < 32);
1266 emit_call_star_EBP_off ( 4 * word_offset );
1267}
1268
njn25e49d8e72002-09-23 09:36:25 +00001269static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001270{
njn25e49d8e72002-09-23 09:36:25 +00001271 if (src != dst) {
1272 VG_(emit_movv_reg_reg) ( 4, src, dst );
1273 ccall_arg_setup_instrs++;
1274 }
njn6431be72002-07-28 09:53:34 +00001275}
njn25e49d8e72002-09-23 09:36:25 +00001276
1277/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1278static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1279{
1280 if (RealReg == tag) {
1281 maybe_emit_movl_reg_reg ( litOrReg, reg );
1282 } else if (Literal == tag) {
1283 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1284 ccall_arg_setup_instrs++;
1285 }
1286 else
njne427a662002-10-02 11:08:25 +00001287 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001288}
1289
1290static
1291void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1292{
1293 if (R_EAX == reg1) {
1294 VG_(emit_swapl_reg_EAX) ( reg2 );
1295 } else if (R_EAX == reg2) {
1296 VG_(emit_swapl_reg_EAX) ( reg1 );
1297 } else {
1298 emit_swapl_reg_reg ( reg1, reg2 );
1299 }
1300 ccall_arg_setup_instrs++;
1301}
1302
1303static
1304void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1305{
1306 if (dst1 != src2) {
1307 maybe_emit_movl_reg_reg ( src1, dst1 );
1308 maybe_emit_movl_reg_reg ( src2, dst2 );
1309
1310 } else if (dst2 != src1) {
1311 maybe_emit_movl_reg_reg ( src2, dst2 );
1312 maybe_emit_movl_reg_reg ( src1, dst1 );
1313
1314 } else {
1315 /* swap to break cycle */
1316 emit_swapl_arg_regs ( dst1, dst2 );
1317 }
1318}
1319
1320static
1321void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1322 UInt dst1, UInt dst2, UInt dst3)
1323{
1324 if (dst1 != src2 && dst1 != src3) {
1325 maybe_emit_movl_reg_reg ( src1, dst1 );
1326 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1327
1328 } else if (dst2 != src1 && dst2 != src3) {
1329 maybe_emit_movl_reg_reg ( src2, dst2 );
1330 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1331
1332 } else if (dst3 != src1 && dst3 != src2) {
1333 maybe_emit_movl_reg_reg ( src3, dst3 );
1334 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1335
1336 } else {
1337 /* break cycle */
1338 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1339 emit_swapl_arg_regs ( dst1, dst2 );
1340 emit_swapl_arg_regs ( dst1, dst3 );
1341
1342 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1343 emit_swapl_arg_regs ( dst1, dst3 );
1344 emit_swapl_arg_regs ( dst1, dst2 );
1345
1346 } else {
njne427a662002-10-02 11:08:25 +00001347 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001348 }
1349 }
1350}
1351
1352static
1353void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1354 UInt src1, UInt src2,
1355 UInt dst1, UInt dst2)
1356{
1357 /* If either are lits, order doesn't matter */
1358 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1359 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1360 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1361
1362 } else {
1363 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1364 }
1365}
1366
1367static
1368void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1369 UInt src1, UInt src2, UInt src3,
1370 UInt dst1, UInt dst2, UInt dst3)
1371{
1372 // SSS: fix this eventually -- make STOREV use two RealRegs?
1373 /* Not supporting literals for 3-arg C functions -- they're only used
1374 by STOREV which has 2 args */
1375 vg_assert(RealReg == tagv[src1] &&
1376 RealReg == tagv[src2] &&
1377 RealReg == tagv[src3]);
1378 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1379 dst1, dst2, dst3 );
1380}
1381
1382/* Synthesise a call to a C function `fn' (which must be registered in
1383 baseBlock) doing all the reg saving and arg handling work.
1384
1385 WARNING: a UInstr should *not* be translated with synth_ccall followed
1386 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1387 such behaviour and everything will fall over.
1388 */
1389void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1390 Tag tagv[], Int ret_reg,
1391 RRegSet regs_live_before, RRegSet regs_live_after )
1392{
1393 Int i;
1394 Int stack_used = 0;
1395 Bool preserve_eax, preserve_ecx, preserve_edx;
1396
1397 vg_assert(0 <= regparms_n && regparms_n <= 3);
1398
1399 ccalls++;
1400
1401 /* If %e[acd]x is live before and after the C call, save/restore it.
1402 Unless the return values clobbers the reg; in this case we must not
1403 save/restore the reg, because the restore would clobber the return
1404 value. (Before and after the UInstr really constitute separate live
1405 ranges, but you miss this if you don't consider what happens during
1406 the UInstr.) */
1407# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001408 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1409 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001410 ret_reg != realReg)
1411
1412 preserve_eax = PRESERVE_REG(R_EAX);
1413 preserve_ecx = PRESERVE_REG(R_ECX);
1414 preserve_edx = PRESERVE_REG(R_EDX);
1415
1416# undef PRESERVE_REG
1417
1418 /* Save caller-save regs as required */
1419 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1420 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1421 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1422
1423 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1424 is the number of args passed in regs (maximum 3 for GCC on x86). */
1425
1426 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001427
njn25e49d8e72002-09-23 09:36:25 +00001428 /* First push stack args (RealRegs or Literals) in reverse order. */
1429 for (i = argc-1; i >= regparms_n; i--) {
1430 switch (tagv[i]) {
1431 case RealReg:
1432 VG_(emit_pushv_reg) ( 4, argv[i] );
1433 break;
1434 case Literal:
1435 /* Use short form of pushl if possible. */
1436 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1437 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1438 else
1439 VG_(emit_pushl_lit32)( argv[i] );
1440 break;
1441 default:
1442 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001443 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001444 }
1445 stack_used += 4;
1446 ccall_arg_setup_instrs++;
1447 }
njn6431be72002-07-28 09:53:34 +00001448
njn25e49d8e72002-09-23 09:36:25 +00001449 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1450 If moving values between registers, be careful not to clobber any on
1451 the way. Happily we can use xchgl to swap registers.
1452 */
1453 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001454
njn25e49d8e72002-09-23 09:36:25 +00001455 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1456 case 3:
1457 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1458 R_EAX, R_EDX, R_ECX );
1459 break;
njn6431be72002-07-28 09:53:34 +00001460
njn25e49d8e72002-09-23 09:36:25 +00001461 /* Less-tricky. Args passed in %eax and %edx. */
1462 case 2:
1463 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1464 break;
1465
1466 /* Easy. Just move arg1 into %eax (if not already in there). */
1467 case 1:
1468 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1469 break;
1470
1471 case 0:
1472 break;
1473
1474 default:
njne427a662002-10-02 11:08:25 +00001475 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001476 }
1477
1478 /* Call the function */
1479 VG_(synth_call) ( False, VG_(helper_offset) ( fn ) );
1480
1481 /* Clear any args from stack */
1482 if (0 != stack_used) {
1483 VG_(emit_add_lit_to_esp) ( stack_used );
1484 ccall_stack_clears++;
1485 }
1486
1487 /* Move return value into ret_reg if necessary and not already there */
1488 if (INVALID_REALREG != ret_reg) {
1489 ccall_retvals++;
1490 if (R_EAX != ret_reg) {
1491 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1492 ccall_retval_movs++;
1493 }
1494 }
1495
1496 /* Restore live caller-save regs as required */
1497 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1498 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1499 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001500}
sewardjde4a1d02002-03-22 01:27:54 +00001501
sewardj2e93c502002-04-12 11:12:52 +00001502static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001503{
sewardj2e93c502002-04-12 11:12:52 +00001504 switch (jmpkind) {
1505 case JmpBoring:
1506 break;
sewardj2e93c502002-04-12 11:12:52 +00001507 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001508 break;
1509 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001510 break;
1511 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001512 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001513 break;
1514 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001515 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001516 break;
1517 default:
njne427a662002-10-02 11:08:25 +00001518 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001519 }
1520}
1521
1522/* Jump to the next translation, by loading its original addr into
1523 %eax and returning to the scheduler. Signal special requirements
1524 by loading a special value into %ebp first.
1525*/
1526static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1527{
1528 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001529 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001530 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001531 emit_ret();
1532}
1533
sewardj22854b92002-11-30 14:00:47 +00001534static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00001535
1536/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001537static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001538{
njn25e49d8e72002-09-23 09:36:25 +00001539 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00001540
1541 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
1542 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
1543 emit_call_patchme();
1544 } else {
1545 load_ebp_from_JmpKind ( jmpkind );
1546 emit_ret();
1547 }
sewardjde4a1d02002-03-22 01:27:54 +00001548}
1549
1550
sewardj2370f3b2002-11-30 15:01:01 +00001551static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
1552static void synth_nonshiftop_lit_reg ( Bool upd_cc,
1553 Opcode opcode, Int size,
1554 UInt lit, Int reg );
1555
sewardjde4a1d02002-03-22 01:27:54 +00001556static void synth_jcond_lit ( Condcode cond, Addr addr )
1557{
sewardj2370f3b2002-11-30 15:01:01 +00001558 UInt mask;
1559 Int delta;
1560
sewardjde4a1d02002-03-22 01:27:54 +00001561 /* Do the following:
1562 get eflags
1563 jmp short if not cond to xyxyxy
1564 addr -> eax
1565 ret
1566 xyxyxy
1567
1568 2 0000 750C jnz xyxyxy
1569 3 0002 B877665544 movl $0x44556677, %eax
1570 4 0007 C3 ret
1571 5 0008 FFE3 jmp *%ebx
1572 6 xyxyxy:
1573 */
sewardj22854b92002-11-30 14:00:47 +00001574 if (VG_(clo_chain_bb)) {
1575 /* When using BB chaining, the jump sequence is:
1576 jmp short if not cond to xyxyxy
1577 addr -> eax
1578 call VG_(patch_me)/jmp target
1579 xyxyxy
1580
1581 je 1f
1582 mov $0x4000d190,%eax // 5
1583 mov %eax, VGOFF_(m_eip)(%ebp) // 3
1584 call 0x40050f9a <vgPlain_patch_me> // 5
1585 1: mov $0x4000d042,%eax
1586 call 0x40050f9a <vgPlain_patch_me>
1587 */
sewardj83f11862002-12-01 02:07:08 +00001588 delta = 5+3+5;
sewardj22854b92002-11-30 14:00:47 +00001589 } else
sewardj2370f3b2002-11-30 15:01:01 +00001590 delta = 5+1;
1591
1592 if (!VG_(clo_fast_jcc)) {
1593 /* We're forced to do it the slow way. */
1594 emit_get_eflags();
1595 cond = invertCondition(cond);
1596 } else {
1597 switch (cond & ~1) {
1598 case CondB: mask = EFlagC; goto common; /* C=1 */
1599 case CondZ: mask = EFlagZ; goto common; /* Z=1 */
1600 case CondBE: mask = EFlagC | EFlagZ; goto common; /* C=1 || Z=1 */
1601 case CondS: mask = EFlagS; goto common; /* S=1 */
1602 case CondP: mask = EFlagP; goto common; /* P=1 */
1603 default:
1604 /* Too complex .. we have to do it the slow way. */
1605 emit_get_eflags();
1606 cond = invertCondition(cond);
1607 break;
1608
1609 common:
1610 VG_(new_emit)();
1611 if ((mask & 0xff) == mask) {
1612 VG_(emitB) ( 0xF6 ); /* Grp3 */
1613 VG_(emit_amode_offregmem_reg)(
1614 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1615 VG_(emitB) (mask);
1616 if (dis)
1617 VG_(printf)("\n\t\ttestb $%x, %d(%%ebp)\n",
1618 mask, VGOFF_(m_eflags) * 4);
1619 } else {
1620 VG_(emitB) ( 0xF7 );
1621 VG_(emit_amode_offregmem_reg)(
1622 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1623 VG_(emitB) (mask);
1624 if (dis)
1625 VG_(printf)("\n\t\ttestx $%x, %d(%%ebp)\n",
1626 mask, VGOFF_(m_eflags) * 4);
1627 }
1628
1629 if (cond & 1)
1630 cond = CondNZ;
1631 else
1632 cond = CondZ;
1633 break;
1634 }
1635 }
1636
1637 VG_(emit_jcondshort_delta) ( cond, delta );
sewardj2e93c502002-04-12 11:12:52 +00001638 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001639}
1640
1641
sewardj2370f3b2002-11-30 15:01:01 +00001642
sewardjde4a1d02002-03-22 01:27:54 +00001643static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1644{
1645 /* 0000 83FF00 cmpl $0, %edi
1646 0003 750A jnz next
1647 0005 B844332211 movl $0x11223344, %eax
1648 000a C3 ret
1649 next:
1650 */
njn25e49d8e72002-09-23 09:36:25 +00001651 VG_(emit_cmpl_zero_reg) ( reg );
sewardj22854b92002-11-30 14:00:47 +00001652 if (VG_(clo_chain_bb))
1653 VG_(emit_jcondshort_delta) ( CondNZ, 5+3+5 );
1654 else
1655 VG_(emit_jcondshort_delta) ( CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001656 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001657}
1658
1659
1660static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1661{
1662 /* Load the zero-extended literal into reg, at size l,
1663 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00001664 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001665}
1666
1667
1668static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
1669{
1670 switch (size) {
1671 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
1672 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
1673 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00001674 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001675 }
1676}
1677
1678
1679static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
1680{
1681 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001682 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
1683 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
1684 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00001685 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001686 }
1687}
1688
1689
1690static void synth_mov_reg_offregmem ( Int size, Int reg,
1691 Int off, Int areg )
1692{
1693 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001694 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
1695 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00001696 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00001697 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00001698 }
1699 else {
njn25e49d8e72002-09-23 09:36:25 +00001700 VG_(emit_swapl_reg_EAX) ( reg );
1701 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
1702 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001703 }
1704 break;
njne427a662002-10-02 11:08:25 +00001705 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00001706 }
1707}
1708
1709
1710static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
1711{
1712 Int s1;
1713 switch (size) {
1714 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
1715 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
1716 case 1: if (reg1 < 4) {
1717 emit_movb_reg_regmem ( reg1, reg2 );
1718 }
1719 else {
1720 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
1721 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1722 emit_swapl_reg_reg ( s1, reg1 );
1723 emit_movb_reg_regmem ( s1, reg2 );
1724 emit_swapl_reg_reg ( s1, reg1 );
1725 }
1726 break;
njne427a662002-10-02 11:08:25 +00001727 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00001728 }
1729}
1730
1731
sewardj478335c2002-10-05 02:44:47 +00001732static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001733 Opcode opcode, Int size,
1734 Int reg )
1735{
1736 /* NB! opcode is a uinstr opcode, not an x86 one! */
1737 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001738 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001739 VG_(emit_unaryopv_reg) ( 4, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001740 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001741 break;
sewardj478335c2002-10-05 02:44:47 +00001742 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001743 VG_(emit_unaryopv_reg) ( 2, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001744 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001745 break;
1746 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001747 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001748 VG_(emit_unaryopb_reg) ( opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001749 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001750 } else {
njn25e49d8e72002-09-23 09:36:25 +00001751 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001752 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001753 VG_(emit_unaryopb_reg) ( opcode, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001754 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001755 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001756 }
1757 break;
njne427a662002-10-02 11:08:25 +00001758 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001759 }
1760}
1761
1762
1763
sewardj478335c2002-10-05 02:44:47 +00001764static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001765 Opcode opcode, Int size,
1766 Int reg1, Int reg2 )
1767{
1768 /* NB! opcode is a uinstr opcode, not an x86 one! */
1769 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001770 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001771 VG_(emit_nonshiftopv_reg_reg) ( 4, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001772 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001773 break;
sewardj478335c2002-10-05 02:44:47 +00001774 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001775 VG_(emit_nonshiftopv_reg_reg) ( 2, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001776 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001777 break;
1778 case 1: { /* Horrible ... */
1779 Int s1, s2;
1780 /* Choose s1 and s2 to be x86 regs which we can talk about the
1781 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
1782 sure s1 != s2 and that neither of them equal either reg1 or
1783 reg2. Then use them as temporaries to make things work. */
1784 if (reg1 < 4 && reg2 < 4) {
sewardj478335c2002-10-05 02:44:47 +00001785 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001786 emit_nonshiftopb_reg_reg(opcode, reg1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001787 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001788 break;
1789 }
1790 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1791 if (reg1 >= 4 && reg2 < 4) {
1792 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001793 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001794 emit_nonshiftopb_reg_reg(opcode, s1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001795 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001796 emit_swapl_reg_reg ( reg1, s1 );
1797 break;
1798 }
1799 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
1800 if (reg1 < 4 && reg2 >= 4) {
1801 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001802 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001803 emit_nonshiftopb_reg_reg(opcode, reg1, s2);
sewardj478335c2002-10-05 02:44:47 +00001804 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001805 emit_swapl_reg_reg ( reg2, s2 );
1806 break;
1807 }
1808 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
1809 emit_swapl_reg_reg ( reg1, s1 );
1810 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001811 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001812 emit_nonshiftopb_reg_reg(opcode, s1, s2);
sewardj478335c2002-10-05 02:44:47 +00001813 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001814 emit_swapl_reg_reg ( reg1, s1 );
1815 emit_swapl_reg_reg ( reg2, s2 );
1816 break;
1817 }
1818 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
1819 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001820 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001821 emit_nonshiftopb_reg_reg(opcode, s1, s1);
sewardj478335c2002-10-05 02:44:47 +00001822 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001823 emit_swapl_reg_reg ( reg1, s1 );
1824 break;
1825 }
njne427a662002-10-02 11:08:25 +00001826 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001827 }
njne427a662002-10-02 11:08:25 +00001828 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001829 }
1830}
1831
1832
1833static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00001834 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001835 Opcode opcode, Int size,
1836 Int off, Int areg, Int reg )
1837{
1838 switch (size) {
1839 case 4:
sewardj478335c2002-10-05 02:44:47 +00001840 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001841 emit_nonshiftopv_offregmem_reg ( 4, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001842 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001843 break;
1844 case 2:
sewardj478335c2002-10-05 02:44:47 +00001845 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001846 emit_nonshiftopv_offregmem_reg ( 2, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001847 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001848 break;
1849 case 1:
1850 if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001851 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001852 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001853 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001854 } else {
njn25e49d8e72002-09-23 09:36:25 +00001855 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001856 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001857 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001858 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001859 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001860 }
1861 break;
1862 default:
njne427a662002-10-02 11:08:25 +00001863 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001864 }
1865}
1866
1867
sewardj478335c2002-10-05 02:44:47 +00001868static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001869 Opcode opcode, Int size,
1870 UInt lit, Int reg )
1871{
1872 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001873 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001874 VG_(emit_nonshiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001875 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001876 break;
sewardj478335c2002-10-05 02:44:47 +00001877 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001878 VG_(emit_nonshiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001879 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001880 break;
1881 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001882 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001883 emit_nonshiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001884 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001885 } else {
njn25e49d8e72002-09-23 09:36:25 +00001886 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001887 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001888 emit_nonshiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001889 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001890 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001891 }
1892 break;
njne427a662002-10-02 11:08:25 +00001893 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001894 }
1895}
1896
1897
1898static void synth_push_reg ( Int size, Int reg )
1899{
1900 switch (size) {
1901 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001902 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001903 break;
1904 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001905 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001906 break;
1907 /* Pray that we don't have to generate this really cruddy bit of
1908 code very often. Could do better, but can I be bothered? */
1909 case 1:
1910 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001911 VG_(emit_add_lit_to_esp)(-1);
1912 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001913 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00001914 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001915 break;
1916 default:
njne427a662002-10-02 11:08:25 +00001917 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001918 }
1919}
1920
1921
1922static void synth_pop_reg ( Int size, Int reg )
1923{
1924 switch (size) {
1925 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001926 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001927 break;
1928 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001929 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001930 break;
1931 case 1:
1932 /* Same comment as above applies. */
1933 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001934 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001935 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00001936 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
1937 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001938 break;
njne427a662002-10-02 11:08:25 +00001939 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001940 }
1941}
1942
1943
sewardj478335c2002-10-05 02:44:47 +00001944static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001945 Opcode opcode, Int size,
1946 Int regs, Int regd )
1947{
1948 synth_push_reg ( size, regd );
1949 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardj478335c2002-10-05 02:44:47 +00001950 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001951 switch (size) {
1952 case 4: emit_shiftopv_cl_stack0 ( 4, opcode ); break;
1953 case 2: emit_shiftopv_cl_stack0 ( 2, opcode ); break;
1954 case 1: emit_shiftopb_cl_stack0 ( opcode ); break;
njne427a662002-10-02 11:08:25 +00001955 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001956 }
sewardj478335c2002-10-05 02:44:47 +00001957 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001958 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
1959 synth_pop_reg ( size, regd );
1960}
1961
1962
sewardj478335c2002-10-05 02:44:47 +00001963static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001964 Opcode opcode, Int size,
1965 UInt lit, Int reg )
1966{
1967 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001968 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001969 VG_(emit_shiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001970 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001971 break;
sewardj478335c2002-10-05 02:44:47 +00001972 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001973 VG_(emit_shiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001974 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001975 break;
1976 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001977 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001978 emit_shiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001979 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001980 } else {
njn25e49d8e72002-09-23 09:36:25 +00001981 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001982 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001983 emit_shiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001984 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001985 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001986 }
1987 break;
njne427a662002-10-02 11:08:25 +00001988 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001989 }
1990}
1991
1992
1993static void synth_setb_reg ( Int reg, Condcode cond )
1994{
1995 emit_get_eflags();
1996 if (reg < 4) {
1997 emit_setb_reg ( reg, cond );
1998 } else {
njn25e49d8e72002-09-23 09:36:25 +00001999 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002000 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00002001 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00002002 }
2003}
2004
2005
2006static void synth_fpu_regmem ( UChar first_byte,
2007 UChar second_byte_masked,
2008 Int reg )
2009{
sewardjde4a1d02002-03-22 01:27:54 +00002010 emit_fpu_regmem ( first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002011}
2012
2013
2014static void synth_fpu_no_mem ( UChar first_byte,
2015 UChar second_byte )
2016{
sewardjde4a1d02002-03-22 01:27:54 +00002017 emit_fpu_no_mem ( first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002018}
2019
2020
2021static void synth_movl_reg_reg ( Int src, Int dst )
2022{
2023 emit_movl_reg_reg ( src, dst );
2024}
2025
2026static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2027{
2028 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002029 VG_(emit_jcondshort_delta) ( invertCondition(cond),
sewardjde4a1d02002-03-22 01:27:54 +00002030 2 /* length of the next insn */ );
2031 emit_movl_reg_reg ( src, dst );
2032}
2033
2034
sewardjde4a1d02002-03-22 01:27:54 +00002035/*----------------------------------------------------*/
2036/*--- Top level of the uinstr -> x86 translation. ---*/
2037/*----------------------------------------------------*/
2038
2039/* Return the byte offset from %ebp (ie, into baseBlock)
2040 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002041static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2042{
2043 if (tag == SpillNo) {
2044 vg_assert(size == 4);
2045 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2046 return 4 * (value + VGOFF_(spillslots));
2047 }
2048 if (tag == ArchReg) {
2049 switch (value) {
2050 case R_EAX: return 4 * VGOFF_(m_eax);
2051 case R_ECX: return 4 * VGOFF_(m_ecx);
2052 case R_EDX: return 4 * VGOFF_(m_edx);
2053 case R_EBX: return 4 * VGOFF_(m_ebx);
2054 case R_ESP:
2055 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2056 else return 4 * VGOFF_(m_esp);
2057 case R_EBP:
2058 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2059 else return 4 * VGOFF_(m_ebp);
2060 case R_ESI:
2061 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2062 else return 4 * VGOFF_(m_esi);
2063 case R_EDI:
2064 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2065 else return 4 * VGOFF_(m_edi);
2066 }
2067 }
njne427a662002-10-02 11:08:25 +00002068 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002069}
2070
sewardjde4a1d02002-03-22 01:27:54 +00002071static Int eflagsOffset ( void )
2072{
2073 return 4 * VGOFF_(m_eflags);
2074}
2075
sewardje1042472002-09-30 12:33:11 +00002076static Int segRegOffset ( UInt archregs )
2077{
2078 switch (archregs) {
2079 case R_CS: return 4 * VGOFF_(m_cs);
2080 case R_SS: return 4 * VGOFF_(m_ss);
2081 case R_DS: return 4 * VGOFF_(m_ds);
2082 case R_ES: return 4 * VGOFF_(m_es);
2083 case R_FS: return 4 * VGOFF_(m_fs);
2084 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002085 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002086 }
2087}
2088
sewardjde4a1d02002-03-22 01:27:54 +00002089
njn25e49d8e72002-09-23 09:36:25 +00002090/* Return the byte offset from %ebp (ie, into baseBlock)
2091 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002092Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002093{
2094 switch (arch) {
2095 case R_EAX: return 4 * VGOFF_(sh_eax);
2096 case R_ECX: return 4 * VGOFF_(sh_ecx);
2097 case R_EDX: return 4 * VGOFF_(sh_edx);
2098 case R_EBX: return 4 * VGOFF_(sh_ebx);
2099 case R_ESP: return 4 * VGOFF_(sh_esp);
2100 case R_EBP: return 4 * VGOFF_(sh_ebp);
2101 case R_ESI: return 4 * VGOFF_(sh_esi);
2102 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002103 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002104 }
2105}
2106
njn4ba5a792002-09-30 10:23:54 +00002107Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002108{
2109 return 4 * VGOFF_(sh_eflags);
2110}
2111
2112
sewardjde4a1d02002-03-22 01:27:54 +00002113
2114static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2115{
2116 if (sz_src == 1 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00002117 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 24, reg );
2118 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002119 }
2120 else if (sz_src == 2 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00002121 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 16, reg );
2122 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002123 }
2124 else if (sz_src == 1 && sz_dst == 2) {
njn25e49d8e72002-09-23 09:36:25 +00002125 VG_(emit_shiftopv_lit_reg) ( 2, SHL, 8, reg );
2126 VG_(emit_shiftopv_lit_reg) ( 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002127 }
2128 else
njne427a662002-10-02 11:08:25 +00002129 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002130}
2131
2132
njn25e49d8e72002-09-23 09:36:25 +00002133static void synth_handle_esp_assignment ( Int i, Int reg,
2134 RRegSet regs_live_before,
2135 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002136{
njn25e49d8e72002-09-23 09:36:25 +00002137 UInt argv[] = { reg };
2138 Tag tagv[] = { RealReg };
2139
2140 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2141 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002142}
2143
2144
sewardjde4a1d02002-03-22 01:27:54 +00002145/*----------------------------------------------------*/
2146/*--- Generate code for a single UInstr. ---*/
2147/*----------------------------------------------------*/
2148
sewardj478335c2002-10-05 02:44:47 +00002149static __inline__
2150Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002151{
2152 return (u->flags_w != FlagsEmpty);
2153}
2154
sewardj478335c2002-10-05 02:44:47 +00002155static __inline__
2156Bool anyFlagUse ( UInstr* u )
2157{
2158 return (u->flags_r != FlagsEmpty || u->flags_w != FlagsEmpty);
2159}
2160
2161
sewardjb5ff83e2002-12-01 19:40:49 +00002162/* *fplive==True indicates that the simulated machine's FPU state is in
sewardj1b7d8022002-11-30 12:35:42 +00002163 the real FPU. If so we need to be very careful not to trash it.
2164 If FPU state is live and we deem it necessary to copy it back to
2165 the simulated machine's FPU state, we do so. The final state of
2166 fpliveness is returned. In short we _must_ do put_fpu_state if
2167 there is any chance at all that the code generated for a UInstr
2168 will change the real FPU state.
2169*/
sewardjb5ff83e2002-12-01 19:40:49 +00002170static void emitUInstr ( UCodeBlock* cb, Int i,
2171 RRegSet regs_live_before,
2172 /* Running state, which we update. */
2173 Bool* fplive, /* True<==>FPU state in real FPU */
2174 Addr* orig_eip, /* previous curr_eip, or zero */
2175 Addr* curr_eip ) /* current eip */
sewardjde4a1d02002-03-22 01:27:54 +00002176{
njn25e49d8e72002-09-23 09:36:25 +00002177 Int old_emitted_code_used;
2178 UInstr* u = &cb->instrs[i];
2179
sewardjde4a1d02002-03-22 01:27:54 +00002180 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002181 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002182
njn25e49d8e72002-09-23 09:36:25 +00002183 old_emitted_code_used = emitted_code_used;
2184
sewardjde4a1d02002-03-22 01:27:54 +00002185 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002186 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002187
sewardjb5ff83e2002-12-01 19:40:49 +00002188 case INCEIP:
2189 /* Advance %EIP some small amount. */
2190 *curr_eip += (UInt)(u->val1);
njn25e49d8e72002-09-23 09:36:25 +00002191
sewardjb5ff83e2002-12-01 19:40:49 +00002192 if (*orig_eip == 0 /* we don't know what the old value was */
2193 || ((*orig_eip & ~0xFF) != (*curr_eip & ~0xFF))) {
2194 /* We have to update all 32 bits of the value. */
2195 VG_(emit_movv_lit_offregmem)(
2196 4, *curr_eip, 4*VGOFF_(m_eip), R_EBP);
2197 } else {
2198 /* Cool! we only need to update lowest 8 bits */
2199 VG_(emit_movb_lit_offregmem)(
2200 *curr_eip & 0xFF, 4*VGOFF_(m_eip)+0, R_EBP);
njn25e49d8e72002-09-23 09:36:25 +00002201 }
njn25e49d8e72002-09-23 09:36:25 +00002202
sewardjb5ff83e2002-12-01 19:40:49 +00002203 *orig_eip = *curr_eip;
sewardjde4a1d02002-03-22 01:27:54 +00002204 break;
sewardjde4a1d02002-03-22 01:27:54 +00002205
2206 case LEA1: {
2207 vg_assert(u->tag1 == RealReg);
2208 vg_assert(u->tag2 == RealReg);
2209 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2210 break;
2211 }
2212
2213 case LEA2: {
2214 vg_assert(u->tag1 == RealReg);
2215 vg_assert(u->tag2 == RealReg);
2216 vg_assert(u->tag3 == RealReg);
2217 emit_lea_sib_reg ( u->lit32, u->extra4b,
2218 u->val1, u->val2, u->val3 );
2219 break;
2220 }
2221
2222 case WIDEN: {
2223 vg_assert(u->tag1 == RealReg);
2224 if (u->signed_widen) {
2225 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2226 } else {
2227 /* no need to generate any code. */
2228 }
2229 break;
2230 }
2231
sewardjde4a1d02002-03-22 01:27:54 +00002232 case STORE: {
2233 vg_assert(u->tag1 == RealReg);
2234 vg_assert(u->tag2 == RealReg);
2235 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002236 break;
2237 }
2238
2239 case LOAD: {
2240 vg_assert(u->tag1 == RealReg);
2241 vg_assert(u->tag2 == RealReg);
2242 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2243 break;
2244 }
2245
sewardjde4a1d02002-03-22 01:27:54 +00002246 case GET: {
2247 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2248 vg_assert(u->tag2 == RealReg);
2249 synth_mov_offregmem_reg (
2250 u->size,
2251 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2252 R_EBP,
2253 u->val2
2254 );
2255 break;
2256 }
2257
2258 case PUT: {
2259 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2260 vg_assert(u->tag1 == RealReg);
2261 if (u->tag2 == ArchReg
2262 && u->val2 == R_ESP
2263 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002264 && (VG_(track_events).new_mem_stack ||
2265 VG_(track_events).new_mem_stack_aligned ||
2266 VG_(track_events).die_mem_stack ||
2267 VG_(track_events).die_mem_stack_aligned ||
2268 VG_(track_events).post_mem_write))
2269 {
2270 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2271 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002272 }
njn25e49d8e72002-09-23 09:36:25 +00002273 else {
2274 synth_mov_reg_offregmem (
2275 u->size,
2276 u->val1,
2277 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2278 R_EBP
2279 );
2280 }
sewardjde4a1d02002-03-22 01:27:54 +00002281 break;
2282 }
2283
sewardje1042472002-09-30 12:33:11 +00002284 case GETSEG: {
2285 vg_assert(u->tag1 == ArchRegS);
2286 vg_assert(u->tag2 == RealReg);
2287 vg_assert(u->size == 2);
2288 synth_mov_offregmem_reg (
2289 4,
2290 segRegOffset( u->val1 ),
2291 R_EBP,
2292 u->val2
2293 );
2294 break;
2295 }
2296
2297 case PUTSEG: {
2298 vg_assert(u->tag1 == RealReg);
2299 vg_assert(u->tag2 == ArchRegS);
2300 vg_assert(u->size == 2);
2301 synth_mov_reg_offregmem (
2302 4,
2303 u->val1,
2304 segRegOffset( u->val2 ),
2305 R_EBP
2306 );
2307 break;
2308 }
2309
sewardjde4a1d02002-03-22 01:27:54 +00002310 case GETF: {
2311 vg_assert(u->size == 2 || u->size == 4);
2312 vg_assert(u->tag1 == RealReg);
2313 synth_mov_offregmem_reg (
2314 u->size,
2315 eflagsOffset(),
2316 R_EBP,
2317 u->val1
2318 );
2319 break;
2320 }
2321
2322 case PUTF: {
2323 vg_assert(u->size == 2 || u->size == 4);
2324 vg_assert(u->tag1 == RealReg);
2325 synth_mov_reg_offregmem (
2326 u->size,
2327 u->val1,
2328 eflagsOffset(),
2329 R_EBP
2330 );
2331 break;
2332 }
2333
2334 case MOV: {
2335 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2336 vg_assert(u->tag2 == RealReg);
2337 switch (u->tag1) {
2338 case RealReg: vg_assert(u->size == 4);
2339 if (u->val1 != u->val2)
2340 synth_movl_reg_reg ( u->val1, u->val2 );
2341 break;
2342 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2343 break;
njne427a662002-10-02 11:08:25 +00002344 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002345 }
2346 break;
2347 }
2348
sewardje1042472002-09-30 12:33:11 +00002349 case USESEG: {
2350 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2351 ones. */
sewardjd077f532002-09-30 21:52:50 +00002352 UInt argv[] = { u->val1, u->val2 };
2353 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002354 UInt ret_reg = u->val2;
2355
2356 vg_assert(u->tag1 == RealReg);
2357 vg_assert(u->tag2 == RealReg);
2358 vg_assert(u->size == 0);
2359
sewardjb5ff83e2002-12-01 19:40:49 +00002360 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002361 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002362 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002363 }
2364
sewardje1042472002-09-30 12:33:11 +00002365 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2366 2, /* args */
2367 0, /* regparms_n */
2368 argv, tagv,
2369 ret_reg, regs_live_before, u->regs_live_after );
2370 break;
2371 }
2372
sewardj478335c2002-10-05 02:44:47 +00002373 case SBB:
2374 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002375 case XOR:
2376 case OR:
2377 case AND:
2378 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002379 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002380 vg_assert(u->tag2 == RealReg);
2381 switch (u->tag1) {
2382 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002383 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002384 u->opcode, u->size, u->lit32, u->val2 );
2385 break;
2386 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002387 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002388 u->opcode, u->size, u->val1, u->val2 );
2389 break;
2390 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002391 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002392 u->opcode, u->size,
2393 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2394 R_EBP,
2395 u->val2 );
2396 break;
njne427a662002-10-02 11:08:25 +00002397 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002398 }
2399 break;
2400 }
2401
sewardj478335c2002-10-05 02:44:47 +00002402 case RCR:
2403 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002404 case ROR:
2405 case ROL:
2406 case SAR:
2407 case SHR:
2408 case SHL: {
2409 vg_assert(u->tag2 == RealReg);
2410 switch (u->tag1) {
2411 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002412 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002413 u->opcode, u->size, u->lit32, u->val2 );
2414 break;
2415 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002416 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002417 u->opcode, u->size, u->val1, u->val2 );
2418 break;
njne427a662002-10-02 11:08:25 +00002419 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002420 }
2421 break;
2422 }
2423
2424 case INC:
2425 case DEC:
2426 case NEG:
2427 case NOT:
2428 vg_assert(u->tag1 == RealReg);
2429 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002430 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002431 break;
2432
2433 case BSWAP:
2434 vg_assert(u->tag1 == RealReg);
2435 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002436 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002437 emit_bswapl_reg ( u->val1 );
2438 break;
2439
2440 case CMOV:
2441 vg_assert(u->tag1 == RealReg);
2442 vg_assert(u->tag2 == RealReg);
2443 vg_assert(u->cond != CondAlways);
2444 vg_assert(u->size == 4);
2445 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2446 break;
2447
2448 case JMP: {
2449 vg_assert(u->tag2 == NoValue);
2450 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardjb5ff83e2002-12-01 19:40:49 +00002451 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002452 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002453 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002454 }
sewardjde4a1d02002-03-22 01:27:54 +00002455 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002456 switch (u->tag1) {
2457 case RealReg:
2458 synth_jmp_reg ( u->val1, u->jmpkind );
2459 break;
2460 case Literal:
2461 synth_jmp_lit ( u->lit32, u->jmpkind );
2462 break;
2463 default:
njne427a662002-10-02 11:08:25 +00002464 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002465 break;
sewardjde4a1d02002-03-22 01:27:54 +00002466 }
2467 } else {
sewardj2e93c502002-04-12 11:12:52 +00002468 switch (u->tag1) {
2469 case RealReg:
njne427a662002-10-02 11:08:25 +00002470 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002471 break;
2472 case Literal:
2473 vg_assert(u->jmpkind == JmpBoring);
2474 synth_jcond_lit ( u->cond, u->lit32 );
2475 break;
2476 default:
njne427a662002-10-02 11:08:25 +00002477 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002478 break;
sewardjde4a1d02002-03-22 01:27:54 +00002479 }
2480 }
2481 break;
2482 }
2483
2484 case JIFZ:
2485 vg_assert(u->tag1 == RealReg);
2486 vg_assert(u->tag2 == Literal);
2487 vg_assert(u->size == 4);
sewardjb5ff83e2002-12-01 19:40:49 +00002488 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002489 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002490 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002491 }
sewardjde4a1d02002-03-22 01:27:54 +00002492 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2493 break;
2494
sewardjde4a1d02002-03-22 01:27:54 +00002495 case PUSH:
2496 vg_assert(u->tag1 == RealReg);
2497 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002498 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002499 break;
2500
2501 case POP:
2502 vg_assert(u->tag1 == RealReg);
2503 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002504 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002505 break;
2506
2507 case CALLM:
2508 vg_assert(u->tag1 == Lit16);
2509 vg_assert(u->tag2 == NoValue);
2510 vg_assert(u->size == 0);
sewardjb5ff83e2002-12-01 19:40:49 +00002511 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002512 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002513 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002514 }
sewardj478335c2002-10-05 02:44:47 +00002515 if (anyFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002516 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002517 VG_(synth_call) ( False, u->val1 );
njn5a74eb82002-08-06 20:56:40 +00002518 if (writeFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002519 emit_put_eflags();
2520 break;
2521
njn25e49d8e72002-09-23 09:36:25 +00002522 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002523 /* If you change this, remember to change USESEG above, since
2524 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002525 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2526 ones. */
2527 UInt argv[] = { u->val1, u->val2, u->val3 };
2528 UInt tagv[] = { RealReg, RealReg, RealReg };
2529 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2530
2531 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2532 else vg_assert(u->tag1 == NoValue);
2533 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2534 else vg_assert(u->tag2 == NoValue);
2535 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2536 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002537 vg_assert(u->size == 0);
2538
sewardjb5ff83e2002-12-01 19:40:49 +00002539 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002540 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002541 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002542 }
njn25e49d8e72002-09-23 09:36:25 +00002543 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2544 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002545 break;
njn25e49d8e72002-09-23 09:36:25 +00002546 }
sewardje1042472002-09-30 12:33:11 +00002547
sewardjde4a1d02002-03-22 01:27:54 +00002548 case CLEAR:
2549 vg_assert(u->tag1 == Lit16);
2550 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002551 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002552 break;
2553
2554 case CC2VAL:
2555 vg_assert(u->tag1 == RealReg);
2556 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00002557 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002558 synth_setb_reg ( u->val1, u->cond );
2559 break;
2560
sewardjde4a1d02002-03-22 01:27:54 +00002561 case FPU_R:
2562 case FPU_W:
2563 vg_assert(u->tag1 == Lit16);
2564 vg_assert(u->tag2 == RealReg);
sewardjb5ff83e2002-12-01 19:40:49 +00002565 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002566 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002567 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00002568 }
sewardjde4a1d02002-03-22 01:27:54 +00002569 synth_fpu_regmem ( (u->val1 >> 8) & 0xFF,
2570 u->val1 & 0xFF,
2571 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002572 break;
2573
2574 case FPU:
2575 vg_assert(u->tag1 == Lit16);
2576 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00002577 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002578 emit_get_eflags();
sewardjb5ff83e2002-12-01 19:40:49 +00002579 if (!(*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002580 emit_get_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002581 *fplive = True;
sewardj1b7d8022002-11-30 12:35:42 +00002582 }
sewardjde4a1d02002-03-22 01:27:54 +00002583 synth_fpu_no_mem ( (u->val1 >> 8) & 0xFF,
2584 u->val1 & 0xFF );
njn5a74eb82002-08-06 20:56:40 +00002585 if (writeFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002586 emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002587 break;
2588
2589 default:
sewardj1b7d8022002-11-30 12:35:42 +00002590 if (VG_(needs).extended_UCode) {
sewardjb5ff83e2002-12-01 19:40:49 +00002591 if (*fplive) {
sewardj1b7d8022002-11-30 12:35:42 +00002592 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002593 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002594 }
njn4ba5a792002-09-30 10:23:54 +00002595 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00002596 } else {
njn25e49d8e72002-09-23 09:36:25 +00002597 VG_(printf)("\nError:\n"
2598 " unhandled opcode: %u. Perhaps "
2599 " VG_(needs).extended_UCode should be set?\n",
2600 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00002601 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00002602 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00002603 }
sewardjde4a1d02002-03-22 01:27:54 +00002604 }
2605
sewardjb5ff83e2002-12-01 19:40:49 +00002606 if (0 && (*fplive)) {
sewardj1b7d8022002-11-30 12:35:42 +00002607 emit_put_fpu_state();
sewardjb5ff83e2002-12-01 19:40:49 +00002608 *fplive = False;
sewardj1b7d8022002-11-30 12:35:42 +00002609 }
2610
njn25e49d8e72002-09-23 09:36:25 +00002611 /* Update UInstr histogram */
2612 vg_assert(u->opcode < 100);
2613 histogram[u->opcode].counts++;
2614 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardjde4a1d02002-03-22 01:27:54 +00002615}
2616
2617
2618/* Emit x86 for the ucode in cb, returning the address of the
2619 generated code and setting *nbytes to its size. */
sewardjb5ff83e2002-12-01 19:40:49 +00002620UChar* VG_(emit_code) ( UCodeBlock* cb,
2621 Int* nbytes,
2622 UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00002623{
2624 Int i;
njn25e49d8e72002-09-23 09:36:25 +00002625 UChar regs_live_before = 0; /* No regs live at BB start */
sewardjb5ff83e2002-12-01 19:40:49 +00002626
sewardj1b7d8022002-11-30 12:35:42 +00002627 Bool fplive;
sewardjb5ff83e2002-12-01 19:40:49 +00002628 Addr orig_eip, curr_eip;
2629
sewardjde4a1d02002-03-22 01:27:54 +00002630 emitted_code_used = 0;
2631 emitted_code_size = 500; /* reasonable initial size */
njn25e49d8e72002-09-23 09:36:25 +00002632 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
sewardj22854b92002-11-30 14:00:47 +00002633 jumpidx = 0;
sewardjde4a1d02002-03-22 01:27:54 +00002634
njn25e49d8e72002-09-23 09:36:25 +00002635 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00002636
sewardj22854b92002-11-30 14:00:47 +00002637 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
2638 zero. We have to do this regardless of whether we're t-chaining
2639 or not. */
2640 VG_(new_emit)();
2641 VG_(emitB) (0xFF); /* decl */
2642 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
2643 if (dis)
2644 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
2645 VG_(emit_jcondshort_delta)(CondNZ, 5+1);
2646 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
2647 emit_ret();
2648
sewardjb5ff83e2002-12-01 19:40:49 +00002649 /* Set up running state. */
2650 fplive = False;
2651 orig_eip = 0;
2652 curr_eip = cb->orig_eip;
2653 vg_assert(curr_eip != 0); /* otherwise the incremental updating
2654 algorithm gets messed up. */
2655
2656 /* for each uinstr ... */
sewardjde4a1d02002-03-22 01:27:54 +00002657 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00002658 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00002659 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00002660
sewardjde4a1d02002-03-22 01:27:54 +00002661 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00002662 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00002663 if (!sane) {
2664 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00002665 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00002666 }
2667 vg_assert(sane);
sewardjb5ff83e2002-12-01 19:40:49 +00002668 emitUInstr( cb, i, regs_live_before,
2669 &fplive, &orig_eip, &curr_eip );
sewardjde4a1d02002-03-22 01:27:54 +00002670 }
njn25e49d8e72002-09-23 09:36:25 +00002671 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00002672 }
njn25e49d8e72002-09-23 09:36:25 +00002673 if (dis) VG_(printf)("\n");
sewardj1b7d8022002-11-30 12:35:42 +00002674 vg_assert(!fplive); /* FPU state must be saved by end of BB */
sewardjde4a1d02002-03-22 01:27:54 +00002675
sewardj22854b92002-11-30 14:00:47 +00002676 if (j != NULL) {
2677 vg_assert(jumpidx <= VG_MAX_JUMPS);
2678 for(i = 0; i < jumpidx; i++)
2679 j[i] = jumps[i];
2680 }
2681
sewardjde4a1d02002-03-22 01:27:54 +00002682 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00002683 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00002684 *nbytes = emitted_code_used;
2685 return emitted_code;
2686}
2687
njn25e49d8e72002-09-23 09:36:25 +00002688#undef dis
2689
sewardjde4a1d02002-03-22 01:27:54 +00002690/*--------------------------------------------------------------------*/
2691/*--- end vg_from_ucode.c ---*/
2692/*--------------------------------------------------------------------*/