blob: 645988cd276400d39377bf5b0d2ebfb6172ae409 [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
1056/* Predicate used in sanity checks elsewhere - returns true if all
1057 jump-sites are calls to VG_(patch_me) */
1058Bool VG_(is_unchained_jumpsite)(Addr a)
1059{
1060 UChar *cp = (UChar *)a;
1061 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1062 Int idelta;
1063
1064 if (*cp++ != 0xE8) /* 0xE8 == call */
1065 return False;
1066
1067 idelta = (*cp++) << 0;
1068 idelta |= (*cp++) << 8;
1069 idelta |= (*cp++) << 16;
1070 idelta |= (*cp++) << 24;
1071
1072 return idelta == delta;
1073}
1074
1075/* Return target address for a direct jmp */
1076Addr VG_(get_jmp_dest)(Addr a)
1077{
1078 Int delta;
1079 UChar *cp = (UChar *)a;
1080
1081 if (*cp++ != 0xE9) /* 0xE9 == jmp */
1082 return 0;
1083
1084 delta = (*cp++) << 0;
1085 delta |= (*cp++) << 8;
1086 delta |= (*cp++) << 16;
1087 delta |= (*cp++) << 24;
1088
1089 return a + VG_PATCHME_JMPSZ + delta;
1090}
1091
1092/* unchain a BB by generating a call to VG_(patch_me) */
1093void VG_(unchain_jumpsite)(Addr a)
1094{
1095 Int delta = ((Addr)&VG_(patch_me)) - (a + VG_PATCHME_CALLSZ);
1096 UChar *cp = (UChar *)a;
1097
1098 if (VG_(is_unchained_jumpsite)(a))
1099 return; /* don't write unnecessarily */
1100
1101 *cp++ = 0xE8; /* call */
1102 *cp++ = (delta >> 0) & 0xff;
1103 *cp++ = (delta >> 8) & 0xff;
1104 *cp++ = (delta >> 16) & 0xff;
1105 *cp++ = (delta >> 24) & 0xff;
1106 VG_(bb_dechain_count)++; /* update stats */
1107}
1108
1109/* This doesn't actually generate a call to VG_(patch_me), but
1110 reserves enough space in the instruction stream for it to happen
1111 and records the offset into the jump table. This is because call
1112 is a relative jump, and so will be affected when this code gets
1113 moved about. The translation table will "unchain" this basic block
1114 on insertion (with VG_(unchain_BB)()), and thereby generate a
1115 proper call instruction. */
1116static void emit_call_patchme( void )
1117{
1118 vg_assert(VG_PATCHME_CALLSZ == 5);
1119
1120 VG_(new_emit)();
1121
1122 if (jumpidx >= VG_MAX_JUMPS) {
1123 /* If there too many jumps in this basic block, fall back to
1124 dispatch loop. We still need to keep it the same size as the
1125 call sequence. */
1126 VG_(emitB) ( 0xC3 ); /* ret */
1127 VG_(emitB) ( 0x90 ); /* nop */
1128 VG_(emitB) ( 0x90 ); /* nop */
1129 VG_(emitB) ( 0x90 ); /* nop */
1130 VG_(emitB) ( 0x90 ); /* nop */
1131
1132 if (dis)
1133 VG_(printf)("\n\t\tret; nop; nop; nop; nop\n");
1134
1135 if (0 && VG_(clo_verbosity))
1136 VG_(message)(Vg_DebugMsg, "too many chained jumps in basic-block");
1137 } else {
1138 jumps[jumpidx++] = emitted_code_used;
1139
1140 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1141 VG_(emitB) ( 0x0B );
1142 VG_(emitB) ( 0x0F ); /* UD2 - undefined instruction */
1143 VG_(emitB) ( 0x0B );
1144 VG_(emitB) ( 0x90 ); /* NOP */
1145
1146 if (dis)
1147 VG_(printf)("\n\t\tud2; ud2; nop\n");
1148 }
1149}
1150
njn25e49d8e72002-09-23 09:36:25 +00001151void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001152{
njn4ba5a792002-09-30 10:23:54 +00001153 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001154 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001155 if (dis)
1156 VG_(printf)("\n\t\tpushal\n");
1157}
1158
njn25e49d8e72002-09-23 09:36:25 +00001159void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001160{
njn4ba5a792002-09-30 10:23:54 +00001161 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001162 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001163 if (dis)
1164 VG_(printf)("\n\t\tpopal\n");
1165}
1166
1167static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1168{
njn4ba5a792002-09-30 10:23:54 +00001169 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001170 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1171 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001172 if (dis)
1173 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1174 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1175}
1176
1177static void emit_lea_sib_reg ( UInt lit, Int scale,
1178 Int regbase, Int regindex, Int reg )
1179{
njn4ba5a792002-09-30 10:23:54 +00001180 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001181 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001182 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1183 if (dis)
1184 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1185 lit, nameIReg(4,regbase),
1186 nameIReg(4,regindex), scale,
1187 nameIReg(4,reg) );
1188}
1189
njn25e49d8e72002-09-23 09:36:25 +00001190void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001191{
njn4ba5a792002-09-30 10:23:54 +00001192 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001193 VG_(emitB) ( 0x0F );
1194 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001195 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1196 if (dis)
1197 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1198}
1199
1200/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001201/*--- Helper offset -> addr translation ---*/
1202/*----------------------------------------------------*/
1203
1204/* Finds the baseBlock offset of a skin-specified helper.
1205 * Searches through compacts first, then non-compacts. */
1206Int VG_(helper_offset)(Addr a)
1207{
1208 Int i;
1209
1210 for (i = 0; i < VG_(n_compact_helpers); i++)
1211 if (VG_(compact_helper_addrs)[i] == a)
1212 return VG_(compact_helper_offsets)[i];
1213 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1214 if (VG_(noncompact_helper_addrs)[i] == a)
1215 return VG_(noncompact_helper_offsets)[i];
1216
1217 /* Shouldn't get here */
1218 VG_(printf)(
1219 "\nCouldn't find offset of helper from its address (%p).\n"
1220 "A helper function probably used hasn't been registered?\n\n", a);
1221
1222 VG_(printf)(" compact helpers: ");
1223 for (i = 0; i < VG_(n_compact_helpers); i++)
1224 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1225
1226 VG_(printf)("\n non-compact helpers: ");
1227 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1228 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1229
1230 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001231 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001232}
1233
1234/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001235/*--- Instruction synthesisers ---*/
1236/*----------------------------------------------------*/
1237
1238static Condcode invertCondition ( Condcode cond )
1239{
1240 return (Condcode)(1 ^ (UInt)cond);
1241}
1242
1243
1244/* Synthesise a call to *baseBlock[offset], ie,
1245 call * (4 x offset)(%ebp).
1246*/
njn25e49d8e72002-09-23 09:36:25 +00001247void VG_(synth_call) ( Bool ensure_shortform, Int word_offset )
sewardjde4a1d02002-03-22 01:27:54 +00001248{
1249 vg_assert(word_offset >= 0);
1250 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1251 if (ensure_shortform)
1252 vg_assert(word_offset < 32);
1253 emit_call_star_EBP_off ( 4 * word_offset );
1254}
1255
njn25e49d8e72002-09-23 09:36:25 +00001256static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001257{
njn25e49d8e72002-09-23 09:36:25 +00001258 if (src != dst) {
1259 VG_(emit_movv_reg_reg) ( 4, src, dst );
1260 ccall_arg_setup_instrs++;
1261 }
njn6431be72002-07-28 09:53:34 +00001262}
njn25e49d8e72002-09-23 09:36:25 +00001263
1264/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1265static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1266{
1267 if (RealReg == tag) {
1268 maybe_emit_movl_reg_reg ( litOrReg, reg );
1269 } else if (Literal == tag) {
1270 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1271 ccall_arg_setup_instrs++;
1272 }
1273 else
njne427a662002-10-02 11:08:25 +00001274 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001275}
1276
1277static
1278void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1279{
1280 if (R_EAX == reg1) {
1281 VG_(emit_swapl_reg_EAX) ( reg2 );
1282 } else if (R_EAX == reg2) {
1283 VG_(emit_swapl_reg_EAX) ( reg1 );
1284 } else {
1285 emit_swapl_reg_reg ( reg1, reg2 );
1286 }
1287 ccall_arg_setup_instrs++;
1288}
1289
1290static
1291void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1292{
1293 if (dst1 != src2) {
1294 maybe_emit_movl_reg_reg ( src1, dst1 );
1295 maybe_emit_movl_reg_reg ( src2, dst2 );
1296
1297 } else if (dst2 != src1) {
1298 maybe_emit_movl_reg_reg ( src2, dst2 );
1299 maybe_emit_movl_reg_reg ( src1, dst1 );
1300
1301 } else {
1302 /* swap to break cycle */
1303 emit_swapl_arg_regs ( dst1, dst2 );
1304 }
1305}
1306
1307static
1308void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1309 UInt dst1, UInt dst2, UInt dst3)
1310{
1311 if (dst1 != src2 && dst1 != src3) {
1312 maybe_emit_movl_reg_reg ( src1, dst1 );
1313 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1314
1315 } else if (dst2 != src1 && dst2 != src3) {
1316 maybe_emit_movl_reg_reg ( src2, dst2 );
1317 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1318
1319 } else if (dst3 != src1 && dst3 != src2) {
1320 maybe_emit_movl_reg_reg ( src3, dst3 );
1321 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1322
1323 } else {
1324 /* break cycle */
1325 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1326 emit_swapl_arg_regs ( dst1, dst2 );
1327 emit_swapl_arg_regs ( dst1, dst3 );
1328
1329 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1330 emit_swapl_arg_regs ( dst1, dst3 );
1331 emit_swapl_arg_regs ( dst1, dst2 );
1332
1333 } else {
njne427a662002-10-02 11:08:25 +00001334 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001335 }
1336 }
1337}
1338
1339static
1340void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1341 UInt src1, UInt src2,
1342 UInt dst1, UInt dst2)
1343{
1344 /* If either are lits, order doesn't matter */
1345 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1346 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1347 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1348
1349 } else {
1350 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1351 }
1352}
1353
1354static
1355void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1356 UInt src1, UInt src2, UInt src3,
1357 UInt dst1, UInt dst2, UInt dst3)
1358{
1359 // SSS: fix this eventually -- make STOREV use two RealRegs?
1360 /* Not supporting literals for 3-arg C functions -- they're only used
1361 by STOREV which has 2 args */
1362 vg_assert(RealReg == tagv[src1] &&
1363 RealReg == tagv[src2] &&
1364 RealReg == tagv[src3]);
1365 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1366 dst1, dst2, dst3 );
1367}
1368
1369/* Synthesise a call to a C function `fn' (which must be registered in
1370 baseBlock) doing all the reg saving and arg handling work.
1371
1372 WARNING: a UInstr should *not* be translated with synth_ccall followed
1373 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1374 such behaviour and everything will fall over.
1375 */
1376void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1377 Tag tagv[], Int ret_reg,
1378 RRegSet regs_live_before, RRegSet regs_live_after )
1379{
1380 Int i;
1381 Int stack_used = 0;
1382 Bool preserve_eax, preserve_ecx, preserve_edx;
1383
1384 vg_assert(0 <= regparms_n && regparms_n <= 3);
1385
1386 ccalls++;
1387
1388 /* If %e[acd]x is live before and after the C call, save/restore it.
1389 Unless the return values clobbers the reg; in this case we must not
1390 save/restore the reg, because the restore would clobber the return
1391 value. (Before and after the UInstr really constitute separate live
1392 ranges, but you miss this if you don't consider what happens during
1393 the UInstr.) */
1394# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001395 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1396 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001397 ret_reg != realReg)
1398
1399 preserve_eax = PRESERVE_REG(R_EAX);
1400 preserve_ecx = PRESERVE_REG(R_ECX);
1401 preserve_edx = PRESERVE_REG(R_EDX);
1402
1403# undef PRESERVE_REG
1404
1405 /* Save caller-save regs as required */
1406 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1407 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1408 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1409
1410 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1411 is the number of args passed in regs (maximum 3 for GCC on x86). */
1412
1413 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001414
njn25e49d8e72002-09-23 09:36:25 +00001415 /* First push stack args (RealRegs or Literals) in reverse order. */
1416 for (i = argc-1; i >= regparms_n; i--) {
1417 switch (tagv[i]) {
1418 case RealReg:
1419 VG_(emit_pushv_reg) ( 4, argv[i] );
1420 break;
1421 case Literal:
1422 /* Use short form of pushl if possible. */
1423 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1424 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1425 else
1426 VG_(emit_pushl_lit32)( argv[i] );
1427 break;
1428 default:
1429 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001430 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001431 }
1432 stack_used += 4;
1433 ccall_arg_setup_instrs++;
1434 }
njn6431be72002-07-28 09:53:34 +00001435
njn25e49d8e72002-09-23 09:36:25 +00001436 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1437 If moving values between registers, be careful not to clobber any on
1438 the way. Happily we can use xchgl to swap registers.
1439 */
1440 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001441
njn25e49d8e72002-09-23 09:36:25 +00001442 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1443 case 3:
1444 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1445 R_EAX, R_EDX, R_ECX );
1446 break;
njn6431be72002-07-28 09:53:34 +00001447
njn25e49d8e72002-09-23 09:36:25 +00001448 /* Less-tricky. Args passed in %eax and %edx. */
1449 case 2:
1450 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1451 break;
1452
1453 /* Easy. Just move arg1 into %eax (if not already in there). */
1454 case 1:
1455 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1456 break;
1457
1458 case 0:
1459 break;
1460
1461 default:
njne427a662002-10-02 11:08:25 +00001462 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001463 }
1464
1465 /* Call the function */
1466 VG_(synth_call) ( False, VG_(helper_offset) ( fn ) );
1467
1468 /* Clear any args from stack */
1469 if (0 != stack_used) {
1470 VG_(emit_add_lit_to_esp) ( stack_used );
1471 ccall_stack_clears++;
1472 }
1473
1474 /* Move return value into ret_reg if necessary and not already there */
1475 if (INVALID_REALREG != ret_reg) {
1476 ccall_retvals++;
1477 if (R_EAX != ret_reg) {
1478 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1479 ccall_retval_movs++;
1480 }
1481 }
1482
1483 /* Restore live caller-save regs as required */
1484 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1485 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1486 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001487}
sewardjde4a1d02002-03-22 01:27:54 +00001488
sewardj2e93c502002-04-12 11:12:52 +00001489static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001490{
sewardj2e93c502002-04-12 11:12:52 +00001491 switch (jmpkind) {
1492 case JmpBoring:
1493 break;
sewardj2e93c502002-04-12 11:12:52 +00001494 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001495 break;
1496 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001497 break;
1498 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001499 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001500 break;
1501 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001502 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001503 break;
1504 default:
njne427a662002-10-02 11:08:25 +00001505 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001506 }
1507}
1508
1509/* Jump to the next translation, by loading its original addr into
1510 %eax and returning to the scheduler. Signal special requirements
1511 by loading a special value into %ebp first.
1512*/
1513static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1514{
1515 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001516 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001517 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001518 emit_ret();
1519}
1520
sewardj22854b92002-11-30 14:00:47 +00001521static void synth_mov_reg_offregmem ( Int size, Int reg, Int off, Int areg );
sewardjde4a1d02002-03-22 01:27:54 +00001522
1523/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001524static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001525{
njn25e49d8e72002-09-23 09:36:25 +00001526 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardj22854b92002-11-30 14:00:47 +00001527
1528 if (VG_(clo_chain_bb) && (jmpkind == JmpBoring || jmpkind == JmpCall)) {
1529 synth_mov_reg_offregmem(4, R_EAX, 4*VGOFF_(m_eip), R_EBP); /* update EIP */
1530 emit_call_patchme();
1531 } else {
1532 load_ebp_from_JmpKind ( jmpkind );
1533 emit_ret();
1534 }
sewardjde4a1d02002-03-22 01:27:54 +00001535}
1536
1537
sewardj2370f3b2002-11-30 15:01:01 +00001538static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg );
1539static void synth_nonshiftop_lit_reg ( Bool upd_cc,
1540 Opcode opcode, Int size,
1541 UInt lit, Int reg );
1542
sewardjde4a1d02002-03-22 01:27:54 +00001543static void synth_jcond_lit ( Condcode cond, Addr addr )
1544{
sewardj2370f3b2002-11-30 15:01:01 +00001545 UInt mask;
1546 Int delta;
1547
sewardjde4a1d02002-03-22 01:27:54 +00001548 /* Do the following:
1549 get eflags
1550 jmp short if not cond to xyxyxy
1551 addr -> eax
1552 ret
1553 xyxyxy
1554
1555 2 0000 750C jnz xyxyxy
1556 3 0002 B877665544 movl $0x44556677, %eax
1557 4 0007 C3 ret
1558 5 0008 FFE3 jmp *%ebx
1559 6 xyxyxy:
1560 */
sewardj22854b92002-11-30 14:00:47 +00001561 if (VG_(clo_chain_bb)) {
1562 /* When using BB chaining, the jump sequence is:
1563 jmp short if not cond to xyxyxy
1564 addr -> eax
1565 call VG_(patch_me)/jmp target
1566 xyxyxy
1567
1568 je 1f
1569 mov $0x4000d190,%eax // 5
1570 mov %eax, VGOFF_(m_eip)(%ebp) // 3
1571 call 0x40050f9a <vgPlain_patch_me> // 5
sewardj2370f3b2002-11-30 15:01:01 +00001572 $01 // 1
sewardj22854b92002-11-30 14:00:47 +00001573 1: mov $0x4000d042,%eax
1574 call 0x40050f9a <vgPlain_patch_me>
1575 */
sewardj2370f3b2002-11-30 15:01:01 +00001576 delta = 5+3+5+1 -1;
sewardj22854b92002-11-30 14:00:47 +00001577 } else
sewardj2370f3b2002-11-30 15:01:01 +00001578 delta = 5+1;
1579
1580 if (!VG_(clo_fast_jcc)) {
1581 /* We're forced to do it the slow way. */
1582 emit_get_eflags();
1583 cond = invertCondition(cond);
1584 } else {
1585 switch (cond & ~1) {
1586 case CondB: mask = EFlagC; goto common; /* C=1 */
1587 case CondZ: mask = EFlagZ; goto common; /* Z=1 */
1588 case CondBE: mask = EFlagC | EFlagZ; goto common; /* C=1 || Z=1 */
1589 case CondS: mask = EFlagS; goto common; /* S=1 */
1590 case CondP: mask = EFlagP; goto common; /* P=1 */
1591 default:
1592 /* Too complex .. we have to do it the slow way. */
1593 emit_get_eflags();
1594 cond = invertCondition(cond);
1595 break;
1596
1597 common:
1598 VG_(new_emit)();
1599 if ((mask & 0xff) == mask) {
1600 VG_(emitB) ( 0xF6 ); /* Grp3 */
1601 VG_(emit_amode_offregmem_reg)(
1602 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1603 VG_(emitB) (mask);
1604 if (dis)
1605 VG_(printf)("\n\t\ttestb $%x, %d(%%ebp)\n",
1606 mask, VGOFF_(m_eflags) * 4);
1607 } else {
1608 VG_(emitB) ( 0xF7 );
1609 VG_(emit_amode_offregmem_reg)(
1610 VGOFF_(m_eflags) * 4, R_EBP, 0 /* subcode for TEST */);
1611 VG_(emitB) (mask);
1612 if (dis)
1613 VG_(printf)("\n\t\ttestx $%x, %d(%%ebp)\n",
1614 mask, VGOFF_(m_eflags) * 4);
1615 }
1616
1617 if (cond & 1)
1618 cond = CondNZ;
1619 else
1620 cond = CondZ;
1621 break;
1622 }
1623 }
1624
1625 VG_(emit_jcondshort_delta) ( cond, delta );
sewardj2e93c502002-04-12 11:12:52 +00001626 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001627}
1628
1629
sewardj2370f3b2002-11-30 15:01:01 +00001630
sewardjde4a1d02002-03-22 01:27:54 +00001631static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1632{
1633 /* 0000 83FF00 cmpl $0, %edi
1634 0003 750A jnz next
1635 0005 B844332211 movl $0x11223344, %eax
1636 000a C3 ret
1637 next:
1638 */
njn25e49d8e72002-09-23 09:36:25 +00001639 VG_(emit_cmpl_zero_reg) ( reg );
sewardj22854b92002-11-30 14:00:47 +00001640 if (VG_(clo_chain_bb))
1641 VG_(emit_jcondshort_delta) ( CondNZ, 5+3+5 );
1642 else
1643 VG_(emit_jcondshort_delta) ( CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001644 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001645}
1646
1647
1648static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1649{
1650 /* Load the zero-extended literal into reg, at size l,
1651 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00001652 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001653}
1654
1655
1656static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
1657{
1658 switch (size) {
1659 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
1660 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
1661 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00001662 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001663 }
1664}
1665
1666
1667static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
1668{
1669 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001670 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
1671 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
1672 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00001673 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001674 }
1675}
1676
1677
1678static void synth_mov_reg_offregmem ( Int size, Int reg,
1679 Int off, Int areg )
1680{
1681 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001682 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
1683 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00001684 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00001685 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00001686 }
1687 else {
njn25e49d8e72002-09-23 09:36:25 +00001688 VG_(emit_swapl_reg_EAX) ( reg );
1689 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
1690 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001691 }
1692 break;
njne427a662002-10-02 11:08:25 +00001693 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00001694 }
1695}
1696
1697
1698static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
1699{
1700 Int s1;
1701 switch (size) {
1702 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
1703 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
1704 case 1: if (reg1 < 4) {
1705 emit_movb_reg_regmem ( reg1, reg2 );
1706 }
1707 else {
1708 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
1709 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1710 emit_swapl_reg_reg ( s1, reg1 );
1711 emit_movb_reg_regmem ( s1, reg2 );
1712 emit_swapl_reg_reg ( s1, reg1 );
1713 }
1714 break;
njne427a662002-10-02 11:08:25 +00001715 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00001716 }
1717}
1718
1719
sewardj478335c2002-10-05 02:44:47 +00001720static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001721 Opcode opcode, Int size,
1722 Int reg )
1723{
1724 /* NB! opcode is a uinstr opcode, not an x86 one! */
1725 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001726 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001727 VG_(emit_unaryopv_reg) ( 4, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001728 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001729 break;
sewardj478335c2002-10-05 02:44:47 +00001730 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001731 VG_(emit_unaryopv_reg) ( 2, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001732 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001733 break;
1734 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001735 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001736 VG_(emit_unaryopb_reg) ( opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001737 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001738 } else {
njn25e49d8e72002-09-23 09:36:25 +00001739 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001740 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001741 VG_(emit_unaryopb_reg) ( opcode, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001742 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001743 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001744 }
1745 break;
njne427a662002-10-02 11:08:25 +00001746 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001747 }
1748}
1749
1750
1751
sewardj478335c2002-10-05 02:44:47 +00001752static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001753 Opcode opcode, Int size,
1754 Int reg1, Int reg2 )
1755{
1756 /* NB! opcode is a uinstr opcode, not an x86 one! */
1757 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001758 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001759 VG_(emit_nonshiftopv_reg_reg) ( 4, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001760 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001761 break;
sewardj478335c2002-10-05 02:44:47 +00001762 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001763 VG_(emit_nonshiftopv_reg_reg) ( 2, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001764 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001765 break;
1766 case 1: { /* Horrible ... */
1767 Int s1, s2;
1768 /* Choose s1 and s2 to be x86 regs which we can talk about the
1769 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
1770 sure s1 != s2 and that neither of them equal either reg1 or
1771 reg2. Then use them as temporaries to make things work. */
1772 if (reg1 < 4 && reg2 < 4) {
sewardj478335c2002-10-05 02:44:47 +00001773 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001774 emit_nonshiftopb_reg_reg(opcode, reg1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001775 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001776 break;
1777 }
1778 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1779 if (reg1 >= 4 && reg2 < 4) {
1780 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001781 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001782 emit_nonshiftopb_reg_reg(opcode, s1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001783 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001784 emit_swapl_reg_reg ( reg1, s1 );
1785 break;
1786 }
1787 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
1788 if (reg1 < 4 && reg2 >= 4) {
1789 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001790 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001791 emit_nonshiftopb_reg_reg(opcode, reg1, s2);
sewardj478335c2002-10-05 02:44:47 +00001792 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001793 emit_swapl_reg_reg ( reg2, s2 );
1794 break;
1795 }
1796 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
1797 emit_swapl_reg_reg ( reg1, s1 );
1798 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001799 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001800 emit_nonshiftopb_reg_reg(opcode, s1, s2);
sewardj478335c2002-10-05 02:44:47 +00001801 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001802 emit_swapl_reg_reg ( reg1, s1 );
1803 emit_swapl_reg_reg ( reg2, s2 );
1804 break;
1805 }
1806 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
1807 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001808 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001809 emit_nonshiftopb_reg_reg(opcode, s1, s1);
sewardj478335c2002-10-05 02:44:47 +00001810 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001811 emit_swapl_reg_reg ( reg1, s1 );
1812 break;
1813 }
njne427a662002-10-02 11:08:25 +00001814 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001815 }
njne427a662002-10-02 11:08:25 +00001816 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001817 }
1818}
1819
1820
1821static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00001822 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001823 Opcode opcode, Int size,
1824 Int off, Int areg, Int reg )
1825{
1826 switch (size) {
1827 case 4:
sewardj478335c2002-10-05 02:44:47 +00001828 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001829 emit_nonshiftopv_offregmem_reg ( 4, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001830 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001831 break;
1832 case 2:
sewardj478335c2002-10-05 02:44:47 +00001833 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001834 emit_nonshiftopv_offregmem_reg ( 2, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001835 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001836 break;
1837 case 1:
1838 if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001839 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001840 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001841 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001842 } else {
njn25e49d8e72002-09-23 09:36:25 +00001843 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001844 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001845 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001846 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001847 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001848 }
1849 break;
1850 default:
njne427a662002-10-02 11:08:25 +00001851 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001852 }
1853}
1854
1855
sewardj478335c2002-10-05 02:44:47 +00001856static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001857 Opcode opcode, Int size,
1858 UInt lit, Int reg )
1859{
1860 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001861 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001862 VG_(emit_nonshiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001863 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001864 break;
sewardj478335c2002-10-05 02:44:47 +00001865 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001866 VG_(emit_nonshiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001867 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001868 break;
1869 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001870 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001871 emit_nonshiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001872 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001873 } else {
njn25e49d8e72002-09-23 09:36:25 +00001874 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001875 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001876 emit_nonshiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001877 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001878 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001879 }
1880 break;
njne427a662002-10-02 11:08:25 +00001881 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001882 }
1883}
1884
1885
1886static void synth_push_reg ( Int size, Int reg )
1887{
1888 switch (size) {
1889 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001890 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001891 break;
1892 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001893 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001894 break;
1895 /* Pray that we don't have to generate this really cruddy bit of
1896 code very often. Could do better, but can I be bothered? */
1897 case 1:
1898 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001899 VG_(emit_add_lit_to_esp)(-1);
1900 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001901 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00001902 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001903 break;
1904 default:
njne427a662002-10-02 11:08:25 +00001905 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001906 }
1907}
1908
1909
1910static void synth_pop_reg ( Int size, Int reg )
1911{
1912 switch (size) {
1913 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001914 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001915 break;
1916 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001917 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001918 break;
1919 case 1:
1920 /* Same comment as above applies. */
1921 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001922 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001923 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00001924 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
1925 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001926 break;
njne427a662002-10-02 11:08:25 +00001927 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001928 }
1929}
1930
1931
sewardj478335c2002-10-05 02:44:47 +00001932static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001933 Opcode opcode, Int size,
1934 Int regs, Int regd )
1935{
1936 synth_push_reg ( size, regd );
1937 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardj478335c2002-10-05 02:44:47 +00001938 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001939 switch (size) {
1940 case 4: emit_shiftopv_cl_stack0 ( 4, opcode ); break;
1941 case 2: emit_shiftopv_cl_stack0 ( 2, opcode ); break;
1942 case 1: emit_shiftopb_cl_stack0 ( opcode ); break;
njne427a662002-10-02 11:08:25 +00001943 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001944 }
sewardj478335c2002-10-05 02:44:47 +00001945 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001946 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
1947 synth_pop_reg ( size, regd );
1948}
1949
1950
sewardj478335c2002-10-05 02:44:47 +00001951static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001952 Opcode opcode, Int size,
1953 UInt lit, Int reg )
1954{
1955 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001956 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001957 VG_(emit_shiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001958 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001959 break;
sewardj478335c2002-10-05 02:44:47 +00001960 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001961 VG_(emit_shiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001962 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001963 break;
1964 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001965 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001966 emit_shiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001967 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001968 } else {
njn25e49d8e72002-09-23 09:36:25 +00001969 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001970 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001971 emit_shiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001972 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001973 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001974 }
1975 break;
njne427a662002-10-02 11:08:25 +00001976 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001977 }
1978}
1979
1980
1981static void synth_setb_reg ( Int reg, Condcode cond )
1982{
1983 emit_get_eflags();
1984 if (reg < 4) {
1985 emit_setb_reg ( reg, cond );
1986 } else {
njn25e49d8e72002-09-23 09:36:25 +00001987 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001988 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00001989 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001990 }
1991}
1992
1993
1994static void synth_fpu_regmem ( UChar first_byte,
1995 UChar second_byte_masked,
1996 Int reg )
1997{
sewardjde4a1d02002-03-22 01:27:54 +00001998 emit_fpu_regmem ( first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001999}
2000
2001
2002static void synth_fpu_no_mem ( UChar first_byte,
2003 UChar second_byte )
2004{
sewardjde4a1d02002-03-22 01:27:54 +00002005 emit_fpu_no_mem ( first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00002006}
2007
2008
2009static void synth_movl_reg_reg ( Int src, Int dst )
2010{
2011 emit_movl_reg_reg ( src, dst );
2012}
2013
2014static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
2015{
2016 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002017 VG_(emit_jcondshort_delta) ( invertCondition(cond),
sewardjde4a1d02002-03-22 01:27:54 +00002018 2 /* length of the next insn */ );
2019 emit_movl_reg_reg ( src, dst );
2020}
2021
2022
sewardjde4a1d02002-03-22 01:27:54 +00002023/*----------------------------------------------------*/
2024/*--- Top level of the uinstr -> x86 translation. ---*/
2025/*----------------------------------------------------*/
2026
2027/* Return the byte offset from %ebp (ie, into baseBlock)
2028 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00002029static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
2030{
2031 if (tag == SpillNo) {
2032 vg_assert(size == 4);
2033 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
2034 return 4 * (value + VGOFF_(spillslots));
2035 }
2036 if (tag == ArchReg) {
2037 switch (value) {
2038 case R_EAX: return 4 * VGOFF_(m_eax);
2039 case R_ECX: return 4 * VGOFF_(m_ecx);
2040 case R_EDX: return 4 * VGOFF_(m_edx);
2041 case R_EBX: return 4 * VGOFF_(m_ebx);
2042 case R_ESP:
2043 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
2044 else return 4 * VGOFF_(m_esp);
2045 case R_EBP:
2046 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
2047 else return 4 * VGOFF_(m_ebp);
2048 case R_ESI:
2049 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
2050 else return 4 * VGOFF_(m_esi);
2051 case R_EDI:
2052 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
2053 else return 4 * VGOFF_(m_edi);
2054 }
2055 }
njne427a662002-10-02 11:08:25 +00002056 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002057}
2058
sewardjde4a1d02002-03-22 01:27:54 +00002059static Int eflagsOffset ( void )
2060{
2061 return 4 * VGOFF_(m_eflags);
2062}
2063
sewardje1042472002-09-30 12:33:11 +00002064static Int segRegOffset ( UInt archregs )
2065{
2066 switch (archregs) {
2067 case R_CS: return 4 * VGOFF_(m_cs);
2068 case R_SS: return 4 * VGOFF_(m_ss);
2069 case R_DS: return 4 * VGOFF_(m_ds);
2070 case R_ES: return 4 * VGOFF_(m_es);
2071 case R_FS: return 4 * VGOFF_(m_fs);
2072 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00002073 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00002074 }
2075}
2076
sewardjde4a1d02002-03-22 01:27:54 +00002077
njn25e49d8e72002-09-23 09:36:25 +00002078/* Return the byte offset from %ebp (ie, into baseBlock)
2079 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00002080Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00002081{
2082 switch (arch) {
2083 case R_EAX: return 4 * VGOFF_(sh_eax);
2084 case R_ECX: return 4 * VGOFF_(sh_ecx);
2085 case R_EDX: return 4 * VGOFF_(sh_edx);
2086 case R_EBX: return 4 * VGOFF_(sh_ebx);
2087 case R_ESP: return 4 * VGOFF_(sh_esp);
2088 case R_EBP: return 4 * VGOFF_(sh_ebp);
2089 case R_ESI: return 4 * VGOFF_(sh_esi);
2090 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00002091 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00002092 }
2093}
2094
njn4ba5a792002-09-30 10:23:54 +00002095Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00002096{
2097 return 4 * VGOFF_(sh_eflags);
2098}
2099
2100
sewardjde4a1d02002-03-22 01:27:54 +00002101
2102static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
2103{
2104 if (sz_src == 1 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00002105 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 24, reg );
2106 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002107 }
2108 else if (sz_src == 2 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00002109 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 16, reg );
2110 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002111 }
2112 else if (sz_src == 1 && sz_dst == 2) {
njn25e49d8e72002-09-23 09:36:25 +00002113 VG_(emit_shiftopv_lit_reg) ( 2, SHL, 8, reg );
2114 VG_(emit_shiftopv_lit_reg) ( 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00002115 }
2116 else
njne427a662002-10-02 11:08:25 +00002117 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00002118}
2119
2120
njn25e49d8e72002-09-23 09:36:25 +00002121static void synth_handle_esp_assignment ( Int i, Int reg,
2122 RRegSet regs_live_before,
2123 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00002124{
njn25e49d8e72002-09-23 09:36:25 +00002125 UInt argv[] = { reg };
2126 Tag tagv[] = { RealReg };
2127
2128 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
2129 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00002130}
2131
2132
sewardjde4a1d02002-03-22 01:27:54 +00002133/*----------------------------------------------------*/
2134/*--- Generate code for a single UInstr. ---*/
2135/*----------------------------------------------------*/
2136
sewardj478335c2002-10-05 02:44:47 +00002137static __inline__
2138Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00002139{
2140 return (u->flags_w != FlagsEmpty);
2141}
2142
sewardj478335c2002-10-05 02:44:47 +00002143static __inline__
2144Bool anyFlagUse ( UInstr* u )
2145{
2146 return (u->flags_r != FlagsEmpty || u->flags_w != FlagsEmpty);
2147}
2148
2149
sewardj1b7d8022002-11-30 12:35:42 +00002150/* fplive==True indicates that the simulated machine's FPU state is in
2151 the real FPU. If so we need to be very careful not to trash it.
2152 If FPU state is live and we deem it necessary to copy it back to
2153 the simulated machine's FPU state, we do so. The final state of
2154 fpliveness is returned. In short we _must_ do put_fpu_state if
2155 there is any chance at all that the code generated for a UInstr
2156 will change the real FPU state.
2157*/
sewardj22854b92002-11-30 14:00:47 +00002158static Bool emitUInstr ( UCodeBlock* cb, Int i,
2159 RRegSet regs_live_before, Bool fplive )
sewardjde4a1d02002-03-22 01:27:54 +00002160{
njn25e49d8e72002-09-23 09:36:25 +00002161 Int old_emitted_code_used;
2162 UInstr* u = &cb->instrs[i];
2163
sewardjde4a1d02002-03-22 01:27:54 +00002164 if (dis)
njn4ba5a792002-09-30 10:23:54 +00002165 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00002166
njn25e49d8e72002-09-23 09:36:25 +00002167 old_emitted_code_used = emitted_code_used;
2168
sewardjde4a1d02002-03-22 01:27:54 +00002169 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00002170 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00002171
2172 case INCEIP: {
njn25e49d8e72002-09-23 09:36:25 +00002173 /* Note: Redundant INCEIP merging. A potentially useful
2174 performance enhancementa, but currently disabled. Reason
2175 is that it needs a surefire way to know if a UInstr might
2176 give rise to a stack snapshot being taken. The logic below
2177 is correct (hopefully ...) for the core UInstrs, but is
2178 incorrect if a skin has its own UInstrs, since the logic
2179 currently assumes that none of them can cause a stack
2180 trace, and that's just wrong. Note this isn't
2181 mission-critical -- the system still functions -- but will
2182 cause incorrect source locations in some situations,
2183 specifically for the memcheck skin. This is known to
2184 confuse programmers, understandable. */
2185# if 0
2186 Bool can_skip;
2187 Int j;
2188
2189 /* Scan forwards to see if this INCEIP dominates (in the
2190 technical sense) a later one, AND there are no CCALLs in
2191 between. If so, skip this one and instead add its count
2192 with the later one. */
2193 can_skip = True;
2194 j = i+1;
2195 while (True) {
2196 if (cb->instrs[j].opcode == CCALL
2197 || cb->instrs[j].opcode == CALLM) {
2198 /* CCALL -- we can't skip this INCEIP. */
2199 can_skip = False;
2200 break;
2201 }
2202 if (cb->instrs[j].opcode == INCEIP) {
2203 /* Another INCEIP. Check that the sum will fit. */
2204 if (cb->instrs[i].val1 + cb->instrs[j].val1 > 127)
2205 can_skip = False;
2206 break;
2207 }
2208 if (cb->instrs[j].opcode == JMP || cb->instrs[j].opcode == JIFZ) {
2209 /* Execution is not guaranteed to get beyond this
2210 point. Give up. */
2211 can_skip = False;
2212 break;
2213 }
2214 j++;
2215 /* Assertion should hold because all blocks should end in an
2216 unconditional JMP, so the above test should get us out of
2217 the loop at the end of a block. */
2218 vg_assert(j < cb->used);
2219 }
2220 if (can_skip) {
2221 /* yay! Accumulate the delta into the next INCEIP. */
2222 // VG_(printf)("skip INCEIP %d\n", cb->instrs[i].val1);
2223 vg_assert(j > i);
2224 vg_assert(j < cb->used);
2225 vg_assert(cb->instrs[j].opcode == INCEIP);
2226 vg_assert(cb->instrs[i].opcode == INCEIP);
2227 vg_assert(cb->instrs[j].tag1 == Lit16);
2228 vg_assert(cb->instrs[i].tag1 == Lit16);
2229 cb->instrs[j].val1 += cb->instrs[i].val1;
2230 /* do nothing now */
2231 } else
2232# endif
2233
2234 {
2235 /* no, we really have to do this, alas */
2236 // VG_(printf)(" do INCEIP %d\n", cb->instrs[i].val1);
2237 vg_assert(u->tag1 == Lit16);
2238 emit_addlit8_offregmem ( u->val1, R_EBP, 4 * VGOFF_(m_eip) );
2239 }
sewardjde4a1d02002-03-22 01:27:54 +00002240 break;
2241 }
2242
2243 case LEA1: {
2244 vg_assert(u->tag1 == RealReg);
2245 vg_assert(u->tag2 == RealReg);
2246 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2247 break;
2248 }
2249
2250 case LEA2: {
2251 vg_assert(u->tag1 == RealReg);
2252 vg_assert(u->tag2 == RealReg);
2253 vg_assert(u->tag3 == RealReg);
2254 emit_lea_sib_reg ( u->lit32, u->extra4b,
2255 u->val1, u->val2, u->val3 );
2256 break;
2257 }
2258
2259 case WIDEN: {
2260 vg_assert(u->tag1 == RealReg);
2261 if (u->signed_widen) {
2262 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2263 } else {
2264 /* no need to generate any code. */
2265 }
2266 break;
2267 }
2268
sewardjde4a1d02002-03-22 01:27:54 +00002269 case STORE: {
2270 vg_assert(u->tag1 == RealReg);
2271 vg_assert(u->tag2 == RealReg);
2272 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002273 break;
2274 }
2275
2276 case LOAD: {
2277 vg_assert(u->tag1 == RealReg);
2278 vg_assert(u->tag2 == RealReg);
2279 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2280 break;
2281 }
2282
sewardjde4a1d02002-03-22 01:27:54 +00002283 case GET: {
2284 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2285 vg_assert(u->tag2 == RealReg);
2286 synth_mov_offregmem_reg (
2287 u->size,
2288 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2289 R_EBP,
2290 u->val2
2291 );
2292 break;
2293 }
2294
2295 case PUT: {
2296 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2297 vg_assert(u->tag1 == RealReg);
2298 if (u->tag2 == ArchReg
2299 && u->val2 == R_ESP
2300 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002301 && (VG_(track_events).new_mem_stack ||
2302 VG_(track_events).new_mem_stack_aligned ||
2303 VG_(track_events).die_mem_stack ||
2304 VG_(track_events).die_mem_stack_aligned ||
2305 VG_(track_events).post_mem_write))
2306 {
2307 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2308 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002309 }
njn25e49d8e72002-09-23 09:36:25 +00002310 else {
2311 synth_mov_reg_offregmem (
2312 u->size,
2313 u->val1,
2314 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2315 R_EBP
2316 );
2317 }
sewardjde4a1d02002-03-22 01:27:54 +00002318 break;
2319 }
2320
sewardje1042472002-09-30 12:33:11 +00002321 case GETSEG: {
2322 vg_assert(u->tag1 == ArchRegS);
2323 vg_assert(u->tag2 == RealReg);
2324 vg_assert(u->size == 2);
2325 synth_mov_offregmem_reg (
2326 4,
2327 segRegOffset( u->val1 ),
2328 R_EBP,
2329 u->val2
2330 );
2331 break;
2332 }
2333
2334 case PUTSEG: {
2335 vg_assert(u->tag1 == RealReg);
2336 vg_assert(u->tag2 == ArchRegS);
2337 vg_assert(u->size == 2);
2338 synth_mov_reg_offregmem (
2339 4,
2340 u->val1,
2341 segRegOffset( u->val2 ),
2342 R_EBP
2343 );
2344 break;
2345 }
2346
sewardjde4a1d02002-03-22 01:27:54 +00002347 case GETF: {
2348 vg_assert(u->size == 2 || u->size == 4);
2349 vg_assert(u->tag1 == RealReg);
2350 synth_mov_offregmem_reg (
2351 u->size,
2352 eflagsOffset(),
2353 R_EBP,
2354 u->val1
2355 );
2356 break;
2357 }
2358
2359 case PUTF: {
2360 vg_assert(u->size == 2 || u->size == 4);
2361 vg_assert(u->tag1 == RealReg);
2362 synth_mov_reg_offregmem (
2363 u->size,
2364 u->val1,
2365 eflagsOffset(),
2366 R_EBP
2367 );
2368 break;
2369 }
2370
2371 case MOV: {
2372 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2373 vg_assert(u->tag2 == RealReg);
2374 switch (u->tag1) {
2375 case RealReg: vg_assert(u->size == 4);
2376 if (u->val1 != u->val2)
2377 synth_movl_reg_reg ( u->val1, u->val2 );
2378 break;
2379 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2380 break;
njne427a662002-10-02 11:08:25 +00002381 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002382 }
2383 break;
2384 }
2385
sewardje1042472002-09-30 12:33:11 +00002386 case USESEG: {
2387 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2388 ones. */
sewardjd077f532002-09-30 21:52:50 +00002389 UInt argv[] = { u->val1, u->val2 };
2390 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002391 UInt ret_reg = u->val2;
2392
2393 vg_assert(u->tag1 == RealReg);
2394 vg_assert(u->tag2 == RealReg);
2395 vg_assert(u->size == 0);
2396
sewardj1b7d8022002-11-30 12:35:42 +00002397 if (fplive) {
2398 emit_put_fpu_state();
2399 fplive = False;
2400 }
2401
sewardje1042472002-09-30 12:33:11 +00002402 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2403 2, /* args */
2404 0, /* regparms_n */
2405 argv, tagv,
2406 ret_reg, regs_live_before, u->regs_live_after );
2407 break;
2408 }
2409
sewardj478335c2002-10-05 02:44:47 +00002410 case SBB:
2411 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002412 case XOR:
2413 case OR:
2414 case AND:
2415 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002416 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002417 vg_assert(u->tag2 == RealReg);
2418 switch (u->tag1) {
2419 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002420 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002421 u->opcode, u->size, u->lit32, u->val2 );
2422 break;
2423 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002424 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002425 u->opcode, u->size, u->val1, u->val2 );
2426 break;
2427 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002428 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002429 u->opcode, u->size,
2430 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2431 R_EBP,
2432 u->val2 );
2433 break;
njne427a662002-10-02 11:08:25 +00002434 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002435 }
2436 break;
2437 }
2438
sewardj478335c2002-10-05 02:44:47 +00002439 case RCR:
2440 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002441 case ROR:
2442 case ROL:
2443 case SAR:
2444 case SHR:
2445 case SHL: {
2446 vg_assert(u->tag2 == RealReg);
2447 switch (u->tag1) {
2448 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002449 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002450 u->opcode, u->size, u->lit32, u->val2 );
2451 break;
2452 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002453 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002454 u->opcode, u->size, u->val1, u->val2 );
2455 break;
njne427a662002-10-02 11:08:25 +00002456 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002457 }
2458 break;
2459 }
2460
2461 case INC:
2462 case DEC:
2463 case NEG:
2464 case NOT:
2465 vg_assert(u->tag1 == RealReg);
2466 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002467 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002468 break;
2469
2470 case BSWAP:
2471 vg_assert(u->tag1 == RealReg);
2472 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002473 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002474 emit_bswapl_reg ( u->val1 );
2475 break;
2476
2477 case CMOV:
2478 vg_assert(u->tag1 == RealReg);
2479 vg_assert(u->tag2 == RealReg);
2480 vg_assert(u->cond != CondAlways);
2481 vg_assert(u->size == 4);
2482 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2483 break;
2484
2485 case JMP: {
2486 vg_assert(u->tag2 == NoValue);
2487 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardj1b7d8022002-11-30 12:35:42 +00002488 if (fplive) {
2489 emit_put_fpu_state();
2490 fplive = False;
2491 }
sewardjde4a1d02002-03-22 01:27:54 +00002492 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002493 switch (u->tag1) {
2494 case RealReg:
2495 synth_jmp_reg ( u->val1, u->jmpkind );
2496 break;
2497 case Literal:
2498 synth_jmp_lit ( u->lit32, u->jmpkind );
2499 break;
2500 default:
njne427a662002-10-02 11:08:25 +00002501 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002502 break;
sewardjde4a1d02002-03-22 01:27:54 +00002503 }
2504 } else {
sewardj2e93c502002-04-12 11:12:52 +00002505 switch (u->tag1) {
2506 case RealReg:
njne427a662002-10-02 11:08:25 +00002507 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002508 break;
2509 case Literal:
2510 vg_assert(u->jmpkind == JmpBoring);
2511 synth_jcond_lit ( u->cond, u->lit32 );
2512 break;
2513 default:
njne427a662002-10-02 11:08:25 +00002514 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002515 break;
sewardjde4a1d02002-03-22 01:27:54 +00002516 }
2517 }
2518 break;
2519 }
2520
2521 case JIFZ:
2522 vg_assert(u->tag1 == RealReg);
2523 vg_assert(u->tag2 == Literal);
2524 vg_assert(u->size == 4);
sewardj1b7d8022002-11-30 12:35:42 +00002525 if (fplive) {
2526 emit_put_fpu_state();
2527 fplive = False;
2528 }
sewardjde4a1d02002-03-22 01:27:54 +00002529 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2530 break;
2531
sewardjde4a1d02002-03-22 01:27:54 +00002532 case PUSH:
2533 vg_assert(u->tag1 == RealReg);
2534 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002535 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002536 break;
2537
2538 case POP:
2539 vg_assert(u->tag1 == RealReg);
2540 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002541 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002542 break;
2543
2544 case CALLM:
2545 vg_assert(u->tag1 == Lit16);
2546 vg_assert(u->tag2 == NoValue);
2547 vg_assert(u->size == 0);
sewardj1b7d8022002-11-30 12:35:42 +00002548 if (fplive) {
2549 emit_put_fpu_state();
2550 fplive = False;
2551 }
sewardj478335c2002-10-05 02:44:47 +00002552 if (anyFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002553 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002554 VG_(synth_call) ( False, u->val1 );
njn5a74eb82002-08-06 20:56:40 +00002555 if (writeFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002556 emit_put_eflags();
2557 break;
2558
njn25e49d8e72002-09-23 09:36:25 +00002559 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002560 /* If you change this, remember to change USESEG above, since
2561 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002562 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2563 ones. */
2564 UInt argv[] = { u->val1, u->val2, u->val3 };
2565 UInt tagv[] = { RealReg, RealReg, RealReg };
2566 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2567
2568 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2569 else vg_assert(u->tag1 == NoValue);
2570 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2571 else vg_assert(u->tag2 == NoValue);
2572 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2573 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002574 vg_assert(u->size == 0);
2575
sewardj1b7d8022002-11-30 12:35:42 +00002576 if (fplive) {
2577 emit_put_fpu_state();
2578 fplive = False;
2579 }
njn25e49d8e72002-09-23 09:36:25 +00002580 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2581 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002582 break;
njn25e49d8e72002-09-23 09:36:25 +00002583 }
sewardje1042472002-09-30 12:33:11 +00002584
sewardjde4a1d02002-03-22 01:27:54 +00002585 case CLEAR:
2586 vg_assert(u->tag1 == Lit16);
2587 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002588 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002589 break;
2590
2591 case CC2VAL:
2592 vg_assert(u->tag1 == RealReg);
2593 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00002594 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002595 synth_setb_reg ( u->val1, u->cond );
2596 break;
2597
sewardjde4a1d02002-03-22 01:27:54 +00002598 case FPU_R:
2599 case FPU_W:
2600 vg_assert(u->tag1 == Lit16);
2601 vg_assert(u->tag2 == RealReg);
sewardj1b7d8022002-11-30 12:35:42 +00002602 if (!fplive) {
2603 emit_get_fpu_state();
2604 fplive = True;
2605 }
sewardjde4a1d02002-03-22 01:27:54 +00002606 synth_fpu_regmem ( (u->val1 >> 8) & 0xFF,
2607 u->val1 & 0xFF,
2608 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002609 break;
2610
2611 case FPU:
2612 vg_assert(u->tag1 == Lit16);
2613 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00002614 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002615 emit_get_eflags();
sewardj1b7d8022002-11-30 12:35:42 +00002616 if (!fplive) {
2617 emit_get_fpu_state();
2618 fplive = True;
2619 }
sewardjde4a1d02002-03-22 01:27:54 +00002620 synth_fpu_no_mem ( (u->val1 >> 8) & 0xFF,
2621 u->val1 & 0xFF );
njn5a74eb82002-08-06 20:56:40 +00002622 if (writeFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002623 emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002624 break;
2625
2626 default:
sewardj1b7d8022002-11-30 12:35:42 +00002627 if (VG_(needs).extended_UCode) {
2628 if (fplive) {
2629 emit_put_fpu_state();
2630 fplive = False;
2631 }
njn4ba5a792002-09-30 10:23:54 +00002632 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00002633 } else {
njn25e49d8e72002-09-23 09:36:25 +00002634 VG_(printf)("\nError:\n"
2635 " unhandled opcode: %u. Perhaps "
2636 " VG_(needs).extended_UCode should be set?\n",
2637 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00002638 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00002639 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00002640 }
sewardjde4a1d02002-03-22 01:27:54 +00002641 }
2642
sewardj1b7d8022002-11-30 12:35:42 +00002643 if (0 && fplive) {
2644 emit_put_fpu_state();
2645 fplive = False;
2646 }
2647
njn25e49d8e72002-09-23 09:36:25 +00002648 /* Update UInstr histogram */
2649 vg_assert(u->opcode < 100);
2650 histogram[u->opcode].counts++;
2651 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardj1b7d8022002-11-30 12:35:42 +00002652
2653 return fplive;
sewardjde4a1d02002-03-22 01:27:54 +00002654}
2655
2656
2657/* Emit x86 for the ucode in cb, returning the address of the
2658 generated code and setting *nbytes to its size. */
sewardj22854b92002-11-30 14:00:47 +00002659UChar* VG_(emit_code) ( UCodeBlock* cb, Int* nbytes, UShort j[VG_MAX_JUMPS] )
sewardjde4a1d02002-03-22 01:27:54 +00002660{
2661 Int i;
njn25e49d8e72002-09-23 09:36:25 +00002662 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00002663 Bool fplive;
sewardj22854b92002-11-30 14:00:47 +00002664
sewardjde4a1d02002-03-22 01:27:54 +00002665 emitted_code_used = 0;
2666 emitted_code_size = 500; /* reasonable initial size */
njn25e49d8e72002-09-23 09:36:25 +00002667 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
sewardj22854b92002-11-30 14:00:47 +00002668 jumpidx = 0;
sewardjde4a1d02002-03-22 01:27:54 +00002669
njn25e49d8e72002-09-23 09:36:25 +00002670 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00002671
sewardj22854b92002-11-30 14:00:47 +00002672 /* Generate decl VG_(dispatch_ctr) and drop into dispatch if we hit
2673 zero. We have to do this regardless of whether we're t-chaining
2674 or not. */
2675 VG_(new_emit)();
2676 VG_(emitB) (0xFF); /* decl */
2677 emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
2678 if (dis)
2679 VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
2680 VG_(emit_jcondshort_delta)(CondNZ, 5+1);
2681 VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
2682 emit_ret();
2683
sewardj1b7d8022002-11-30 12:35:42 +00002684 fplive = False;
sewardjde4a1d02002-03-22 01:27:54 +00002685 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00002686 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00002687 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00002688
sewardjde4a1d02002-03-22 01:27:54 +00002689 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00002690 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00002691 if (!sane) {
2692 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00002693 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00002694 }
2695 vg_assert(sane);
sewardj1b7d8022002-11-30 12:35:42 +00002696 fplive = emitUInstr( cb, i, regs_live_before, fplive );
sewardjde4a1d02002-03-22 01:27:54 +00002697 }
njn25e49d8e72002-09-23 09:36:25 +00002698 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00002699 }
njn25e49d8e72002-09-23 09:36:25 +00002700 if (dis) VG_(printf)("\n");
sewardj1b7d8022002-11-30 12:35:42 +00002701 vg_assert(!fplive); /* FPU state must be saved by end of BB */
sewardjde4a1d02002-03-22 01:27:54 +00002702
sewardj22854b92002-11-30 14:00:47 +00002703 if (j != NULL) {
2704 vg_assert(jumpidx <= VG_MAX_JUMPS);
2705 for(i = 0; i < jumpidx; i++)
2706 j[i] = jumps[i];
2707 }
2708
sewardjde4a1d02002-03-22 01:27:54 +00002709 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00002710 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00002711 *nbytes = emitted_code_used;
2712 return emitted_code;
2713}
2714
njn25e49d8e72002-09-23 09:36:25 +00002715#undef dis
2716
sewardjde4a1d02002-03-22 01:27:54 +00002717/*--------------------------------------------------------------------*/
2718/*--- end vg_from_ucode.c ---*/
2719/*--------------------------------------------------------------------*/