blob: feff35ad95e8896fd655160080b7d414fb63cceb [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
njn25e49d8e72002-09-23 09:36:25 +000072/* Statistics about C functions called from generated code. */
73static UInt ccalls = 0;
74static UInt ccall_reg_saves = 0;
75static UInt ccall_args = 0;
76static UInt ccall_arg_setup_instrs = 0;
77static UInt ccall_stack_clears = 0;
78static UInt ccall_retvals = 0;
79static UInt ccall_retval_movs = 0;
80
81/* Statistics about frequency of each UInstr */
82typedef
83 struct {
84 UInt counts;
85 UInt size;
86 } Histogram;
87
88/* Automatically zeroed because it's static. */
89static Histogram histogram[100];
90
91void VG_(print_ccall_stats)(void)
92{
93 VG_(message)(Vg_DebugMsg,
94 " ccalls: %u C calls, %u%% saves+restores avoided"
95 " (%d bytes)",
96 ccalls,
97 100-(UInt)(ccall_reg_saves/(double)(ccalls*3)*100),
98 ((ccalls*3) - ccall_reg_saves)*2);
99 VG_(message)(Vg_DebugMsg,
100 " %u args, avg 0.%d setup instrs each (%d bytes)",
101 ccall_args,
102 (UInt)(ccall_arg_setup_instrs/(double)ccall_args*100),
103 (ccall_args - ccall_arg_setup_instrs)*2);
104 VG_(message)(Vg_DebugMsg,
105 " %d%% clear the stack (%d bytes)",
106 (UInt)(ccall_stack_clears/(double)ccalls*100),
107 (ccalls - ccall_stack_clears)*3);
108 VG_(message)(Vg_DebugMsg,
109 " %u retvals, %u%% of reg-reg movs avoided (%d bytes)",
110 ccall_retvals,
111 ( ccall_retvals == 0
112 ? 100
113 : 100-(UInt)(ccall_retval_movs /
114 (double)ccall_retvals*100)),
115 (ccall_retvals-ccall_retval_movs)*2);
116}
117
118void VG_(print_UInstr_histogram)(void)
119{
120 Int i, j;
121 UInt total_counts = 0;
122 UInt total_size = 0;
sewardj6c3769f2002-11-29 01:02:45 +0000123
njn25e49d8e72002-09-23 09:36:25 +0000124 for (i = 0; i < 100; i++) {
125 total_counts += histogram[i].counts;
126 total_size += histogram[i].size;
127 }
128
129 VG_(printf)("-- UInstr frequencies -----------\n");
130 for (i = 0; i < 100; i++) {
131 if (0 != histogram[i].counts) {
132
133 UInt count_pc =
134 (UInt)(histogram[i].counts/(double)total_counts*100 + 0.5);
135 UInt size_pc =
136 (UInt)(histogram[i].size /(double)total_size *100 + 0.5);
137 UInt avg_size =
138 (UInt)(histogram[i].size / (double)histogram[i].counts + 0.5);
139
140 VG_(printf)("%-7s:%8u (%2u%%), avg %2dB (%2u%%) |",
njn4ba5a792002-09-30 10:23:54 +0000141 VG_(name_UOpcode)(True, i),
njn25e49d8e72002-09-23 09:36:25 +0000142 histogram[i].counts, count_pc,
143 avg_size, size_pc);
144
145 for (j = 0; j < size_pc; j++) VG_(printf)("O");
146 VG_(printf)("\n");
147
148 } else {
149 vg_assert(0 == histogram[i].size);
150 }
151 }
152
153 VG_(printf)("total UInstrs %u, total size %u\n", total_counts, total_size);
154}
155
sewardjde4a1d02002-03-22 01:27:54 +0000156static void expandEmittedCode ( void )
157{
158 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000159 UChar *tmp = VG_(arena_malloc)(VG_AR_JITTER, 2 * emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +0000160 /* VG_(printf)("expand to %d\n", 2 * emitted_code_size); */
161 for (i = 0; i < emitted_code_size; i++)
162 tmp[i] = emitted_code[i];
njn25e49d8e72002-09-23 09:36:25 +0000163 VG_(arena_free)(VG_AR_JITTER, emitted_code);
sewardjde4a1d02002-03-22 01:27:54 +0000164 emitted_code = tmp;
165 emitted_code_size *= 2;
166}
167
njn25e49d8e72002-09-23 09:36:25 +0000168/* Local calls will be inlined, cross-module ones not */
169__inline__ void VG_(emitB) ( UInt b )
sewardjde4a1d02002-03-22 01:27:54 +0000170{
171 if (dis) {
172 if (b < 16) VG_(printf)("0%x ", b); else VG_(printf)("%2x ", b);
173 }
174 if (emitted_code_used == emitted_code_size)
175 expandEmittedCode();
176
177 emitted_code[emitted_code_used] = (UChar)b;
178 emitted_code_used++;
179}
180
njn25e49d8e72002-09-23 09:36:25 +0000181__inline__ void VG_(emitW) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000182{
njn25e49d8e72002-09-23 09:36:25 +0000183 VG_(emitB) ( (l) & 0x000000FF );
184 VG_(emitB) ( (l >> 8) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000185}
186
njn25e49d8e72002-09-23 09:36:25 +0000187__inline__ void VG_(emitL) ( UInt l )
sewardjde4a1d02002-03-22 01:27:54 +0000188{
njn25e49d8e72002-09-23 09:36:25 +0000189 VG_(emitB) ( (l) & 0x000000FF );
190 VG_(emitB) ( (l >> 8) & 0x000000FF );
191 VG_(emitB) ( (l >> 16) & 0x000000FF );
192 VG_(emitB) ( (l >> 24) & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000193}
194
njn4ba5a792002-09-30 10:23:54 +0000195__inline__ void VG_(new_emit) ( void )
sewardjde4a1d02002-03-22 01:27:54 +0000196{
197 if (dis)
198 VG_(printf)("\t %4d: ", emitted_code_used );
199}
200
sewardjde4a1d02002-03-22 01:27:54 +0000201
202/*----------------------------------------------------*/
203/*--- Addressing modes ---*/
204/*----------------------------------------------------*/
205
206static __inline__ UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
207{
208 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
209}
210
211static __inline__ UChar mkSIB ( Int scale, Int regindex, Int regbase )
212{
213 Int shift;
214 switch (scale) {
215 case 1: shift = 0; break;
216 case 2: shift = 1; break;
217 case 4: shift = 2; break;
218 case 8: shift = 3; break;
njne427a662002-10-02 11:08:25 +0000219 default: VG_(core_panic)( "mkSIB" );
sewardjde4a1d02002-03-22 01:27:54 +0000220 }
221 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
222}
223
224static __inline__ void emit_amode_litmem_reg ( Addr addr, Int reg )
225{
226 /* ($ADDR), reg */
njn25e49d8e72002-09-23 09:36:25 +0000227 VG_(emitB) ( mkModRegRM(0, reg, 5) );
228 VG_(emitL) ( addr );
sewardjde4a1d02002-03-22 01:27:54 +0000229}
230
231static __inline__ void emit_amode_regmem_reg ( Int regmem, Int reg )
232{
233 /* (regmem), reg */
234 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000235 VG_(core_panic)("emit_amode_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +0000236 if (regmem == R_EBP) {
njn25e49d8e72002-09-23 09:36:25 +0000237 VG_(emitB) ( mkModRegRM(1, reg, 5) );
238 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000239 } else {
njn25e49d8e72002-09-23 09:36:25 +0000240 VG_(emitB)( mkModRegRM(0, reg, regmem) );
sewardjde4a1d02002-03-22 01:27:54 +0000241 }
242}
243
njn25e49d8e72002-09-23 09:36:25 +0000244void VG_(emit_amode_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000245{
246 if (regmem == R_ESP)
njne427a662002-10-02 11:08:25 +0000247 VG_(core_panic)("emit_amode_offregmem_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000248 if (off < -128 || off > 127) {
249 /* Use a large offset */
250 /* d32(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000251 VG_(emitB) ( mkModRegRM(2, reg, regmem) );
252 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000253 } else {
254 /* d8(regmem), reg */
njn25e49d8e72002-09-23 09:36:25 +0000255 VG_(emitB) ( mkModRegRM(1, reg, regmem) );
256 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000257 }
258}
259
260static __inline__ void emit_amode_sib_reg ( Int off, Int scale, Int regbase,
261 Int regindex, Int reg )
262{
263 if (regindex == R_ESP)
njne427a662002-10-02 11:08:25 +0000264 VG_(core_panic)("emit_amode_sib_reg(ESP)");
sewardjde4a1d02002-03-22 01:27:54 +0000265 if (off < -128 || off > 127) {
266 /* Use a 32-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000267 VG_(emitB) ( mkModRegRM(2, reg, 4) ); /* SIB with 32-bit displacement */
268 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
269 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000270 } else {
271 /* Use an 8-bit offset */
njn25e49d8e72002-09-23 09:36:25 +0000272 VG_(emitB) ( mkModRegRM(1, reg, 4) ); /* SIB with 8-bit displacement */
273 VG_(emitB) ( mkSIB( scale, regindex, regbase ) );
274 VG_(emitB) ( off & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000275 }
276}
277
njn25e49d8e72002-09-23 09:36:25 +0000278void VG_(emit_amode_ereg_greg) ( Int e_reg, Int g_reg )
sewardjde4a1d02002-03-22 01:27:54 +0000279{
280 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000281 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000282}
283
284static __inline__ void emit_amode_greg_ereg ( Int g_reg, Int e_reg )
285{
286 /* other_reg, reg */
njn25e49d8e72002-09-23 09:36:25 +0000287 VG_(emitB) ( mkModRegRM(3, g_reg, e_reg) );
sewardjde4a1d02002-03-22 01:27:54 +0000288}
289
290
291/*----------------------------------------------------*/
292/*--- Opcode translation ---*/
293/*----------------------------------------------------*/
294
295static __inline__ Int mkGrp1opcode ( Opcode opc )
296{
297 switch (opc) {
298 case ADD: return 0;
299 case OR: return 1;
300 case ADC: return 2;
301 case SBB: return 3;
302 case AND: return 4;
303 case SUB: return 5;
304 case XOR: return 6;
njne427a662002-10-02 11:08:25 +0000305 default: VG_(core_panic)("mkGrp1opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000306 }
307}
308
309static __inline__ Int mkGrp2opcode ( Opcode opc )
310{
311 switch (opc) {
312 case ROL: return 0;
313 case ROR: return 1;
314 case RCL: return 2;
315 case RCR: return 3;
316 case SHL: return 4;
317 case SHR: return 5;
318 case SAR: return 7;
njne427a662002-10-02 11:08:25 +0000319 default: VG_(core_panic)("mkGrp2opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000320 }
321}
322
323static __inline__ Int mkGrp3opcode ( Opcode opc )
324{
325 switch (opc) {
326 case NOT: return 2;
327 case NEG: return 3;
njne427a662002-10-02 11:08:25 +0000328 default: VG_(core_panic)("mkGrp3opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000329 }
330}
331
332static __inline__ Int mkGrp4opcode ( Opcode opc )
333{
334 switch (opc) {
335 case INC: return 0;
336 case DEC: return 1;
njne427a662002-10-02 11:08:25 +0000337 default: VG_(core_panic)("mkGrp4opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000338 }
339}
340
341static __inline__ Int mkGrp5opcode ( Opcode opc )
342{
343 switch (opc) {
344 case CALLM: return 2;
345 case JMP: return 4;
njne427a662002-10-02 11:08:25 +0000346 default: VG_(core_panic)("mkGrp5opcode");
sewardjde4a1d02002-03-22 01:27:54 +0000347 }
348}
349
350static __inline__ UChar mkPrimaryOpcode ( Opcode opc )
351{
352 switch (opc) {
353 case ADD: return 0x00;
354 case ADC: return 0x10;
355 case AND: return 0x20;
356 case XOR: return 0x30;
357 case OR: return 0x08;
358 case SBB: return 0x18;
359 case SUB: return 0x28;
njne427a662002-10-02 11:08:25 +0000360 default: VG_(core_panic)("mkPrimaryOpcode");
sewardjde4a1d02002-03-22 01:27:54 +0000361 }
362}
363
364/*----------------------------------------------------*/
365/*--- v-size (4, or 2 with OSO) insn emitters ---*/
366/*----------------------------------------------------*/
367
njn25e49d8e72002-09-23 09:36:25 +0000368void VG_(emit_movv_offregmem_reg) ( Int sz, Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000369{
njn4ba5a792002-09-30 10:23:54 +0000370 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000371 if (sz == 2) VG_(emitB) ( 0x66 );
372 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
373 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000374 if (dis)
375 VG_(printf)( "\n\t\tmov%c\t0x%x(%s), %s\n",
376 nameISize(sz), off, nameIReg(4,areg), nameIReg(sz,reg));
377}
378
njn25e49d8e72002-09-23 09:36:25 +0000379void VG_(emit_movv_reg_offregmem) ( Int sz, Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000380{
njn4ba5a792002-09-30 10:23:54 +0000381 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000382 if (sz == 2) VG_(emitB) ( 0x66 );
383 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
384 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000385 if (dis)
386 VG_(printf)( "\n\t\tmov%c\t%s, 0x%x(%s)\n",
387 nameISize(sz), nameIReg(sz,reg), off, nameIReg(4,areg));
388}
389
390static void emit_movv_regmem_reg ( Int sz, Int reg1, Int reg2 )
391{
njn4ba5a792002-09-30 10:23:54 +0000392 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000393 if (sz == 2) VG_(emitB) ( 0x66 );
394 VG_(emitB) ( 0x8B ); /* MOV Ev, Gv */
sewardjde4a1d02002-03-22 01:27:54 +0000395 emit_amode_regmem_reg ( reg1, reg2 );
396 if (dis)
397 VG_(printf)( "\n\t\tmov%c\t(%s), %s\n",
398 nameISize(sz), nameIReg(4,reg1), nameIReg(sz,reg2));
399}
400
401static void emit_movv_reg_regmem ( Int sz, Int reg1, Int reg2 )
402{
njn4ba5a792002-09-30 10:23:54 +0000403 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000404 if (sz == 2) VG_(emitB) ( 0x66 );
405 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000406 emit_amode_regmem_reg ( reg2, reg1 );
407 if (dis)
408 VG_(printf)( "\n\t\tmov%c\t%s, (%s)\n",
409 nameISize(sz), nameIReg(sz,reg1), nameIReg(4,reg2));
410}
411
njn25e49d8e72002-09-23 09:36:25 +0000412void VG_(emit_movv_reg_reg) ( Int sz, Int reg1, Int reg2 )
sewardjde4a1d02002-03-22 01:27:54 +0000413{
njn4ba5a792002-09-30 10:23:54 +0000414 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000415 if (sz == 2) VG_(emitB) ( 0x66 );
416 VG_(emitB) ( 0x89 ); /* MOV Gv, Ev */
417 VG_(emit_amode_ereg_greg) ( reg2, reg1 );
sewardjde4a1d02002-03-22 01:27:54 +0000418 if (dis)
419 VG_(printf)( "\n\t\tmov%c\t%s, %s\n",
420 nameISize(sz), nameIReg(sz,reg1), nameIReg(sz,reg2));
421}
422
njn25e49d8e72002-09-23 09:36:25 +0000423void VG_(emit_nonshiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000424{
njn4ba5a792002-09-30 10:23:54 +0000425 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000426 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000427 if (lit == VG_(extend_s_8to32)(lit & 0x000000FF)) {
428 /* short form OK */
njn25e49d8e72002-09-23 09:36:25 +0000429 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
430 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
431 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000432 } else {
njn25e49d8e72002-09-23 09:36:25 +0000433 VG_(emitB) ( 0x81 ); /* Grp1 Iv,Ev */
434 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
435 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000436 }
437 if (dis)
438 VG_(printf)( "\n\t\t%s%c\t$0x%x, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000439 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000440 lit, nameIReg(sz,reg));
441}
442
njn25e49d8e72002-09-23 09:36:25 +0000443void VG_(emit_shiftopv_lit_reg) ( Int sz, Opcode opc, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000444{
njn4ba5a792002-09-30 10:23:54 +0000445 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000446 if (sz == 2) VG_(emitB) ( 0x66 );
447 VG_(emitB) ( 0xC1 ); /* Grp2 Ib,Ev */
448 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
449 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000450 if (dis)
451 VG_(printf)( "\n\t\t%s%c\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000452 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000453 lit, nameIReg(sz,reg));
454}
455
456static void emit_shiftopv_cl_stack0 ( Int sz, Opcode opc )
457{
njn4ba5a792002-09-30 10:23:54 +0000458 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000459 if (sz == 2) VG_(emitB) ( 0x66 );
460 VG_(emitB) ( 0xD3 ); /* Grp2 CL,Ev */
461 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
462 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
463 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000464 if (dis)
465 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000466 VG_(name_UOpcode)(False,opc), nameISize(sz) );
sewardjde4a1d02002-03-22 01:27:54 +0000467}
468
469static void emit_shiftopb_cl_stack0 ( Opcode opc )
470{
njn4ba5a792002-09-30 10:23:54 +0000471 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000472 VG_(emitB) ( 0xD2 ); /* Grp2 CL,Eb */
473 VG_(emitB) ( mkModRegRM ( 1, mkGrp2opcode(opc), 4 ) );
474 VG_(emitB) ( 0x24 ); /* a SIB, I think `d8(%esp)' */
475 VG_(emitB) ( 0x00 ); /* the d8 displacement */
sewardjde4a1d02002-03-22 01:27:54 +0000476 if (dis)
477 VG_(printf)("\n\t\t%s%c %%cl, 0(%%esp)\n",
njn4ba5a792002-09-30 10:23:54 +0000478 VG_(name_UOpcode)(False,opc), nameISize(1) );
sewardjde4a1d02002-03-22 01:27:54 +0000479}
480
481static void emit_nonshiftopv_offregmem_reg ( Int sz, Opcode opc,
482 Int off, Int areg, Int reg )
483{
njn4ba5a792002-09-30 10:23:54 +0000484 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000485 if (sz == 2) VG_(emitB) ( 0x66 );
486 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
487 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000488 if (dis)
489 VG_(printf)( "\n\t\t%s%c\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000490 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000491 off, nameIReg(4,areg), nameIReg(sz,reg));
492}
493
njn25e49d8e72002-09-23 09:36:25 +0000494void VG_(emit_nonshiftopv_reg_reg) ( Int sz, Opcode opc,
sewardjde4a1d02002-03-22 01:27:54 +0000495 Int reg1, Int reg2 )
496{
njn4ba5a792002-09-30 10:23:54 +0000497 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000498 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000499# if 0
500 /* Perfectly correct, but the GNU assembler uses the other form.
501 Therefore we too use the other form, to aid verification. */
njn25e49d8e72002-09-23 09:36:25 +0000502 VG_(emitB) ( 3 + mkPrimaryOpcode(opc) ); /* op Ev, Gv */
503 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000504# else
njn25e49d8e72002-09-23 09:36:25 +0000505 VG_(emitB) ( 1 + mkPrimaryOpcode(opc) ); /* op Gv, Ev */
sewardjde4a1d02002-03-22 01:27:54 +0000506 emit_amode_greg_ereg ( reg1, reg2 );
507# endif
508 if (dis)
509 VG_(printf)( "\n\t\t%s%c\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000510 VG_(name_UOpcode)(False,opc), nameISize(sz),
sewardjde4a1d02002-03-22 01:27:54 +0000511 nameIReg(sz,reg1), nameIReg(sz,reg2));
512}
513
njn25e49d8e72002-09-23 09:36:25 +0000514void VG_(emit_movv_lit_reg) ( Int sz, UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000515{
516 if (lit == 0) {
njn25e49d8e72002-09-23 09:36:25 +0000517 VG_(emit_nonshiftopv_reg_reg) ( sz, XOR, reg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000518 return;
519 }
njn4ba5a792002-09-30 10:23:54 +0000520 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000521 if (sz == 2) VG_(emitB) ( 0x66 );
522 VG_(emitB) ( 0xB8+reg ); /* MOV imm, Gv */
523 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000524 if (dis)
525 VG_(printf)( "\n\t\tmov%c\t$0x%x, %s\n",
526 nameISize(sz), lit, nameIReg(sz,reg));
527}
528
njn25e49d8e72002-09-23 09:36:25 +0000529void VG_(emit_unaryopv_reg) ( Int sz, Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000530{
njn4ba5a792002-09-30 10:23:54 +0000531 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000532 if (sz == 2) VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000533 switch (opc) {
534 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000535 VG_(emitB) ( 0xF7 );
536 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000537 if (dis)
538 VG_(printf)( "\n\t\tneg%c\t%s\n",
539 nameISize(sz), nameIReg(sz,reg));
540 break;
541 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000542 VG_(emitB) ( 0xF7 );
543 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000544 if (dis)
545 VG_(printf)( "\n\t\tnot%c\t%s\n",
546 nameISize(sz), nameIReg(sz,reg));
547 break;
548 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000549 VG_(emitB) ( 0x48 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000550 if (dis)
551 VG_(printf)( "\n\t\tdec%c\t%s\n",
552 nameISize(sz), nameIReg(sz,reg));
553 break;
554 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000555 VG_(emitB) ( 0x40 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000556 if (dis)
557 VG_(printf)( "\n\t\tinc%c\t%s\n",
558 nameISize(sz), nameIReg(sz,reg));
559 break;
560 default:
njne427a662002-10-02 11:08:25 +0000561 VG_(core_panic)("VG_(emit_unaryopv_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000562 }
563}
564
njn25e49d8e72002-09-23 09:36:25 +0000565void VG_(emit_pushv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000566{
njn4ba5a792002-09-30 10:23:54 +0000567 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000568 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000569 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000570 } else {
571 vg_assert(sz == 4);
572 }
njn25e49d8e72002-09-23 09:36:25 +0000573 VG_(emitB) ( 0x50 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000574 if (dis)
575 VG_(printf)("\n\t\tpush%c %s\n", nameISize(sz), nameIReg(sz,reg));
576}
577
njn25e49d8e72002-09-23 09:36:25 +0000578void VG_(emit_popv_reg) ( Int sz, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000579{
njn4ba5a792002-09-30 10:23:54 +0000580 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000581 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000582 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000583 } else {
584 vg_assert(sz == 4);
585 }
njn25e49d8e72002-09-23 09:36:25 +0000586 VG_(emitB) ( 0x58 + reg );
sewardjde4a1d02002-03-22 01:27:54 +0000587 if (dis)
588 VG_(printf)("\n\t\tpop%c %s\n", nameISize(sz), nameIReg(sz,reg));
589}
590
njn25e49d8e72002-09-23 09:36:25 +0000591void VG_(emit_pushl_lit32) ( UInt int32 )
592{
njn4ba5a792002-09-30 10:23:54 +0000593 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000594 VG_(emitB) ( 0x68 );
595 VG_(emitL) ( int32 );
596 if (dis)
597 VG_(printf)("\n\t\tpushl $0x%x\n", int32 );
598}
599
600void VG_(emit_pushl_lit8) ( Int lit8 )
sewardjde4a1d02002-03-22 01:27:54 +0000601{
602 vg_assert(lit8 >= -128 && lit8 < 128);
njn4ba5a792002-09-30 10:23:54 +0000603 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000604 VG_(emitB) ( 0x6A );
605 VG_(emitB) ( (UChar)((UInt)lit8) );
sewardjde4a1d02002-03-22 01:27:54 +0000606 if (dis)
607 VG_(printf)("\n\t\tpushl $%d\n", lit8 );
608}
609
njn25e49d8e72002-09-23 09:36:25 +0000610void VG_(emit_cmpl_zero_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000611{
njn4ba5a792002-09-30 10:23:54 +0000612 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000613 VG_(emitB) ( 0x83 );
614 VG_(emit_amode_ereg_greg) ( reg, 7 /* Grp 3 opcode for CMP */ );
615 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000616 if (dis)
617 VG_(printf)("\n\t\tcmpl $0, %s\n", nameIReg(4,reg));
618}
619
620static void emit_swapl_reg_ECX ( Int reg )
621{
njn4ba5a792002-09-30 10:23:54 +0000622 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000623 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
624 VG_(emit_amode_ereg_greg) ( reg, R_ECX );
sewardjde4a1d02002-03-22 01:27:54 +0000625 if (dis)
626 VG_(printf)("\n\t\txchgl %%ecx, %s\n", nameIReg(4,reg));
627}
628
njn25e49d8e72002-09-23 09:36:25 +0000629void VG_(emit_swapl_reg_EAX) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000630{
njn4ba5a792002-09-30 10:23:54 +0000631 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000632 VG_(emitB) ( 0x90 + reg ); /* XCHG Gv,eAX */
sewardjde4a1d02002-03-22 01:27:54 +0000633 if (dis)
634 VG_(printf)("\n\t\txchgl %%eax, %s\n", nameIReg(4,reg));
635}
636
637static void emit_swapl_reg_reg ( Int reg1, Int reg2 )
638{
njn4ba5a792002-09-30 10:23:54 +0000639 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000640 VG_(emitB) ( 0x87 ); /* XCHG Gv,Ev */
641 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000642 if (dis)
643 VG_(printf)("\n\t\txchgl %s, %s\n", nameIReg(4,reg1),
644 nameIReg(4,reg2));
645}
646
647static void emit_bswapl_reg ( Int reg )
648{
njn4ba5a792002-09-30 10:23:54 +0000649 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000650 VG_(emitB) ( 0x0F );
651 VG_(emitB) ( 0xC8 + reg ); /* BSWAP r32 */
sewardjde4a1d02002-03-22 01:27:54 +0000652 if (dis)
653 VG_(printf)("\n\t\tbswapl %s\n", nameIReg(4,reg));
654}
655
656static void emit_movl_reg_reg ( Int regs, Int regd )
657{
njn4ba5a792002-09-30 10:23:54 +0000658 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000659 VG_(emitB) ( 0x89 ); /* MOV Gv,Ev */
660 VG_(emit_amode_ereg_greg) ( regd, regs );
sewardjde4a1d02002-03-22 01:27:54 +0000661 if (dis)
662 VG_(printf)("\n\t\tmovl %s, %s\n", nameIReg(4,regs), nameIReg(4,regd));
663}
664
njn25e49d8e72002-09-23 09:36:25 +0000665void VG_(emit_movv_lit_offregmem) ( Int sz, UInt lit, Int off, Int memreg )
sewardjde4a1d02002-03-22 01:27:54 +0000666{
njn4ba5a792002-09-30 10:23:54 +0000667 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000668 if (sz == 2) {
njn25e49d8e72002-09-23 09:36:25 +0000669 VG_(emitB) ( 0x66 );
sewardjde4a1d02002-03-22 01:27:54 +0000670 } else {
671 vg_assert(sz == 4);
672 }
njn25e49d8e72002-09-23 09:36:25 +0000673 VG_(emitB) ( 0xC7 ); /* Grp11 Ev */
674 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
675 if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000676 if (dis)
677 VG_(printf)( "\n\t\tmov%c\t$0x%x, 0x%x(%s)\n",
678 nameISize(sz), lit, off, nameIReg(4,memreg) );
679}
680
681
682/*----------------------------------------------------*/
683/*--- b-size (1 byte) instruction emitters ---*/
684/*----------------------------------------------------*/
685
686/* There is some doubt as to whether C6 (Grp 11) is in the
687 486 insn set. ToDo: investigate. */
njn25e49d8e72002-09-23 09:36:25 +0000688void VG_(emit_movb_lit_offregmem) ( UInt lit, Int off, Int memreg )
689{
njn4ba5a792002-09-30 10:23:54 +0000690 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000691 VG_(emitB) ( 0xC6 ); /* Grp11 Eb */
692 VG_(emit_amode_offregmem_reg) ( off, memreg, 0 /* Grp11 subopcode for MOV */ );
693 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000694 if (dis)
695 VG_(printf)( "\n\t\tmovb\t$0x%x, 0x%x(%s)\n",
696 lit, off, nameIReg(4,memreg) );
njn25e49d8e72002-09-23 09:36:25 +0000697}
698
sewardjde4a1d02002-03-22 01:27:54 +0000699static void emit_nonshiftopb_offregmem_reg ( Opcode opc,
700 Int off, Int areg, Int reg )
701{
njn4ba5a792002-09-30 10:23:54 +0000702 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000703 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
704 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000705 if (dis)
706 VG_(printf)( "\n\t\t%sb\t0x%x(%s), %s\n",
njn4ba5a792002-09-30 10:23:54 +0000707 VG_(name_UOpcode)(False,opc), off, nameIReg(4,areg),
sewardjde4a1d02002-03-22 01:27:54 +0000708 nameIReg(1,reg));
709}
710
njn25e49d8e72002-09-23 09:36:25 +0000711void VG_(emit_movb_reg_offregmem) ( Int reg, Int off, Int areg )
sewardjde4a1d02002-03-22 01:27:54 +0000712{
713 /* Could do better when reg == %al. */
njn4ba5a792002-09-30 10:23:54 +0000714 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000715 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
716 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000717 if (dis)
718 VG_(printf)( "\n\t\tmovb\t%s, 0x%x(%s)\n",
719 nameIReg(1,reg), off, nameIReg(4,areg));
720}
721
722static void emit_nonshiftopb_reg_reg ( Opcode opc, Int reg1, Int reg2 )
723{
njn4ba5a792002-09-30 10:23:54 +0000724 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000725 VG_(emitB) ( 2 + mkPrimaryOpcode(opc) ); /* op Eb, Gb */
726 VG_(emit_amode_ereg_greg) ( reg1, reg2 );
sewardjde4a1d02002-03-22 01:27:54 +0000727 if (dis)
728 VG_(printf)( "\n\t\t%sb\t%s, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000729 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000730 nameIReg(1,reg1), nameIReg(1,reg2));
731}
732
733static void emit_movb_reg_regmem ( Int reg1, Int reg2 )
734{
njn4ba5a792002-09-30 10:23:54 +0000735 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000736 VG_(emitB) ( 0x88 ); /* MOV G1, E1 */
sewardjde4a1d02002-03-22 01:27:54 +0000737 emit_amode_regmem_reg ( reg2, reg1 );
738 if (dis)
739 VG_(printf)( "\n\t\tmovb\t%s, (%s)\n", nameIReg(1,reg1),
740 nameIReg(4,reg2));
741}
742
743static void emit_nonshiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
744{
njn4ba5a792002-09-30 10:23:54 +0000745 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000746 VG_(emitB) ( 0x80 ); /* Grp1 Ib,Eb */
747 VG_(emit_amode_ereg_greg) ( reg, mkGrp1opcode(opc) );
748 VG_(emitB) ( lit & 0x000000FF );
sewardjde4a1d02002-03-22 01:27:54 +0000749 if (dis)
njn4ba5a792002-09-30 10:23:54 +0000750 VG_(printf)( "\n\t\t%sb\t$0x%x, %s\n", VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000751 lit, nameIReg(1,reg));
752}
753
754static void emit_shiftopb_lit_reg ( Opcode opc, UInt lit, Int reg )
755{
njn4ba5a792002-09-30 10:23:54 +0000756 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000757 VG_(emitB) ( 0xC0 ); /* Grp2 Ib,Eb */
758 VG_(emit_amode_ereg_greg) ( reg, mkGrp2opcode(opc) );
759 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000760 if (dis)
761 VG_(printf)( "\n\t\t%sb\t$%d, %s\n",
njn4ba5a792002-09-30 10:23:54 +0000762 VG_(name_UOpcode)(False,opc),
sewardjde4a1d02002-03-22 01:27:54 +0000763 lit, nameIReg(1,reg));
764}
765
njn25e49d8e72002-09-23 09:36:25 +0000766void VG_(emit_unaryopb_reg) ( Opcode opc, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000767{
njn4ba5a792002-09-30 10:23:54 +0000768 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000769 switch (opc) {
770 case INC:
njn25e49d8e72002-09-23 09:36:25 +0000771 VG_(emitB) ( 0xFE );
772 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(INC) );
sewardjde4a1d02002-03-22 01:27:54 +0000773 if (dis)
774 VG_(printf)( "\n\t\tincb\t%s\n", nameIReg(1,reg));
775 break;
776 case DEC:
njn25e49d8e72002-09-23 09:36:25 +0000777 VG_(emitB) ( 0xFE );
778 VG_(emit_amode_ereg_greg) ( reg, mkGrp4opcode(DEC) );
sewardjde4a1d02002-03-22 01:27:54 +0000779 if (dis)
780 VG_(printf)( "\n\t\tdecb\t%s\n", nameIReg(1,reg));
781 break;
782 case NOT:
njn25e49d8e72002-09-23 09:36:25 +0000783 VG_(emitB) ( 0xF6 );
784 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NOT) );
sewardjde4a1d02002-03-22 01:27:54 +0000785 if (dis)
786 VG_(printf)( "\n\t\tnotb\t%s\n", nameIReg(1,reg));
787 break;
788 case NEG:
njn25e49d8e72002-09-23 09:36:25 +0000789 VG_(emitB) ( 0xF6 );
790 VG_(emit_amode_ereg_greg) ( reg, mkGrp3opcode(NEG) );
sewardjde4a1d02002-03-22 01:27:54 +0000791 if (dis)
792 VG_(printf)( "\n\t\tnegb\t%s\n", nameIReg(1,reg));
793 break;
794 default:
njne427a662002-10-02 11:08:25 +0000795 VG_(core_panic)("VG_(emit_unaryopb_reg)");
sewardjde4a1d02002-03-22 01:27:54 +0000796 }
797}
798
njn25e49d8e72002-09-23 09:36:25 +0000799void VG_(emit_testb_lit_reg) ( UInt lit, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000800{
njn4ba5a792002-09-30 10:23:54 +0000801 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000802 VG_(emitB) ( 0xF6 ); /* Grp3 Eb */
803 VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
804 VG_(emitB) ( lit );
sewardjde4a1d02002-03-22 01:27:54 +0000805 if (dis)
806 VG_(printf)("\n\t\ttestb $0x%x, %s\n", lit, nameIReg(1,reg));
807}
808
sewardjde4a1d02002-03-22 01:27:54 +0000809/*----------------------------------------------------*/
810/*--- zero-extended load emitters ---*/
811/*----------------------------------------------------*/
812
njn25e49d8e72002-09-23 09:36:25 +0000813void VG_(emit_movzbl_offregmem_reg) ( Int off, Int regmem, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000814{
njn4ba5a792002-09-30 10:23:54 +0000815 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000816 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
817 VG_(emit_amode_offregmem_reg) ( off, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000818 if (dis)
819 VG_(printf)( "\n\t\tmovzbl\t0x%x(%s), %s\n",
820 off, nameIReg(4,regmem), nameIReg(4,reg));
821}
822
823static void emit_movzbl_regmem_reg ( Int reg1, Int reg2 )
824{
njn4ba5a792002-09-30 10:23:54 +0000825 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000826 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB6 ); /* MOVZBL */
sewardjde4a1d02002-03-22 01:27:54 +0000827 emit_amode_regmem_reg ( reg1, reg2 );
828 if (dis)
829 VG_(printf)( "\n\t\tmovzbl\t(%s), %s\n", nameIReg(4,reg1),
830 nameIReg(4,reg2));
831}
832
njn25e49d8e72002-09-23 09:36:25 +0000833void VG_(emit_movzwl_offregmem_reg) ( Int off, Int areg, Int reg )
sewardjde4a1d02002-03-22 01:27:54 +0000834{
njn4ba5a792002-09-30 10:23:54 +0000835 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000836 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
837 VG_(emit_amode_offregmem_reg) ( off, areg, reg );
sewardjde4a1d02002-03-22 01:27:54 +0000838 if (dis)
839 VG_(printf)( "\n\t\tmovzwl\t0x%x(%s), %s\n",
840 off, nameIReg(4,areg), nameIReg(4,reg));
841}
842
843static void emit_movzwl_regmem_reg ( Int reg1, Int reg2 )
844{
njn4ba5a792002-09-30 10:23:54 +0000845 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000846 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0xB7 ); /* MOVZWL */
sewardjde4a1d02002-03-22 01:27:54 +0000847 emit_amode_regmem_reg ( reg1, reg2 );
848 if (dis)
849 VG_(printf)( "\n\t\tmovzwl\t(%s), %s\n", nameIReg(4,reg1),
850 nameIReg(4,reg2));
851}
852
853/*----------------------------------------------------*/
854/*--- FPU instruction emitters ---*/
855/*----------------------------------------------------*/
856
857static void emit_get_fpu_state ( void )
858{
859 Int off = 4 * VGOFF_(m_fpustate);
njn4ba5a792002-09-30 10:23:54 +0000860 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000861 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xA5 ); /* frstor d32(%ebp) */
862 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000863 if (dis)
864 VG_(printf)("\n\t\tfrstor\t%d(%%ebp)\n", off );
865}
866
867static void emit_put_fpu_state ( void )
868{
869 Int off = 4 * VGOFF_(m_fpustate);
njn4ba5a792002-09-30 10:23:54 +0000870 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000871 VG_(emitB) ( 0xDD ); VG_(emitB) ( 0xB5 ); /* fnsave d32(%ebp) */
872 VG_(emitL) ( off );
sewardjde4a1d02002-03-22 01:27:54 +0000873 if (dis)
874 VG_(printf)("\n\t\tfnsave\t%d(%%ebp)\n", off );
875}
876
877static void emit_fpu_no_mem ( UChar first_byte,
878 UChar second_byte )
879{
njn4ba5a792002-09-30 10:23:54 +0000880 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000881 VG_(emitB) ( first_byte );
882 VG_(emitB) ( second_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000883 if (dis)
884 VG_(printf)("\n\t\tfpu-0x%x:0x%x\n",
885 (UInt)first_byte, (UInt)second_byte );
886}
887
888static void emit_fpu_regmem ( UChar first_byte,
889 UChar second_byte_masked,
890 Int reg )
891{
njn4ba5a792002-09-30 10:23:54 +0000892 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000893 VG_(emitB) ( first_byte );
sewardjde4a1d02002-03-22 01:27:54 +0000894 emit_amode_regmem_reg ( reg, second_byte_masked >> 3 );
895 if (dis)
896 VG_(printf)("\n\t\tfpu-0x%x:0x%x-(%s)\n",
897 (UInt)first_byte, (UInt)second_byte_masked,
898 nameIReg(4,reg) );
899}
900
901
902/*----------------------------------------------------*/
903/*--- misc instruction emitters ---*/
904/*----------------------------------------------------*/
905
njn25e49d8e72002-09-23 09:36:25 +0000906void VG_(emit_call_reg) ( Int reg )
907{
njn4ba5a792002-09-30 10:23:54 +0000908 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000909 VG_(emitB) ( 0xFF ); /* Grp5 */
910 VG_(emit_amode_ereg_greg) ( reg, mkGrp5opcode(CALLM) );
911 if (dis)
sewardjde4a1d02002-03-22 01:27:54 +0000912 VG_(printf)( "\n\t\tcall\t*%s\n", nameIReg(4,reg) );
njn25e49d8e72002-09-23 09:36:25 +0000913}
914
sewardjde4a1d02002-03-22 01:27:54 +0000915static void emit_call_star_EBP_off ( Int byte_off )
916{
njn4ba5a792002-09-30 10:23:54 +0000917 VG_(new_emit)();
sewardjde4a1d02002-03-22 01:27:54 +0000918 if (byte_off < -128 || byte_off > 127) {
njn25e49d8e72002-09-23 09:36:25 +0000919 VG_(emitB) ( 0xFF );
920 VG_(emitB) ( 0x95 );
921 VG_(emitL) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000922 } else {
njn25e49d8e72002-09-23 09:36:25 +0000923 VG_(emitB) ( 0xFF );
924 VG_(emitB) ( 0x55 );
925 VG_(emitB) ( byte_off );
sewardjde4a1d02002-03-22 01:27:54 +0000926 }
927 if (dis)
928 VG_(printf)( "\n\t\tcall * %d(%%ebp)\n", byte_off );
929}
930
931
932static void emit_addlit8_offregmem ( Int lit8, Int regmem, Int off )
933{
934 vg_assert(lit8 >= -128 && lit8 < 128);
njn4ba5a792002-09-30 10:23:54 +0000935 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000936 VG_(emitB) ( 0x83 ); /* Grp1 Ib,Ev */
937 VG_(emit_amode_offregmem_reg) ( off, regmem,
sewardjde4a1d02002-03-22 01:27:54 +0000938 0 /* Grp1 subopcode for ADD */ );
njn25e49d8e72002-09-23 09:36:25 +0000939 VG_(emitB) ( lit8 & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000940 if (dis)
941 VG_(printf)( "\n\t\taddl $%d, %d(%s)\n", lit8, off,
942 nameIReg(4,regmem));
943}
944
945
njn25e49d8e72002-09-23 09:36:25 +0000946void VG_(emit_add_lit_to_esp) ( Int lit )
sewardjde4a1d02002-03-22 01:27:54 +0000947{
njne427a662002-10-02 11:08:25 +0000948 if (lit < -128 || lit > 127) VG_(core_panic)("VG_(emit_add_lit_to_esp)");
njn4ba5a792002-09-30 10:23:54 +0000949 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000950 VG_(emitB) ( 0x83 );
951 VG_(emitB) ( 0xC4 );
952 VG_(emitB) ( lit & 0xFF );
sewardjde4a1d02002-03-22 01:27:54 +0000953 if (dis)
954 VG_(printf)( "\n\t\taddl $%d, %%esp\n", lit );
955}
956
957
958static void emit_movb_AL_zeroESPmem ( void )
959{
960 /* movb %al, 0(%esp) */
961 /* 88442400 movb %al, 0(%esp) */
njn4ba5a792002-09-30 10:23:54 +0000962 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000963 VG_(emitB) ( 0x88 );
964 VG_(emitB) ( 0x44 );
965 VG_(emitB) ( 0x24 );
966 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000967 if (dis)
968 VG_(printf)( "\n\t\tmovb %%al, 0(%%esp)\n" );
969}
970
971static void emit_movb_zeroESPmem_AL ( void )
972{
973 /* movb 0(%esp), %al */
974 /* 8A442400 movb 0(%esp), %al */
njn4ba5a792002-09-30 10:23:54 +0000975 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000976 VG_(emitB) ( 0x8A );
977 VG_(emitB) ( 0x44 );
978 VG_(emitB) ( 0x24 );
979 VG_(emitB) ( 0x00 );
sewardjde4a1d02002-03-22 01:27:54 +0000980 if (dis)
981 VG_(printf)( "\n\t\tmovb 0(%%esp), %%al\n" );
982}
983
984
985/* Emit a jump short with an 8-bit signed offset. Note that the
986 offset is that which should be added to %eip once %eip has been
987 advanced over this insn. */
njn25e49d8e72002-09-23 09:36:25 +0000988void VG_(emit_jcondshort_delta) ( Condcode cond, Int delta )
sewardjde4a1d02002-03-22 01:27:54 +0000989{
990 vg_assert(delta >= -128 && delta <= 127);
njn4ba5a792002-09-30 10:23:54 +0000991 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +0000992 VG_(emitB) ( 0x70 + (UInt)cond );
993 VG_(emitB) ( (UChar)delta );
sewardjde4a1d02002-03-22 01:27:54 +0000994 if (dis)
995 VG_(printf)( "\n\t\tj%s-8\t%%eip+%d\n",
996 VG_(nameCondcode)(cond), delta );
997}
998
999static void emit_get_eflags ( void )
1000{
1001 Int off = 4 * VGOFF_(m_eflags);
1002 vg_assert(off >= 0 && off < 128);
njn4ba5a792002-09-30 10:23:54 +00001003 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001004 VG_(emitB) ( 0xFF ); /* PUSHL off(%ebp) */
1005 VG_(emitB) ( 0x75 );
1006 VG_(emitB) ( off );
1007 VG_(emitB) ( 0x9D ); /* POPFL */
sewardjde4a1d02002-03-22 01:27:54 +00001008 if (dis)
1009 VG_(printf)( "\n\t\tpushl %d(%%ebp) ; popfl\n", off );
1010}
1011
1012static void emit_put_eflags ( void )
1013{
1014 Int off = 4 * VGOFF_(m_eflags);
1015 vg_assert(off >= 0 && off < 128);
njn4ba5a792002-09-30 10:23:54 +00001016 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001017 VG_(emitB) ( 0x9C ); /* PUSHFL */
1018 VG_(emitB) ( 0x8F ); /* POPL vg_m_state.m_eflags */
1019 VG_(emitB) ( 0x45 );
1020 VG_(emitB) ( off );
sewardjde4a1d02002-03-22 01:27:54 +00001021 if (dis)
1022 VG_(printf)( "\n\t\tpushfl ; popl %d(%%ebp)\n", off );
1023}
1024
1025static void emit_setb_reg ( Int reg, Condcode cond )
1026{
njn4ba5a792002-09-30 10:23:54 +00001027 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001028 VG_(emitB) ( 0x0F ); VG_(emitB) ( 0x90 + (UChar)cond );
1029 VG_(emit_amode_ereg_greg) ( reg, 0 );
sewardjde4a1d02002-03-22 01:27:54 +00001030 if (dis)
1031 VG_(printf)("\n\t\tset%s %s\n",
1032 VG_(nameCondcode)(cond), nameIReg(1,reg));
1033}
1034
1035static void emit_ret ( void )
1036{
njn4ba5a792002-09-30 10:23:54 +00001037 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001038 VG_(emitB) ( 0xC3 ); /* RET */
sewardjde4a1d02002-03-22 01:27:54 +00001039 if (dis)
1040 VG_(printf)("\n\t\tret\n");
1041}
1042
njn25e49d8e72002-09-23 09:36:25 +00001043void VG_(emit_pushal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001044{
njn4ba5a792002-09-30 10:23:54 +00001045 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001046 VG_(emitB) ( 0x60 ); /* PUSHAL */
sewardjde4a1d02002-03-22 01:27:54 +00001047 if (dis)
1048 VG_(printf)("\n\t\tpushal\n");
1049}
1050
njn25e49d8e72002-09-23 09:36:25 +00001051void VG_(emit_popal) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001052{
njn4ba5a792002-09-30 10:23:54 +00001053 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001054 VG_(emitB) ( 0x61 ); /* POPAL */
sewardjde4a1d02002-03-22 01:27:54 +00001055 if (dis)
1056 VG_(printf)("\n\t\tpopal\n");
1057}
1058
1059static void emit_lea_litreg_reg ( UInt lit, Int regmem, Int reg )
1060{
njn4ba5a792002-09-30 10:23:54 +00001061 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001062 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
1063 VG_(emit_amode_offregmem_reg) ( (Int)lit, regmem, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001064 if (dis)
1065 VG_(printf)("\n\t\tleal 0x%x(%s), %s\n",
1066 lit, nameIReg(4,regmem), nameIReg(4,reg) );
1067}
1068
1069static void emit_lea_sib_reg ( UInt lit, Int scale,
1070 Int regbase, Int regindex, Int reg )
1071{
njn4ba5a792002-09-30 10:23:54 +00001072 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001073 VG_(emitB) ( 0x8D ); /* LEA M,Gv */
sewardjde4a1d02002-03-22 01:27:54 +00001074 emit_amode_sib_reg ( (Int)lit, scale, regbase, regindex, reg );
1075 if (dis)
1076 VG_(printf)("\n\t\tleal 0x%x(%s,%s,%d), %s\n",
1077 lit, nameIReg(4,regbase),
1078 nameIReg(4,regindex), scale,
1079 nameIReg(4,reg) );
1080}
1081
njn25e49d8e72002-09-23 09:36:25 +00001082void VG_(emit_AMD_prefetch_reg) ( Int reg )
sewardjde4a1d02002-03-22 01:27:54 +00001083{
njn4ba5a792002-09-30 10:23:54 +00001084 VG_(new_emit)();
njn25e49d8e72002-09-23 09:36:25 +00001085 VG_(emitB) ( 0x0F );
1086 VG_(emitB) ( 0x0D );
sewardjde4a1d02002-03-22 01:27:54 +00001087 emit_amode_regmem_reg ( reg, 1 /* 0 is prefetch; 1 is prefetchw */ );
1088 if (dis)
1089 VG_(printf)("\n\t\tamd-prefetch (%s)\n", nameIReg(4,reg) );
1090}
1091
1092/*----------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001093/*--- Helper offset -> addr translation ---*/
1094/*----------------------------------------------------*/
1095
1096/* Finds the baseBlock offset of a skin-specified helper.
1097 * Searches through compacts first, then non-compacts. */
1098Int VG_(helper_offset)(Addr a)
1099{
1100 Int i;
1101
1102 for (i = 0; i < VG_(n_compact_helpers); i++)
1103 if (VG_(compact_helper_addrs)[i] == a)
1104 return VG_(compact_helper_offsets)[i];
1105 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1106 if (VG_(noncompact_helper_addrs)[i] == a)
1107 return VG_(noncompact_helper_offsets)[i];
1108
1109 /* Shouldn't get here */
1110 VG_(printf)(
1111 "\nCouldn't find offset of helper from its address (%p).\n"
1112 "A helper function probably used hasn't been registered?\n\n", a);
1113
1114 VG_(printf)(" compact helpers: ");
1115 for (i = 0; i < VG_(n_compact_helpers); i++)
1116 VG_(printf)("%p ", VG_(compact_helper_addrs)[i]);
1117
1118 VG_(printf)("\n non-compact helpers: ");
1119 for (i = 0; i < VG_(n_noncompact_helpers); i++)
1120 VG_(printf)("%p ", VG_(noncompact_helper_addrs)[i]);
1121
1122 VG_(printf)("\n");
njne427a662002-10-02 11:08:25 +00001123 VG_(skin_panic)("Unfound helper");
njn25e49d8e72002-09-23 09:36:25 +00001124}
1125
1126/*----------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +00001127/*--- Instruction synthesisers ---*/
1128/*----------------------------------------------------*/
1129
1130static Condcode invertCondition ( Condcode cond )
1131{
1132 return (Condcode)(1 ^ (UInt)cond);
1133}
1134
1135
1136/* Synthesise a call to *baseBlock[offset], ie,
1137 call * (4 x offset)(%ebp).
1138*/
njn25e49d8e72002-09-23 09:36:25 +00001139void VG_(synth_call) ( Bool ensure_shortform, Int word_offset )
sewardjde4a1d02002-03-22 01:27:54 +00001140{
1141 vg_assert(word_offset >= 0);
1142 vg_assert(word_offset < VG_BASEBLOCK_WORDS);
1143 if (ensure_shortform)
1144 vg_assert(word_offset < 32);
1145 emit_call_star_EBP_off ( 4 * word_offset );
1146}
1147
njn25e49d8e72002-09-23 09:36:25 +00001148static void maybe_emit_movl_reg_reg ( UInt src, UInt dst )
njn6431be72002-07-28 09:53:34 +00001149{
njn25e49d8e72002-09-23 09:36:25 +00001150 if (src != dst) {
1151 VG_(emit_movv_reg_reg) ( 4, src, dst );
1152 ccall_arg_setup_instrs++;
1153 }
njn6431be72002-07-28 09:53:34 +00001154}
njn25e49d8e72002-09-23 09:36:25 +00001155
1156/* 'maybe' because it is sometimes skipped eg. for "movl %eax,%eax" */
1157static void maybe_emit_movl_litOrReg_reg ( UInt litOrReg, Tag tag, UInt reg )
1158{
1159 if (RealReg == tag) {
1160 maybe_emit_movl_reg_reg ( litOrReg, reg );
1161 } else if (Literal == tag) {
1162 VG_(emit_movv_lit_reg) ( 4, litOrReg, reg );
1163 ccall_arg_setup_instrs++;
1164 }
1165 else
njne427a662002-10-02 11:08:25 +00001166 VG_(core_panic)("emit_movl_litOrReg_reg: unexpected tag");
njn25e49d8e72002-09-23 09:36:25 +00001167}
1168
1169static
1170void emit_swapl_arg_regs ( UInt reg1, UInt reg2 )
1171{
1172 if (R_EAX == reg1) {
1173 VG_(emit_swapl_reg_EAX) ( reg2 );
1174 } else if (R_EAX == reg2) {
1175 VG_(emit_swapl_reg_EAX) ( reg1 );
1176 } else {
1177 emit_swapl_reg_reg ( reg1, reg2 );
1178 }
1179 ccall_arg_setup_instrs++;
1180}
1181
1182static
1183void emit_two_regs_args_setup ( UInt src1, UInt src2, UInt dst1, UInt dst2)
1184{
1185 if (dst1 != src2) {
1186 maybe_emit_movl_reg_reg ( src1, dst1 );
1187 maybe_emit_movl_reg_reg ( src2, dst2 );
1188
1189 } else if (dst2 != src1) {
1190 maybe_emit_movl_reg_reg ( src2, dst2 );
1191 maybe_emit_movl_reg_reg ( src1, dst1 );
1192
1193 } else {
1194 /* swap to break cycle */
1195 emit_swapl_arg_regs ( dst1, dst2 );
1196 }
1197}
1198
1199static
1200void emit_three_regs_args_setup ( UInt src1, UInt src2, UInt src3,
1201 UInt dst1, UInt dst2, UInt dst3)
1202{
1203 if (dst1 != src2 && dst1 != src3) {
1204 maybe_emit_movl_reg_reg ( src1, dst1 );
1205 emit_two_regs_args_setup ( src2, src3, dst2, dst3 );
1206
1207 } else if (dst2 != src1 && dst2 != src3) {
1208 maybe_emit_movl_reg_reg ( src2, dst2 );
1209 emit_two_regs_args_setup ( src1, src3, dst1, dst3 );
1210
1211 } else if (dst3 != src1 && dst3 != src2) {
1212 maybe_emit_movl_reg_reg ( src3, dst3 );
1213 emit_two_regs_args_setup ( src1, src2, dst1, dst2 );
1214
1215 } else {
1216 /* break cycle */
1217 if (dst1 == src2 && dst2 == src3 && dst3 == src1) {
1218 emit_swapl_arg_regs ( dst1, dst2 );
1219 emit_swapl_arg_regs ( dst1, dst3 );
1220
1221 } else if (dst1 == src3 && dst2 == src1 && dst3 == src2) {
1222 emit_swapl_arg_regs ( dst1, dst3 );
1223 emit_swapl_arg_regs ( dst1, dst2 );
1224
1225 } else {
njne427a662002-10-02 11:08:25 +00001226 VG_(core_panic)("impossible 3-cycle");
njn25e49d8e72002-09-23 09:36:25 +00001227 }
1228 }
1229}
1230
1231static
1232void emit_two_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1233 UInt src1, UInt src2,
1234 UInt dst1, UInt dst2)
1235{
1236 /* If either are lits, order doesn't matter */
1237 if (Literal == tagv[src1] || Literal == tagv[src2]) {
1238 maybe_emit_movl_litOrReg_reg ( argv[src1], tagv[src1], dst1 );
1239 maybe_emit_movl_litOrReg_reg ( argv[src2], tagv[src2], dst2 );
1240
1241 } else {
1242 emit_two_regs_args_setup ( argv[src1], argv[src2], dst1, dst2 );
1243 }
1244}
1245
1246static
1247void emit_three_regs_or_lits_args_setup ( UInt argv[], Tag tagv[],
1248 UInt src1, UInt src2, UInt src3,
1249 UInt dst1, UInt dst2, UInt dst3)
1250{
1251 // SSS: fix this eventually -- make STOREV use two RealRegs?
1252 /* Not supporting literals for 3-arg C functions -- they're only used
1253 by STOREV which has 2 args */
1254 vg_assert(RealReg == tagv[src1] &&
1255 RealReg == tagv[src2] &&
1256 RealReg == tagv[src3]);
1257 emit_three_regs_args_setup ( argv[src1], argv[src2], argv[src3],
1258 dst1, dst2, dst3 );
1259}
1260
1261/* Synthesise a call to a C function `fn' (which must be registered in
1262 baseBlock) doing all the reg saving and arg handling work.
1263
1264 WARNING: a UInstr should *not* be translated with synth_ccall followed
1265 by some other x86 assembly code; vg_liveness_analysis() doesn't expect
1266 such behaviour and everything will fall over.
1267 */
1268void VG_(synth_ccall) ( Addr fn, Int argc, Int regparms_n, UInt argv[],
1269 Tag tagv[], Int ret_reg,
1270 RRegSet regs_live_before, RRegSet regs_live_after )
1271{
1272 Int i;
1273 Int stack_used = 0;
1274 Bool preserve_eax, preserve_ecx, preserve_edx;
1275
1276 vg_assert(0 <= regparms_n && regparms_n <= 3);
1277
1278 ccalls++;
1279
1280 /* If %e[acd]x is live before and after the C call, save/restore it.
1281 Unless the return values clobbers the reg; in this case we must not
1282 save/restore the reg, because the restore would clobber the return
1283 value. (Before and after the UInstr really constitute separate live
1284 ranges, but you miss this if you don't consider what happens during
1285 the UInstr.) */
1286# define PRESERVE_REG(realReg) \
njn4ba5a792002-09-30 10:23:54 +00001287 (IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_before) && \
1288 IS_RREG_LIVE(VG_(realreg_to_rank)(realReg), regs_live_after) && \
njn25e49d8e72002-09-23 09:36:25 +00001289 ret_reg != realReg)
1290
1291 preserve_eax = PRESERVE_REG(R_EAX);
1292 preserve_ecx = PRESERVE_REG(R_ECX);
1293 preserve_edx = PRESERVE_REG(R_EDX);
1294
1295# undef PRESERVE_REG
1296
1297 /* Save caller-save regs as required */
1298 if (preserve_eax) { VG_(emit_pushv_reg) ( 4, R_EAX ); ccall_reg_saves++; }
1299 if (preserve_ecx) { VG_(emit_pushv_reg) ( 4, R_ECX ); ccall_reg_saves++; }
1300 if (preserve_edx) { VG_(emit_pushv_reg) ( 4, R_EDX ); ccall_reg_saves++; }
1301
1302 /* Args are passed in two groups: (a) via stack (b) via regs. regparms_n
1303 is the number of args passed in regs (maximum 3 for GCC on x86). */
1304
1305 ccall_args += argc;
njn6431be72002-07-28 09:53:34 +00001306
njn25e49d8e72002-09-23 09:36:25 +00001307 /* First push stack args (RealRegs or Literals) in reverse order. */
1308 for (i = argc-1; i >= regparms_n; i--) {
1309 switch (tagv[i]) {
1310 case RealReg:
1311 VG_(emit_pushv_reg) ( 4, argv[i] );
1312 break;
1313 case Literal:
1314 /* Use short form of pushl if possible. */
1315 if (argv[i] == VG_(extend_s_8to32) ( argv[i] ))
1316 VG_(emit_pushl_lit8) ( VG_(extend_s_8to32)(argv[i]) );
1317 else
1318 VG_(emit_pushl_lit32)( argv[i] );
1319 break;
1320 default:
1321 VG_(printf)("tag=%d\n", tagv[i]);
njne427a662002-10-02 11:08:25 +00001322 VG_(core_panic)("VG_(synth_ccall): bad tag");
njn25e49d8e72002-09-23 09:36:25 +00001323 }
1324 stack_used += 4;
1325 ccall_arg_setup_instrs++;
1326 }
njn6431be72002-07-28 09:53:34 +00001327
njn25e49d8e72002-09-23 09:36:25 +00001328 /* Then setup args in registers (arg[123] --> %e[adc]x; note order!).
1329 If moving values between registers, be careful not to clobber any on
1330 the way. Happily we can use xchgl to swap registers.
1331 */
1332 switch (regparms_n) {
njn6431be72002-07-28 09:53:34 +00001333
njn25e49d8e72002-09-23 09:36:25 +00001334 /* Trickiest. Args passed in %eax, %edx, and %ecx. */
1335 case 3:
1336 emit_three_regs_or_lits_args_setup ( argv, tagv, 0, 1, 2,
1337 R_EAX, R_EDX, R_ECX );
1338 break;
njn6431be72002-07-28 09:53:34 +00001339
njn25e49d8e72002-09-23 09:36:25 +00001340 /* Less-tricky. Args passed in %eax and %edx. */
1341 case 2:
1342 emit_two_regs_or_lits_args_setup ( argv, tagv, 0, 1, R_EAX, R_EDX );
1343 break;
1344
1345 /* Easy. Just move arg1 into %eax (if not already in there). */
1346 case 1:
1347 maybe_emit_movl_litOrReg_reg ( argv[0], tagv[0], R_EAX );
1348 break;
1349
1350 case 0:
1351 break;
1352
1353 default:
njne427a662002-10-02 11:08:25 +00001354 VG_(core_panic)("VG_(synth_call): regparms_n value not in range 0..3");
njn25e49d8e72002-09-23 09:36:25 +00001355 }
1356
1357 /* Call the function */
1358 VG_(synth_call) ( False, VG_(helper_offset) ( fn ) );
1359
1360 /* Clear any args from stack */
1361 if (0 != stack_used) {
1362 VG_(emit_add_lit_to_esp) ( stack_used );
1363 ccall_stack_clears++;
1364 }
1365
1366 /* Move return value into ret_reg if necessary and not already there */
1367 if (INVALID_REALREG != ret_reg) {
1368 ccall_retvals++;
1369 if (R_EAX != ret_reg) {
1370 VG_(emit_movv_reg_reg) ( 4, R_EAX, ret_reg );
1371 ccall_retval_movs++;
1372 }
1373 }
1374
1375 /* Restore live caller-save regs as required */
1376 if (preserve_edx) VG_(emit_popv_reg) ( 4, R_EDX );
1377 if (preserve_ecx) VG_(emit_popv_reg) ( 4, R_ECX );
1378 if (preserve_eax) VG_(emit_popv_reg) ( 4, R_EAX );
njn6431be72002-07-28 09:53:34 +00001379}
sewardjde4a1d02002-03-22 01:27:54 +00001380
sewardj2e93c502002-04-12 11:12:52 +00001381static void load_ebp_from_JmpKind ( JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001382{
sewardj2e93c502002-04-12 11:12:52 +00001383 switch (jmpkind) {
1384 case JmpBoring:
1385 break;
sewardj2e93c502002-04-12 11:12:52 +00001386 case JmpRet:
njn25e49d8e72002-09-23 09:36:25 +00001387 break;
1388 case JmpCall:
sewardj2e93c502002-04-12 11:12:52 +00001389 break;
1390 case JmpSyscall:
njn25e49d8e72002-09-23 09:36:25 +00001391 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_SYSCALL, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001392 break;
1393 case JmpClientReq:
njn25e49d8e72002-09-23 09:36:25 +00001394 VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
sewardj2e93c502002-04-12 11:12:52 +00001395 break;
1396 default:
njne427a662002-10-02 11:08:25 +00001397 VG_(core_panic)("load_ebp_from_JmpKind");
sewardj2e93c502002-04-12 11:12:52 +00001398 }
1399}
1400
1401/* Jump to the next translation, by loading its original addr into
1402 %eax and returning to the scheduler. Signal special requirements
1403 by loading a special value into %ebp first.
1404*/
1405static void synth_jmp_reg ( Int reg, JmpKind jmpkind )
1406{
1407 load_ebp_from_JmpKind ( jmpkind );
sewardjde4a1d02002-03-22 01:27:54 +00001408 if (reg != R_EAX)
njn25e49d8e72002-09-23 09:36:25 +00001409 VG_(emit_movv_reg_reg) ( 4, reg, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001410 emit_ret();
1411}
1412
1413
1414/* Same deal as synth_jmp_reg. */
sewardj2e93c502002-04-12 11:12:52 +00001415static void synth_jmp_lit ( Addr addr, JmpKind jmpkind )
sewardjde4a1d02002-03-22 01:27:54 +00001416{
sewardj2e93c502002-04-12 11:12:52 +00001417 load_ebp_from_JmpKind ( jmpkind );
njn25e49d8e72002-09-23 09:36:25 +00001418 VG_(emit_movv_lit_reg) ( 4, addr, R_EAX );
sewardjde4a1d02002-03-22 01:27:54 +00001419 emit_ret();
1420}
1421
1422
sewardjde4a1d02002-03-22 01:27:54 +00001423static void synth_jcond_lit ( Condcode cond, Addr addr )
1424{
1425 /* Do the following:
1426 get eflags
1427 jmp short if not cond to xyxyxy
1428 addr -> eax
1429 ret
1430 xyxyxy
1431
1432 2 0000 750C jnz xyxyxy
1433 3 0002 B877665544 movl $0x44556677, %eax
1434 4 0007 C3 ret
1435 5 0008 FFE3 jmp *%ebx
1436 6 xyxyxy:
1437 */
1438 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001439 VG_(emit_jcondshort_delta) ( invertCondition(cond), 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001440 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001441}
1442
1443
1444static void synth_jmp_ifzero_reg_lit ( Int reg, Addr addr )
1445{
1446 /* 0000 83FF00 cmpl $0, %edi
1447 0003 750A jnz next
1448 0005 B844332211 movl $0x11223344, %eax
1449 000a C3 ret
1450 next:
1451 */
njn25e49d8e72002-09-23 09:36:25 +00001452 VG_(emit_cmpl_zero_reg) ( reg );
1453 VG_(emit_jcondshort_delta) ( CondNZ, 5+1 );
sewardj2e93c502002-04-12 11:12:52 +00001454 synth_jmp_lit ( addr, JmpBoring );
sewardjde4a1d02002-03-22 01:27:54 +00001455}
1456
1457
1458static void synth_mov_lit_reg ( Int size, UInt lit, Int reg )
1459{
1460 /* Load the zero-extended literal into reg, at size l,
1461 regardless of the request size. */
njn25e49d8e72002-09-23 09:36:25 +00001462 VG_(emit_movv_lit_reg) ( 4, lit, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001463}
1464
1465
1466static void synth_mov_regmem_reg ( Int size, Int reg1, Int reg2 )
1467{
1468 switch (size) {
1469 case 4: emit_movv_regmem_reg ( 4, reg1, reg2 ); break;
1470 case 2: emit_movzwl_regmem_reg ( reg1, reg2 ); break;
1471 case 1: emit_movzbl_regmem_reg ( reg1, reg2 ); break;
njne427a662002-10-02 11:08:25 +00001472 default: VG_(core_panic)("synth_mov_regmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001473 }
1474}
1475
1476
1477static void synth_mov_offregmem_reg ( Int size, Int off, Int areg, Int reg )
1478{
1479 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001480 case 4: VG_(emit_movv_offregmem_reg) ( 4, off, areg, reg ); break;
1481 case 2: VG_(emit_movzwl_offregmem_reg) ( off, areg, reg ); break;
1482 case 1: VG_(emit_movzbl_offregmem_reg) ( off, areg, reg ); break;
njne427a662002-10-02 11:08:25 +00001483 default: VG_(core_panic)("synth_mov_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001484 }
1485}
1486
1487
1488static void synth_mov_reg_offregmem ( Int size, Int reg,
1489 Int off, Int areg )
1490{
1491 switch (size) {
njn25e49d8e72002-09-23 09:36:25 +00001492 case 4: VG_(emit_movv_reg_offregmem) ( 4, reg, off, areg ); break;
1493 case 2: VG_(emit_movv_reg_offregmem) ( 2, reg, off, areg ); break;
sewardjde4a1d02002-03-22 01:27:54 +00001494 case 1: if (reg < 4) {
njn25e49d8e72002-09-23 09:36:25 +00001495 VG_(emit_movb_reg_offregmem) ( reg, off, areg );
sewardjde4a1d02002-03-22 01:27:54 +00001496 }
1497 else {
njn25e49d8e72002-09-23 09:36:25 +00001498 VG_(emit_swapl_reg_EAX) ( reg );
1499 VG_(emit_movb_reg_offregmem) ( R_AL, off, areg );
1500 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001501 }
1502 break;
njne427a662002-10-02 11:08:25 +00001503 default: VG_(core_panic)("synth_mov_reg_offregmem");
sewardjde4a1d02002-03-22 01:27:54 +00001504 }
1505}
1506
1507
1508static void synth_mov_reg_memreg ( Int size, Int reg1, Int reg2 )
1509{
1510 Int s1;
1511 switch (size) {
1512 case 4: emit_movv_reg_regmem ( 4, reg1, reg2 ); break;
1513 case 2: emit_movv_reg_regmem ( 2, reg1, reg2 ); break;
1514 case 1: if (reg1 < 4) {
1515 emit_movb_reg_regmem ( reg1, reg2 );
1516 }
1517 else {
1518 /* Choose a swap reg which is < 4 and not reg1 or reg2. */
1519 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1520 emit_swapl_reg_reg ( s1, reg1 );
1521 emit_movb_reg_regmem ( s1, reg2 );
1522 emit_swapl_reg_reg ( s1, reg1 );
1523 }
1524 break;
njne427a662002-10-02 11:08:25 +00001525 default: VG_(core_panic)("synth_mov_reg_litmem");
sewardjde4a1d02002-03-22 01:27:54 +00001526 }
1527}
1528
1529
sewardj478335c2002-10-05 02:44:47 +00001530static void synth_unaryop_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001531 Opcode opcode, Int size,
1532 Int reg )
1533{
1534 /* NB! opcode is a uinstr opcode, not an x86 one! */
1535 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001536 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001537 VG_(emit_unaryopv_reg) ( 4, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001538 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001539 break;
sewardj478335c2002-10-05 02:44:47 +00001540 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001541 VG_(emit_unaryopv_reg) ( 2, opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001542 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001543 break;
1544 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001545 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001546 VG_(emit_unaryopb_reg) ( opcode, reg );
sewardj478335c2002-10-05 02:44:47 +00001547 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001548 } else {
njn25e49d8e72002-09-23 09:36:25 +00001549 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001550 if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001551 VG_(emit_unaryopb_reg) ( opcode, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001552 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001553 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001554 }
1555 break;
njne427a662002-10-02 11:08:25 +00001556 default: VG_(core_panic)("synth_unaryop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001557 }
1558}
1559
1560
1561
sewardj478335c2002-10-05 02:44:47 +00001562static void synth_nonshiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001563 Opcode opcode, Int size,
1564 Int reg1, Int reg2 )
1565{
1566 /* NB! opcode is a uinstr opcode, not an x86 one! */
1567 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001568 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001569 VG_(emit_nonshiftopv_reg_reg) ( 4, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001570 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001571 break;
sewardj478335c2002-10-05 02:44:47 +00001572 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001573 VG_(emit_nonshiftopv_reg_reg) ( 2, opcode, reg1, reg2 );
sewardj478335c2002-10-05 02:44:47 +00001574 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001575 break;
1576 case 1: { /* Horrible ... */
1577 Int s1, s2;
1578 /* Choose s1 and s2 to be x86 regs which we can talk about the
1579 lowest 8 bits, ie either %eax, %ebx, %ecx or %edx. Make
1580 sure s1 != s2 and that neither of them equal either reg1 or
1581 reg2. Then use them as temporaries to make things work. */
1582 if (reg1 < 4 && reg2 < 4) {
sewardj478335c2002-10-05 02:44:47 +00001583 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001584 emit_nonshiftopb_reg_reg(opcode, reg1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001585 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001586 break;
1587 }
1588 for (s1 = 0; s1 == reg1 || s1 == reg2; s1++) ;
1589 if (reg1 >= 4 && reg2 < 4) {
1590 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001591 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001592 emit_nonshiftopb_reg_reg(opcode, s1, reg2);
sewardj478335c2002-10-05 02:44:47 +00001593 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001594 emit_swapl_reg_reg ( reg1, s1 );
1595 break;
1596 }
1597 for (s2 = 0; s2 == reg1 || s2 == reg2 || s2 == s1; s2++) ;
1598 if (reg1 < 4 && reg2 >= 4) {
1599 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001600 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001601 emit_nonshiftopb_reg_reg(opcode, reg1, s2);
sewardj478335c2002-10-05 02:44:47 +00001602 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001603 emit_swapl_reg_reg ( reg2, s2 );
1604 break;
1605 }
1606 if (reg1 >= 4 && reg2 >= 4 && reg1 != reg2) {
1607 emit_swapl_reg_reg ( reg1, s1 );
1608 emit_swapl_reg_reg ( reg2, s2 );
sewardj478335c2002-10-05 02:44:47 +00001609 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001610 emit_nonshiftopb_reg_reg(opcode, s1, s2);
sewardj478335c2002-10-05 02:44:47 +00001611 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001612 emit_swapl_reg_reg ( reg1, s1 );
1613 emit_swapl_reg_reg ( reg2, s2 );
1614 break;
1615 }
1616 if (reg1 >= 4 && reg2 >= 4 && reg1 == reg2) {
1617 emit_swapl_reg_reg ( reg1, s1 );
sewardj478335c2002-10-05 02:44:47 +00001618 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001619 emit_nonshiftopb_reg_reg(opcode, s1, s1);
sewardj478335c2002-10-05 02:44:47 +00001620 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001621 emit_swapl_reg_reg ( reg1, s1 );
1622 break;
1623 }
njne427a662002-10-02 11:08:25 +00001624 VG_(core_panic)("synth_nonshiftopb_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001625 }
njne427a662002-10-02 11:08:25 +00001626 default: VG_(core_panic)("synth_nonshiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001627 }
1628}
1629
1630
1631static void synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00001632 Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001633 Opcode opcode, Int size,
1634 Int off, Int areg, Int reg )
1635{
1636 switch (size) {
1637 case 4:
sewardj478335c2002-10-05 02:44:47 +00001638 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001639 emit_nonshiftopv_offregmem_reg ( 4, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001640 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001641 break;
1642 case 2:
sewardj478335c2002-10-05 02:44:47 +00001643 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001644 emit_nonshiftopv_offregmem_reg ( 2, opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001645 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001646 break;
1647 case 1:
1648 if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001649 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001650 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, reg );
sewardj478335c2002-10-05 02:44:47 +00001651 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001652 } else {
njn25e49d8e72002-09-23 09:36:25 +00001653 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001654 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001655 emit_nonshiftopb_offregmem_reg ( opcode, off, areg, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001656 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001657 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001658 }
1659 break;
1660 default:
njne427a662002-10-02 11:08:25 +00001661 VG_(core_panic)("synth_nonshiftop_offregmem_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001662 }
1663}
1664
1665
sewardj478335c2002-10-05 02:44:47 +00001666static void synth_nonshiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001667 Opcode opcode, Int size,
1668 UInt lit, Int reg )
1669{
1670 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001671 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001672 VG_(emit_nonshiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001673 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001674 break;
sewardj478335c2002-10-05 02:44:47 +00001675 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001676 VG_(emit_nonshiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001677 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001678 break;
1679 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001680 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001681 emit_nonshiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001682 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001683 } else {
njn25e49d8e72002-09-23 09:36:25 +00001684 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001685 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001686 emit_nonshiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001687 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001688 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001689 }
1690 break;
njne427a662002-10-02 11:08:25 +00001691 default: VG_(core_panic)("synth_nonshiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001692 }
1693}
1694
1695
1696static void synth_push_reg ( Int size, Int reg )
1697{
1698 switch (size) {
1699 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001700 VG_(emit_pushv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001701 break;
1702 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001703 VG_(emit_pushv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001704 break;
1705 /* Pray that we don't have to generate this really cruddy bit of
1706 code very often. Could do better, but can I be bothered? */
1707 case 1:
1708 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001709 VG_(emit_add_lit_to_esp)(-1);
1710 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001711 emit_movb_AL_zeroESPmem();
njn25e49d8e72002-09-23 09:36:25 +00001712 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001713 break;
1714 default:
njne427a662002-10-02 11:08:25 +00001715 VG_(core_panic)("synth_push_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001716 }
1717}
1718
1719
1720static void synth_pop_reg ( Int size, Int reg )
1721{
1722 switch (size) {
1723 case 4:
njn25e49d8e72002-09-23 09:36:25 +00001724 VG_(emit_popv_reg) ( 4, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001725 break;
1726 case 2:
njn25e49d8e72002-09-23 09:36:25 +00001727 VG_(emit_popv_reg) ( 2, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001728 break;
1729 case 1:
1730 /* Same comment as above applies. */
1731 vg_assert(reg != R_ESP); /* duh */
njn25e49d8e72002-09-23 09:36:25 +00001732 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001733 emit_movb_zeroESPmem_AL();
njn25e49d8e72002-09-23 09:36:25 +00001734 if (reg != R_EAX) VG_(emit_swapl_reg_EAX) ( reg );
1735 VG_(emit_add_lit_to_esp)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001736 break;
njne427a662002-10-02 11:08:25 +00001737 default: VG_(core_panic)("synth_pop_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001738 }
1739}
1740
1741
sewardj478335c2002-10-05 02:44:47 +00001742static void synth_shiftop_reg_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001743 Opcode opcode, Int size,
1744 Int regs, Int regd )
1745{
1746 synth_push_reg ( size, regd );
1747 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
sewardj478335c2002-10-05 02:44:47 +00001748 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001749 switch (size) {
1750 case 4: emit_shiftopv_cl_stack0 ( 4, opcode ); break;
1751 case 2: emit_shiftopv_cl_stack0 ( 2, opcode ); break;
1752 case 1: emit_shiftopb_cl_stack0 ( opcode ); break;
njne427a662002-10-02 11:08:25 +00001753 default: VG_(core_panic)("synth_shiftop_reg_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001754 }
sewardj478335c2002-10-05 02:44:47 +00001755 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001756 if (regs != R_ECX) emit_swapl_reg_ECX ( regs );
1757 synth_pop_reg ( size, regd );
1758}
1759
1760
sewardj478335c2002-10-05 02:44:47 +00001761static void synth_shiftop_lit_reg ( Bool upd_cc,
sewardjde4a1d02002-03-22 01:27:54 +00001762 Opcode opcode, Int size,
1763 UInt lit, Int reg )
1764{
1765 switch (size) {
sewardj478335c2002-10-05 02:44:47 +00001766 case 4: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001767 VG_(emit_shiftopv_lit_reg) ( 4, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001768 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001769 break;
sewardj478335c2002-10-05 02:44:47 +00001770 case 2: if (upd_cc) emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001771 VG_(emit_shiftopv_lit_reg) ( 2, opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001772 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001773 break;
1774 case 1: if (reg < 4) {
sewardj478335c2002-10-05 02:44:47 +00001775 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001776 emit_shiftopb_lit_reg ( opcode, lit, reg );
sewardj478335c2002-10-05 02:44:47 +00001777 if (upd_cc) emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001778 } else {
njn25e49d8e72002-09-23 09:36:25 +00001779 VG_(emit_swapl_reg_EAX) ( reg );
sewardj478335c2002-10-05 02:44:47 +00001780 if (upd_cc) emit_get_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00001781 emit_shiftopb_lit_reg ( opcode, lit, R_AL );
sewardj478335c2002-10-05 02:44:47 +00001782 if (upd_cc) emit_put_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001783 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001784 }
1785 break;
njne427a662002-10-02 11:08:25 +00001786 default: VG_(core_panic)("synth_shiftop_lit_reg");
sewardjde4a1d02002-03-22 01:27:54 +00001787 }
1788}
1789
1790
1791static void synth_setb_reg ( Int reg, Condcode cond )
1792{
1793 emit_get_eflags();
1794 if (reg < 4) {
1795 emit_setb_reg ( reg, cond );
1796 } else {
njn25e49d8e72002-09-23 09:36:25 +00001797 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001798 emit_setb_reg ( R_AL, cond );
njn25e49d8e72002-09-23 09:36:25 +00001799 VG_(emit_swapl_reg_EAX) ( reg );
sewardjde4a1d02002-03-22 01:27:54 +00001800 }
1801}
1802
1803
1804static void synth_fpu_regmem ( UChar first_byte,
1805 UChar second_byte_masked,
1806 Int reg )
1807{
sewardjde4a1d02002-03-22 01:27:54 +00001808 emit_fpu_regmem ( first_byte, second_byte_masked, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001809}
1810
1811
1812static void synth_fpu_no_mem ( UChar first_byte,
1813 UChar second_byte )
1814{
sewardjde4a1d02002-03-22 01:27:54 +00001815 emit_fpu_no_mem ( first_byte, second_byte );
sewardjde4a1d02002-03-22 01:27:54 +00001816}
1817
1818
1819static void synth_movl_reg_reg ( Int src, Int dst )
1820{
1821 emit_movl_reg_reg ( src, dst );
1822}
1823
1824static void synth_cmovl_reg_reg ( Condcode cond, Int src, Int dst )
1825{
1826 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00001827 VG_(emit_jcondshort_delta) ( invertCondition(cond),
sewardjde4a1d02002-03-22 01:27:54 +00001828 2 /* length of the next insn */ );
1829 emit_movl_reg_reg ( src, dst );
1830}
1831
1832
sewardjde4a1d02002-03-22 01:27:54 +00001833/*----------------------------------------------------*/
1834/*--- Top level of the uinstr -> x86 translation. ---*/
1835/*----------------------------------------------------*/
1836
1837/* Return the byte offset from %ebp (ie, into baseBlock)
1838 for the specified ArchReg or SpillNo. */
sewardjde4a1d02002-03-22 01:27:54 +00001839static Int spillOrArchOffset ( Int size, Tag tag, UInt value )
1840{
1841 if (tag == SpillNo) {
1842 vg_assert(size == 4);
1843 vg_assert(value >= 0 && value < VG_MAX_SPILLSLOTS);
1844 return 4 * (value + VGOFF_(spillslots));
1845 }
1846 if (tag == ArchReg) {
1847 switch (value) {
1848 case R_EAX: return 4 * VGOFF_(m_eax);
1849 case R_ECX: return 4 * VGOFF_(m_ecx);
1850 case R_EDX: return 4 * VGOFF_(m_edx);
1851 case R_EBX: return 4 * VGOFF_(m_ebx);
1852 case R_ESP:
1853 if (size == 1) return 4 * VGOFF_(m_eax) + 1;
1854 else return 4 * VGOFF_(m_esp);
1855 case R_EBP:
1856 if (size == 1) return 4 * VGOFF_(m_ecx) + 1;
1857 else return 4 * VGOFF_(m_ebp);
1858 case R_ESI:
1859 if (size == 1) return 4 * VGOFF_(m_edx) + 1;
1860 else return 4 * VGOFF_(m_esi);
1861 case R_EDI:
1862 if (size == 1) return 4 * VGOFF_(m_ebx) + 1;
1863 else return 4 * VGOFF_(m_edi);
1864 }
1865 }
njne427a662002-10-02 11:08:25 +00001866 VG_(core_panic)("spillOrArchOffset");
sewardjde4a1d02002-03-22 01:27:54 +00001867}
1868
sewardjde4a1d02002-03-22 01:27:54 +00001869static Int eflagsOffset ( void )
1870{
1871 return 4 * VGOFF_(m_eflags);
1872}
1873
sewardje1042472002-09-30 12:33:11 +00001874static Int segRegOffset ( UInt archregs )
1875{
1876 switch (archregs) {
1877 case R_CS: return 4 * VGOFF_(m_cs);
1878 case R_SS: return 4 * VGOFF_(m_ss);
1879 case R_DS: return 4 * VGOFF_(m_ds);
1880 case R_ES: return 4 * VGOFF_(m_es);
1881 case R_FS: return 4 * VGOFF_(m_fs);
1882 case R_GS: return 4 * VGOFF_(m_gs);
njne427a662002-10-02 11:08:25 +00001883 default: VG_(core_panic)("segRegOffset");
sewardje1042472002-09-30 12:33:11 +00001884 }
1885}
1886
sewardjde4a1d02002-03-22 01:27:54 +00001887
njn25e49d8e72002-09-23 09:36:25 +00001888/* Return the byte offset from %ebp (ie, into baseBlock)
1889 for the specified shadow register */
njn4ba5a792002-09-30 10:23:54 +00001890Int VG_(shadow_reg_offset) ( Int arch )
sewardjde4a1d02002-03-22 01:27:54 +00001891{
1892 switch (arch) {
1893 case R_EAX: return 4 * VGOFF_(sh_eax);
1894 case R_ECX: return 4 * VGOFF_(sh_ecx);
1895 case R_EDX: return 4 * VGOFF_(sh_edx);
1896 case R_EBX: return 4 * VGOFF_(sh_ebx);
1897 case R_ESP: return 4 * VGOFF_(sh_esp);
1898 case R_EBP: return 4 * VGOFF_(sh_ebp);
1899 case R_ESI: return 4 * VGOFF_(sh_esi);
1900 case R_EDI: return 4 * VGOFF_(sh_edi);
njne427a662002-10-02 11:08:25 +00001901 default: VG_(core_panic)( "shadowOffset");
sewardjde4a1d02002-03-22 01:27:54 +00001902 }
1903}
1904
njn4ba5a792002-09-30 10:23:54 +00001905Int VG_(shadow_flags_offset) ( void )
sewardjde4a1d02002-03-22 01:27:54 +00001906{
1907 return 4 * VGOFF_(sh_eflags);
1908}
1909
1910
sewardjde4a1d02002-03-22 01:27:54 +00001911
1912static void synth_WIDEN_signed ( Int sz_src, Int sz_dst, Int reg )
1913{
1914 if (sz_src == 1 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00001915 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 24, reg );
1916 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 24, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001917 }
1918 else if (sz_src == 2 && sz_dst == 4) {
njn25e49d8e72002-09-23 09:36:25 +00001919 VG_(emit_shiftopv_lit_reg) ( 4, SHL, 16, reg );
1920 VG_(emit_shiftopv_lit_reg) ( 4, SAR, 16, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001921 }
1922 else if (sz_src == 1 && sz_dst == 2) {
njn25e49d8e72002-09-23 09:36:25 +00001923 VG_(emit_shiftopv_lit_reg) ( 2, SHL, 8, reg );
1924 VG_(emit_shiftopv_lit_reg) ( 2, SAR, 8, reg );
sewardjde4a1d02002-03-22 01:27:54 +00001925 }
1926 else
njne427a662002-10-02 11:08:25 +00001927 VG_(core_panic)("synth_WIDEN");
sewardjde4a1d02002-03-22 01:27:54 +00001928}
1929
1930
njn25e49d8e72002-09-23 09:36:25 +00001931static void synth_handle_esp_assignment ( Int i, Int reg,
1932 RRegSet regs_live_before,
1933 RRegSet regs_live_after )
sewardjde4a1d02002-03-22 01:27:54 +00001934{
njn25e49d8e72002-09-23 09:36:25 +00001935 UInt argv[] = { reg };
1936 Tag tagv[] = { RealReg };
1937
1938 VG_(synth_ccall) ( (Addr) VG_(handle_esp_assignment), 1, 1, argv, tagv,
1939 INVALID_REALREG, regs_live_before, regs_live_after);
sewardjde4a1d02002-03-22 01:27:54 +00001940}
1941
1942
sewardjde4a1d02002-03-22 01:27:54 +00001943/*----------------------------------------------------*/
1944/*--- Generate code for a single UInstr. ---*/
1945/*----------------------------------------------------*/
1946
sewardj478335c2002-10-05 02:44:47 +00001947static __inline__
1948Bool writeFlagUse ( UInstr* u )
njn5a74eb82002-08-06 20:56:40 +00001949{
1950 return (u->flags_w != FlagsEmpty);
1951}
1952
sewardj478335c2002-10-05 02:44:47 +00001953static __inline__
1954Bool anyFlagUse ( UInstr* u )
1955{
1956 return (u->flags_r != FlagsEmpty || u->flags_w != FlagsEmpty);
1957}
1958
1959
sewardj1b7d8022002-11-30 12:35:42 +00001960/* fplive==True indicates that the simulated machine's FPU state is in
1961 the real FPU. If so we need to be very careful not to trash it.
1962 If FPU state is live and we deem it necessary to copy it back to
1963 the simulated machine's FPU state, we do so. The final state of
1964 fpliveness is returned. In short we _must_ do put_fpu_state if
1965 there is any chance at all that the code generated for a UInstr
1966 will change the real FPU state.
1967*/
1968static Bool emitUInstr ( UCodeBlock* cb, Int i, RRegSet regs_live_before,
1969 Bool fplive )
sewardjde4a1d02002-03-22 01:27:54 +00001970{
njn25e49d8e72002-09-23 09:36:25 +00001971 Int old_emitted_code_used;
1972 UInstr* u = &cb->instrs[i];
1973
sewardjde4a1d02002-03-22 01:27:54 +00001974 if (dis)
njn4ba5a792002-09-30 10:23:54 +00001975 VG_(pp_UInstr_regs)(i, u);
sewardjde4a1d02002-03-22 01:27:54 +00001976
njn25e49d8e72002-09-23 09:36:25 +00001977 old_emitted_code_used = emitted_code_used;
1978
sewardjde4a1d02002-03-22 01:27:54 +00001979 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +00001980 case NOP: case LOCK: case CALLM_S: case CALLM_E: break;
sewardjde4a1d02002-03-22 01:27:54 +00001981
1982 case INCEIP: {
njn25e49d8e72002-09-23 09:36:25 +00001983 /* Note: Redundant INCEIP merging. A potentially useful
1984 performance enhancementa, but currently disabled. Reason
1985 is that it needs a surefire way to know if a UInstr might
1986 give rise to a stack snapshot being taken. The logic below
1987 is correct (hopefully ...) for the core UInstrs, but is
1988 incorrect if a skin has its own UInstrs, since the logic
1989 currently assumes that none of them can cause a stack
1990 trace, and that's just wrong. Note this isn't
1991 mission-critical -- the system still functions -- but will
1992 cause incorrect source locations in some situations,
1993 specifically for the memcheck skin. This is known to
1994 confuse programmers, understandable. */
1995# if 0
1996 Bool can_skip;
1997 Int j;
1998
1999 /* Scan forwards to see if this INCEIP dominates (in the
2000 technical sense) a later one, AND there are no CCALLs in
2001 between. If so, skip this one and instead add its count
2002 with the later one. */
2003 can_skip = True;
2004 j = i+1;
2005 while (True) {
2006 if (cb->instrs[j].opcode == CCALL
2007 || cb->instrs[j].opcode == CALLM) {
2008 /* CCALL -- we can't skip this INCEIP. */
2009 can_skip = False;
2010 break;
2011 }
2012 if (cb->instrs[j].opcode == INCEIP) {
2013 /* Another INCEIP. Check that the sum will fit. */
2014 if (cb->instrs[i].val1 + cb->instrs[j].val1 > 127)
2015 can_skip = False;
2016 break;
2017 }
2018 if (cb->instrs[j].opcode == JMP || cb->instrs[j].opcode == JIFZ) {
2019 /* Execution is not guaranteed to get beyond this
2020 point. Give up. */
2021 can_skip = False;
2022 break;
2023 }
2024 j++;
2025 /* Assertion should hold because all blocks should end in an
2026 unconditional JMP, so the above test should get us out of
2027 the loop at the end of a block. */
2028 vg_assert(j < cb->used);
2029 }
2030 if (can_skip) {
2031 /* yay! Accumulate the delta into the next INCEIP. */
2032 // VG_(printf)("skip INCEIP %d\n", cb->instrs[i].val1);
2033 vg_assert(j > i);
2034 vg_assert(j < cb->used);
2035 vg_assert(cb->instrs[j].opcode == INCEIP);
2036 vg_assert(cb->instrs[i].opcode == INCEIP);
2037 vg_assert(cb->instrs[j].tag1 == Lit16);
2038 vg_assert(cb->instrs[i].tag1 == Lit16);
2039 cb->instrs[j].val1 += cb->instrs[i].val1;
2040 /* do nothing now */
2041 } else
2042# endif
2043
2044 {
2045 /* no, we really have to do this, alas */
2046 // VG_(printf)(" do INCEIP %d\n", cb->instrs[i].val1);
2047 vg_assert(u->tag1 == Lit16);
2048 emit_addlit8_offregmem ( u->val1, R_EBP, 4 * VGOFF_(m_eip) );
2049 }
sewardjde4a1d02002-03-22 01:27:54 +00002050 break;
2051 }
2052
2053 case LEA1: {
2054 vg_assert(u->tag1 == RealReg);
2055 vg_assert(u->tag2 == RealReg);
2056 emit_lea_litreg_reg ( u->lit32, u->val1, u->val2 );
2057 break;
2058 }
2059
2060 case LEA2: {
2061 vg_assert(u->tag1 == RealReg);
2062 vg_assert(u->tag2 == RealReg);
2063 vg_assert(u->tag3 == RealReg);
2064 emit_lea_sib_reg ( u->lit32, u->extra4b,
2065 u->val1, u->val2, u->val3 );
2066 break;
2067 }
2068
2069 case WIDEN: {
2070 vg_assert(u->tag1 == RealReg);
2071 if (u->signed_widen) {
2072 synth_WIDEN_signed ( u->extra4b, u->size, u->val1 );
2073 } else {
2074 /* no need to generate any code. */
2075 }
2076 break;
2077 }
2078
sewardjde4a1d02002-03-22 01:27:54 +00002079 case STORE: {
2080 vg_assert(u->tag1 == RealReg);
2081 vg_assert(u->tag2 == RealReg);
2082 synth_mov_reg_memreg ( u->size, u->val1, u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002083 break;
2084 }
2085
2086 case LOAD: {
2087 vg_assert(u->tag1 == RealReg);
2088 vg_assert(u->tag2 == RealReg);
2089 synth_mov_regmem_reg ( u->size, u->val1, u->val2 );
2090 break;
2091 }
2092
sewardjde4a1d02002-03-22 01:27:54 +00002093 case GET: {
2094 vg_assert(u->tag1 == ArchReg || u->tag1 == SpillNo);
2095 vg_assert(u->tag2 == RealReg);
2096 synth_mov_offregmem_reg (
2097 u->size,
2098 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2099 R_EBP,
2100 u->val2
2101 );
2102 break;
2103 }
2104
2105 case PUT: {
2106 vg_assert(u->tag2 == ArchReg || u->tag2 == SpillNo);
2107 vg_assert(u->tag1 == RealReg);
2108 if (u->tag2 == ArchReg
2109 && u->val2 == R_ESP
2110 && u->size == 4
njn25e49d8e72002-09-23 09:36:25 +00002111 && (VG_(track_events).new_mem_stack ||
2112 VG_(track_events).new_mem_stack_aligned ||
2113 VG_(track_events).die_mem_stack ||
2114 VG_(track_events).die_mem_stack_aligned ||
2115 VG_(track_events).post_mem_write))
2116 {
2117 synth_handle_esp_assignment ( i, u->val1, regs_live_before,
2118 u->regs_live_after );
sewardjde4a1d02002-03-22 01:27:54 +00002119 }
njn25e49d8e72002-09-23 09:36:25 +00002120 else {
2121 synth_mov_reg_offregmem (
2122 u->size,
2123 u->val1,
2124 spillOrArchOffset( u->size, u->tag2, u->val2 ),
2125 R_EBP
2126 );
2127 }
sewardjde4a1d02002-03-22 01:27:54 +00002128 break;
2129 }
2130
sewardje1042472002-09-30 12:33:11 +00002131 case GETSEG: {
2132 vg_assert(u->tag1 == ArchRegS);
2133 vg_assert(u->tag2 == RealReg);
2134 vg_assert(u->size == 2);
2135 synth_mov_offregmem_reg (
2136 4,
2137 segRegOffset( u->val1 ),
2138 R_EBP,
2139 u->val2
2140 );
2141 break;
2142 }
2143
2144 case PUTSEG: {
2145 vg_assert(u->tag1 == RealReg);
2146 vg_assert(u->tag2 == ArchRegS);
2147 vg_assert(u->size == 2);
2148 synth_mov_reg_offregmem (
2149 4,
2150 u->val1,
2151 segRegOffset( u->val2 ),
2152 R_EBP
2153 );
2154 break;
2155 }
2156
sewardjde4a1d02002-03-22 01:27:54 +00002157 case GETF: {
2158 vg_assert(u->size == 2 || u->size == 4);
2159 vg_assert(u->tag1 == RealReg);
2160 synth_mov_offregmem_reg (
2161 u->size,
2162 eflagsOffset(),
2163 R_EBP,
2164 u->val1
2165 );
2166 break;
2167 }
2168
2169 case PUTF: {
2170 vg_assert(u->size == 2 || u->size == 4);
2171 vg_assert(u->tag1 == RealReg);
2172 synth_mov_reg_offregmem (
2173 u->size,
2174 u->val1,
2175 eflagsOffset(),
2176 R_EBP
2177 );
2178 break;
2179 }
2180
2181 case MOV: {
2182 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
2183 vg_assert(u->tag2 == RealReg);
2184 switch (u->tag1) {
2185 case RealReg: vg_assert(u->size == 4);
2186 if (u->val1 != u->val2)
2187 synth_movl_reg_reg ( u->val1, u->val2 );
2188 break;
2189 case Literal: synth_mov_lit_reg ( u->size, u->lit32, u->val2 );
2190 break;
njne427a662002-10-02 11:08:25 +00002191 default: VG_(core_panic)("emitUInstr:mov");
sewardjde4a1d02002-03-22 01:27:54 +00002192 }
2193 break;
2194 }
2195
sewardje1042472002-09-30 12:33:11 +00002196 case USESEG: {
2197 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2198 ones. */
sewardjd077f532002-09-30 21:52:50 +00002199 UInt argv[] = { u->val1, u->val2 };
2200 UInt tagv[] = { RealReg, RealReg };
sewardje1042472002-09-30 12:33:11 +00002201 UInt ret_reg = u->val2;
2202
2203 vg_assert(u->tag1 == RealReg);
2204 vg_assert(u->tag2 == RealReg);
2205 vg_assert(u->size == 0);
2206
sewardj1b7d8022002-11-30 12:35:42 +00002207 if (fplive) {
2208 emit_put_fpu_state();
2209 fplive = False;
2210 }
2211
sewardje1042472002-09-30 12:33:11 +00002212 VG_(synth_ccall) ( (Addr) & VG_(do_useseg),
2213 2, /* args */
2214 0, /* regparms_n */
2215 argv, tagv,
2216 ret_reg, regs_live_before, u->regs_live_after );
2217 break;
2218 }
2219
sewardj478335c2002-10-05 02:44:47 +00002220 case SBB:
2221 case ADC:
sewardjde4a1d02002-03-22 01:27:54 +00002222 case XOR:
2223 case OR:
2224 case AND:
2225 case SUB:
sewardj478335c2002-10-05 02:44:47 +00002226 case ADD: {
sewardjde4a1d02002-03-22 01:27:54 +00002227 vg_assert(u->tag2 == RealReg);
2228 switch (u->tag1) {
2229 case Literal: synth_nonshiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002230 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002231 u->opcode, u->size, u->lit32, u->val2 );
2232 break;
2233 case RealReg: synth_nonshiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002234 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002235 u->opcode, u->size, u->val1, u->val2 );
2236 break;
2237 case ArchReg: synth_nonshiftop_offregmem_reg (
sewardj478335c2002-10-05 02:44:47 +00002238 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002239 u->opcode, u->size,
2240 spillOrArchOffset( u->size, u->tag1, u->val1 ),
2241 R_EBP,
2242 u->val2 );
2243 break;
njne427a662002-10-02 11:08:25 +00002244 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002245 }
2246 break;
2247 }
2248
sewardj478335c2002-10-05 02:44:47 +00002249 case RCR:
2250 case RCL:
sewardjde4a1d02002-03-22 01:27:54 +00002251 case ROR:
2252 case ROL:
2253 case SAR:
2254 case SHR:
2255 case SHL: {
2256 vg_assert(u->tag2 == RealReg);
2257 switch (u->tag1) {
2258 case Literal: synth_shiftop_lit_reg (
sewardj478335c2002-10-05 02:44:47 +00002259 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002260 u->opcode, u->size, u->lit32, u->val2 );
2261 break;
2262 case RealReg: synth_shiftop_reg_reg (
sewardj478335c2002-10-05 02:44:47 +00002263 anyFlagUse(u),
sewardjde4a1d02002-03-22 01:27:54 +00002264 u->opcode, u->size, u->val1, u->val2 );
2265 break;
njne427a662002-10-02 11:08:25 +00002266 default: VG_(core_panic)("emitUInstr:non-shift-op");
sewardjde4a1d02002-03-22 01:27:54 +00002267 }
2268 break;
2269 }
2270
2271 case INC:
2272 case DEC:
2273 case NEG:
2274 case NOT:
2275 vg_assert(u->tag1 == RealReg);
2276 synth_unaryop_reg (
sewardj478335c2002-10-05 02:44:47 +00002277 anyFlagUse(u), u->opcode, u->size, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002278 break;
2279
2280 case BSWAP:
2281 vg_assert(u->tag1 == RealReg);
2282 vg_assert(u->size == 4);
njn4ba5a792002-09-30 10:23:54 +00002283 vg_assert(!VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002284 emit_bswapl_reg ( u->val1 );
2285 break;
2286
2287 case CMOV:
2288 vg_assert(u->tag1 == RealReg);
2289 vg_assert(u->tag2 == RealReg);
2290 vg_assert(u->cond != CondAlways);
2291 vg_assert(u->size == 4);
2292 synth_cmovl_reg_reg ( u->cond, u->val1, u->val2 );
2293 break;
2294
2295 case JMP: {
2296 vg_assert(u->tag2 == NoValue);
2297 vg_assert(u->tag1 == RealReg || u->tag1 == Literal);
sewardj1b7d8022002-11-30 12:35:42 +00002298 if (fplive) {
2299 emit_put_fpu_state();
2300 fplive = False;
2301 }
sewardjde4a1d02002-03-22 01:27:54 +00002302 if (u->cond == CondAlways) {
sewardj2e93c502002-04-12 11:12:52 +00002303 switch (u->tag1) {
2304 case RealReg:
2305 synth_jmp_reg ( u->val1, u->jmpkind );
2306 break;
2307 case Literal:
2308 synth_jmp_lit ( u->lit32, u->jmpkind );
2309 break;
2310 default:
njne427a662002-10-02 11:08:25 +00002311 VG_(core_panic)("emitUInstr(JMP, unconditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002312 break;
sewardjde4a1d02002-03-22 01:27:54 +00002313 }
2314 } else {
sewardj2e93c502002-04-12 11:12:52 +00002315 switch (u->tag1) {
2316 case RealReg:
njne427a662002-10-02 11:08:25 +00002317 VG_(core_panic)("emitUInstr(JMP, conditional, RealReg)");
sewardj2e93c502002-04-12 11:12:52 +00002318 break;
2319 case Literal:
2320 vg_assert(u->jmpkind == JmpBoring);
2321 synth_jcond_lit ( u->cond, u->lit32 );
2322 break;
2323 default:
njne427a662002-10-02 11:08:25 +00002324 VG_(core_panic)("emitUInstr(JMP, conditional, default)");
sewardj2e93c502002-04-12 11:12:52 +00002325 break;
sewardjde4a1d02002-03-22 01:27:54 +00002326 }
2327 }
2328 break;
2329 }
2330
2331 case JIFZ:
2332 vg_assert(u->tag1 == RealReg);
2333 vg_assert(u->tag2 == Literal);
2334 vg_assert(u->size == 4);
sewardj1b7d8022002-11-30 12:35:42 +00002335 if (fplive) {
2336 emit_put_fpu_state();
2337 fplive = False;
2338 }
sewardjde4a1d02002-03-22 01:27:54 +00002339 synth_jmp_ifzero_reg_lit ( u->val1, u->lit32 );
2340 break;
2341
sewardjde4a1d02002-03-22 01:27:54 +00002342 case PUSH:
2343 vg_assert(u->tag1 == RealReg);
2344 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002345 VG_(emit_pushv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002346 break;
2347
2348 case POP:
2349 vg_assert(u->tag1 == RealReg);
2350 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002351 VG_(emit_popv_reg) ( 4, u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002352 break;
2353
2354 case CALLM:
2355 vg_assert(u->tag1 == Lit16);
2356 vg_assert(u->tag2 == NoValue);
2357 vg_assert(u->size == 0);
sewardj1b7d8022002-11-30 12:35:42 +00002358 if (fplive) {
2359 emit_put_fpu_state();
2360 fplive = False;
2361 }
sewardj478335c2002-10-05 02:44:47 +00002362 if (anyFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002363 emit_get_eflags();
njn25e49d8e72002-09-23 09:36:25 +00002364 VG_(synth_call) ( False, u->val1 );
njn5a74eb82002-08-06 20:56:40 +00002365 if (writeFlagUse ( u ))
sewardjde4a1d02002-03-22 01:27:54 +00002366 emit_put_eflags();
2367 break;
2368
njn25e49d8e72002-09-23 09:36:25 +00002369 case CCALL: {
sewardje1042472002-09-30 12:33:11 +00002370 /* If you change this, remember to change USESEG above, since
2371 that's just a copy of this, slightly simplified. */
njn25e49d8e72002-09-23 09:36:25 +00002372 /* Lazy: copy all three vals; synth_ccall ignores any unnecessary
2373 ones. */
2374 UInt argv[] = { u->val1, u->val2, u->val3 };
2375 UInt tagv[] = { RealReg, RealReg, RealReg };
2376 UInt ret_reg = ( u->has_ret_val ? u->val3 : INVALID_REALREG );
2377
2378 if (u->argc >= 1) vg_assert(u->tag1 == RealReg);
2379 else vg_assert(u->tag1 == NoValue);
2380 if (u->argc >= 2) vg_assert(u->tag2 == RealReg);
2381 else vg_assert(u->tag2 == NoValue);
2382 if (u->argc == 3 || u->has_ret_val) vg_assert(u->tag3 == RealReg);
2383 else vg_assert(u->tag3 == NoValue);
njn6431be72002-07-28 09:53:34 +00002384 vg_assert(u->size == 0);
2385
sewardj1b7d8022002-11-30 12:35:42 +00002386 if (fplive) {
2387 emit_put_fpu_state();
2388 fplive = False;
2389 }
njn25e49d8e72002-09-23 09:36:25 +00002390 VG_(synth_ccall) ( u->lit32, u->argc, u->regparms_n, argv, tagv,
2391 ret_reg, regs_live_before, u->regs_live_after );
njn6431be72002-07-28 09:53:34 +00002392 break;
njn25e49d8e72002-09-23 09:36:25 +00002393 }
sewardje1042472002-09-30 12:33:11 +00002394
sewardjde4a1d02002-03-22 01:27:54 +00002395 case CLEAR:
2396 vg_assert(u->tag1 == Lit16);
2397 vg_assert(u->tag2 == NoValue);
njn25e49d8e72002-09-23 09:36:25 +00002398 VG_(emit_add_lit_to_esp) ( u->val1 );
sewardjde4a1d02002-03-22 01:27:54 +00002399 break;
2400
2401 case CC2VAL:
2402 vg_assert(u->tag1 == RealReg);
2403 vg_assert(u->tag2 == NoValue);
njn4ba5a792002-09-30 10:23:54 +00002404 vg_assert(VG_(any_flag_use)(u));
sewardjde4a1d02002-03-22 01:27:54 +00002405 synth_setb_reg ( u->val1, u->cond );
2406 break;
2407
sewardjde4a1d02002-03-22 01:27:54 +00002408 case FPU_R:
2409 case FPU_W:
2410 vg_assert(u->tag1 == Lit16);
2411 vg_assert(u->tag2 == RealReg);
sewardj1b7d8022002-11-30 12:35:42 +00002412 if (!fplive) {
2413 emit_get_fpu_state();
2414 fplive = True;
2415 }
sewardjde4a1d02002-03-22 01:27:54 +00002416 synth_fpu_regmem ( (u->val1 >> 8) & 0xFF,
2417 u->val1 & 0xFF,
2418 u->val2 );
sewardjde4a1d02002-03-22 01:27:54 +00002419 break;
2420
2421 case FPU:
2422 vg_assert(u->tag1 == Lit16);
2423 vg_assert(u->tag2 == NoValue);
sewardj478335c2002-10-05 02:44:47 +00002424 if (anyFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002425 emit_get_eflags();
sewardj1b7d8022002-11-30 12:35:42 +00002426 if (!fplive) {
2427 emit_get_fpu_state();
2428 fplive = True;
2429 }
sewardjde4a1d02002-03-22 01:27:54 +00002430 synth_fpu_no_mem ( (u->val1 >> 8) & 0xFF,
2431 u->val1 & 0xFF );
njn5a74eb82002-08-06 20:56:40 +00002432 if (writeFlagUse ( u ))
sewardj4a7456e2002-03-24 13:52:19 +00002433 emit_put_eflags();
sewardjde4a1d02002-03-22 01:27:54 +00002434 break;
2435
2436 default:
sewardj1b7d8022002-11-30 12:35:42 +00002437 if (VG_(needs).extended_UCode) {
2438 if (fplive) {
2439 emit_put_fpu_state();
2440 fplive = False;
2441 }
njn4ba5a792002-09-30 10:23:54 +00002442 SK_(emit_XUInstr)(u, regs_live_before);
sewardj1b7d8022002-11-30 12:35:42 +00002443 } else {
njn25e49d8e72002-09-23 09:36:25 +00002444 VG_(printf)("\nError:\n"
2445 " unhandled opcode: %u. Perhaps "
2446 " VG_(needs).extended_UCode should be set?\n",
2447 u->opcode);
njn4ba5a792002-09-30 10:23:54 +00002448 VG_(pp_UInstr)(0,u);
njne427a662002-10-02 11:08:25 +00002449 VG_(core_panic)("emitUInstr: unimplemented opcode");
njn25e49d8e72002-09-23 09:36:25 +00002450 }
sewardjde4a1d02002-03-22 01:27:54 +00002451 }
2452
sewardj1b7d8022002-11-30 12:35:42 +00002453 if (0 && fplive) {
2454 emit_put_fpu_state();
2455 fplive = False;
2456 }
2457
njn25e49d8e72002-09-23 09:36:25 +00002458 /* Update UInstr histogram */
2459 vg_assert(u->opcode < 100);
2460 histogram[u->opcode].counts++;
2461 histogram[u->opcode].size += (emitted_code_used - old_emitted_code_used);
sewardj1b7d8022002-11-30 12:35:42 +00002462
2463 return fplive;
sewardjde4a1d02002-03-22 01:27:54 +00002464}
2465
2466
2467/* Emit x86 for the ucode in cb, returning the address of the
2468 generated code and setting *nbytes to its size. */
2469UChar* VG_(emit_code) ( UCodeBlock* cb, Int* nbytes )
2470{
2471 Int i;
njn25e49d8e72002-09-23 09:36:25 +00002472 UChar regs_live_before = 0; /* No regs live at BB start */
sewardj1b7d8022002-11-30 12:35:42 +00002473 Bool fplive;
2474
sewardjde4a1d02002-03-22 01:27:54 +00002475 emitted_code_used = 0;
2476 emitted_code_size = 500; /* reasonable initial size */
njn25e49d8e72002-09-23 09:36:25 +00002477 emitted_code = VG_(arena_malloc)(VG_AR_JITTER, emitted_code_size);
sewardjde4a1d02002-03-22 01:27:54 +00002478
njn25e49d8e72002-09-23 09:36:25 +00002479 if (dis) VG_(printf)("Generated x86 code:\n");
sewardjde4a1d02002-03-22 01:27:54 +00002480
sewardj1b7d8022002-11-30 12:35:42 +00002481 fplive = False;
sewardjde4a1d02002-03-22 01:27:54 +00002482 for (i = 0; i < cb->used; i++) {
njn25e49d8e72002-09-23 09:36:25 +00002483 UInstr* u = &cb->instrs[i];
sewardjde4a1d02002-03-22 01:27:54 +00002484 if (cb->instrs[i].opcode != NOP) {
njn25e49d8e72002-09-23 09:36:25 +00002485
sewardjde4a1d02002-03-22 01:27:54 +00002486 /* Check on the sanity of this insn. */
njn25e49d8e72002-09-23 09:36:25 +00002487 Bool sane = VG_(saneUInstr)( False, False, u );
sewardjde4a1d02002-03-22 01:27:54 +00002488 if (!sane) {
2489 VG_(printf)("\ninsane instruction\n");
njn4ba5a792002-09-30 10:23:54 +00002490 VG_(up_UInstr)( i, u );
sewardjde4a1d02002-03-22 01:27:54 +00002491 }
2492 vg_assert(sane);
sewardj1b7d8022002-11-30 12:35:42 +00002493 fplive = emitUInstr( cb, i, regs_live_before, fplive );
sewardjde4a1d02002-03-22 01:27:54 +00002494 }
njn25e49d8e72002-09-23 09:36:25 +00002495 regs_live_before = u->regs_live_after;
sewardjde4a1d02002-03-22 01:27:54 +00002496 }
njn25e49d8e72002-09-23 09:36:25 +00002497 if (dis) VG_(printf)("\n");
sewardj1b7d8022002-11-30 12:35:42 +00002498 vg_assert(!fplive); /* FPU state must be saved by end of BB */
sewardjde4a1d02002-03-22 01:27:54 +00002499
2500 /* Returns a pointer to the emitted code. This will have to be
njn25e49d8e72002-09-23 09:36:25 +00002501 copied by the caller into the translation cache, and then freed */
sewardjde4a1d02002-03-22 01:27:54 +00002502 *nbytes = emitted_code_used;
2503 return emitted_code;
2504}
2505
njn25e49d8e72002-09-23 09:36:25 +00002506#undef dis
2507
sewardjde4a1d02002-03-22 01:27:54 +00002508/*--------------------------------------------------------------------*/
2509/*--- end vg_from_ucode.c ---*/
2510/*--------------------------------------------------------------------*/