bug fix
[mono.git] / mono / jit / x86.brg
1 /*
2  * x86.brg: X86 code generator
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11
12 #include <glib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <math.h>
16 #ifndef PLATFORM_WIN32
17 #include <signal.h>
18 #include <sys/syscall.h>
19 #endif
20
21 #include <mono/metadata/blob.h>
22 #include <mono/metadata/metadata.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/appdomain.h>
27 #include <mono/metadata/marshal.h>
28 #include <mono/arch/x86/x86-codegen.h>
29
30 #include "regset.h"
31 #include "jit.h"
32
33 /*
34  * Pull the list of opcodes
35  */
36 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
37         a = i,
38
39 enum {
40 #include "mono/cil/opcode.def"
41         LAST = 0xff
42 };
43 #undef OPDEF
44
45 void print_lmf (void);
46
47 #define MBTREE_TYPE  MBTree
48 #define MBCGEN_TYPE  MonoFlowGraph
49 #define MBCOST_DATA  MonoFlowGraph
50 #define MBALLOC_STATE mono_mempool_alloc (data->mp, sizeof (MBState))
51
52 typedef enum {
53         AMImmediate       = 0,  // ptr
54         AMBase            = 1,  // V[REG]  
55         AMIndex           = 2,  // V[REG*X] 
56         AMBaseIndex       = 3,  // V[REG*X][REG] 
57 } X86AddMode;
58
59 typedef struct {
60         int           offset;
61         X86AddMode    amode:2;
62         unsigned int  shift:2;
63         gint8         basereg;
64         gint8         indexreg;
65 } X86AddressInfo;
66
67 struct _MBTree {
68         guint16   op;
69         unsigned  last_instr:1;
70         unsigned  spilled:1;
71         
72         MBTree   *left, *right;
73         gpointer  state;
74         gpointer  emit;
75
76         gint32    addr;
77         gint32    cli_addr;
78
79         gint8     reg1;
80         gint8     reg2;
81         gint8     reg3;
82         
83         MonoValueType svt;
84
85         union {
86                 gint32 i;
87                 gint64 l;
88                 gpointer p;
89                 MonoMethod *m;
90                 MonoBBlock *bb;
91                 MonoClass *klass;
92                 MonoClassField *field;
93                 X86AddressInfo ainfo;
94                 MonoJitCallInfo ci;
95                 MonoJitFieldInfo fi;
96                 MonoJitBranchInfo bi;
97         } data;
98 };
99
100 gint64   mono_llmult        (gint64 a, gint64 b);
101 guint64  mono_llmult_ovf    (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh);
102 guint64  mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh);
103 gint64   mono_lldiv         (gint64 a, gint64 b);
104 gint64   mono_llrem         (gint64 a, gint64 b);
105 guint64  mono_lldiv_un      (guint64 a, guint64 b);
106 guint64  mono_llrem_un      (guint64 a, guint64 b);
107 gpointer mono_ldsflda       (MonoClass *klass, int offset);
108
109 gpointer mono_ldvirtftn     (MonoObject *this, int slot);
110 gpointer mono_ldintftn      (MonoObject *this, int slot);
111 gpointer mono_ldftn         (MonoMethod *method);
112
113 void mono_emit_fast_iconv(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
114 void mono_emit_fast_iconv_i8(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
115
116 MonoArray*
117 mono_array_new_wrapper  (MonoClass *eclass, guint32 n);
118 MonoObject *
119 mono_object_new_wrapper (MonoClass *klass);
120 MonoString*
121 mono_ldstr_wrapper      (MonoImage *image, guint32 ind);
122
123 gpointer
124 get_mono_object_isinst (void);
125
126 #define MB_OPT_LEVEL 1
127
128 #if MB_OPT_LEVEL == 0
129 #define MB_USE_OPT1(c) 65535
130 #define MB_USE_OPT2(c) 65535
131 #endif
132 #if MB_OPT_LEVEL == 1
133 #define MB_USE_OPT1(c) c
134 #define MB_USE_OPT2(c) 65535
135 #endif
136 #if MB_OPT_LEVEL >= 2
137 #define MB_USE_OPT1(c) c
138 #define MB_USE_OPT2(c) c
139 #endif
140
141 //#define DEBUG
142
143 #define REAL_PRINT_REG(text,reg) \
144 mono_assert (reg >= 0); \
145 x86_push_reg (s->code, X86_EAX); \
146 x86_push_reg (s->code, X86_EDX); \
147 x86_push_reg (s->code, X86_ECX); \
148 x86_push_reg (s->code, reg); \
149 x86_push_imm (s->code, reg); \
150 x86_push_imm (s->code, text " %d %p\n"); \
151 x86_mov_reg_imm (s->code, X86_EAX, printf); \
152 x86_call_reg (s->code, X86_EAX); \
153 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
154 x86_pop_reg (s->code, X86_ECX); \
155 x86_pop_reg (s->code, X86_EDX); \
156 x86_pop_reg (s->code, X86_EAX);
157
158 void *
159 debug_memcopy (void *dest, const void *src, size_t n);
160
161 #ifdef DEBUG
162 #define MEMCOPY debug_memcopy
163 #define PRINT_REG(text,reg) REAL_PRINT_REG(text,reg)
164 #else
165
166 #define MEMCOPY memcpy
167
168 #define PRINT_REG(x,y)
169
170 #endif
171
172 /* The call instruction for virtual functions must have a known
173  * size (used by x86_magic_trampoline)
174  */
175 #define x86_call_virtual(inst,basereg,disp)                    \
176         do {                                                   \
177                 *(inst)++ = (unsigned char)0xff;               \
178                 x86_address_byte ((inst), 2, 2, (basereg));    \
179                 x86_imm_emit32 ((inst), (disp));               \
180         } while (0)
181
182 /* emit an exception if condition is fail */
183 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)       \
184         do {                                                   \
185                 gpointer t;                                    \
186                 x86_branch8 (s->code, cond, 10, signed);       \
187                 x86_push_imm (s->code, exc_name);              \
188                 t = arch_get_throw_exception_by_name ();       \
189                 mono_add_jump_info (s, s->code,                \
190                                     MONO_JUMP_INFO_ABS, t);    \
191                 x86_call_code (s->code, 0);                    \
192         } while (0); 
193
194 /* we use this macro to move one lreg to another - source and
195    destination may overlap, but the register allocator has to
196    make sure that ((d1 < d2) && (s1 < s2))
197 */
198 #define MOVE_LREG(d1,d2,s1,s2)                                        \
199         do {                                                          \
200                 g_assert ((d1 < d2) && (s1 < s2));                    \
201                 if ((d1) <= (s1)) {                                   \
202                         if ((d1) != (s1))                             \
203                                 x86_mov_reg_reg (s->code, d1, s1, 4); \
204                         if ((d2) != (s2))                             \
205                                 x86_mov_reg_reg (s->code, d2, s2, 4); \
206                 } else {                                              \
207                         if ((d2) != (s2))                             \
208                                 x86_mov_reg_reg (s->code, d2, s2, 4); \
209                         if ((d1) != (s1))                             \
210                                 x86_mov_reg_reg (s->code, d1, s1, 4); \
211                 }                                                     \
212         } while (0); 
213         
214
215 %%
216
217 #
218 # terminal definitions
219 #
220
221 # constants
222 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
223 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8 LDIND_OBJ 
224 %term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
225 %term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ CALL_I4 CALL_I8 CALL_R8 CALL_VOID
226 %term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY JMP
227 %term ADD ADD_OVF ADD_OVF_UN SUB SUB_OVF SUB_OVF_UN MUL MUL_OVF MUL_OVF_UN 
228 %term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT CKFINITE
229 %term COMPARE CBRANCH BRTRUE BRFALSE CSET
230 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U1 CONV_U2 CONV_U4 CONV_U8 CONV_R4 CONV_R8 CONV_R_UN
231 %term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWARR_SPEC NEWOBJ NEWOBJ_SPEC
232 %term INITBLK CPBLK CPSRC POP INITOBJ LOCALLOC
233 %term ISINST CASTCLASS UNBOX
234 %term CONV_OVF_I1 CONV_OVF_U1 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U4 CONV_OVF_U8 CONV_OVF_I4
235 %term CONV_OVF_I4_UN CONV_OVF_U1_UN CONV_OVF_U2_UN
236 %term CONV_OVF_I2_UN CONV_OVF_I8_UN CONV_OVF_I1_UN 
237 %term EXCEPTION THROW RETHROW HANDLER CHECKTHIS
238 %term LDLEN LDELEMA LDFTN LDVIRTFTN LDSTR LDSFLDA
239 %term REMOTE_LDFLDA REMOTE_STIND_I1 REMOTE_STIND_I2 REMOTE_STIND_I4
240 %term REMOTE_STIND_I8 REMOTE_STIND_R4 REMOTE_STIND_R8 REMOTE_STIND_OBJ
241 %term SIN COS SQRT
242
243 %term FUNC1 PROC3 FREE OBJADDR
244
245 #
246 # we start at stmt
247 #
248 %start stmt
249
250 #
251 # tree definitions
252 #
253
254 #
255 # x86 adressing mode
256 #
257
258 acon: CONST_I4 {
259         tree->data.ainfo.offset = tree->data.i;
260         tree->data.ainfo.amode = AMImmediate;
261 }
262
263 acon: ADDR_G {
264         tree->data.ainfo.offset = tree->data.i;
265         tree->data.ainfo.amode = AMImmediate;
266 }
267
268 acon: ADD (ADDR_G, CONST_I4) {
269         tree->data.ainfo.offset = (unsigned)tree->left->data.p + tree->right->data.i;
270         tree->data.ainfo.amode = AMImmediate;
271 }
272
273 base: acon
274
275 base: reg {
276         tree->data.ainfo.offset = 0;
277         tree->data.ainfo.basereg = tree->reg1;
278         tree->data.ainfo.amode = AMBase;
279 }
280
281 base: ADD (reg, CONST_I4) {
282         tree->data.ainfo.offset = tree->right->data.i;
283         tree->data.ainfo.basereg = tree->left->reg1;
284         tree->data.ainfo.amode = AMBase;
285 }
286
287 base: ADDR_L {
288         tree->data.ainfo.offset = VARINFO (s, tree->data.i).offset;
289         tree->data.ainfo.basereg = X86_EBP;
290         tree->data.ainfo.amode = AMBase;
291 } cost {
292         MBCOND (VARINFO (data, tree->data.i).reg < 0);
293         return 0;
294 }
295
296 index: reg {
297         tree->data.ainfo.offset = 0;
298         tree->data.ainfo.indexreg = tree->reg1;
299         tree->data.ainfo.shift = 0;
300         tree->data.ainfo.amode = AMIndex;
301 }
302
303 index: SHL (reg, CONST_I4) {
304         tree->data.ainfo.offset = 0;
305         tree->data.ainfo.amode = AMIndex;
306         tree->data.ainfo.indexreg = tree->left->reg1;
307         tree->data.ainfo.shift = tree->right->data.i;
308 } cost {
309         MBCOND (tree->right->data.i == 0 ||
310                 tree->right->data.i == 1 ||
311                 tree->right->data.i == 2 ||
312                 tree->right->data.i == 3);
313
314         return 0;
315 }
316
317 index: MUL (reg, CONST_I4) {
318         static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
319   
320         tree->data.ainfo.offset = 0;
321         tree->data.ainfo.amode = AMIndex;
322         tree->data.ainfo.indexreg = tree->left->reg1;
323         tree->data.ainfo.shift = fast_log2 [tree->right->data.i];
324 } cost {
325         MBCOND (tree->right->data.i == 1 ||
326                 tree->right->data.i == 2 ||
327                 tree->right->data.i == 4 ||
328                 tree->right->data.i == 8);
329
330         return 0;
331 }
332
333 addr: base
334
335 addr: index
336
337 addr: ADD (index, base) {
338         tree->data.ainfo.offset = tree->right->data.ainfo.offset;
339         tree->data.ainfo.basereg = tree->right->data.ainfo.basereg;
340         tree->data.ainfo.amode = tree->left->data.ainfo.amode | 
341                 tree->right->data.ainfo.amode;
342         tree->data.ainfo.shift = tree->left->data.ainfo.shift;
343         tree->data.ainfo.indexreg = tree->left->data.ainfo.indexreg;
344 }
345
346 # we pass exception in ECX to catch handler
347 reg: EXCEPTION {
348         int offset = VARINFO (s, tree->data.i).offset;
349         int reg = VARINFO (s, tree->data.i).reg;
350
351         if (tree->reg1 != X86_ECX)
352                 x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
353         
354         /* store it so that we can RETHROW it later */
355         if (reg < 0)
356                 x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
357         else
358                 x86_mov_reg_reg (s->code, reg, tree->reg1, 4);
359 }
360
361 stmt: THROW (reg) {
362         gpointer target;
363
364         x86_push_reg (s->code, tree->left->reg1);
365         target = arch_get_throw_exception ();
366         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
367         x86_call_code (s->code, target);
368 }
369
370 stmt: RETHROW {
371         int off = VARINFO (s, tree->data.i).offset;
372         int reg = VARINFO (s, tree->data.i).reg;
373         gpointer target;
374
375         if (reg < 0)
376                 x86_push_membase (s->code, X86_EBP, off);
377         else
378                 x86_push_reg (s->code, reg);
379
380         target = arch_get_throw_exception ();
381         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
382         x86_call_code (s->code, target);
383 }
384
385 stmt: HANDLER {
386         /* save ESP (used by ENDFINALLY) */
387         x86_mov_membase_reg (s->code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
388         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
389         x86_call_imm (s->code, 0); 
390 }
391
392 stmt: ENDFINALLY {
393         /* restore ESP - which can be modified when we allocate value types
394          * in the finally handler */
395         x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, mono_exc_esp_offset, 4);
396         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
397         x86_ret (s->code);
398 }
399
400 stmt: STIND_I4 (ADDR_L, ADD (LDIND_I4 (ADDR_L), CONST_I4)) {
401         int vn = tree->left->data.i;
402         int treg = VARINFO (s, vn).reg;
403         int offset = VARINFO (s, vn).offset;
404         int data = tree->right->right->data.i;
405
406         if (data == 1) {
407                 if (treg >= 0)
408                         x86_inc_reg (s->code, treg);
409                 else 
410                         x86_inc_membase (s->code, X86_EBP, offset);
411         } else {
412                 if (treg >= 0)
413                         x86_alu_reg_imm (s->code, X86_ADD, treg, data);
414                 else
415                         x86_alu_membase_imm (s->code, X86_ADD, X86_EBP, offset, data);
416         }
417 } cost {
418         MBCOND (tree->right->left->left->data.i == tree->left->data.i);
419         return 0;
420 }
421
422 stmt: STIND_I4 (ADDR_L, SUB (LDIND_I4 (ADDR_L), CONST_I4)) {
423         int vn = tree->left->data.i;
424         int treg = VARINFO (s, vn).reg;
425         int offset = VARINFO (s, vn).offset;
426         int data = tree->right->right->data.i;
427
428         if (data == 1) {
429                 if (treg >= 0)
430                         x86_dec_reg (s->code, treg);
431                 else 
432                         x86_dec_membase (s->code, X86_EBP, offset);
433         } else {
434                 if (treg >= 0)
435                         x86_alu_reg_imm (s->code, X86_SUB, treg, data);
436                 else
437                         x86_alu_membase_imm (s->code, X86_SUB, X86_EBP, offset, data);
438         }
439 } cost {
440         MBCOND (tree->right->left->left->data.i == tree->left->data.i);
441         return 0;
442 }
443
444 stmt: STIND_I4 (ADDR_L, ADD (LDIND_I4 (ADDR_L), reg)) {
445         int vn = tree->left->data.i;
446         int treg = VARINFO (s, vn).reg;
447         int sreg = tree->right->right->reg1;
448         int offset = VARINFO (s, vn).offset;
449
450         if (treg >= 0)
451                 x86_alu_reg_reg (s->code, X86_ADD, treg, sreg);
452         else
453                 x86_alu_membase_reg (s->code, X86_ADD, X86_EBP, offset, sreg);
454
455 } cost {
456         MBCOND (tree->right->left->left->data.i == tree->left->data.i);
457         return 0;
458 }
459
460 stmt: STIND_I4 (ADDR_L, LDIND_I4 (ADDR_L)) {
461         int treg1 = VARINFO (s, tree->left->data.i).reg;
462         int treg2 = VARINFO (s, tree->right->left->data.i).reg;
463         int offset1 = VARINFO (s, tree->left->data.i).offset;
464         int offset2 = VARINFO (s, tree->right->left->data.i).offset;
465
466         //{static int cx= 0; printf ("CX %5d\n", cx++);}
467
468         if (treg1 >= 0 && treg2 >= 0) {
469                 x86_mov_reg_reg (s->code, treg1, treg2, 4);
470                 return;
471         }
472         if (treg1 >= 0 && treg2 < 0) {
473                 x86_mov_reg_membase (s->code, treg1, X86_EBP, offset2, 4);
474                 return;
475         }
476         if (treg1 < 0 && treg2 >= 0) {
477                 x86_mov_membase_reg (s->code, X86_EBP, offset1, treg2, 4);
478                 return;
479         }
480
481         g_assert_not_reached ();
482
483 } cost {
484         MBCOND (VARINFO (data, tree->left->data.i).reg >= 0 ||
485                 VARINFO (data, tree->right->left->data.i).reg >= 0);
486         return 0;
487 }
488
489 stmt: STIND_I4 (addr, CONST_I4) {
490         switch (tree->left->data.ainfo.amode) {
491
492         case AMImmediate:
493                 x86_mov_mem_imm (s->code, tree->left->data.ainfo.offset, tree->right->data.i, 4);
494                 break;
495                 
496         case AMBase:
497                 x86_mov_membase_imm (s->code, tree->left->data.ainfo.basereg, 
498                                      tree->left->data.ainfo.offset, tree->right->data.i, 4);
499                 break;          
500         case AMIndex:
501                 x86_mov_memindex_imm (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
502                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
503                                       tree->right->data.i, 4);
504                 break;          
505         case AMBaseIndex:
506                 x86_mov_memindex_imm (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
507                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
508                                       tree->right->data.i, 4);
509                 break;          
510         }
511 }
512
513 stmt: STIND_I4 (addr, reg) {
514
515         switch (tree->left->data.ainfo.amode) {
516
517         case AMImmediate:
518                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
519                 break;
520                 
521         case AMBase:
522                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
523                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
524                 break;          
525         case AMIndex:
526                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
527                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
528                                       tree->right->reg1, 4);
529                 break;          
530         case AMBaseIndex:
531                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
532                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
533                                       tree->right->reg1, 4);
534                 break;          
535         }
536 }
537
538 stmt: REMOTE_STIND_I4 (reg, reg) {
539         guint8 *br[2];
540         int treg = X86_EAX;
541         int lreg = tree->left->reg1;
542         int rreg = tree->right->reg1;
543         int offset;
544
545         if (lreg == treg)
546                 treg = X86_EDX;
547
548         if (rreg == treg)
549                 treg = X86_ECX;
550
551         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
552         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
553         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
554
555         /* this is a transparent proxy - remote the call */
556
557         /* save value to stack */
558         x86_push_reg (s->code, rreg);
559
560         x86_push_reg (s->code, X86_ESP);
561         x86_push_imm (s->code, tree->data.fi.field);
562         x86_push_imm (s->code, tree->data.fi.klass);
563         x86_push_reg (s->code, lreg);
564         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
565         x86_call_code (s->code, 0);
566         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
567
568         br [1] = s->code; x86_jump8 (s->code, 0);
569
570         x86_patch (br [0], s->code);
571         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
572                 tree->data.fi.field->offset;
573         x86_mov_membase_reg (s->code, lreg, offset, rreg, 4);
574
575         x86_patch (br [1], s->code);
576 }
577
578 stmt: STIND_I1 (addr, reg) {
579         PRINT_REG ("STIND_I1", tree->right->reg1);
580
581         switch (tree->left->data.ainfo.amode) {
582
583         case AMImmediate:
584                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 1);
585                 break;
586                 
587         case AMBase:
588                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
589                                      tree->left->data.ainfo.offset, tree->right->reg1, 1);
590                 break;          
591         case AMIndex:
592                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
593                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
594                                       tree->right->reg1, 1);
595                 break;          
596         case AMBaseIndex:
597                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
598                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
599                                       tree->right->reg1, 1);
600                 break;          
601         }
602 }
603
604 stmt: REMOTE_STIND_I1 (reg, reg) {
605         guint8 *br[2];
606         int treg = X86_EAX;
607         int lreg = tree->left->reg1;
608         int rreg = tree->right->reg1;
609         int offset;
610
611         if (lreg == treg)
612                 treg = X86_EDX;
613
614         if (rreg == treg)
615                 treg = X86_ECX;
616
617         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
618         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
619         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
620
621         /* this is a transparent proxy - remote the call */
622
623         /* save value to stack */
624         x86_push_reg (s->code, rreg);
625
626         x86_push_reg (s->code, X86_ESP);
627         x86_push_imm (s->code, tree->data.fi.field);
628         x86_push_imm (s->code, tree->data.fi.klass);
629         x86_push_reg (s->code, lreg);
630         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
631         x86_call_code (s->code, 0);
632         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
633
634         br [1] = s->code; x86_jump8 (s->code, 0);
635
636         x86_patch (br [0], s->code);
637         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
638                 tree->data.fi.field->offset;
639         x86_mov_membase_reg (s->code, lreg, offset, rreg, 1);
640
641         x86_patch (br [1], s->code);
642 }
643
644 stmt: STIND_I2 (addr, reg) {
645         PRINT_REG ("STIND_I2", tree->right->reg1);
646
647         switch (tree->left->data.ainfo.amode) {
648
649         case AMImmediate:
650                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 2);
651                 break;
652                 
653         case AMBase:
654                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
655                                      tree->left->data.ainfo.offset, tree->right->reg1, 2);
656                 break;          
657         case AMIndex:
658                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
659                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
660                                       tree->right->reg1, 2);
661                 break;          
662         case AMBaseIndex:
663                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
664                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
665                                       tree->right->reg1, 2);
666                 break;          
667         }
668 }
669
670 stmt: REMOTE_STIND_I2 (reg, reg) {
671         guint8 *br[2];
672         int treg = X86_EAX;
673         int lreg = tree->left->reg1;
674         int rreg = tree->right->reg1;
675         int offset;
676
677         if (lreg == treg)
678                 treg = X86_EDX;
679
680         if (rreg == treg)
681                 treg = X86_ECX;
682
683         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
684         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
685         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
686
687         /* this is a transparent proxy - remote the call */
688
689         /* save value to stack */
690         x86_push_reg (s->code, rreg);
691
692         x86_push_reg (s->code, X86_ESP);
693         x86_push_imm (s->code, tree->data.fi.field);
694         x86_push_imm (s->code, tree->data.fi.klass);
695         x86_push_reg (s->code, lreg);
696         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
697         x86_call_code (s->code, 0);
698         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
699
700         br [1] = s->code; x86_jump8 (s->code, 0);
701
702         x86_patch (br [0], s->code);
703         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
704                 tree->data.fi.field->offset;
705         x86_mov_membase_reg (s->code, lreg, offset, rreg, 2);
706
707         x86_patch (br [1], s->code);
708 }
709
710 reg: LDIND_I4 (ADDR_L) {
711         int treg = VARINFO (s, tree->left->data.i).reg;
712
713         if (treg != tree->reg1)
714                 x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
715
716 } cost {
717         MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
718         return 0;
719 }
720
721 stmt: STIND_I4 (ADDR_L, CONST_I4) {
722         int treg = VARINFO (s, tree->left->data.i).reg;
723
724         x86_mov_reg_imm (s->code, treg, tree->right->data.i);
725
726 } cost {
727         MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
728         return 0;
729 }
730
731 stmt: STIND_I4 (ADDR_L, LDIND_I4 (ADDR_L)) {
732         int treg = VARINFO (s, tree->left->data.i).reg;
733         int offset = VARINFO (s, tree->right->left->data.i).offset;
734         
735         x86_mov_reg_membase (s->code, treg, X86_EBP, offset, 4);
736 } cost {
737         MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
738         MBCOND ((VARINFO (data, tree->right->left->data.i).reg < 0));
739         return 0;
740 }
741
742 stmt: STIND_I4 (ADDR_L, reg) {
743         int treg = VARINFO (s, tree->left->data.i).reg;
744
745         if (treg != tree->right->reg1)
746                 x86_mov_reg_reg (s->code, treg, tree->right->reg1, 4);
747
748 } cost {
749         MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
750         return 0;
751 }
752
753
754 reg: LDIND_I4 (addr) {
755
756         switch (tree->left->data.ainfo.amode) {
757
758         case AMImmediate:
759                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
760                 break;
761
762         case AMBase:
763                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
764                                      tree->left->data.ainfo.offset, 4);
765                 break;          
766         case AMIndex:
767                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
768                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
769                 break;          
770         case AMBaseIndex:
771                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
772                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
773                                       tree->left->data.ainfo.shift, 4);
774                 break;          
775         }
776
777
778         PRINT_REG ("LDIND_I4", tree->reg1);
779 }
780
781 reg: LDIND_I1 (addr) {
782         switch (tree->left->data.ainfo.amode) {
783
784         case AMImmediate:
785                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, FALSE);
786                 break;
787
788         case AMBase:
789                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
790                                    tree->left->data.ainfo.offset, TRUE, FALSE);
791                 break;          
792         case AMIndex:
793                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
794                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, FALSE);
795                 break;          
796         case AMBaseIndex:
797                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
798                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
799                                     tree->left->data.ainfo.shift, TRUE, FALSE);
800                 break;          
801         }
802
803         PRINT_REG ("LDIND_I1", tree->reg1);
804 }
805
806 reg: LDIND_U1 (addr) {
807         switch (tree->left->data.ainfo.amode) {
808
809         case AMImmediate:
810                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, FALSE);
811                 break;
812
813         case AMBase:
814                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
815                                    tree->left->data.ainfo.offset, FALSE, FALSE);
816                 break;          
817         case AMIndex:
818                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
819                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, FALSE);
820                 break;          
821         case AMBaseIndex:
822                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
823                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
824                                     tree->left->data.ainfo.shift, FALSE, FALSE);
825                 break;          
826         }
827
828         PRINT_REG ("LDIND_U1", tree->reg1);
829 }
830
831 reg: LDIND_I2 (addr) {
832         switch (tree->left->data.ainfo.amode) {
833
834         case AMImmediate:
835                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, TRUE);
836                 break;
837
838         case AMBase:
839                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
840                                    tree->left->data.ainfo.offset, TRUE, TRUE);
841                 break;          
842         case AMIndex:
843                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
844                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, TRUE);
845                 break;          
846         case AMBaseIndex:
847                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
848                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
849                                     tree->left->data.ainfo.shift, TRUE, TRUE);
850                 break;          
851         }
852
853         PRINT_REG ("LDIND_U2", tree->reg1);
854 }
855
856 reg: LDIND_U2 (addr) {
857         switch (tree->left->data.ainfo.amode) {
858
859         case AMImmediate:
860                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, TRUE);
861                 break;
862
863         case AMBase:
864                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
865                                    tree->left->data.ainfo.offset, FALSE, TRUE);
866                 break;          
867         case AMIndex:
868                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
869                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, TRUE);
870                 break;          
871         case AMBaseIndex:
872                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
873                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
874                                     tree->left->data.ainfo.shift, FALSE, TRUE);
875                 break;          
876         }
877
878         PRINT_REG ("LDIND_U2", tree->reg1);
879 }
880
881 reg: REMOTE_LDFLDA (reg) {
882         guint8 *br[2];
883         int treg = X86_EAX;
884         int lreg = tree->left->reg1;
885
886         if (lreg == X86_EAX)
887                 treg = X86_EDX;
888
889         if (tree->reg1 != treg)
890                 x86_push_reg (s->code, treg);
891
892         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
893         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
894         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
895
896         /* this is a transparent proxy - remote the call */
897         if (treg != X86_EAX)
898                 x86_push_reg (s->code, X86_EAX);
899         if (treg != X86_EDX)
900                 x86_push_reg (s->code, X86_EDX);
901         x86_push_reg (s->code, X86_ECX);
902
903         x86_push_reg (s->code, X86_ESP);
904         x86_push_imm (s->code, tree->data.fi.field);
905         x86_push_imm (s->code, tree->data.fi.klass);
906         x86_push_reg (s->code, lreg);
907         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_load_remote_field);
908         x86_call_code (s->code, 0);
909         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
910
911         if (treg != X86_EAX)
912                 x86_mov_reg_reg (s->code, treg, X86_EAX, 4);
913
914         x86_pop_reg (s->code, X86_ECX);
915         if (treg != X86_EDX)
916                 x86_pop_reg (s->code, X86_EDX);
917         if (treg != X86_EAX)
918                 x86_pop_reg (s->code, X86_EAX);
919
920         x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
921
922         br [1] = s->code; x86_jump8 (s->code, 0);
923         
924         x86_patch (br [0], s->code);
925         if (tree->data.fi.klass->valuetype)
926                 x86_lea_membase (s->code, tree->reg1, lreg, 
927                                  tree->data.fi.field->offset - sizeof (MonoObject));
928         else 
929                 x86_lea_membase (s->code, tree->reg1, lreg, tree->data.fi.field->offset);
930
931         x86_patch (br [1], s->code);
932
933         if (tree->reg1 != treg)
934                 x86_pop_reg (s->code, treg);
935 }
936
937 reg: ADDR_L {
938         int offset = VARINFO (s, tree->data.i).offset;  
939
940         x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
941         
942         PRINT_REG ("ADDR_L",  tree->reg1);
943 } cost {
944         MBCOND (VARINFO (data, tree->data.i).reg < 0);
945         return 5;
946 }
947
948
949 reg: ADDR_G 5 {
950         x86_mov_reg_imm (s->code, tree->reg1, tree->data.p);
951 }
952
953 reg: CONV_I1 (reg) {
954         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
955 }
956
957 reg: CONV_U1 (reg) {
958         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
959 }
960
961 reg: CONV_I2 (reg) {
962         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
963 }
964
965 reg: CONV_U2 (reg) {
966         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
967 }
968
969 reg: CONST_I4 1 {
970         x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
971 }
972
973 reg: CONV_I4 (reg) {
974         if (tree->reg1 != tree->left->reg1)
975                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
976         PRINT_REG ("CONV_I4", tree->left->reg1);
977
978
979 reg: CONV_U4 (reg) {
980         if (tree->reg1 != tree->left->reg1)
981                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
982         PRINT_REG ("CONV_U4", tree->left->reg1);
983
984
985 reg: CONV_OVF_I4 (reg) {
986         if (tree->reg1 != tree->left->reg1)
987                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
988         PRINT_REG ("CONV_OVF_I4", tree->left->reg1);
989 }
990
991 reg: CONV_OVF_U4 (reg) {
992         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
993         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
994         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
995         if (tree->reg1 != tree->left->reg1)
996                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
997 }
998
999 reg: CONV_OVF_I4_UN (reg) {
1000         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
1001         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
1002         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
1003         if (tree->reg1 != tree->left->reg1)
1004                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1005 }
1006
1007 reg: CONV_OVF_I1 (reg) {
1008         /* probe value to be within -128 to 127 */
1009         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 127);
1010         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
1011         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -128);
1012         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GT, TRUE, "OverflowException");      
1013         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
1014 }
1015
1016 reg: CONV_OVF_I1_UN (reg) {
1017         /* probe values between 0 to 128 */
1018         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff80);
1019         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1020         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1021 }
1022
1023 reg: CONV_OVF_U1 (reg) {
1024         /* Keep in sync with CONV_OVF_U1_UN routine below, they are the same on 32-bit machines */
1025         /* probe value to be within 0 to 255 */
1026         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
1027         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1028         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1029 }
1030
1031 reg: CONV_OVF_U1_UN (reg) {
1032         /* Keep in sync with CONV_OVF_U1 routine above, they are the same on 32-bit machines */
1033         /* probe value to be within 0 to 255 */
1034         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
1035         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1036         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1037 }
1038
1039 reg: CONV_OVF_I2 (reg) {        
1040         /* Probe value to be within -32768 and 32767 */
1041         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 32767);
1042         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
1043         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -32768);
1044         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GE, TRUE, "OverflowException");      
1045         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
1046 }
1047
1048 reg: CONV_OVF_U2 (reg) {
1049         /* Keep in sync with CONV_OVF_U2_UN below, they are the same on 32-bit machines */
1050         /* Probe value to be within 0 and 65535 */
1051         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
1052         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");      
1053         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1054 }
1055
1056 reg: CONV_OVF_U2_UN (reg) {
1057         /* Keep in sync with CONV_OVF_U2 above, they are the same on 32-bit machines */
1058         /* Probe value to be within 0 and 65535 */
1059         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
1060         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1061         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1062 }
1063
1064 reg: CONV_OVF_I2_UN (reg) {
1065         /* Convert uint value into short, value within 0 and 32767 */
1066         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff8000);
1067         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1068         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1069 }
1070
1071 reg: MUL (reg, CONST_I4) "MB_USE_OPT1(0)" {
1072         unsigned int i, j, k, v;
1073
1074         v = tree->right->data.i;
1075         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1076                 if (v & j)
1077                         break;
1078         }
1079
1080         if (v < 0 || i == 32 || v & k) {
1081                 switch (v) {
1082                 case 3:
1083                         /* LEA r1, [r2 + r2*2] */
1084                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1085                         break;
1086                 case 5:
1087                         /* LEA r1, [r2 + r2*4] */
1088                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1089                         break;
1090                 case 6:
1091                         /* LEA r1, [r2 + r2*2] */
1092                         /* ADD r1, r1          */
1093                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1094                         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
1095                         break;
1096                 case 9:
1097                         /* LEA r1, [r2 + r2*8] */
1098                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 3);
1099                         break;
1100                 case 10:
1101                         /* LEA r1, [r2 + r2*4] */
1102                         /* ADD r1, r1          */
1103                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1104                         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
1105                         break;
1106                 case 12:
1107                         /* LEA r1, [r2 + r2*2] */
1108                         /* SHL r1, 2           */
1109                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1110                         x86_shift_reg_imm (s->code, X86_SHL, tree->reg1, 2);
1111                         break;
1112                 case 25:
1113                         /* LEA r1, [r2 + r2*4] */
1114                         /* LEA r1, [r1 + r1*4] */
1115                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1116                         x86_lea_memindex (s->code, tree->reg1, tree->reg1, 0, tree->reg1, 2);
1117                         break;
1118                 case 100:
1119                         /* LEA r1, [r2 + r2*4] */
1120                         /* SHL r1, 2           */
1121                         /* LEA r1, [r1 + r1*4] */
1122                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1123                         x86_shift_reg_imm (s->code, X86_SHL, tree->reg1, 2);
1124                         x86_lea_memindex (s->code, tree->reg1, tree->reg1, 0, tree->reg1, 2);
1125                         break;
1126                 default:
1127                         x86_imul_reg_reg_imm (s->code, tree->reg1, tree->left->reg1, tree->right->data.i);
1128                         break;
1129                 }
1130         } else {
1131                 x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, i);
1132                 if (tree->reg1 != tree->left->reg1)
1133                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1134         }
1135 }
1136
1137 reg: MUL (reg, reg) {
1138         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
1139
1140         if (tree->reg1 != tree->left->reg1)
1141                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1142 }
1143
1144 reg: MUL_OVF (reg, reg) {
1145         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
1146         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1147
1148         if (tree->reg1 != tree->left->reg1)
1149                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1150 }
1151
1152 reg: MUL_OVF_UN (reg, reg) {
1153         mono_assert (tree->right->reg1 != X86_EAX);
1154         
1155         if (tree->left->reg1 != X86_EAX)
1156                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1157
1158         x86_mul_reg (s->code, tree->right->reg1, FALSE);
1159         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");
1160
1161         mono_assert (tree->reg1 == X86_EAX &&
1162                      tree->reg2 == X86_EDX);
1163 }
1164
1165 reg: DIV (reg, CONST_I4) {
1166         unsigned int i, j, k, v;
1167
1168         v = tree->right->data.i;
1169         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1170                 if (v & j)
1171                         break;
1172         }
1173
1174         x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg1, i);
1175         if (tree->reg1 != tree->left->reg1)
1176                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1177
1178 } cost {
1179         unsigned int i, j, k, v;
1180
1181         if (v < 0) 
1182                 return MBMAXCOST;
1183
1184         v = tree->right->data.i;
1185         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1186                 if (v & j)
1187                         break;
1188         }
1189         
1190         if (i == 32 || v & k) 
1191                 return MBMAXCOST;
1192
1193         return 0;
1194
1195 }
1196
1197 reg: DIV (reg, reg) {
1198         mono_assert (tree->right->reg1 != X86_EAX);
1199
1200         if (tree->left->reg1 != X86_EAX)
1201                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1202
1203         x86_cdq (s->code);
1204         x86_div_reg (s->code, tree->right->reg1, TRUE);
1205
1206         mono_assert (tree->reg1 == X86_EAX &&
1207                      tree->reg2 == X86_EDX);
1208 }
1209
1210 reg: DIV_UN (reg, CONST_I4) {
1211         unsigned int i, j, k, v;
1212         double f, r;
1213
1214         v = tree->right->data.i;
1215         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1216                 if (v & j)
1217                         break;
1218         }
1219
1220         if (i == 32 || v & k)  {
1221                 for (i = 32, j = 0x80000000; --i >= 0; j >>= 1) {
1222                         if (v & j) break;
1223                 }
1224
1225                 /* k = 32 + number of significant bits in v - 1 */
1226                 k = 32 + i;
1227
1228                 f = 1.0f / v;
1229                 for (i = 0; i < k; i++) f *= 2.0f;
1230
1231
1232                 r = f - floor(f);
1233
1234                 if (r == 0) {
1235                         x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, k - 32);
1236                         if (tree->reg1 != tree->left->reg1)
1237                                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1238                 } else if (r < 0.5f) {
1239                         if (tree->left->reg1 != X86_EAX)
1240                                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1241                         x86_mov_reg_imm (s->code, X86_EDX, (guint32) floor(f));
1242                         /* x86_inc_reg (s->code, X86_EAX); */
1243                         /* INC is faster but we have to check for overflow. */
1244                         x86_alu_reg_imm (s->code, X86_ADD, X86_EAX, 1);
1245                         x86_branch8(s->code, X86_CC_C, 2, FALSE);
1246                         x86_mul_reg (s->code, X86_EDX, FALSE);
1247                         x86_shift_reg_imm (s->code, X86_SHR, X86_EDX, k - 32);
1248                         if (tree->reg1 != X86_EDX)
1249                                 x86_mov_reg_reg (s->code, tree->reg1, X86_EDX, 4);
1250                 } else {
1251                         if (tree->left->reg1 != X86_EAX)
1252                                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1253                         x86_mov_reg_imm (s->code, X86_EDX, (guint32) ceil(f));
1254                         x86_mul_reg (s->code, X86_EDX, FALSE);
1255                         x86_shift_reg_imm (s->code, X86_SHR, X86_EDX, k - 32);
1256                         if (tree->reg1 != X86_EDX)
1257                                 x86_mov_reg_reg (s->code, tree->reg1, X86_EDX, 4);
1258                 }
1259         } else {
1260                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, i);
1261                 if (tree->reg1 != tree->left->reg1)
1262                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1263         }
1264
1265 }
1266
1267 reg: DIV_UN (reg, reg) {
1268         mono_assert (tree->right->reg1 != X86_EAX);
1269
1270         if (tree->left->reg1 != X86_EAX)
1271                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1272
1273         x86_mov_reg_imm (s->code, X86_EDX, 0);
1274         x86_div_reg (s->code, tree->right->reg1, FALSE);
1275
1276         mono_assert (tree->reg1 == X86_EAX &&
1277                      tree->reg2 == X86_EDX);
1278 }
1279
1280 reg: REM (reg, reg) {
1281         mono_assert (tree->right->reg1 != X86_EAX);
1282         mono_assert (tree->right->reg1 != X86_EDX);
1283
1284         if (tree->left->reg1 != X86_EAX)
1285                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1286
1287         /* sign extend to 64bit in EAX/EDX */
1288         x86_cdq (s->code);
1289         x86_div_reg (s->code, tree->right->reg1, TRUE);
1290         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
1291
1292         mono_assert (tree->reg1 == X86_EAX &&
1293                      tree->reg2 == X86_EDX);
1294 }
1295
1296 reg: REM_UN (reg, reg) {
1297         mono_assert (tree->right->reg1 != X86_EAX);
1298         mono_assert (tree->right->reg1 != X86_EDX);
1299
1300         if (tree->left->reg1 != X86_EAX)
1301                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1302
1303         /* zero extend to 64bit in EAX/EDX */
1304         x86_mov_reg_imm (s->code, X86_EDX, 0); 
1305         x86_div_reg (s->code, tree->right->reg1, FALSE);
1306         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
1307
1308         mono_assert (tree->reg1 == X86_EAX &&
1309                      tree->reg2 == X86_EDX);
1310 }
1311
1312 reg: ADD (reg, CONST_I4) "MB_USE_OPT1(0)" {
1313         if (tree->right->data.i == 1)
1314                 x86_inc_reg (s->code, tree->left->reg1);
1315         else 
1316                 x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, tree->right->data.i);
1317
1318         if (tree->reg1 != tree->left->reg1)
1319                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1320
1321 }
1322
1323 reg: ADD (reg, LDIND_I4 (ADDR_L)) {
1324         int treg = VARINFO (s, tree->right->left->data.i).reg;
1325
1326         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, treg);
1327
1328         if (tree->reg1 != tree->left->reg1)
1329                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1330 } cost {
1331         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
1332         return 0;
1333 }
1334
1335 reg: ADD (reg, reg) {
1336         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1337
1338         if (tree->reg1 != tree->left->reg1)
1339                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1340 }
1341
1342 reg: ADD_OVF (reg, reg) {
1343         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1344         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1345
1346         if (tree->reg1 != tree->left->reg1)
1347                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1348 }
1349
1350 reg: ADD_OVF_UN (reg, reg) {
1351         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1352         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
1353
1354         if (tree->reg1 != tree->left->reg1)
1355                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1356 }
1357
1358 reg: SUB (reg, CONST_I4) "MB_USE_OPT1(0)" {
1359         if (tree->right->data.i == 1)
1360                 x86_dec_reg (s->code, tree->left->reg1);
1361         else
1362                 x86_alu_reg_imm (s->code, X86_SUB, tree->left->reg1, tree->right->data.i);
1363
1364         if (tree->reg1 != tree->left->reg1)
1365                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1366 }
1367
1368 reg: SUB (reg, LDIND_I4 (ADDR_L)) {
1369         int treg = VARINFO (s, tree->right->left->data.i).reg;
1370
1371         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, treg);
1372
1373         if (tree->reg1 != tree->left->reg1)
1374                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1375 } cost {
1376         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
1377         return 0;
1378 }
1379
1380 reg: SUB (reg, reg) {
1381         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1382
1383         if (tree->reg1 != tree->left->reg1)
1384                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1385 }
1386
1387 reg: SUB_OVF (reg, reg) {
1388         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1389         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1390
1391         if (tree->reg1 != tree->left->reg1)
1392                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1393 }
1394
1395 reg: SUB_OVF_UN (reg, reg) {
1396         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1397         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
1398
1399         if (tree->reg1 != tree->left->reg1)
1400                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1401 }
1402
1403 reg: CSET (cflags) {
1404
1405         switch (tree->data.i) {
1406         case CEE_CEQ:
1407                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
1408                 break;
1409         case CEE_CGT:
1410                 x86_set_reg (s->code, X86_CC_GT, tree->reg1, TRUE);
1411                 break;
1412         case CEE_CGT_UN:
1413                 x86_set_reg (s->code, X86_CC_GT, tree->reg1, FALSE);
1414                 break;
1415         case CEE_CLT:
1416                 x86_set_reg (s->code, X86_CC_LT, tree->reg1, TRUE);
1417                 break;
1418         case CEE_CLT_UN:
1419                 x86_set_reg (s->code, X86_CC_LT, tree->reg1, FALSE);
1420                 break;
1421         default:
1422                 g_assert_not_reached ();
1423         }
1424
1425         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
1426 }
1427
1428 reg: AND (reg, CONST_I4) "MB_USE_OPT1(0)" {
1429         x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, tree->right->data.i);
1430
1431         if (tree->reg1 != tree->left->reg1)
1432                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1433 }
1434
1435 reg: AND (reg, reg) {
1436         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
1437
1438         if (tree->reg1 != tree->left->reg1)
1439                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1440 }
1441
1442 reg: OR (reg, CONST_I4) "MB_USE_OPT1(0)" {
1443         x86_alu_reg_imm (s->code, X86_OR, tree->left->reg1, tree->right->data.i);
1444
1445         if (tree->reg1 != tree->left->reg1)
1446                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1447 }
1448
1449 reg: OR (reg, reg) {
1450         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
1451
1452         if (tree->reg1 != tree->left->reg1)
1453                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1454 }
1455
1456 reg: XOR (reg, CONST_I4) "MB_USE_OPT1(0)" {
1457         x86_alu_reg_imm (s->code, X86_XOR, tree->left->reg1, tree->right->data.i);
1458
1459         if (tree->reg1 != tree->left->reg1)
1460                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1461 }
1462
1463 reg: XOR (reg, reg) {
1464         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->right->reg1);
1465
1466         if (tree->reg1 != tree->left->reg1)
1467                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1468 }
1469
1470 reg: NEG (reg) {
1471         x86_neg_reg (s->code, tree->left->reg1);
1472
1473         if (tree->reg1 != tree->left->reg1)
1474                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1475 }
1476
1477 reg: NOT (reg) {
1478         x86_not_reg (s->code, tree->left->reg1);
1479
1480         if (tree->reg1 != tree->left->reg1)
1481                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1482 }
1483
1484 reg: SHL (reg, CONST_I4) {
1485         x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
1486
1487         if (tree->reg1 != tree->left->reg1)
1488                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1489 }
1490
1491 reg: SHL (reg, reg) {
1492         if (tree->right->reg1 != X86_ECX) {
1493                 x86_push_reg (s->code, X86_ECX);
1494                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1495         }
1496         x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
1497
1498         if (tree->reg1 != tree->left->reg1)
1499                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1500
1501         if (tree->right->reg1 != X86_ECX)
1502                 x86_pop_reg (s->code, X86_ECX);
1503
1504         mono_assert (tree->reg1 != X86_ECX &&
1505                      tree->left->reg1 != X86_ECX);
1506 }
1507
1508 reg: SHR (reg, CONST_I4) {
1509         x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg1, tree->right->data.i);
1510
1511         if (tree->reg1 != tree->left->reg1)
1512                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1513 }
1514
1515 reg: SHR (reg, reg) {
1516         if (tree->right->reg1 != X86_ECX) {
1517                 x86_push_reg (s->code, X86_ECX);
1518                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1519         }
1520
1521         x86_shift_reg (s->code, X86_SAR, tree->left->reg1);
1522
1523         if (tree->reg1 != tree->left->reg1)
1524                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1525
1526         if (tree->right->reg1 != X86_ECX)
1527                 x86_pop_reg (s->code, X86_ECX);
1528
1529         mono_assert (tree->reg1 != X86_ECX &&
1530                      tree->left->reg1 != X86_ECX);
1531 }
1532
1533 reg: SHR_UN (reg, CONST_I4) {
1534         x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, tree->right->data.i);
1535
1536         if (tree->reg1 != tree->left->reg1)
1537                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1538 }
1539
1540 reg: SHR_UN (reg, reg) {
1541         if (tree->right->reg1 != X86_ECX) {
1542                 x86_push_reg (s->code, X86_ECX);
1543                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1544         }
1545
1546         x86_shift_reg (s->code, X86_SHR, tree->left->reg1);
1547
1548         if (tree->reg1 != tree->left->reg1)
1549                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1550
1551         if (tree->right->reg1 != X86_ECX)
1552                 x86_pop_reg (s->code, X86_ECX);
1553
1554         mono_assert (tree->reg1 != X86_ECX &&
1555                      tree->left->reg1 != X86_ECX);
1556 }
1557
1558 reg: LDSFLDA (CONST_I4) {
1559         if (tree->reg1 != X86_EAX)
1560                 x86_push_reg (s->code, X86_EAX);
1561         x86_push_reg (s->code, X86_ECX);
1562         x86_push_reg (s->code, X86_EDX);
1563
1564         x86_push_imm (s->code, tree->left->data.i);
1565         x86_push_imm (s->code, tree->data.klass);
1566         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldsflda);
1567         x86_call_code (s->code, 0);
1568         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1569         
1570         x86_pop_reg (s->code, X86_EDX);
1571         x86_pop_reg (s->code, X86_ECX);
1572         if (tree->reg1 != X86_EAX) {
1573                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1574                 x86_pop_reg (s->code, X86_EAX);
1575         }
1576 }
1577
1578 # array support
1579 reg: LDLEN (reg) {      
1580         x86_mov_reg_membase (s->code, tree->reg1, tree->left->reg1,  
1581                              G_STRUCT_OFFSET (MonoArray, max_length), 4);
1582 }
1583
1584 reg: LDELEMA (reg, CONST_I4) {
1585         int ind;
1586
1587         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length), tree->right->data.i);
1588         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GT, FALSE, "IndexOutOfRangeException");
1589        
1590         ind = tree->data.i * tree->right->data.i + G_STRUCT_OFFSET (MonoArray, vector);
1591         
1592         x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, ind);
1593
1594         if (tree->reg1 != tree->left->reg1)
1595                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1596
1597 }
1598
1599 reg: LDELEMA (reg, reg) {
1600
1601         x86_alu_reg_membase (s->code, X86_CMP, tree->right->reg1, tree->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length));
1602         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LT, FALSE, "IndexOutOfRangeException");
1603
1604         if (tree->data.i == 1 || tree->data.i == 2 || 
1605             tree->data.i == 4 || tree->data.i == 8) {
1606                 static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
1607                 x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 
1608                                   G_STRUCT_OFFSET (MonoArray, vector), tree->right->reg1, 
1609                                   fast_log2 [tree->data.i]);
1610         } else {
1611                 x86_imul_reg_reg_imm (s->code, tree->right->reg1, tree->right->reg1, tree->data.i);
1612                 x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
1613                 x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, G_STRUCT_OFFSET (MonoArray, vector));
1614         }
1615 }
1616
1617 reg: LDSTR {
1618         if (tree->reg1 != X86_EAX)
1619                 x86_push_reg (s->code, X86_EAX);
1620         x86_push_reg (s->code, X86_ECX);
1621         x86_push_reg (s->code, X86_EDX);
1622
1623         x86_push_imm (s->code, tree->data.p);
1624         x86_push_imm (s->code, s->method->klass->image);
1625         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldstr_wrapper);
1626         x86_call_code (s->code, 0);
1627         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1628
1629         x86_pop_reg (s->code, X86_EDX);
1630         x86_pop_reg (s->code, X86_ECX);
1631         if (tree->reg1 != X86_EAX) {
1632                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1633                 x86_pop_reg (s->code, X86_EAX);
1634         }
1635
1636         PRINT_REG ("LDSTR", tree->reg1);        
1637 }
1638
1639 reg: NEWARR (reg) {
1640         if (tree->reg1 != X86_EAX)
1641                 x86_push_reg (s->code, X86_EAX);
1642         x86_push_reg (s->code, X86_ECX);
1643         x86_push_reg (s->code, X86_EDX);
1644
1645         x86_push_reg (s->code, tree->left->reg1);
1646         x86_push_imm (s->code, tree->data.p);
1647         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_wrapper);
1648         x86_call_code (s->code, 0);
1649         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
1650
1651         x86_pop_reg (s->code, X86_EDX);
1652         x86_pop_reg (s->code, X86_ECX);
1653         if (tree->reg1 != X86_EAX) {
1654                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1655                 x86_pop_reg (s->code, X86_EAX);
1656         }
1657
1658         PRINT_REG ("NEWARR", tree->reg1);
1659 }
1660
1661 reg: NEWARR_SPEC (reg) {
1662         if (tree->reg1 != X86_EAX)
1663                 x86_push_reg (s->code, X86_EAX);
1664         x86_push_reg (s->code, X86_ECX);
1665         x86_push_reg (s->code, X86_EDX);
1666
1667         x86_push_reg (s->code, tree->left->reg1);
1668         x86_push_imm (s->code, tree->data.p);
1669         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_specific);
1670         x86_call_code (s->code, 0);
1671         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
1672
1673         x86_pop_reg (s->code, X86_EDX);
1674         x86_pop_reg (s->code, X86_ECX);
1675         if (tree->reg1 != X86_EAX) {
1676                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1677                 x86_pop_reg (s->code, X86_EAX);
1678         }
1679
1680         PRINT_REG ("NEWARR_SPEC", tree->reg1);
1681 }
1682
1683 reg: NEWOBJ {
1684         if (tree->reg1 != X86_EAX)
1685                 x86_push_reg (s->code, X86_EAX);
1686         x86_push_reg (s->code, X86_ECX);
1687         x86_push_reg (s->code, X86_EDX);
1688
1689         x86_push_imm (s->code, tree->data.klass);
1690         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_wrapper);
1691         x86_call_code (s->code, 0);
1692         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1693
1694         x86_pop_reg (s->code, X86_EDX);
1695         x86_pop_reg (s->code, X86_ECX);
1696         if (tree->reg1 != X86_EAX) {
1697                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1698                 x86_pop_reg (s->code, X86_EAX);
1699         }
1700         PRINT_REG ("NEWOBJ", tree->reg1);
1701 }
1702
1703 reg: NEWOBJ_SPEC {
1704         if (tree->reg1 != X86_EAX)
1705                 x86_push_reg (s->code, X86_EAX);
1706         x86_push_reg (s->code, X86_ECX);
1707         x86_push_reg (s->code, X86_EDX);
1708
1709         x86_push_imm (s->code, tree->data.p);
1710         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_specific);
1711         x86_call_code (s->code, 0);
1712         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1713
1714         x86_pop_reg (s->code, X86_EDX);
1715         x86_pop_reg (s->code, X86_ECX);
1716         if (tree->reg1 != X86_EAX) {
1717                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1718                 x86_pop_reg (s->code, X86_EAX);
1719         }
1720         PRINT_REG ("NEWOBJ_SPEC", tree->reg1);
1721 }
1722
1723 reg: OBJADDR (reg) {
1724         if (tree->left->reg1 != tree->reg1)
1725                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1726 }
1727
1728 stmt: FREE (reg) {
1729         x86_push_reg (s->code, X86_EAX);
1730         x86_push_reg (s->code, X86_ECX);
1731         x86_push_reg (s->code, X86_EDX);
1732
1733         x86_push_reg (s->code, tree->left->reg1);
1734
1735         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, g_free);
1736         x86_call_code (s->code, 0);
1737         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
1738         
1739         x86_pop_reg (s->code, X86_EDX);
1740         x86_pop_reg (s->code, X86_ECX);
1741         x86_pop_reg (s->code, X86_EAX);
1742 }
1743
1744 stmt: PROC3 (reg, CPSRC (reg, reg)) {
1745         int dest_reg = tree->left->reg1;
1746         int source_reg = tree->right->left->reg1;
1747         int size_reg = tree->right->right->reg1;
1748
1749         x86_push_reg (s->code, X86_EAX);
1750         x86_push_reg (s->code, X86_ECX);
1751         x86_push_reg (s->code, X86_EDX);
1752
1753         x86_push_reg (s->code, size_reg);
1754         x86_push_reg (s->code, source_reg);
1755         x86_push_reg (s->code, dest_reg);
1756
1757         switch (tree->data.i) {
1758         case MONO_MARSHAL_CONV_STR_BYVALSTR:
1759                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_string_to_byvalstr);
1760                 break;
1761         case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1762                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_string_to_byvalwstr);
1763                 break;
1764         default:
1765                 g_assert_not_reached ();
1766         }
1767
1768         x86_call_code (s->code, 0);
1769         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
1770
1771         x86_pop_reg (s->code, X86_EDX);
1772         x86_pop_reg (s->code, X86_ECX);
1773         x86_pop_reg (s->code, X86_EAX);
1774 }
1775
1776 reg: FUNC1 (reg) {
1777         if (tree->reg1 != X86_EAX)
1778                 x86_push_reg (s->code, X86_EAX);
1779         x86_push_reg (s->code, X86_ECX);
1780         x86_push_reg (s->code, X86_EDX);
1781
1782         x86_push_reg (s->code, tree->left->reg1);
1783
1784         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
1785         x86_call_code (s->code, 0);
1786         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1787
1788         x86_pop_reg (s->code, X86_EDX);
1789         x86_pop_reg (s->code, X86_ECX);
1790         if (tree->reg1 != X86_EAX) {
1791                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1792                 x86_pop_reg (s->code, X86_EAX);
1793         }
1794 }
1795
1796
1797 reg: LOCALLOC (reg) {
1798         int offset = 0;
1799         /* size must be aligned to 4 bytes */
1800         x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, 3);
1801         x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, ~3);
1802
1803         /* allocate space on stack */
1804         x86_alu_reg_reg (s->code, X86_SUB, X86_ESP, tree->left->reg1);
1805
1806         if (tree->data.i) {
1807                 /* initialize with zero */
1808                 if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX) {
1809                         x86_push_reg (s->code, X86_EAX);
1810                         offset += 4;
1811                 }
1812                 if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX) {
1813                         x86_push_reg (s->code, X86_ECX);
1814                         offset += 4;
1815                 }
1816                 if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI) {
1817                         x86_push_reg (s->code, X86_EDI);
1818                         offset += 4;
1819                 }
1820                 
1821                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, 2);
1822                 if (tree->left->reg1 != X86_ECX)
1823                         x86_mov_reg_imm (s->code, X86_ECX, tree->left->reg1);
1824                 x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
1825                                 
1826                 x86_lea_membase (s->code, X86_EDI, X86_ESP, offset);
1827                 x86_cld (s->code);
1828                 x86_prefix (s->code, X86_REP_PREFIX);
1829                 x86_stosl (s->code);
1830                 
1831                 if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI)
1832                         x86_pop_reg (s->code, X86_EDI);
1833                 if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX)
1834                         x86_pop_reg (s->code, X86_ECX);
1835                 if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX)
1836                         x86_pop_reg (s->code, X86_EAX);
1837         }
1838
1839         x86_mov_reg_reg (s->code, tree->reg1, X86_ESP, 4);
1840 }
1841
1842 reg: UNBOX (reg) {
1843         if (tree->reg1 != tree->left->reg1)
1844                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1845
1846         x86_push_reg (s->code, tree->reg1);
1847         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1848         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1849         x86_alu_membase_imm (s->code, X86_CMP, tree->reg1, 
1850                              G_STRUCT_OFFSET (MonoClass, element_class), ((int)(tree->data.klass->element_class)));
1851         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "InvalidCastException");
1852         x86_pop_reg (s->code, tree->reg1);
1853         x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
1854 }
1855
1856 reg: CASTCLASS (reg) {
1857         MonoClass *klass = tree->data.klass;
1858         guint8 *br [2];
1859         int lreg = tree->left->reg1;
1860         
1861         x86_push_reg (s->code, lreg);
1862         x86_test_reg_reg (s->code, lreg, lreg);
1863         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
1864
1865         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1866                 /* lreg = obj->vtable */
1867                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1868
1869                 x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoVTable, max_interface_id), 
1870                                      klass->interface_id);
1871                 EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GE, FALSE, "InvalidCastException");
1872                 /* lreg = obj->vtable->interface_offsets */
1873                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1874                 x86_alu_membase_imm (s->code, X86_CMP, lreg, klass->interface_id << 2, 0);
1875                 EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, FALSE, "InvalidCastException");
1876         } else {
1877
1878                 /* lreg = obj->vtable */
1879                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1880                 /* lreg = obj->vtable->klass */
1881                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1882
1883                 if (klass->rank) {
1884
1885                         x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoClass, rank), klass->rank);
1886                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "InvalidCastException");
1887                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, element_class), 4);
1888                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1889                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->element_class->baseval);
1890                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->element_class->diffval);
1891                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, FALSE, "InvalidCastException");
1892
1893                 } else {
1894
1895                         if (klass->marshalbyref) {
1896                                 /* check for transparent_proxy */               
1897                                 x86_alu_reg_imm (s->code, X86_CMP, lreg, (int)mono_defaults.transparent_proxy_class);
1898                                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1899                 
1900                                 /* lreg = obj */
1901                                 x86_mov_reg_membase (s->code, lreg, X86_ESP, 0, 4);
1902                                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoTransparentProxy, 
1903                                                                                            klass), 4);
1904
1905                                 x86_patch (br [1], s->code);
1906                         }
1907
1908                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1909                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->baseval);
1910                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->diffval);
1911                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, FALSE, "InvalidCastException");          
1912                 }
1913         }
1914
1915         x86_patch (br [0], s->code);
1916         x86_pop_reg (s->code, tree->reg1);
1917 }
1918
1919 reg: ISINST (reg) {
1920         MonoClass *klass = tree->data.klass;
1921         guint8 *br [3];
1922         int lreg = tree->left->reg1;
1923         
1924         x86_push_reg (s->code, lreg);
1925         x86_test_reg_reg (s->code, lreg, lreg);
1926         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
1927
1928         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1929                 /* lreg = obj->vtable */
1930                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1931
1932                 x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoVTable, max_interface_id), 
1933                                      klass->interface_id);
1934                 br [1] = s->code; x86_branch8 (s->code, X86_CC_LT, 0, FALSE);
1935                 /* lreg = obj->vtable->interface_offsets */
1936                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1937                 x86_alu_membase_imm (s->code, X86_CMP, lreg, klass->interface_id << 2, 0);
1938                 br [2] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1939                 x86_patch (br [1], s->code);
1940                 x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1941                 x86_patch (br [2], s->code);
1942
1943         } else {
1944
1945                 /* lreg = obj->vtable */
1946                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1947                 /* lreg = obj->vtable->klass */
1948                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1949
1950                 if (klass->rank) {
1951
1952                         x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoClass, rank), klass->rank);
1953                         br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1954                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, element_class), 4);
1955                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1956                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->element_class->baseval);
1957                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->element_class->diffval);
1958                         br [2] = s->code; x86_branch8 (s->code, X86_CC_LE, 0, FALSE);
1959                         x86_patch (br [1], s->code);
1960                         x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1961                         x86_patch (br [2], s->code);
1962
1963                 } else {
1964
1965                         if (klass->marshalbyref) {
1966                                 /* check for transparent_proxy */               
1967                                 x86_alu_reg_imm (s->code, X86_CMP, lreg, (int)mono_defaults.transparent_proxy_class);
1968                                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1969                 
1970                                 /* lreg = obj */
1971                                 x86_mov_reg_membase (s->code, lreg, X86_ESP, 0, 4);
1972                                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoTransparentProxy, 
1973                                                                                            klass), 4);
1974                                 x86_patch (br [1], s->code);
1975                         }
1976
1977                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1978                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->baseval);
1979                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->diffval);
1980                         br [2] = s->code; x86_branch8 (s->code, X86_CC_LE, 0, FALSE);
1981                         x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1982                         x86_patch (br [2], s->code);
1983                 }
1984         }
1985
1986         x86_patch (br [0], s->code);
1987         x86_pop_reg (s->code, tree->reg1);
1988 }
1989
1990 stmt: INITOBJ (reg) {
1991         int i, j;
1992
1993         i = tree->data.i;
1994
1995         if (i == 1 || i == 2 || i == 4) {
1996                 x86_mov_membase_imm (s->code, tree->left->reg1, 0, 0, i);
1997                 return;
1998         }
1999
2000         i = tree->data.i / 4;
2001         j = tree->data.i % 4;
2002
2003         if (tree->left->reg1 != X86_EDI) {
2004                 x86_push_reg (s->code, X86_EDI);
2005                 x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
2006         }
2007
2008         if (i) {
2009                 x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
2010                 x86_mov_reg_imm (s->code, X86_ECX, i);
2011                 x86_cld (s->code);
2012                 x86_prefix (s->code, X86_REP_PREFIX);
2013                 x86_stosl (s->code);
2014
2015                 for (i = 0; i < j; i++)
2016                         x86_stosb (s->code);
2017
2018         } else {
2019                 g_assert (j == 3);
2020                 x86_mov_membase_imm (s->code, X86_EDI, 0, 0, 2);
2021                 x86_mov_membase_imm (s->code, X86_EDI, 2, 0, 1);
2022         }
2023
2024
2025
2026         if (tree->left->reg1 != X86_EDI)
2027                 x86_pop_reg (s->code, X86_EDI);
2028 }
2029
2030 stmt: CPBLK (reg, CPSRC (reg, CONST_I4)) {
2031         int dest_reg = tree->left->reg1;
2032         int source_reg = tree->right->left->reg1;
2033         int count = tree->right->right->data.i;
2034         int sreg = dest_reg != X86_EAX ? X86_EAX : X86_EDX;
2035         int spill_pos = 0, dest_offset = 0, source_offset = 0;
2036         int save_esi = FALSE, save_edi = FALSE;
2037
2038         // TODO: handle unaligned. prefix
2039
2040         switch (count) {
2041         case 0:
2042                 break;
2043         case 1:
2044                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 1);
2045                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 1);
2046                 break;
2047         case 2:
2048                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
2049                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
2050                 break;
2051         case 3:
2052                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
2053                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
2054                 x86_mov_reg_membase (s->code, sreg, source_reg, 2, 1);
2055                 x86_mov_membase_reg (s->code, dest_reg, 2, sreg, 1);
2056                 break;
2057         case 4:
2058                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
2059                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
2060                 break;
2061         case 5:
2062                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
2063                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
2064                 x86_mov_reg_membase (s->code, sreg, source_reg, 4, 1);
2065                 x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 1);
2066                 break;
2067         case 6:
2068                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
2069                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
2070                 x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
2071                 x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
2072                 break;
2073         case 7:
2074                 x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
2075                 x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
2076                 x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
2077                 x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
2078                 x86_mov_reg_membase (s->code, sreg, source_reg, 6, 1);
2079                 x86_mov_membase_reg (s->code, dest_reg, 6, sreg, 1);
2080                 break;
2081         case 8:
2082                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2083                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2084                 break;
2085         case 9:
2086                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2087                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2088                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 1);
2089                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 1);
2090                 break;
2091         case 10:
2092                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2093                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2094                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
2095                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
2096                 break;
2097         case 11:
2098                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2099                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2100                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
2101                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
2102                 x86_mov_reg_membase (s->code, sreg, source_reg, 10, 1);
2103                 x86_mov_membase_reg (s->code, dest_reg, 10, sreg, 1);
2104                 break;
2105         case 12:
2106                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2107                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2108                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
2109                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
2110                 break;
2111         case 13:
2112                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2113                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2114                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
2115                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
2116                 x86_mov_reg_membase (s->code, sreg, source_reg, 12, 1);
2117                 x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 1);
2118                 break;
2119         case 14:
2120                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2121                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2122                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
2123                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
2124                 x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
2125                 x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
2126                 break;
2127         case 15:
2128                 x86_fild_membase (s->code, source_reg, 0, TRUE);
2129                 x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
2130                 x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
2131                 x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
2132                 x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
2133                 x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
2134                 x86_mov_reg_membase (s->code, sreg, source_reg, 14, 1);
2135                 x86_mov_membase_reg (s->code, dest_reg, 14, sreg, 1);
2136                 break;
2137         default: 
2138                 g_assert (count > 15);
2139
2140                 if (dest_reg != X86_ESI && source_reg != X86_ESI &&
2141                     mono_regset_reg_used (s->rs, X86_ESI))
2142                         save_esi = TRUE;
2143                 if (dest_reg != X86_EDI && source_reg != X86_EDI &&
2144                     mono_regset_reg_used (s->rs, X86_EDI))
2145                         save_edi = TRUE;
2146
2147                 if (save_esi)
2148                         x86_push_reg (s->code, X86_ESI);
2149                 if (save_edi)
2150                         x86_push_reg (s->code, X86_EDI);
2151
2152                 if (dest_reg == X86_ESI) {
2153                         dest_offset = ++spill_pos; 
2154                 }          
2155                 if (source_reg == X86_EDI) {
2156                         source_offset = ++spill_pos; 
2157                 }          
2158
2159                 if (source_offset)
2160                         x86_push_reg (s->code, source_reg);
2161                 if (dest_offset)
2162                         x86_push_reg (s->code, dest_reg);
2163         
2164                 if (source_reg != X86_ESI) {
2165                         if (source_offset)
2166                                 x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
2167                         else
2168                                 x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
2169                 }
2170                 if (dest_reg != X86_EDI) {
2171                         if (dest_offset)
2172                                 x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
2173                         else
2174                                 x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
2175                 }
2176
2177                 x86_mov_reg_imm (s->code, X86_ECX, count >> 2); 
2178                 x86_cld (s->code);
2179                 x86_prefix (s->code, X86_REP_PREFIX);
2180                 x86_movsd (s->code);
2181
2182                 switch (count & 3) {
2183                 case 1:
2184                         x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 1);
2185                         x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 1);
2186                         break;
2187                 case 2:
2188                         x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
2189                         x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
2190                         break;
2191                 case 3:
2192                         x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
2193                         x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
2194                         x86_mov_reg_membase (s->code, sreg, X86_ESI, 2, 1);
2195                         x86_mov_membase_reg (s->code, X86_EDI, 2, sreg, 1);
2196                         break;
2197                 default:
2198                         break;
2199                 }
2200
2201                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
2202
2203                 if (save_edi)
2204                         x86_pop_reg (s->code, X86_EDI);
2205                 if (save_esi)
2206                         x86_pop_reg (s->code, X86_ESI);
2207
2208                 break;
2209         }
2210 } cost {
2211         MBCOND (mono_inline_memcpy);
2212         return 0;
2213 }
2214
2215 stmt: CPBLK (reg, CPSRC (reg, reg)) {
2216         int dest_reg = tree->left->reg1;
2217         int source_reg = tree->right->left->reg1;
2218         int size_reg = tree->right->right->reg1;
2219         int spill_pos = 0, size_offset = 0, dest_offset = 0, source_offset = 0;
2220         int save_esi = FALSE, save_edi = FALSE;
2221
2222         if (!mono_inline_memcpy) {
2223                 x86_push_reg (s->code, size_reg);
2224                 x86_push_reg (s->code, source_reg);
2225                 x86_push_reg (s->code, dest_reg);
2226                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memmove);
2227                 x86_call_code (s->code, 0);
2228                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2229         } else {
2230                 if (dest_reg != X86_ESI && source_reg != X86_ESI && size_reg != X86_ESI &&
2231                     mono_regset_reg_used (s->rs, X86_ESI))
2232                         save_esi = TRUE;
2233                 if (dest_reg != X86_EDI && source_reg != X86_EDI && size_reg != X86_EDI &&
2234                     mono_regset_reg_used (s->rs, X86_EDI))
2235                         save_edi = TRUE;
2236
2237                 if (save_esi)
2238                         x86_push_reg (s->code, X86_ESI);
2239                 if (save_edi)
2240                         x86_push_reg (s->code, X86_EDI);
2241
2242                 if (size_reg == X86_EDI || size_reg == X86_ESI) {
2243                         size_offset = ++spill_pos; 
2244                 }          
2245                 if (dest_reg == X86_ECX || dest_reg == X86_ESI) {
2246                         dest_offset = ++spill_pos; 
2247                 }          
2248                 if (source_reg == X86_ECX || source_reg == X86_EDI) {
2249                         source_offset = ++spill_pos; 
2250                 }          
2251
2252                 if (source_offset)
2253                         x86_push_reg (s->code, source_reg);
2254                 if (dest_offset)
2255                         x86_push_reg (s->code, dest_reg);
2256                 if (size_offset)
2257                         x86_push_reg (s->code, size_reg);
2258         
2259                 if (source_reg != X86_ESI) {
2260                         if (source_offset)
2261                                 x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
2262                         else
2263                                 x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
2264                 }
2265                 if (dest_reg != X86_EDI) {
2266                         if (dest_offset)
2267                                 x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
2268                         else
2269                                 x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
2270                 }
2271                 if (size_reg != X86_ECX) {
2272                         if (size_offset)
2273                                 x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
2274                         else
2275                                 x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
2276                 }
2277
2278                 x86_push_reg (s->code, X86_ECX);
2279                 x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
2280
2281                 x86_cld (s->code);
2282         
2283                 // move whole dwords first
2284                 x86_prefix (s->code, X86_REP_PREFIX);
2285                 x86_movsd (s->code);
2286
2287                 x86_pop_reg (s->code, X86_ECX);
2288                 x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
2289
2290                 // move remaining bytes (if any)
2291                 x86_prefix (s->code, X86_REP_PREFIX);
2292                 x86_movsb (s->code);
2293
2294                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
2295                 
2296                 if (save_edi)
2297                         x86_pop_reg (s->code, X86_EDI);
2298                 if (save_esi)
2299                         x86_pop_reg (s->code, X86_ESI);
2300         }
2301 }
2302
2303 stmt: INITBLK (reg, CPSRC (reg, CONST_I4)) {
2304         int dest_reg = tree->left->reg1;
2305         int value_reg = tree->right->left->reg1;
2306         int size = tree->right->right->data.i;
2307         int spill_pos = 0, dest_offset = 0, value_offset = 0;
2308         int save_edi = FALSE;
2309         int i, j;
2310
2311         i = size / 4;
2312         j = size % 4;
2313
2314         if (mono_inline_memcpy) {
2315
2316                 if (dest_reg != X86_EDI && value_reg != X86_EDI &&
2317                     mono_regset_reg_used (s->rs, X86_EDI)) {
2318                         save_edi = TRUE;
2319                         x86_push_reg (s->code, X86_EDI);
2320                 }
2321
2322                 if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
2323                         dest_offset = ++spill_pos; 
2324                 }          
2325                 if (value_reg == X86_ECX || value_reg == X86_EDI) {
2326                         value_offset = ++spill_pos; 
2327                 }          
2328
2329                 if (value_offset)
2330                         x86_push_reg (s->code, value_reg);
2331                 if (dest_offset)
2332                         x86_push_reg (s->code, dest_reg);
2333
2334                 if (value_reg != X86_EAX) {
2335                         if (value_offset)
2336                                 x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
2337                         else
2338                                 x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
2339                 }
2340                 if (dest_reg != X86_EDI) {
2341                         if (dest_offset)
2342                                 x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
2343                         else
2344                                 x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
2345                 }
2346
2347                 x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
2348                 x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
2349                 x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
2350                 x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
2351                 x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
2352                 x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
2353                 x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
2354
2355                 if (i) {
2356                         x86_mov_reg_imm (s->code, X86_ECX, i);
2357                         x86_cld (s->code);
2358                         x86_prefix (s->code, X86_REP_PREFIX);
2359                         x86_stosd (s->code);
2360                 }
2361
2362                 for (i = 0; i < j; i++)
2363                         x86_stosb (s->code);
2364         
2365                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
2366
2367                 if (save_edi)
2368                         x86_pop_reg (s->code, X86_EDI);
2369
2370         } else {
2371                 x86_push_imm (s->code, size);
2372                 x86_push_reg (s->code, value_reg);
2373                 x86_push_reg (s->code, dest_reg);
2374                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
2375                 x86_call_code (s->code, 0);
2376                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2377         }
2378 } cost {
2379         MBCOND (mono_inline_memcpy);
2380         return 0;
2381 }
2382
2383 stmt: INITBLK (reg, CPSRC (reg, reg)) {
2384         int dest_reg = tree->left->reg1;
2385         int value_reg = tree->right->left->reg1;
2386         int size_reg = tree->right->right->reg1;
2387         int spill_pos = 0, size_offset = 0, dest_offset = 0, value_offset = 0;
2388         int save_edi = FALSE;
2389
2390         if (mono_inline_memcpy) {
2391
2392                 if (dest_reg != X86_EDI && size_reg != X86_EDI && size_reg != X86_EDI &&
2393                     mono_regset_reg_used (s->rs, X86_EDI)) {
2394                         save_edi = TRUE;
2395                         x86_push_reg (s->code, X86_EDI);
2396                 }
2397
2398                 if (size_reg == X86_EDI || size_reg == X86_EAX) {
2399                         size_offset = ++spill_pos; 
2400                 }          
2401                 if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
2402                         dest_offset = ++spill_pos; 
2403                 }          
2404                 if (value_reg == X86_ECX || value_reg == X86_EDI) {
2405                         value_offset = ++spill_pos; 
2406                 }          
2407
2408                 if (value_offset)
2409                         x86_push_reg (s->code, value_reg);
2410                 if (dest_offset)
2411                         x86_push_reg (s->code, dest_reg);
2412                 if (size_offset)
2413                         x86_push_reg (s->code, size_reg);
2414
2415                 if (value_reg != X86_EAX) {
2416                         if (value_offset)
2417                                 x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
2418                         else
2419                                 x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
2420                 }
2421                 if (dest_reg != X86_EDI) {
2422                         if (dest_offset)
2423                                 x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
2424                         else
2425                                 x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
2426                 }
2427                 if (size_reg != X86_ECX) {
2428                         if (size_offset)
2429                                 x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
2430                         else
2431                                 x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
2432                 }
2433
2434                 x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
2435                 x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
2436                 x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
2437                 x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
2438                 x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
2439                 x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
2440                 x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
2441
2442                 x86_push_reg (s->code, X86_ECX);
2443                 x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
2444                 x86_cld (s->code);
2445
2446                 // init whole dwords first
2447                 x86_prefix (s->code, X86_REP_PREFIX);
2448                 x86_stosd (s->code);
2449
2450                 x86_pop_reg (s->code, X86_ECX);
2451                 x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
2452
2453                 // init remaining bytes (if any)
2454                 x86_prefix (s->code, X86_REP_PREFIX);
2455                 x86_stosb (s->code);
2456
2457                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
2458
2459                 if (save_edi)
2460                         x86_pop_reg (s->code, X86_EDI);
2461
2462         } else {
2463                 x86_push_reg (s->code, size_reg);
2464                 x86_push_reg (s->code, value_reg);
2465                 x86_push_reg (s->code, dest_reg);
2466                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
2467                 x86_call_code (s->code, 0);
2468                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2469         }
2470 }
2471
2472 stmt: NOP
2473
2474 stmt: POP (reg)
2475
2476 stmt: BR {
2477         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2478         x86_jump32 (s->code, 0); 
2479 }
2480
2481 cflags: COMPARE (reg, LDIND_I4 (ADDR_L)) {
2482         int treg = VARINFO (s, tree->right->left->data.i).reg;
2483         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, treg);
2484 } cost {
2485         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
2486         return 0;
2487 }
2488
2489 cflags: COMPARE (LDIND_I4 (ADDR_L), CONST_I4) {
2490         int treg = VARINFO (s, tree->left->left->data.i).reg;
2491         x86_alu_reg_imm (s->code, X86_CMP, treg, tree->right->data.i);
2492 } cost {
2493         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
2494         return 0;
2495 }
2496
2497 cflags: COMPARE (LDIND_I4 (ADDR_L), reg) {
2498         int treg = VARINFO (s, tree->left->left->data.i).reg;
2499         x86_alu_reg_reg (s->code, X86_CMP, treg, tree->right->reg1);
2500 } cost {
2501         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
2502         return 0;
2503 }
2504
2505 cflags: COMPARE (LDIND_I4 (ADDR_L), CONST_I4) {
2506         int offset = VARINFO (s, tree->left->left->data.i).offset;
2507         x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset,  tree->right->data.i);
2508 } cost {
2509         MBCOND ((VARINFO (data, tree->left->left->data.i).reg < 0));
2510         return 0;
2511 }
2512
2513 cflags: COMPARE (reg, CONST_I4) {
2514         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
2515 }
2516
2517 cflags: COMPARE (reg, reg) {
2518         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2519 }
2520
2521
2522 stmt: CBRANCH (cflags) {
2523         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
2524
2525         switch (tree->data.bi.cond) {
2526         case CEE_BLT:
2527                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE); 
2528                 break;
2529         case CEE_BLT_UN:
2530                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE); 
2531                 break;
2532         case CEE_BGT:
2533                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE); 
2534                 break;
2535         case CEE_BGT_UN:
2536                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE); 
2537                 break;
2538         case CEE_BEQ:
2539                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2540                 break;
2541         case CEE_BNE_UN:
2542                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
2543                 break;
2544         case CEE_BGE:
2545                 x86_branch32 (s->code, X86_CC_GE, 0, TRUE);
2546                 break;
2547         case CEE_BGE_UN:
2548                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
2549                 break;
2550         case CEE_BLE:
2551                 x86_branch32 (s->code, X86_CC_LE, 0, TRUE);
2552                 break;
2553         case CEE_BLE_UN:
2554                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
2555                 break;
2556         default:
2557                 g_assert_not_reached ();
2558         }
2559 }
2560
2561 stmt: BRTRUE (LDIND_I4 (ADDR_L)) {
2562         int treg = VARINFO (s, tree->left->left->data.i).reg;
2563         int offset = VARINFO (s, tree->left->left->data.i).offset;
2564
2565         if (treg >= 0)
2566                 x86_test_reg_reg (s->code, treg, treg);
2567         else
2568                 x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, 0);
2569
2570         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2571         x86_branch32 (s->code, X86_CC_NE, 0, TRUE);
2572 }
2573
2574 stmt: BRTRUE (reg) {
2575         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2576         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2577         x86_branch32 (s->code, X86_CC_NE, 0, TRUE);
2578 }
2579
2580 stmt: BRFALSE (LDIND_I4 (ADDR_L)) {
2581         int treg = VARINFO (s, tree->left->left->data.i).reg;
2582         int offset = VARINFO (s, tree->left->left->data.i).offset;
2583
2584         if (treg >= 0)
2585                 x86_test_reg_reg (s->code, treg, treg);
2586         else
2587                 x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, 0);
2588
2589         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2590         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2591
2592         //{static int cx= 0; printf ("CX1 %5d\n", cx++);}
2593 }
2594
2595 stmt: BRFALSE (reg) {
2596         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2597         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2598         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2599 }
2600
2601 stmt: BREAK {
2602         x86_breakpoint (s->code);
2603 }
2604
2605 stmt: RET (reg) {
2606         if (tree->left->reg1 != X86_EAX)
2607                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
2608
2609         if (!tree->last_instr) {
2610                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
2611                 x86_jump32 (s->code, 0);      
2612         }
2613 }
2614
2615 stmt: RET_VOID {
2616         if (!tree->last_instr) {
2617                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
2618                 x86_jump32 (s->code, 0);      
2619         } 
2620 }
2621
2622
2623 stmt: ARG_I4 (LDIND_I4 (addr)) {
2624         MBTree *at = tree->left->left;
2625
2626         switch (at->data.ainfo.amode) {
2627
2628         case AMImmediate:
2629                 x86_push_mem (s->code, at->data.ainfo.offset);
2630                 break;
2631
2632         case AMBase:
2633                 x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
2634                 break;          
2635         case AMIndex:
2636                 x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
2637                                    at->data.ainfo.indexreg, at->data.ainfo.shift);
2638                 break;          
2639         case AMBaseIndex:
2640                 x86_push_memindex (s->code, at->data.ainfo.basereg, 
2641                                    at->data.ainfo.offset, at->data.ainfo.indexreg, 
2642                                    at->data.ainfo.shift);
2643                 break;          
2644         }
2645 }
2646
2647 stmt: ARG_I4 (LDIND_I4 (ADDR_L)) {
2648         int treg = VARINFO (s, tree->left->left->data.i).reg;
2649         x86_push_reg (s->code, treg);
2650 } cost {
2651         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
2652         return 0;
2653 }
2654
2655 stmt: ARG_I4 (reg) {
2656         x86_push_reg (s->code, tree->left->reg1);
2657         PRINT_REG ("ARG_I4",  tree->left->reg1);
2658 }
2659
2660 stmt: ARG_I4 (ADDR_G) {
2661         x86_push_imm (s->code, tree->left->data.p);
2662 }
2663
2664 stmt: ARG_I4 (CONST_I4) "MB_USE_OPT1(0)" {
2665         x86_push_imm (s->code, tree->left->data.i);
2666 }
2667
2668 this: reg {
2669         PRINT_REG ("THIS", tree->reg1);
2670 }
2671
2672 reg: CHECKTHIS (reg) {
2673         /* try to access the vtable - this will raise an exception
2674          * if the object is NULL */
2675         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, 0, 0);
2676         if (tree->reg1 != tree->left->reg1)
2677                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2678 }
2679
2680 stmt: CHECKTHIS (reg) {
2681         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, 0, 0);
2682 }
2683
2684 stmt: JMP
2685 {
2686         int pos = -4;
2687
2688         /* restore callee saved registers */
2689         if (mono_regset_reg_used (s->rs, X86_EBX)) {
2690                 x86_mov_reg_membase (s->code, X86_EBX, X86_EBP, pos, 4);
2691                 pos -= 4;
2692         }
2693         if (mono_regset_reg_used (s->rs, X86_EDI)) {
2694                 x86_mov_reg_membase (s->code, X86_EDI, X86_EBP, pos, 4);
2695                 pos -= 4;
2696         }
2697         if (mono_regset_reg_used (s->rs, X86_ESI)) {
2698                 x86_mov_reg_membase (s->code, X86_ESI, X86_EBP, pos, 4);
2699                 pos -= 4;
2700         }
2701         /* restore ESP/EBP */
2702         x86_leave (s->code);
2703
2704         /* jump to the method */
2705         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
2706         x86_jump32 (s->code, 0);
2707 }
2708
2709 this: NOP
2710
2711 reg: CALL_I4 (this, reg) {
2712         int treg = X86_EAX;
2713         int lreg = tree->left->reg1;
2714         int rreg = tree->right->reg1;
2715         
2716         if (lreg == treg || rreg == treg) 
2717                 treg = X86_EDX;
2718         if (lreg == treg || rreg == treg) 
2719                 treg = X86_ECX;
2720         if (lreg == treg || rreg == treg) 
2721                 mono_assert_not_reached ();
2722
2723         if (tree->left->op != MB_TERM_NOP) {
2724                 mono_assert (lreg >= 0);
2725                 x86_push_reg (s->code, lreg);
2726                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2727         }
2728
2729         if (tree->data.ci.vtype_num) {
2730                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2731                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2732                 x86_push_reg (s->code, treg);
2733         }
2734
2735         x86_call_reg (s->code, rreg);
2736
2737         if (tree->data.ci.args_size)
2738                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2739         
2740         PRINT_REG ("CALL_I4", tree->reg1);
2741
2742         mono_assert (tree->reg1 == X86_EAX);
2743 }
2744
2745 reg: CALL_I4 (this, ADDR_G) {
2746         int lreg = tree->left->reg1;
2747         int treg = X86_EAX;
2748
2749         if (lreg == treg) 
2750                 treg = X86_EDX;
2751         
2752         if (tree->left->op != MB_TERM_NOP) {
2753                 mono_assert (lreg >= 0);
2754                 x86_push_reg (s->code, lreg);
2755                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2756         }
2757
2758         if (tree->data.ci.vtype_num) {
2759                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2760                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2761                 x86_push_reg (s->code, treg);
2762         }
2763
2764         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
2765         x86_call_code (s->code, 0);
2766
2767         if (tree->data.ci.args_size)
2768                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2769
2770         PRINT_REG ("CALL_I4", tree->reg1);
2771
2772         mono_assert (tree->reg1 == X86_EAX);
2773 }
2774
2775 reg: LDVIRTFTN (reg, INTF_ADDR) {
2776         /* we cant return the value in the vtable, because it can be
2777          * a magic trampoline, and we cant pass that to the outside world */
2778         
2779         if (tree->reg1 != X86_EAX)
2780                 x86_push_reg (s->code, X86_EAX);
2781         x86_push_reg (s->code, X86_ECX);
2782         x86_push_reg (s->code, X86_EDX);
2783
2784         x86_push_imm (s->code, tree->right->data.m->klass->interface_id);
2785         x86_push_reg (s->code, tree->left->reg1);
2786         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldintftn);
2787         x86_call_code (s->code, 0);
2788         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
2789
2790         x86_pop_reg (s->code, X86_EDX);
2791         x86_pop_reg (s->code, X86_ECX);
2792         if (tree->reg1 != X86_EAX) {
2793                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
2794                 x86_pop_reg (s->code, X86_EAX);
2795         }
2796 }
2797
2798 reg: CALL_I4 (this, INTF_ADDR) {
2799         int lreg = tree->left->reg1;
2800         int treg = X86_EAX;
2801
2802         if (lreg == treg) 
2803                 treg = X86_EDX;
2804
2805         if (tree->left->op != MB_TERM_NOP) {
2806                 mono_assert (lreg >= 0);
2807                 x86_push_reg (s->code, lreg);
2808         }
2809
2810         if (tree->data.ci.vtype_num) {
2811                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2812                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2813                 x86_push_reg (s->code, treg);
2814         }
2815
2816         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2817         x86_mov_reg_membase (s->code, lreg, lreg, 
2818                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2819         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2820         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2821
2822         if (tree->data.ci.args_size)
2823                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2824
2825         PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
2826
2827         mono_assert (tree->reg1 == X86_EAX);
2828 }
2829
2830 reg: LDVIRTFTN (reg, VFUNC_ADDR) {
2831         /* we cant return the value in the vtable, because it can be
2832          * a magic trampoline, and we cant pass that to the outside world */
2833         
2834         if (tree->reg1 != X86_EAX)
2835                 x86_push_reg (s->code, X86_EAX);
2836         x86_push_reg (s->code, X86_ECX);
2837         x86_push_reg (s->code, X86_EDX);
2838
2839         x86_push_imm (s->code, tree->right->data.m->slot);
2840         x86_push_reg (s->code, tree->left->reg1);
2841         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldvirtftn);
2842         x86_call_code (s->code, 0);
2843         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
2844
2845         x86_pop_reg (s->code, X86_EDX);
2846         x86_pop_reg (s->code, X86_ECX);
2847         if (tree->reg1 != X86_EAX) {
2848                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
2849                 x86_pop_reg (s->code, X86_EAX);
2850         }
2851 }
2852
2853 reg: LDFTN {
2854         if (tree->reg1 != X86_EAX)
2855                 x86_push_reg (s->code, X86_EAX);
2856         x86_push_reg (s->code, X86_ECX);
2857         x86_push_reg (s->code, X86_EDX);
2858
2859         x86_push_imm (s->code, tree->data.m);
2860         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldftn);
2861         x86_call_code (s->code, 0);
2862         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
2863
2864         x86_pop_reg (s->code, X86_EDX);
2865         x86_pop_reg (s->code, X86_ECX);
2866         if (tree->reg1 != X86_EAX) {
2867                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
2868                 x86_pop_reg (s->code, X86_EAX);
2869         }
2870 }
2871
2872
2873 reg: CALL_I4 (this, VFUNC_ADDR) {
2874         int lreg = tree->left->reg1;
2875         int treg = X86_EAX;
2876
2877         if (lreg == treg) 
2878                 treg = X86_EDX;
2879
2880         if (tree->left->op != MB_TERM_NOP) {
2881                 mono_assert (lreg >= 0);
2882                 x86_push_reg (s->code, lreg);
2883         }
2884
2885         if (tree->data.ci.vtype_num) {
2886                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2887                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2888                 x86_push_reg (s->code, treg);
2889         }
2890
2891         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);        
2892         x86_call_virtual (s->code, lreg, 
2893                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
2894
2895         if (tree->data.ci.args_size)
2896                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2897
2898         PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
2899
2900         mono_assert (tree->reg1 == X86_EAX);
2901 }
2902
2903 stmt: CALL_VOID (this, ADDR_G) {
2904         int lreg = tree->left->reg1;
2905         int treg = X86_EAX;
2906
2907         if (lreg == treg) 
2908                 treg = X86_EDX;
2909         
2910         if (tree->left->op != MB_TERM_NOP) {
2911                 mono_assert (lreg >= 0);
2912                 x86_push_reg (s->code, lreg);
2913                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2914         }
2915
2916         if (tree->data.ci.vtype_num) {
2917                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2918                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2919                 x86_push_reg (s->code, treg);
2920         }
2921
2922         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
2923         x86_call_code (s->code, 0);
2924
2925         if (tree->data.ci.args_size)
2926                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2927 }
2928
2929 stmt: CALL_VOID (this, reg) {
2930         int treg = X86_EAX;
2931         int lreg = tree->left->reg1;
2932         int rreg = tree->right->reg1;
2933
2934         if (lreg == treg || rreg == treg) 
2935                 treg = X86_EDX;
2936         if (lreg == treg || rreg == treg) 
2937                 treg = X86_ECX;
2938         if (lreg == treg || rreg == treg) 
2939                 mono_assert_not_reached ();
2940         
2941         if (tree->left->op != MB_TERM_NOP) {
2942                 mono_assert (lreg >= 0);
2943                 x86_push_reg (s->code, lreg);
2944                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2945         }
2946
2947         if (tree->data.ci.vtype_num) {
2948                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2949                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2950                 x86_push_reg (s->code, treg);
2951         }
2952
2953         x86_call_reg (s->code, tree->right->reg1);
2954
2955         if (tree->data.ci.args_size)
2956                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2957 }
2958
2959 stmt: CALL_VOID (this, INTF_ADDR) {
2960         int lreg = tree->left->reg1;
2961         int treg = X86_EAX;
2962
2963         if (lreg == treg) 
2964                 treg = X86_EDX;
2965
2966         if (tree->left->op != MB_TERM_NOP) {
2967                 mono_assert (lreg >= 0);
2968                 x86_push_reg (s->code, lreg);
2969         }
2970
2971         if (tree->data.ci.vtype_num) {
2972                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2973                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2974                 x86_push_reg (s->code, treg);
2975         }
2976
2977         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2978         x86_mov_reg_membase (s->code, lreg, lreg, 
2979                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2980         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2981         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2982
2983         if (tree->data.ci.args_size)
2984                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2985 }
2986
2987 stmt: CALL_VOID (this, VFUNC_ADDR) {
2988         int lreg = tree->left->reg1;
2989         int treg = X86_EAX;
2990
2991         if (lreg == treg) 
2992                 treg = X86_EDX;
2993
2994         if (tree->left->op != MB_TERM_NOP) {
2995                 mono_assert (lreg >= 0);
2996                 x86_push_reg (s->code, lreg);
2997         }
2998
2999         if (tree->data.ci.vtype_num) {
3000                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3001                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3002                 x86_push_reg (s->code, treg);
3003         }
3004
3005         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3006         x86_call_virtual (s->code, lreg, 
3007                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
3008
3009         if (tree->data.ci.args_size)
3010                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3011 }
3012
3013 stmt: SWITCH (reg) {
3014         guint32 offset;
3015         guint32 *jt = (guint32 *)tree->data.p;
3016
3017         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, jt [0]);
3018         offset = 6 + (guint32)s->code;
3019         x86_branch32 (s->code, X86_CC_GE, jt [jt [0] + 1] - offset, FALSE);
3020
3021         x86_mov_reg_memindex (s->code, X86_EAX, X86_NOBASEREG, 
3022                               tree->data.i + 4, tree->left->reg1, 2, 4);        
3023         x86_jump_reg (s->code, X86_EAX);
3024 }
3025
3026 #
3027 # 64 bit integers
3028 #
3029
3030 reg: CONV_I1 (lreg) {
3031         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
3032
3033
3034 reg: CONV_U1 (lreg) {
3035         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
3036
3037
3038 reg: CONV_I2 (lreg) {
3039         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
3040
3041
3042 reg: CONV_U2 (lreg) {
3043         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
3044
3045
3046 reg: CONV_I4 (lreg) {
3047         if (tree->reg1 != tree->left->reg1)
3048                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3049
3050
3051 reg: CONV_U4 (lreg) {
3052         if (tree->reg1 != tree->left->reg1)
3053                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3054
3055
3056
3057 reg: CONV_OVF_I4 (lreg){
3058         guint8 *start = s->code;
3059         guchar* o1, *o2, *o3, *o4, *o5;
3060         int i;
3061
3062         /* 
3063          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3064          */
3065         for (i = 0; i < 2; i++) {
3066                 s->code = start;
3067
3068                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
3069
3070                 /* If the low word top bit is set, see if we are negative */
3071                 x86_branch8 (s->code, X86_CC_LT, o3 - o1, TRUE);
3072                 o1 = s->code;
3073
3074                 /* We are not negative (no top bit set, check for our top word to be zero */
3075                 x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
3076                 x86_branch8 (s->code, X86_CC_EQ, o4 - o2, TRUE);
3077                 o2 = s->code;
3078
3079                 /* throw exception */
3080                 x86_push_imm (s->code, "OverflowException");
3081                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
3082                                     arch_get_throw_exception_by_name ());
3083                 x86_call_code (s->code, 0);
3084         
3085                 o3 = s->code;
3086                 /* our top bit is set, check that top word is 0xfffffff */
3087                 x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg2, 0xffffffff);
3088                 
3089                 o4 = s->code;
3090                 /* nope, emit exception */
3091                 x86_branch8 (s->code, X86_CC_NE, o2 - o5, TRUE);
3092                 o5 = s->code;
3093
3094                 if (tree->reg1 != tree->left->reg1)
3095                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3096         }
3097 }
3098 reg: CONV_OVF_I4 (lreg){
3099         guint8 *br [3], *label [1];
3100
3101         /* 
3102          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3103          */
3104         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
3105
3106         /* If the low word top bit is set, see if we are negative */
3107         br [0] = s->code; x86_branch8 (s->code, X86_CC_LT, 0, TRUE);
3108
3109         /* We are not negative (no top bit set, check for our top word to be zero */
3110         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
3111         br [1] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, TRUE);
3112         label [0] = s->code;
3113
3114         /* throw exception */
3115         x86_push_imm (s->code, "OverflowException");
3116         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
3117                             arch_get_throw_exception_by_name ());
3118         x86_call_code (s->code, 0);
3119         
3120         x86_patch (br [0], s->code);
3121         /* our top bit is set, check that top word is 0xfffffff */
3122         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg2, 0xffffffff);
3123                 
3124         x86_patch (br [1], s->code);
3125         /* nope, emit exception */
3126         br [2] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3127         x86_patch (br [2], label [0]);
3128
3129         if (tree->reg1 != tree->left->reg1)
3130                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3131 }
3132
3133 reg: CONV_OVF_U4 (lreg) {
3134         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
3135         /* top word must be 0 */
3136         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
3137         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
3138         if (tree->reg1 != tree->left->reg1)
3139                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3140 }
3141
3142 reg: CONV_OVF_I4_UN (lreg) {
3143         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
3144         /* top word must be 0 */
3145         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
3146         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
3147         if (tree->reg1 != tree->left->reg1)
3148                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3149 }
3150
3151 stmt: POP (lreg)
3152
3153 lreg: CONST_I8 1 {
3154         x86_mov_reg_imm (s->code, tree->reg1, *((gint32 *)&tree->data.p));
3155         x86_mov_reg_imm (s->code, tree->reg2, *((gint32 *)&tree->data.p + 1));
3156 }
3157
3158 lreg: CONV_I8 (CONST_I4) {
3159         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
3160
3161         if (tree->left->data.i >= 0)
3162                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3163         else 
3164                 x86_mov_reg_imm (s->code, tree->reg2, -1);              
3165 }
3166
3167 lreg: CONV_I8 (reg) {
3168         guint8 *i1;
3169
3170         if (tree->reg1 != tree->left->reg1)
3171                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3172
3173         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3174         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
3175         x86_branch8 (s->code, X86_CC_GE, 5, TRUE);
3176         i1 = s->code;
3177         x86_mov_reg_imm (s->code, tree->reg2, -1); 
3178         mono_assert ((s->code - i1) == 5);
3179 }
3180
3181 lreg: CONV_U8 (CONST_I4) 1 {
3182         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
3183         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3184 }
3185
3186 lreg: CONV_U8 (reg) {
3187         if (tree->reg1 != tree->left->reg1)
3188                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3189         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3190 }
3191
3192 lreg: CONV_OVF_U8 (CONST_I4) {
3193         if (tree->left->data.i < 0){
3194                 x86_push_imm (s->code, "OverflowException");
3195                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
3196                                     arch_get_throw_exception_by_name ());
3197                 x86_call_code (s->code, 0);
3198         } else {
3199                 x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
3200                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3201         }
3202 }
3203
3204 lreg: CONV_OVF_I8_UN (CONST_I4) {
3205         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
3206         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3207 }
3208
3209 lreg: CONV_OVF_U8 (reg) {
3210         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
3211         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
3212
3213         if (tree->reg1 != tree->left->reg1)
3214                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3215         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3216 }
3217
3218 lreg: CONV_OVF_I8_UN (reg) {
3219         /* Convert uint value into int64, we pass everything */
3220         if (tree->reg1 != tree->left->reg1)
3221                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3222         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
3223 }
3224
3225 stmt: STIND_I8 (addr, lreg) {
3226
3227         switch (tree->left->data.ainfo.amode) {
3228
3229         case AMImmediate:
3230                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
3231                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
3232                 break;
3233                 
3234         case AMBase:
3235                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
3236                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
3237                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
3238                                      tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
3239                 break;          
3240         case AMIndex:
3241                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
3242                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
3243                                       tree->right->reg1, 4);
3244                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset + 4,
3245                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
3246                                       tree->right->reg2, 4);
3247                 break;          
3248         case AMBaseIndex:
3249                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
3250                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
3251                                       tree->right->reg1, 4);
3252                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset + 4,
3253                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
3254                                       tree->right->reg2, 4);
3255                 break;          
3256         }
3257 }
3258
3259 stmt: REMOTE_STIND_I8 (reg, lreg) {
3260         guint8 *br[2];
3261         int offset;
3262
3263         x86_push_reg (s->code, tree->right->reg1);
3264         x86_mov_reg_membase (s->code, tree->right->reg1, tree->left->reg1, 0, 4);
3265         x86_alu_membase_imm (s->code, X86_CMP, tree->right->reg1, 0, ((int)mono_defaults.transparent_proxy_class));
3266         x86_pop_reg (s->code, tree->right->reg1);
3267         
3268         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3269
3270         /* this is a transparent proxy - remote the call */
3271
3272         /* save value to stack */
3273         x86_push_reg (s->code, tree->right->reg2);
3274         x86_push_reg (s->code, tree->right->reg1);
3275
3276         x86_push_reg (s->code, X86_ESP);
3277         x86_push_imm (s->code, tree->data.fi.field);
3278         x86_push_imm (s->code, tree->data.fi.klass);
3279         x86_push_reg (s->code, tree->left->reg1);
3280         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
3281         x86_call_code (s->code, 0);
3282         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 24);
3283
3284         br [1] = s->code; x86_jump8 (s->code, 0);
3285
3286         x86_patch (br [0], s->code);
3287         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
3288                 tree->data.fi.field->offset;
3289         x86_mov_membase_reg (s->code, tree->left->reg1, offset, tree->right->reg1, 4);
3290         x86_mov_membase_reg (s->code, tree->left->reg1, offset + 4, tree->right->reg2, 4);
3291
3292         x86_patch (br [1], s->code);
3293 }
3294
3295
3296 # an addr can use two address register (base and index register). The must take care 
3297 # that we do not override them (thus the use of x86_lea)
3298 lreg: LDIND_I8 (addr) {
3299
3300         switch (tree->left->data.ainfo.amode) {
3301
3302         case AMImmediate:
3303                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
3304                 x86_mov_reg_mem (s->code, tree->reg2, tree->left->data.ainfo.offset + 4, 4);
3305                 break;
3306
3307         case AMBase:
3308                 x86_lea_membase (s->code, tree->reg2, tree->left->data.ainfo.basereg,
3309                                  tree->left->data.ainfo.offset);
3310                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
3311                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
3312                 break;          
3313         case AMIndex:
3314                 x86_lea_memindex (s->code, tree->reg2, X86_NOBASEREG, tree->left->data.ainfo.offset,
3315                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift);
3316                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
3317                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
3318                 break;          
3319         case AMBaseIndex:
3320                 x86_lea_memindex (s->code, tree->reg2, tree->left->data.ainfo.basereg, 
3321                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3322                                   tree->left->data.ainfo.shift);
3323                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
3324                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
3325                 break;          
3326         }
3327         PRINT_REG ("LDIND_I8_0", tree->reg1);
3328         PRINT_REG ("LDIND_I8_1", tree->reg2);
3329 }
3330
3331 lreg: SHR (lreg, CONST_I4) {
3332         if (tree->right->data.i < 32) {
3333                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
3334                 x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg2, tree->right->data.i);
3335                 if (tree->reg1 != tree->left->reg1)
3336                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3337                 if (tree->reg2 != tree->left->reg2)
3338                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
3339         } else if (tree->right->data.i < 64) {
3340                 if (tree->reg1 != tree->left->reg2)
3341                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
3342                 if (tree->reg2 != tree->left->reg2)
3343                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
3344                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);
3345                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg1, (tree->right->data.i - 32));
3346         } /* else unspecified result */
3347 }
3348
3349 lreg: SHR_UN (lreg, CONST_I4) {
3350         if (tree->right->data.i < 32) {
3351                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
3352                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg2, tree->right->data.i);
3353                 if (tree->reg1 != tree->left->reg1)
3354                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3355                 if (tree->reg2 != tree->left->reg2)
3356                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
3357         } else if (tree->right->data.i < 64) {
3358                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
3359                 x86_shift_reg_imm (s->code, X86_SHR, tree->reg1, (tree->right->data.i - 32));
3360                 x86_mov_reg_imm (s->code, tree->reg2, 0);
3361         } /* else unspecified result */
3362 }
3363
3364 lreg: SHR (lreg, reg) {
3365         guint8 *br [1];
3366
3367         if (tree->right->reg1 != X86_ECX)
3368                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
3369
3370         x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
3371         x86_shift_reg (s->code, X86_SAR, tree->left->reg2);
3372         x86_test_reg_imm (s->code, X86_ECX, 32);
3373         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
3374         x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
3375         x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);           
3376         x86_patch (br [0], s->code);
3377
3378         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3379 }
3380
3381 lreg: SHR_UN (lreg, reg) {
3382         guint8 *br [1];
3383
3384         if (tree->right->reg1 != X86_ECX)
3385                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
3386
3387         x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
3388         x86_shift_reg (s->code, X86_SHR, tree->left->reg2);
3389         x86_test_reg_imm (s->code, X86_ECX, 32);
3390         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
3391         x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
3392         x86_shift_reg_imm (s->code, X86_SHR, tree->reg2, 31);           
3393         x86_patch (br [0], s->code);
3394
3395         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3396 }
3397
3398 lreg: SHL (lreg, CONST_I4) {
3399         if (tree->right->data.i < 32) {
3400                 x86_shld_reg_imm (s->code, tree->left->reg2, tree->left->reg1, tree->right->data.i);
3401                 x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
3402                 if (tree->reg1 != tree->left->reg1)
3403                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3404                 if (tree->reg2 != tree->left->reg2)
3405                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
3406         } else if (tree->right->data.i < 64) {
3407                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg1, 4);
3408                 x86_shift_reg_imm (s->code, X86_SHL, tree->reg2, (tree->right->data.i - 32));
3409                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg1, tree->reg1);     
3410         } /* else unspecified result */
3411 }
3412
3413 lreg: SHL (lreg, reg) {
3414         guint8 *br [1];
3415
3416         if (tree->right->reg1 != X86_ECX)
3417                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
3418
3419         x86_shld_reg (s->code, tree->left->reg2, tree->left->reg1);
3420         x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
3421         x86_test_reg_imm (s->code, X86_ECX, 32);
3422         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
3423         x86_mov_reg_reg (s->code, tree->left->reg2, tree->left->reg1, 4);
3424         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->left->reg1); 
3425         x86_patch (br [0], s->code);
3426
3427         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3428 }
3429
3430 lreg: ADD (lreg, lreg) {
3431         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
3432         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
3433
3434         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3435 }
3436
3437 lreg: ADD_OVF (lreg, lreg) {
3438         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
3439         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
3440         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
3441
3442         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3443 }
3444
3445 lreg: ADD_OVF_UN (lreg, lreg) {
3446         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
3447         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
3448         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
3449
3450         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3451 }
3452
3453 lreg: SUB (lreg, lreg) {
3454         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
3455         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
3456
3457         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3458 }
3459
3460 lreg: SUB_OVF (lreg, lreg) {
3461         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
3462         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
3463         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
3464
3465         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3466 }
3467
3468 lreg: SUB_OVF_UN (lreg, lreg) {
3469         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
3470         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
3471         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
3472
3473         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3474 }
3475
3476 lreg: AND (lreg, lreg) {
3477         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
3478         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg2, tree->right->reg2);
3479
3480         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3481 }
3482
3483 lreg: OR (lreg, lreg) {
3484         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
3485         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg2, tree->right->reg2);
3486
3487         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3488 }
3489
3490 lreg: XOR (lreg, lreg) {
3491         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->right->reg1);
3492         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg2, tree->right->reg2);
3493
3494         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3495 }
3496
3497 lreg: NEG (lreg) {
3498         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3499
3500         x86_neg_reg (s->code, tree->reg1);
3501         x86_alu_reg_imm (s->code, X86_ADC, tree->reg2, 0);
3502         x86_neg_reg (s->code, tree->reg2);
3503 }
3504
3505 lreg: NOT (lreg) {
3506         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
3507
3508         x86_not_reg (s->code, tree->reg1);
3509         x86_not_reg (s->code, tree->reg2);
3510 }
3511
3512 lreg: MUL (lreg, lreg) {
3513         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3514                 x86_push_reg (s->code, X86_ECX);
3515
3516         x86_push_reg (s->code, tree->right->reg2);
3517         x86_push_reg (s->code, tree->right->reg1);
3518         x86_push_reg (s->code, tree->left->reg2);
3519         x86_push_reg (s->code, tree->left->reg1);
3520         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult);
3521         x86_call_code (s->code, 0);
3522         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3523
3524         if (mono_regset_reg_used (s->rs, X86_ECX))
3525                 x86_pop_reg (s->code, X86_ECX);
3526
3527         mono_assert (tree->reg1 == X86_EAX &&
3528                   tree->reg2 == X86_EDX);
3529 }
3530
3531 lreg: MUL_OVF (lreg, lreg) {
3532         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3533                 x86_push_reg (s->code, X86_ECX);
3534
3535         x86_push_reg (s->code, tree->right->reg2);
3536         x86_push_reg (s->code, tree->right->reg1);
3537         x86_push_reg (s->code, tree->left->reg2);
3538         x86_push_reg (s->code, tree->left->reg1);
3539         /* pass a pointer to store the resulting exception -
3540          * ugly, but it works */
3541         x86_push_reg (s->code, X86_ESP); 
3542         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult_ovf);
3543         x86_call_code (s->code, 0);
3544         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
3545         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
3546         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
3547
3548         /* cond. emit exception */
3549         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
3550         x86_push_reg (s->code, X86_ECX);
3551         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
3552         x86_call_code (s->code, 0);
3553
3554         if (mono_regset_reg_used (s->rs, X86_ECX))
3555                 x86_pop_reg (s->code, X86_ECX);
3556
3557         mono_assert (tree->reg1 == X86_EAX &&
3558                      tree->reg2 == X86_EDX);
3559 }
3560
3561 lreg: MUL_OVF_UN (lreg, lreg) {
3562         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3563                 x86_push_reg (s->code, X86_ECX);
3564
3565         x86_push_reg (s->code, tree->right->reg2);
3566         x86_push_reg (s->code, tree->right->reg1);
3567         x86_push_reg (s->code, tree->left->reg2);
3568         x86_push_reg (s->code, tree->left->reg1);
3569         /* pass a pointer to store the resulting exception -
3570          * ugly, but it works */
3571         x86_push_reg (s->code, X86_ESP); 
3572         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult_ovf_un);
3573         x86_call_code (s->code, 0);
3574         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
3575         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
3576         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
3577
3578         /* cond. emit exception */
3579         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
3580         x86_push_reg (s->code, X86_ECX);                                 
3581         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
3582         x86_call_code (s->code, 0);
3583
3584         if (mono_regset_reg_used (s->rs, X86_ECX))
3585                 x86_pop_reg (s->code, X86_ECX);
3586
3587         mono_assert (tree->reg1 == X86_EAX &&
3588                      tree->reg2 == X86_EDX);
3589 }
3590
3591 lreg: DIV (lreg, lreg) {
3592         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3593                 x86_push_reg (s->code, X86_ECX);
3594
3595         x86_push_reg (s->code, tree->right->reg2);
3596         x86_push_reg (s->code, tree->right->reg1);
3597         x86_push_reg (s->code, tree->left->reg2);
3598         x86_push_reg (s->code, tree->left->reg1);
3599         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_lldiv);
3600         x86_call_code (s->code, 0);
3601         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3602
3603         if (mono_regset_reg_used (s->rs, X86_ECX))
3604                 x86_pop_reg (s->code, X86_ECX);
3605
3606         mono_assert (tree->reg1 == X86_EAX &&
3607                      tree->reg2 == X86_EDX);
3608 }
3609
3610 lreg: REM (lreg, lreg) {
3611         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3612                 x86_push_reg (s->code, X86_ECX);
3613
3614         x86_push_reg (s->code, tree->right->reg2);
3615         x86_push_reg (s->code, tree->right->reg1);
3616         x86_push_reg (s->code, tree->left->reg2);
3617         x86_push_reg (s->code, tree->left->reg1);
3618         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llrem);
3619         x86_call_code (s->code, 0);
3620         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3621
3622         if (mono_regset_reg_used (s->rs, X86_ECX))
3623                 x86_pop_reg (s->code, X86_ECX);
3624
3625         mono_assert (tree->reg1 == X86_EAX &&
3626                      tree->reg2 == X86_EDX);
3627 }
3628
3629 lreg: DIV_UN (lreg, lreg) {
3630         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3631                 x86_push_reg (s->code, X86_ECX);
3632
3633         x86_push_reg (s->code, tree->right->reg2);
3634         x86_push_reg (s->code, tree->right->reg1);
3635         x86_push_reg (s->code, tree->left->reg2);
3636         x86_push_reg (s->code, tree->left->reg1);
3637         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_lldiv_un);
3638         x86_call_code (s->code, 0);
3639         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3640
3641         if (mono_regset_reg_used (s->rs, X86_ECX))
3642                 x86_pop_reg (s->code, X86_ECX);
3643
3644         mono_assert (tree->reg1 == X86_EAX &&
3645                      tree->reg2 == X86_EDX);
3646 }
3647
3648 lreg: REM_UN (lreg, lreg) {
3649         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3650                 x86_push_reg (s->code, X86_ECX);
3651
3652         x86_push_reg (s->code, tree->right->reg2);
3653         x86_push_reg (s->code, tree->right->reg1);
3654         x86_push_reg (s->code, tree->left->reg2);
3655         x86_push_reg (s->code, tree->left->reg1);
3656         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llrem_un);
3657         x86_call_code (s->code, 0);
3658         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3659
3660         if (mono_regset_reg_used (s->rs, X86_ECX))
3661                 x86_pop_reg (s->code, X86_ECX);
3662
3663         mono_assert (tree->reg1 == X86_EAX &&
3664                      tree->reg2 == X86_EDX);
3665 }
3666
3667 lreg: CALL_I8 (this, reg) {
3668         int treg = X86_EAX;
3669         int lreg = tree->left->reg1;
3670         int rreg = tree->right->reg1;
3671         
3672         if (lreg == treg || rreg == treg) 
3673                 treg = X86_EDX;
3674         if (lreg == treg || rreg == treg) 
3675                 treg = X86_ECX;
3676         if (lreg == treg || rreg == treg) 
3677                 mono_assert_not_reached ();
3678
3679         if (tree->left->op != MB_TERM_NOP) {
3680                 mono_assert (lreg >= 0);
3681                 x86_push_reg (s->code, lreg);
3682                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
3683         }
3684
3685         if (tree->data.ci.vtype_num) {
3686                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3687                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3688                 x86_push_reg (s->code, treg);
3689         }
3690
3691         x86_call_reg (s->code, rreg);
3692
3693         if (tree->data.ci.args_size)
3694                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3695         
3696         PRINT_REG ("CALL_I8", tree->reg1);
3697
3698         mono_assert (tree->reg1 == X86_EAX);
3699         mono_assert (tree->reg2 == X86_EDX);
3700 }
3701
3702 lreg: CALL_I8 (this, ADDR_G) {
3703         int lreg = tree->left->reg1;
3704         int treg = X86_EAX;
3705
3706         if (lreg == treg) 
3707                 treg = X86_EDX;
3708         
3709         if (tree->left->op != MB_TERM_NOP) {
3710                 mono_assert (lreg >= 0);
3711                 x86_push_reg (s->code, lreg);
3712                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
3713         }
3714
3715         if (tree->data.ci.vtype_num) {
3716                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3717                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3718                 x86_push_reg (s->code, treg);
3719         }
3720
3721         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
3722         x86_call_code (s->code, 0);
3723
3724         if (tree->data.ci.args_size)
3725                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3726
3727         mono_assert (tree->reg1 == X86_EAX);
3728         mono_assert (tree->reg2 == X86_EDX);
3729 }
3730
3731 lreg: CALL_I8 (this, VFUNC_ADDR) {
3732         int lreg = tree->left->reg1;
3733         int treg = X86_EAX;
3734
3735         if (lreg == treg) 
3736                 treg = X86_EDX;
3737
3738         if (tree->left->op != MB_TERM_NOP) {
3739                 mono_assert (lreg >= 0);
3740                 x86_push_reg (s->code, lreg);
3741         }
3742
3743         if (tree->data.ci.vtype_num) {
3744                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3745                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3746                 x86_push_reg (s->code, treg);
3747         }
3748
3749         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3750         x86_call_virtual (s->code, lreg, 
3751                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
3752
3753         if (tree->data.ci.args_size)
3754                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3755
3756         PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
3757         PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
3758
3759         mono_assert (tree->reg1 == X86_EAX);
3760         mono_assert (tree->reg2 == X86_EDX);
3761 }
3762
3763 lreg: CALL_I8 (this, INTF_ADDR) {
3764         int lreg = tree->left->reg1;
3765         int treg = X86_EAX;
3766
3767         if (lreg == treg) 
3768                 treg = X86_EDX;
3769
3770         if (tree->left->op != MB_TERM_NOP) {
3771                 mono_assert (lreg >= 0);
3772                 x86_push_reg (s->code, lreg);
3773         }
3774
3775         if (tree->data.ci.vtype_num) {
3776                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3777                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3778                 x86_push_reg (s->code, treg);
3779         }
3780
3781         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3782         x86_mov_reg_membase (s->code, lreg, lreg, 
3783                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
3784         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
3785         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
3786
3787         if (tree->data.ci.args_size)
3788                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3789
3790         PRINT_REG ("CALL_I8(INTERFACE)", tree->reg1);
3791
3792         mono_assert (tree->reg1 == X86_EAX);
3793         mono_assert (tree->reg2 == X86_EDX);
3794 }
3795
3796 stmt: RET (lreg) {
3797         if (tree->left->reg1 != X86_EAX) {
3798                 if (tree->left->reg2 != X86_EAX) {
3799                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
3800                         if (tree->left->reg2 != X86_EDX)
3801                                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
3802                 } else { 
3803                         x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg2, 4);
3804                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
3805                         x86_mov_reg_reg (s->code, X86_EDX, X86_ECX, 4);
3806                 }
3807         } else if (tree->left->reg2 != X86_EDX) {
3808                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
3809         }
3810
3811         if (!tree->last_instr) {
3812                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
3813                 x86_jump32 (s->code, 0);      
3814         }
3815 }
3816
3817
3818 stmt: ARG_I8 (lreg) {
3819         x86_push_reg (s->code, tree->left->reg2);
3820         x86_push_reg (s->code, tree->left->reg1);
3821 }
3822
3823 reg: CSET (COMPARE (lreg, lreg)) {
3824         guint8 *br [4];
3825         int lreg1, lreg2, rreg1, rreg2;
3826
3827         lreg1 = tree->left->left->reg1;
3828         lreg2 = tree->left->left->reg2;
3829         rreg1 = tree->left->right->reg1;
3830         rreg2 = tree->left->right->reg2;
3831
3832
3833         if (tree->data.i == CEE_CEQ) {
3834                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3835                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3836                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3837                 x86_patch (br [0], s->code);
3838                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, FALSE);
3839                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
3840                 return;
3841         }
3842
3843         switch (tree->data.i) {
3844         case CEE_CGT:
3845                 x86_alu_reg_reg (s->code, X86_CMP, rreg2, lreg2);
3846                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, TRUE);
3847                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3848                 x86_alu_reg_reg (s->code, X86_CMP, rreg1, lreg1);
3849                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3850                 break;
3851         case CEE_CGT_UN:
3852                 x86_alu_reg_reg (s->code, X86_CMP, rreg2, lreg2);
3853                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, FALSE);
3854                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3855                 x86_alu_reg_reg (s->code, X86_CMP, rreg1, lreg1);
3856                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3857                 break;
3858         case CEE_CLT:
3859                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3860                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, TRUE);
3861                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3862                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3863                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3864                 break;
3865         case CEE_CLT_UN:
3866                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3867                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, FALSE);
3868                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3869                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3870                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3871                 break;
3872         default:
3873                 g_assert_not_reached ();
3874         }
3875
3876         /* set result to 1 */
3877         x86_patch (br [1], s->code);
3878         x86_mov_reg_imm (s->code, tree->reg1, 1);
3879         br [3] = s->code; x86_jump8 (s->code, 0);
3880
3881         /* set result to 0 */
3882         x86_patch (br [0], s->code);
3883         x86_patch (br [2], s->code);
3884         x86_mov_reg_imm (s->code, tree->reg1, 0);       
3885
3886         x86_patch (br [3], s->code);
3887 }
3888
3889 stmt: CBRANCH (COMPARE (lreg, lreg)) {
3890         guint8 *br [1];
3891         int lreg1, lreg2, rreg1, rreg2;
3892
3893         lreg1 = tree->left->left->reg1;
3894         lreg2 = tree->left->left->reg2;
3895         rreg1 = tree->left->right->reg1;
3896         rreg2 = tree->left->right->reg2;
3897
3898         switch (tree->data.bi.cond) {
3899         case CEE_BLT:
3900                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3901                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3902                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
3903                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3904                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3905                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3906                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3907                 x86_patch (br [0], s->code);    
3908                 break;
3909         case CEE_BLT_UN:
3910                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3911                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3912                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3913                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3914                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3915                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3916                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3917                 x86_patch (br [0], s->code);    
3918                 break;
3919         case CEE_BGT:
3920                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3921                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3922                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
3923                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3924                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3925                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3926                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3927                 x86_patch (br [0], s->code);    
3928                 break;
3929         case CEE_BGT_UN:
3930                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3931                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3932                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3933                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3934                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3935                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3936                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3937                 x86_patch (br [0], s->code);    
3938                 break;
3939         case CEE_BEQ:
3940                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3941                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3942                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3943                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3944                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
3945                 x86_patch (br [0], s->code);
3946                 break;
3947         case CEE_BNE_UN:
3948                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3949                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3950                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3951                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3952                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3953                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3954                 break;
3955         case CEE_BGE:
3956                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3957                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3958                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
3959                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3960                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3961                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3962                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3963                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
3964                 x86_patch (br [0], s->code);
3965                 break;
3966         case CEE_BGE_UN:
3967                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3968                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3969                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3970                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3971                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3972                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3973                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
3974                 x86_patch (br [0], s->code);    
3975                 break;
3976         case CEE_BLE:
3977                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3978                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3979                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
3980                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3981                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3982                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3983                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
3984                 x86_patch (br [0], s->code);    
3985                 break;
3986         case CEE_BLE_UN:
3987                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3988                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3989                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3990                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3991                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3992                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3993                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
3994                 x86_patch (br [0], s->code);    
3995                 break;
3996         default:
3997                 g_assert_not_reached ();
3998         }       
3999 }
4000
4001 #
4002 # floating point 
4003
4004 #stmt: STLOC (CONV_I4 (freg)) {
4005 #       // fixme: set CW
4006 #       x86_fist_pop_membase (s->code, X86_EBP, tree->data.i, FALSE);
4007 #} 
4008
4009 reg: CONV_I1 (freg) {
4010         if (mono_use_fast_iconv) {
4011                 mono_emit_fast_iconv(s, tree);
4012                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, FALSE);
4013         } else {
4014                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4015                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4016                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4017                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4018                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4019                 x86_fldcw_membase (s->code, X86_ESP, 2);
4020                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4021                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4022                 x86_pop_reg (s->code, tree->reg1);
4023                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, FALSE);
4024                 x86_fldcw_membase (s->code, X86_ESP, 0);
4025                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4026         }
4027 }
4028
4029 reg: CONV_U1 (freg) {
4030         if (mono_use_fast_iconv) {
4031                 mono_emit_fast_iconv(s, tree);
4032                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
4033         } else {
4034                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4035                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4036                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4037                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4038                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4039                 x86_fldcw_membase (s->code, X86_ESP, 2);
4040                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4041                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4042                 x86_pop_reg (s->code, tree->reg1);
4043                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
4044                 x86_fldcw_membase (s->code, X86_ESP, 0);
4045                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4046         }
4047 }
4048
4049 reg: CONV_I2 (freg) {
4050         if (mono_use_fast_iconv) {
4051                 mono_emit_fast_iconv(s, tree);
4052                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, TRUE);
4053         } else {
4054                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4055                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4056                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4057                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4058                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4059                 x86_fldcw_membase (s->code, X86_ESP, 2);
4060                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4061                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4062                 x86_pop_reg (s->code, tree->reg1);
4063                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, TRUE);
4064                 x86_fldcw_membase (s->code, X86_ESP, 0);
4065                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4066         }
4067 }
4068
4069 reg: CONV_U2 (freg) {
4070         if (mono_use_fast_iconv) {
4071                 mono_emit_fast_iconv(s, tree);
4072                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, TRUE);
4073         } else {
4074                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4075                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4076                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4077                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4078                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4079                 x86_fldcw_membase (s->code, X86_ESP, 2);
4080                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4081                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4082                 x86_pop_reg (s->code, tree->reg1);
4083                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, TRUE);
4084                 x86_fldcw_membase (s->code, X86_ESP, 0);
4085                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4086         }
4087 }
4088
4089 reg: CONV_I4 (freg) {
4090         if (mono_use_fast_iconv) {
4091                 mono_emit_fast_iconv(s, tree);
4092         } else {
4093                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4094                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4095                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4096                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4097                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4098                 x86_fldcw_membase (s->code, X86_ESP, 2);
4099                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4100                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4101                 x86_pop_reg (s->code, tree->reg1);
4102                 x86_fldcw_membase (s->code, X86_ESP, 0);
4103                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4104         }
4105 }
4106
4107 reg: CONV_U4 (freg) {
4108         if (mono_use_fast_iconv) {
4109                 mono_emit_fast_iconv(s, tree);
4110         } else {
4111                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4112                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4113                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4114                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4115                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4116                 x86_fldcw_membase (s->code, X86_ESP, 2);
4117                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
4118                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
4119                 x86_pop_reg (s->code, tree->reg1);
4120                 x86_fldcw_membase (s->code, X86_ESP, 0);
4121                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4122         }
4123 }
4124
4125 lreg: CONV_I8 (freg) {
4126         if (mono_use_fast_iconv) {
4127                 mono_emit_fast_iconv_i8(s, tree);
4128         } else {
4129                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4130                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4131                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4132                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4133                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4134                 x86_fldcw_membase (s->code, X86_ESP, 2);
4135                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
4136                 x86_fist_pop_membase (s->code, X86_ESP, 0, TRUE);
4137                 x86_pop_reg (s->code, tree->reg1);
4138                 x86_pop_reg (s->code, tree->reg2);
4139                 x86_fldcw_membase (s->code, X86_ESP, 0);
4140                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4141         }
4142 }
4143
4144 lreg: CONV_U8 (freg) {
4145         if (mono_use_fast_iconv) {
4146                 mono_emit_fast_iconv_i8(s, tree);
4147         } else {
4148                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4149                 x86_fnstcw_membase(s->code, X86_ESP, 0);
4150                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
4151                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
4152                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
4153                 x86_fldcw_membase (s->code, X86_ESP, 2);
4154                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
4155                 x86_fist_pop_membase (s->code, X86_ESP, 0, TRUE);
4156                 x86_pop_reg (s->code, tree->reg1);
4157                 x86_pop_reg (s->code, tree->reg2);
4158                 x86_fldcw_membase (s->code, X86_ESP, 0);
4159                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4160         }
4161 }
4162
4163 reg: CSET (COMPARE (freg, freg)) {
4164         int treg = tree->reg1;
4165
4166         if (treg != X86_EAX)
4167                 x86_push_reg (s->code, X86_EAX);
4168
4169         x86_fcompp (s->code);
4170         x86_fnstsw (s->code);
4171         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
4172
4173         switch (tree->data.i) {
4174         case CEE_CEQ:
4175                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
4176                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
4177                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
4178                 break;
4179         case CEE_CGT:
4180                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4181                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
4182                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
4183                 break;
4184         case CEE_CGT_UN:
4185                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4186                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
4187                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
4188                 break;
4189         case CEE_CLT:
4190                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
4191                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
4192                 break;
4193         case CEE_CLT_UN:
4194                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
4195                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
4196                 break;
4197         default:
4198                 g_assert_not_reached ();
4199         }
4200         
4201         if (treg != X86_EAX)
4202                 x86_pop_reg (s->code, X86_EAX);
4203 }
4204
4205 freg: CONV_R8 (freg) {
4206         /* nothing to do */
4207 }
4208
4209 freg: CONV_R4 (freg) {
4210         /* fixme: nothing to do ??*/
4211 }
4212
4213 freg: CONV_R8 (LDIND_I4 (ADDR_G)) {
4214         x86_fild (s->code, tree->left->left->data.p, FALSE);
4215 }
4216
4217 freg: CONV_R4 (reg) {
4218         x86_push_reg (s->code, tree->left->reg1);
4219         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
4220         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4221 }
4222
4223 freg: CONV_R8 (reg) {
4224         x86_push_reg (s->code, tree->left->reg1);
4225         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
4226         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
4227 }
4228
4229 freg: CONV_R_UN (reg) {
4230         x86_push_imm (s->code, 0);
4231         x86_push_reg (s->code, tree->left->reg1);
4232         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
4233         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
4234 }
4235
4236 freg: CONV_R_UN (lreg) {
4237         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
4238         guint8 *br [1];
4239
4240         /* load 64bit integer to FP stack */
4241         x86_push_imm (s->code, 0);
4242         x86_push_reg (s->code, tree->left->reg2);
4243         x86_push_reg (s->code, tree->left->reg1);
4244         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
4245         /* store as 80bit FP value */
4246         x86_fst80_membase (s->code, X86_ESP, 0);
4247
4248         /* test if lreg is negative */
4249         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
4250         br [0] = s->code; x86_branch8 (s->code, X86_CC_GEZ, 0, TRUE);
4251
4252         /* add correction constant mn */
4253         x86_fld80_mem (s->code, mn);
4254         x86_fld80_membase (s->code, X86_ESP, 0);
4255         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
4256         x86_fst80_membase (s->code, X86_ESP, 0);
4257
4258         x86_patch (br [0], s->code);
4259
4260         x86_fld80_membase (s->code, X86_ESP, 0);
4261         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4262 }
4263
4264 freg: CONV_R4 (lreg) {
4265         x86_push_reg (s->code, tree->left->reg2);
4266         x86_push_reg (s->code, tree->left->reg1);
4267         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
4268         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
4269 }
4270
4271 freg: CONV_R8 (lreg) {
4272         x86_push_reg (s->code, tree->left->reg2);
4273         x86_push_reg (s->code, tree->left->reg1);
4274         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
4275         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
4276 }
4277
4278 freg: CONST_R4 {
4279         float f = *(float *)tree->data.p;
4280
4281         if (f == 0.0)
4282                 x86_fldz (s->code);
4283         else if (f == 1.0)
4284                 x86_fld1(s->code);
4285         else
4286                 x86_fld (s->code, tree->data.p, FALSE);
4287 }
4288
4289 freg: CONST_R8 {
4290         double d = *(double *)tree->data.p;
4291
4292         if (d == 0.0)
4293                 x86_fldz (s->code);
4294         else if (d == 1.0)
4295                 x86_fld1(s->code);
4296         else
4297                 x86_fld (s->code, tree->data.p, TRUE);
4298 }
4299
4300 freg: LDIND_R4 (addr) {
4301
4302         switch (tree->left->data.ainfo.amode) {
4303
4304         case AMImmediate:
4305                 x86_fld (s->code, tree->left->data.ainfo.offset, FALSE);
4306                 break;
4307
4308         case AMBase:
4309                 x86_fld_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, FALSE);
4310                 break;          
4311         case AMIndex:
4312                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
4313                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4314                                   tree->left->data.ainfo.shift);
4315                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE);
4316                 break;          
4317         case AMBaseIndex:
4318                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
4319                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4320                                   tree->left->data.ainfo.shift);
4321                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE);
4322                 break;          
4323         }
4324 }
4325
4326 freg: LDIND_R8 (addr) {
4327
4328         switch (tree->left->data.ainfo.amode) {
4329
4330         case AMImmediate:
4331                 x86_fld (s->code, tree->left->data.ainfo.offset, TRUE);
4332                 break;
4333
4334         case AMBase:
4335                 x86_fld_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, TRUE);
4336                 break;          
4337         case AMIndex:
4338                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
4339                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4340                                   tree->left->data.ainfo.shift);
4341                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE);
4342                 break;          
4343         case AMBaseIndex:
4344                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
4345                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4346                                   tree->left->data.ainfo.shift);
4347                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE);
4348                 break;          
4349         }
4350 }
4351
4352
4353 freg: ADD (freg, freg) {
4354         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
4355 }
4356
4357 freg: SUB (freg, freg) {
4358         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE);
4359 }
4360
4361 freg: MUL (freg, freg) {
4362         x86_fp_op_reg (s->code, X86_FMUL, 1, TRUE);
4363 }
4364
4365 freg: DIV (freg, freg) {
4366         x86_fp_op_reg (s->code, X86_FDIV, 1, TRUE);
4367 }
4368
4369 freg: CKFINITE (freg) {
4370         x86_push_reg (s->code, X86_EAX);
4371         x86_fxam (s->code);
4372         x86_fnstsw (s->code);
4373         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4100);
4374         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4375         x86_pop_reg (s->code, X86_EAX);
4376         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, FALSE, "ArithmeticException");
4377 }
4378
4379 freg: REM (freg, freg) {
4380         guint8 *l1, *l2;
4381
4382         /* we need to exchange ST(0) with ST(1) */
4383         x86_fxch (s->code, 1);
4384
4385         /* this requires a loop, because fprem1 somtimes 
4386          * returns a partial remainder */
4387         l1 = s->code;
4388         x86_fprem1 (s->code);
4389         x86_fnstsw (s->code);
4390         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x0400);
4391         l2 = s->code + 2;
4392         x86_branch8 (s->code, X86_CC_NE, l1 - l2, FALSE);
4393
4394         /* pop result */
4395         x86_fstp (s->code, 1);
4396 }
4397
4398 freg: NEG (freg) {
4399         x86_fchs (s->code);
4400 }
4401
4402 stmt: POP (freg)
4403
4404 stmt: STIND_R4 (addr, freg) {
4405
4406         switch (tree->left->data.ainfo.amode) {
4407
4408         case AMImmediate:
4409                 x86_fst (s->code, tree->left->data.ainfo.offset, FALSE, TRUE);
4410                 break;
4411
4412         case AMBase:
4413                 x86_fst_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, 
4414                                  FALSE, TRUE);
4415                 break;          
4416         case AMIndex:
4417                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
4418                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4419                                   tree->left->data.ainfo.shift);
4420                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE, TRUE);
4421                 break;          
4422         case AMBaseIndex:
4423                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
4424                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4425                                   tree->left->data.ainfo.shift);
4426                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE, TRUE);
4427                 break;          
4428         }
4429 }
4430
4431 stmt: STIND_R8 (addr, freg) {
4432
4433         switch (tree->left->data.ainfo.amode) {
4434
4435         case AMImmediate:
4436                 x86_fst (s->code, tree->left->data.ainfo.offset, TRUE, TRUE);
4437                 break;
4438
4439         case AMBase:
4440                 x86_fst_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, 
4441                                  TRUE, TRUE);
4442                 break;          
4443         case AMIndex:
4444                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
4445                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4446                                   tree->left->data.ainfo.shift);
4447                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE, TRUE);
4448                 break;          
4449         case AMBaseIndex:
4450                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
4451                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
4452                                   tree->left->data.ainfo.shift);
4453                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE, TRUE);
4454                 break;          
4455         }
4456 }
4457
4458 stmt: REMOTE_STIND_R4 (reg, freg) {
4459         guint8 *br[2];
4460         int treg = X86_EAX;
4461         int lreg = tree->left->reg1;
4462         int offset;
4463
4464         if (lreg == treg)
4465                 treg = X86_EDX;
4466
4467         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
4468         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
4469         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE); 
4470
4471         /* this is a transparent proxy - remote the call */
4472
4473         /* save value to stack */
4474         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4475         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
4476
4477         x86_push_reg (s->code, X86_ESP);
4478         x86_push_imm (s->code, tree->data.fi.field);
4479         x86_push_imm (s->code, tree->data.fi.klass);
4480         x86_push_reg (s->code, lreg);
4481         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
4482         x86_call_code (s->code, 0);
4483         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
4484
4485         br [1] = s->code; x86_jump8 (s->code, 0); 
4486
4487         x86_patch (br [0], s->code);
4488         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
4489                 tree->data.fi.field->offset;
4490         x86_fst_membase (s->code, lreg, offset, FALSE, TRUE);
4491
4492         x86_patch (br [1], s->code);
4493 }
4494
4495 stmt: REMOTE_STIND_R8 (reg, freg) {
4496         guint8 *br[2];
4497         int treg = X86_EAX;
4498         int lreg = tree->left->reg1;
4499         int offset;
4500
4501         if (lreg == treg)
4502                 treg = X86_EDX;
4503
4504         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
4505         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
4506         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE); 
4507
4508         /* this is a transparent proxy - remote the call */
4509
4510         /* save value to stack */
4511         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
4512         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
4513
4514         x86_push_reg (s->code, X86_ESP);
4515         x86_push_imm (s->code, tree->data.fi.field);
4516         x86_push_imm (s->code, tree->data.fi.klass);
4517         x86_push_reg (s->code, lreg);
4518         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
4519         x86_call_code (s->code, 0);
4520         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 24);
4521
4522         br [1] = s->code; x86_jump8 (s->code, 0);
4523
4524         x86_patch (br [0], s->code);
4525         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
4526                 tree->data.fi.field->offset;
4527         x86_fst_membase (s->code, lreg, offset, TRUE, TRUE);
4528
4529         x86_patch (br [1], s->code);
4530 }
4531
4532 stmt: ARG_R4 (freg) {
4533         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
4534         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
4535 }
4536
4537 stmt: ARG_R8 (freg) {
4538         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
4539         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
4540 }
4541
4542 # fixme: we need to implement unordered and ordered compares
4543
4544 stmt: CBRANCH (COMPARE (freg, freg)) {
4545
4546         x86_fcompp (s->code);
4547         x86_fnstsw (s->code);
4548         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
4549
4550         switch (tree->data.bi.cond) {
4551         case CEE_BLT:
4552                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4553                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
4554                 break;
4555         case CEE_BLT_UN:
4556                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4557                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
4558                 break;
4559         case CEE_BGT:
4560                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4561                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4562                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
4563                 break;
4564         case CEE_BGT_UN:
4565                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4566                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4567                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
4568                 break;
4569         case CEE_BEQ:
4570                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
4571                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4572                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
4573                 break;
4574         case CEE_BNE_UN:
4575                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
4576                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4577                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
4578                 break;
4579         case CEE_BGE:
4580                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4581                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
4582                 break;
4583         case CEE_BGE_UN:
4584                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4585                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
4586                 break;
4587         case CEE_BLE:
4588                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4589                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4590                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
4591                 break;
4592         case CEE_BLE_UN:
4593                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
4594                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
4595                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
4596                 break;
4597         default:
4598                 g_assert_not_reached ();
4599         }
4600 }
4601
4602 freg: CALL_R8 (this, reg) {
4603         int treg = X86_EAX;
4604         int lreg = tree->left->reg1;
4605         int rreg = tree->right->reg1;
4606         
4607         if (lreg == treg || rreg == treg) 
4608                 treg = X86_EDX;
4609         if (lreg == treg || rreg == treg) 
4610                 treg = X86_ECX;
4611         if (lreg == treg || rreg == treg) 
4612                 mono_assert_not_reached ();
4613
4614         if (tree->left->op != MB_TERM_NOP) {
4615                 mono_assert (lreg >= 0);
4616                 x86_push_reg (s->code, lreg);
4617                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
4618         }
4619
4620         if (tree->data.ci.vtype_num) {
4621                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4622                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4623                 x86_push_reg (s->code, treg);
4624         }
4625
4626         x86_call_reg (s->code, rreg);
4627
4628         if (tree->data.ci.args_size)
4629                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);   
4630 }
4631
4632 freg: CALL_R8 (this, ADDR_G) {
4633         int lreg = tree->left->reg1;
4634         int treg = X86_EAX;
4635
4636         if (lreg == treg) 
4637                 treg = X86_EDX;
4638         
4639         if (tree->left->op != MB_TERM_NOP) {
4640                 mono_assert (lreg >= 0);
4641                 x86_push_reg (s->code, lreg);
4642                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
4643         }
4644
4645         if (tree->data.ci.vtype_num) {
4646                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4647                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4648                 x86_push_reg (s->code, treg);
4649         }
4650
4651         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
4652         x86_call_code (s->code, 0);
4653
4654         if (tree->data.ci.args_size)
4655                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4656 }
4657
4658 freg: CALL_R8 (this, INTF_ADDR) {
4659         int lreg = tree->left->reg1;
4660         int treg = X86_EAX;
4661
4662         if (lreg == treg) 
4663                 treg = X86_EDX;
4664
4665         if (tree->left->op != MB_TERM_NOP) {
4666                 mono_assert (lreg >= 0);
4667                 x86_push_reg (s->code, lreg);
4668         }
4669
4670         if (tree->data.ci.vtype_num) {
4671                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4672                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4673                 x86_push_reg (s->code, treg);
4674         }
4675
4676         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
4677         x86_mov_reg_membase (s->code, lreg, lreg, 
4678                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
4679         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
4680         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
4681
4682         if (tree->data.ci.args_size)
4683                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4684 }
4685
4686 freg: CALL_R8 (this, VFUNC_ADDR) {
4687         int lreg = tree->left->reg1;
4688         int treg = X86_EAX;
4689
4690         if (lreg == treg) 
4691                 treg = X86_EDX;
4692
4693         if (tree->left->op != MB_TERM_NOP) {
4694                 mono_assert (lreg >= 0);
4695                 x86_push_reg (s->code, lreg);
4696         }
4697
4698         if (tree->data.ci.vtype_num) {
4699                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4700                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4701                 x86_push_reg (s->code, treg);
4702         }
4703
4704         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
4705         x86_call_virtual (s->code, lreg, 
4706                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
4707
4708         if (tree->data.ci.args_size)
4709                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4710 }
4711
4712 stmt: RET (freg) {
4713         if (!tree->last_instr) {
4714                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
4715                 x86_jump32 (s->code, 0);      
4716         }
4717 }
4718
4719 freg: SIN (freg) {
4720         x86_fsin (s->code);
4721 }
4722
4723 freg: COS (freg) {
4724         x86_fcos (s->code);
4725 }
4726
4727 freg: SQRT (freg) {
4728         x86_fsqrt (s->code);
4729 }
4730
4731 # support for value types
4732
4733 reg: LDIND_OBJ (reg) {
4734         if (tree->left->reg1 != tree->reg1)
4735                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
4736 }
4737
4738 stmt: STIND_OBJ (reg, reg) {
4739         mono_assert (tree->data.i > 0);
4740
4741         x86_push_imm (s->code, tree->data.i);
4742         x86_push_reg (s->code, tree->right->reg1);
4743         x86_push_reg (s->code, tree->left->reg1);
4744         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4745         x86_call_code (s->code, 0);
4746         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4747 }
4748
4749 stmt: REMOTE_STIND_OBJ (reg, reg) {
4750         guint8 *br[2];
4751         int treg = X86_EAX;
4752         int lreg = tree->left->reg1;
4753         int rreg = tree->right->reg1;
4754         int size, offset;
4755
4756         if (lreg == treg)
4757                 treg = X86_EDX;
4758
4759         if (rreg == treg)
4760                 treg = X86_ECX;
4761
4762         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
4763         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
4764         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
4765
4766         /* this is a transparent proxy - remote the call */
4767
4768         x86_push_reg (s->code, rreg);
4769         x86_push_imm (s->code, tree->data.fi.field);
4770         x86_push_imm (s->code, tree->data.fi.klass);
4771         x86_push_reg (s->code, lreg);
4772         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
4773         x86_call_code (s->code, 0);
4774         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
4775
4776         br [1] = s->code; x86_jump8 (s->code, 0);
4777
4778         x86_patch (br [0], s->code);
4779
4780         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
4781                 tree->data.fi.field->offset;
4782
4783         size = mono_class_value_size (tree->data.fi.field->type->data.klass, NULL);
4784         x86_push_imm (s->code, size);
4785         x86_push_reg (s->code, tree->right->reg1);
4786         x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, offset);   
4787         x86_push_reg (s->code, tree->left->reg1);
4788         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4789         x86_call_code (s->code, 0);
4790         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4791
4792         x86_patch (br [1], s->code);
4793 }
4794
4795 stmt: ARG_OBJ (CONST_I4) {
4796         x86_push_imm (s->code, tree->left->data.i);     
4797 }
4798
4799 stmt: ARG_OBJ (reg) {
4800         int size = tree->data.i;
4801         int sa;
4802         
4803         mono_assert (size > 0);
4804         sa = size + 3;
4805         sa &= ~3;
4806
4807         /* reserve space for the argument */
4808         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
4809
4810         x86_push_reg (s->code, X86_EAX);
4811         x86_push_reg (s->code, X86_EDX);
4812         x86_push_reg (s->code, X86_ECX);
4813
4814         x86_push_imm (s->code, size);
4815         x86_push_reg (s->code, tree->left->reg1);
4816         x86_lea_membase (s->code, X86_EAX, X86_ESP, 5*4);
4817         x86_push_reg (s->code, X86_EAX);
4818
4819         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4820         x86_call_code (s->code, 0);
4821         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4822
4823         x86_pop_reg (s->code, X86_ECX);
4824         x86_pop_reg (s->code, X86_EDX);
4825         x86_pop_reg (s->code, X86_EAX);
4826 }
4827
4828 stmt: RET_OBJ (reg) {
4829         int size = tree->data.i;
4830
4831         x86_push_imm (s->code, size);
4832         x86_push_reg (s->code, tree->left->reg1);
4833         x86_push_membase (s->code, X86_EBP, 8);
4834
4835
4836         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4837         x86_call_code (s->code, 0);
4838
4839         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4840
4841         if (!tree->last_instr) {
4842                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
4843                 x86_jump32 (s->code, 0);      
4844         }
4845 }
4846
4847 %% 
4848
4849 #include "jit.h"
4850
4851 gint64 
4852 mono_llmult (gint64 a, gint64 b)
4853 {
4854         return a * b;
4855 }
4856
4857 guint64  
4858 mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh)
4859 {
4860         guint64 res, t1;
4861
4862         // fixme: this is incredible slow
4863
4864         if (ah && bh)
4865                 goto raise_exception;
4866
4867         res = (guint64)al * (guint64)bl;
4868
4869         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
4870
4871         if (t1 > 0xffffffff)
4872                 goto raise_exception;
4873
4874         res += ((guint64)t1) << 32; 
4875
4876         *exc = NULL;
4877         return res;
4878
4879  raise_exception:
4880         *exc = mono_get_exception_overflow ();
4881         return 0;
4882 }
4883
4884 guint64  
4885 mono_llmult_ovf (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh)
4886 {
4887         gint64 res, t1;
4888
4889         // fixme: check for overflow
4890
4891         res = (gint64)al * (gint64)bl;
4892
4893         t1 = (gint64)ah * bl + al * (gint64)bh;
4894
4895         res += ((gint64)t1) << 32; 
4896
4897         *exc = NULL;
4898         return res;
4899 /*
4900  raise_exception:
4901         *exc = mono_get_exception_overflow ();
4902         return 0;
4903 */
4904 }
4905
4906 gint64 
4907 mono_lldiv (gint64 a, gint64 b)
4908 {
4909         return a / b;
4910 }
4911
4912 gint64 
4913 mono_llrem (gint64 a, gint64 b)
4914 {
4915         return a % b;
4916 }
4917
4918 guint64 
4919 mono_lldiv_un (guint64 a, guint64 b)
4920 {
4921         return a / b;
4922 }
4923
4924 guint64 
4925 mono_llrem_un (guint64 a, guint64 b)
4926 {
4927         return a % b;
4928 }
4929
4930 MonoArray*
4931 mono_array_new_wrapper  (MonoClass *eclass, guint32 n)
4932 {
4933         MonoDomain *domain = mono_domain_get ();
4934
4935         return mono_array_new (domain, eclass, n);
4936 }
4937
4938 MonoObject *
4939 mono_object_new_wrapper (MonoClass *klass)
4940 {
4941         MonoDomain *domain = mono_domain_get ();
4942
4943         return mono_object_new (domain, klass);
4944 }
4945
4946 MonoString*
4947 mono_ldstr_wrapper (MonoImage *image, guint32 ind)
4948 {
4949         MonoDomain *domain = mono_domain_get ();
4950
4951         return mono_ldstr (domain, image, ind);
4952 }
4953
4954 gpointer 
4955 mono_ldsflda (MonoClass *klass, int offset)
4956 {
4957         MonoDomain *domain = mono_domain_get ();
4958         MonoVTable *vt;
4959         gpointer addr;
4960         
4961         vt = mono_class_vtable (domain, klass);
4962         addr = (char*)(vt->data) + offset;
4963
4964         return addr;
4965 }
4966
4967 void *
4968 debug_memcopy (void *dest, const void *src, size_t n)
4969 {
4970         int i, l = n;
4971
4972         printf ("MEMCPY(%p to %p [%d]) ", src, dest, n);
4973
4974         for (i = 0; i < l; i++)
4975                 printf ("%02x ", *((guint8 *)src + i));
4976         printf ("\n");
4977         
4978         return memcpy (dest, src, n);
4979 }
4980
4981 void mono_emit_fast_iconv (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
4982 {
4983         guint8* br [3];
4984         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 12);
4985         x86_fist_membase (s->code, X86_ESP, 8, TRUE); // rounded value
4986         x86_fst_membase (s->code, X86_ESP, 0, FALSE, FALSE); // float value
4987         x86_fp_int_op_membase (s->code, X86_FSUB, X86_ESP, 8, TRUE);
4988         x86_fst_membase (s->code, X86_ESP, 4, FALSE, TRUE); // diff
4989
4990         x86_pop_reg (s->code, tree->reg1); // float value
4991         x86_test_reg_reg (s->code, tree->reg1, tree->reg1);
4992         br[0] = s->code; x86_branch8 (s->code, X86_CC_S, 0, TRUE);
4993
4994         x86_pop_reg (s->code, tree->reg1); // diff
4995         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
4996         x86_pop_reg (s->code, tree->reg1); // rounded value
4997         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, 0);
4998         br[1] = s->code; x86_jump8 (s->code, 0);
4999
5000         // freg is negative
5001         x86_patch (br[0], s->code);
5002
5003         x86_pop_reg (s->code, tree->reg1); // diff
5004         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
5005         x86_pop_reg (s->code, tree->reg1); // rounded value
5006         br[2] = s->code; x86_branch8 (s->code, X86_CC_Z, 0, FALSE);
5007         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, -1);
5008         x86_patch (br[1], s->code);
5009         x86_patch (br[2], s->code);
5010 }
5011
5012 void mono_emit_fast_iconv_i8 (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
5013 {
5014         guint8* br [3];
5015         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 16);
5016         x86_fld_reg (s->code, 0);
5017         x86_fist_pop_membase (s->code, X86_ESP, 8, TRUE); // rounded value (qword)
5018         x86_fst_membase (s->code, X86_ESP, 0, FALSE, FALSE); // float value
5019         x86_fild_membase (s->code, X86_ESP, 8, TRUE);
5020         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE); // diff
5021         x86_fst_membase (s->code, X86_ESP, 4, FALSE, TRUE); // diff
5022
5023         x86_pop_reg (s->code, tree->reg1); // float value
5024         x86_test_reg_reg (s->code, tree->reg1, tree->reg1);
5025         br[0] = s->code; x86_branch8 (s->code, X86_CC_S, 0, TRUE);
5026
5027         x86_pop_reg (s->code, tree->reg1); // diff
5028         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
5029         x86_pop_reg (s->code, tree->reg1); // rounded value
5030         x86_pop_reg (s->code, tree->reg2);
5031         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, 0);
5032         x86_alu_reg_imm (s->code, X86_SBB, tree->reg2, 0);
5033         br[1] = s->code; x86_jump8 (s->code, 0);
5034
5035         // freg is negative
5036         x86_patch (br[0], s->code);
5037
5038         x86_pop_reg (s->code, tree->reg1); // diff
5039         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
5040         x86_pop_reg (s->code, tree->reg1); // rounded value
5041         x86_pop_reg (s->code, tree->reg2);
5042         br[2] = s->code; x86_branch8 (s->code, X86_CC_Z, 0, FALSE);
5043         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, -1);
5044         x86_alu_reg_imm (s->code, X86_SBB, tree->reg2, -1);
5045         x86_patch (br[1], s->code);
5046         x86_patch (br[2], s->code);
5047 }
5048
5049 gpointer 
5050 mono_ldvirtftn (MonoObject *this, int slot)
5051 {
5052         MonoClass *class;
5053         MonoMethod *m;
5054         gpointer addr;
5055         gboolean is_proxy = FALSE;
5056         g_assert (this);
5057
5058         if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
5059                 class = ((MonoTransparentProxy *)this)->klass;
5060                 is_proxy = TRUE;
5061         }
5062
5063         
5064         g_assert (slot <= class->vtable_size);
5065
5066         m = class->vtable [slot];
5067
5068         if (is_proxy) {
5069                 return mono_jit_create_remoting_trampoline (m);
5070         } else {
5071                 EnterCriticalSection (metadata_section);
5072                 addr = mono_compile_method (m);
5073                 LeaveCriticalSection (metadata_section);
5074                 return addr;
5075         }
5076 }
5077
5078 gpointer 
5079 mono_ldintftn (MonoObject *this, int slot)
5080 {
5081         MonoClass *class;
5082         MonoMethod *m;
5083         gpointer addr;
5084         gboolean is_proxy = FALSE;
5085         g_assert (this);
5086
5087         if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
5088                 class = ((MonoTransparentProxy *)this)->klass;
5089                 is_proxy = TRUE;
5090         }
5091
5092         g_assert (slot < class->interface_count);
5093
5094         slot = class->interface_offsets [slot];
5095
5096         m = class->vtable [slot];
5097
5098         if (is_proxy) {
5099                 return mono_jit_create_remoting_trampoline (m);
5100         } else {
5101                 EnterCriticalSection (metadata_section);
5102                 addr = mono_compile_method (m);
5103                 LeaveCriticalSection (metadata_section);
5104                 return addr;
5105         }
5106 }
5107
5108 gpointer mono_ldftn (MonoMethod *method)
5109 {
5110         gpointer addr;
5111
5112         EnterCriticalSection (metadata_section);
5113         addr = mono_compile_method (method);
5114         LeaveCriticalSection (metadata_section);
5115
5116         return addr;
5117 }