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