2002-05-21 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/arch/x86/x86-codegen.h>
28
29 #include "regset.h"
30 #include "jit.h"
31
32 /*
33  * Pull the list of opcodes
34  */
35 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
36         a = i,
37
38 enum {
39 #include "mono/cil/opcode.def"
40         LAST = 0xff
41 };
42 #undef OPDEF
43
44 void print_lmf (void);
45
46 #define MBTREE_TYPE  MBTree
47 #define MBCGEN_TYPE  MonoFlowGraph
48 #define MBCOST_DATA  MonoFlowGraph
49 #define MBALLOC_STATE mono_mempool_alloc (data->mp, sizeof (MBState))
50
51 typedef enum {
52         AMImmediate       = 0,  // ptr
53         AMBase            = 1,  // V[REG]  
54         AMIndex           = 2,  // V[REG*X] 
55         AMBaseIndex       = 3,  // V[REG*X][REG] 
56 } X86AddMode;
57
58 typedef struct {
59         int           offset;
60         X86AddMode    amode:2;
61         unsigned int  shift:2;
62         gint8         basereg;
63         gint8         indexreg;
64 } X86AddressInfo;
65
66 struct _MBTree {
67         guint16   op;
68         unsigned  last_instr:1;
69         unsigned  spilled:1;
70         
71         MBTree   *left, *right;
72         gpointer  state;
73         gpointer  emit;
74
75         gint32    addr;
76         gint32    cli_addr;
77
78         gint8     reg1;
79         gint8     reg2;
80         gint8     reg3;
81         
82         MonoValueType svt;
83
84         union {
85                 gint32 i;
86                 gint64 l;
87                 gpointer p;
88                 MonoMethod *m;
89                 MonoBBlock *bb;
90                 MonoClass *klass;
91                 MonoClassField *field;
92                 X86AddressInfo ainfo;
93                 MonoJitCallInfo ci;
94                 MonoJitFieldInfo fi;
95                 MonoJitBranchInfo bi;
96         } data;
97 };
98
99 gint64   mono_llmult        (gint64 a, gint64 b);
100 guint64  mono_llmult_ovf    (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh);
101 guint64  mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh);
102 gint64   mono_lldiv         (gint64 a, gint64 b);
103 gint64   mono_llrem         (gint64 a, gint64 b);
104 guint64  mono_lldiv_un      (guint64 a, guint64 b);
105 guint64  mono_llrem_un      (guint64 a, guint64 b);
106 gpointer mono_ldsflda       (MonoClass *klass, int offset);
107
108 void mono_emit_fast_iconv(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
109 void mono_emit_fast_iconv_i8(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
110
111 MonoArray*
112 mono_array_new_wrapper  (MonoClass *eclass, guint32 n);
113 MonoObject *
114 mono_object_new_wrapper (MonoClass *klass);
115 MonoString*
116 mono_ldstr_wrapper      (MonoImage *image, guint32 ind);
117
118 gpointer
119 get_mono_object_isinst (void);
120
121 #define MB_OPT_LEVEL 1
122
123 #if MB_OPT_LEVEL == 0
124 #define MB_USE_OPT1(c) 65535
125 #define MB_USE_OPT2(c) 65535
126 #endif
127 #if MB_OPT_LEVEL == 1
128 #define MB_USE_OPT1(c) c
129 #define MB_USE_OPT2(c) 65535
130 #endif
131 #if MB_OPT_LEVEL >= 2
132 #define MB_USE_OPT1(c) c
133 #define MB_USE_OPT2(c) c
134 #endif
135
136 //#define DEBUG
137
138 #define REAL_PRINT_REG(text,reg) \
139 mono_assert (reg >= 0); \
140 x86_push_reg (s->code, X86_EAX); \
141 x86_push_reg (s->code, X86_EDX); \
142 x86_push_reg (s->code, X86_ECX); \
143 x86_push_reg (s->code, reg); \
144 x86_push_imm (s->code, reg); \
145 x86_push_imm (s->code, text " %d %p\n"); \
146 x86_mov_reg_imm (s->code, X86_EAX, printf); \
147 x86_call_reg (s->code, X86_EAX); \
148 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
149 x86_pop_reg (s->code, X86_ECX); \
150 x86_pop_reg (s->code, X86_EDX); \
151 x86_pop_reg (s->code, X86_EAX);
152
153 #ifdef DEBUG
154 #define MEMCOPY debug_memcpy
155 void *MEMCOPY (void *dest, const void *src, size_t n);
156
157 #define PRINT_REG(text,reg) REAL_PRINT_REG(text,reg)
158 #else
159
160 #define MEMCOPY memcpy
161
162 #define PRINT_REG(x,y)
163
164 #endif
165
166 /* The call instruction for virtual functions must have a known
167  * size (used by x86_magic_trampoline)
168  */
169 #define x86_call_virtual(inst,basereg,disp)                    \
170         do {                                                   \
171                 *(inst)++ = (unsigned char)0xff;               \
172                 x86_address_byte ((inst), 2, 2, (basereg));    \
173                 x86_imm_emit32 ((inst), (disp));               \
174         } while (0)
175
176 /* emit an exception if condition is fail */
177 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)       \
178         do {                                                   \
179                 gpointer t;                                    \
180                 x86_branch8 (s->code, cond, 10, signed);       \
181                 x86_push_imm (s->code, exc_name);              \
182                 t = arch_get_throw_exception_by_name ();       \
183                 mono_add_jump_info (s, s->code,                \
184                                     MONO_JUMP_INFO_ABS, t);    \
185                 x86_call_code (s->code, 0);                    \
186         } while (0); 
187
188 /* we use this macro to move one lreg to another - source and
189    destination may overlap, but the register allocator has to
190    make sure that ((d1 < d2) && (s1 < s2))
191 */
192 #define MOVE_LREG(d1,d2,s1,s2)                                        \
193         do {                                                          \
194                 g_assert ((d1 < d2) && (s1 < s2));                    \
195                 if ((d1) <= (s1)) {                                   \
196                         if ((d1) != (s1))                             \
197                                 x86_mov_reg_reg (s->code, d1, s1, 4); \
198                         if ((d2) != (s2))                             \
199                                 x86_mov_reg_reg (s->code, d2, s2, 4); \
200                 } else {                                              \
201                         if ((d2) != (s2))                             \
202                                 x86_mov_reg_reg (s->code, d2, s2, 4); \
203                         if ((d1) != (s1))                             \
204                                 x86_mov_reg_reg (s->code, d1, s1, 4); \
205                 }                                                     \
206         } while (0); 
207         
208
209 %%
210
211 #
212 # terminal definitions
213 #
214
215 # constatnts
216 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
217 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8 LDIND_OBJ 
218 %term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
219 %term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ ARG_STRING CALL_I4 CALL_I8 CALL_R8 CALL_VOID
220 %term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY
221 %term ADD ADD_OVF ADD_OVF_UN SUB SUB_OVF SUB_OVF_UN MUL MUL_OVF MUL_OVF_UN 
222 %term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
223 %term COMPARE CBRANCH BRTRUE BRFALSE CSET
224 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U1 CONV_U2 CONV_U4 CONV_U8 CONV_R4 CONV_R8 CONV_R_UN
225 %term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWARR_SPEC NEWOBJ NEWOBJ_SPEC NEWSTRUCT CPOBJ POP INITOBJ
226 %term ISINST CASTCLASS UNBOX
227 %term CONV_OVF_I1 CONV_OVF_U1 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U4 CONV_OVF_U8 CONV_OVF_I4
228 %term CONV_OVF_I4_UN CONV_OVF_U1_UN CONV_OVF_U2_UN
229 %term CONV_OVF_I2_UN CONV_OVF_I8_UN CONV_OVF_I1_UN 
230 %term EXCEPTION THROW RETHROW HANDLER CHECKTHIS
231 %term LDLEN LDELEMA LDFTN LDVIRTFTN LDSTR LDSFLDA
232 %term REMOTE_LDFLDA REMOTE_STIND_I1 REMOTE_STIND_I2 REMOTE_STIND_I4
233 %term REMOTE_STIND_I8 REMOTE_STIND_R4 REMOTE_STIND_R8 REMOTE_STIND_OBJ
234 #
235 # we start at stmt
236 #
237 %start stmt
238
239 #
240 # tree definitions
241 #
242
243 # integer constant folding
244 coni4: AND (coni4, coni4) {
245         tree->data.i = tree->left->data.i & tree->right->data.i;
246 }
247
248 coni4: OR (coni4, coni4) {
249         tree->data.i = tree->left->data.i | tree->right->data.i;
250 }
251
252 coni4: XOR (coni4, coni4) {
253         tree->data.i = tree->left->data.i ^ tree->right->data.i;
254 }
255
256 coni4: SHL (coni4, coni4) {
257         tree->data.i = tree->left->data.i << tree->right->data.i;
258 }
259
260 coni4: SHR (coni4, coni4) {
261         tree->data.i = tree->left->data.i >> tree->right->data.i;
262 }
263
264 coni4: NOT (coni4) {
265         tree->data.i = ~tree->left->data.i;
266 }
267
268 coni4: ADD (coni4, coni4) {
269         tree->data.i = tree->left->data.i + tree->right->data.i;
270 }
271
272 coni4: SUB (coni4, coni4) {
273         tree->data.i = tree->left->data.i - tree->right->data.i;
274 }
275
276 coni4: MUL (coni4, coni4) {
277         tree->data.i = tree->left->data.i * tree->right->data.i;
278 }
279
280 coni4: DIV (coni4, coni4) {
281         tree->data.i = tree->left->data.i / tree->right->data.i;
282 } cost {
283         MBCOND (tree->right->data.i)
284         return 0;
285 }
286
287 coni4: REM (coni4, coni4) {
288         tree->data.i = tree->left->data.i % tree->right->data.i;
289 } cost {
290         MBCOND (tree->right->data.i)
291         return 0;
292 }
293
294 coni4: CONST_I4 {
295         /* do nothing */
296 }
297
298 #
299 # x86 adressing mode
300 #
301
302 acon: coni4 {
303         tree->data.ainfo.offset = tree->data.i;
304         tree->data.ainfo.amode = AMImmediate;
305 }
306
307 acon: ADDR_G {
308         tree->data.ainfo.offset = tree->data.i;
309         tree->data.ainfo.amode = AMImmediate;
310 }
311
312 acon: ADD (ADDR_G, coni4) {
313         tree->data.ainfo.offset = (unsigned)tree->left->data.p + tree->right->data.i;
314         tree->data.ainfo.amode = AMImmediate;
315 }
316
317 base: acon
318
319 base: reg {
320         tree->data.ainfo.offset = 0;
321         tree->data.ainfo.basereg = tree->reg1;
322         tree->data.ainfo.amode = AMBase;
323 }
324
325 base: ADD (reg, coni4) {
326         tree->data.ainfo.offset = tree->right->data.i;
327         tree->data.ainfo.basereg = tree->left->reg1;
328         tree->data.ainfo.amode = AMBase;
329 }
330
331 base: ADDR_L {
332         tree->data.ainfo.offset = VARINFO (s, tree->data.i).offset;
333         tree->data.ainfo.basereg = X86_EBP;
334         tree->data.ainfo.amode = AMBase;
335 } cost {
336         MBCOND (VARINFO (data, tree->data.i).reg < 0);
337         return 0;
338 }
339
340 index: reg {
341         tree->data.ainfo.offset = 0;
342         tree->data.ainfo.indexreg = tree->reg1;
343         tree->data.ainfo.shift = 0;
344         tree->data.ainfo.amode = AMIndex;
345 }
346
347 index: SHL (reg, coni4) {
348         tree->data.ainfo.offset = 0;
349         tree->data.ainfo.amode = AMIndex;
350         tree->data.ainfo.indexreg = tree->left->reg1;
351         tree->data.ainfo.shift = tree->right->data.i;
352 } cost {
353         MBCOND (tree->right->data.i == 0 ||
354                 tree->right->data.i == 1 ||
355                 tree->right->data.i == 2 ||
356                 tree->right->data.i == 3);
357
358         return 0;
359 }
360
361 index: MUL (reg, coni4) {
362         static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
363   
364         tree->data.ainfo.offset = 0;
365         tree->data.ainfo.amode = AMIndex;
366         tree->data.ainfo.indexreg = tree->left->reg1;
367         tree->data.ainfo.shift = fast_log2 [tree->right->data.i];
368 } cost {
369         MBCOND (tree->right->data.i == 1 ||
370                 tree->right->data.i == 2 ||
371                 tree->right->data.i == 4 ||
372                 tree->right->data.i == 8);
373
374         return 0;
375 }
376
377 addr: base
378
379 addr: index
380
381 addr: ADD (index, base) {
382         tree->data.ainfo.offset = tree->right->data.ainfo.offset;
383         tree->data.ainfo.basereg = tree->right->data.ainfo.basereg;
384         tree->data.ainfo.amode = tree->left->data.ainfo.amode | 
385                 tree->right->data.ainfo.amode;
386         tree->data.ainfo.shift = tree->left->data.ainfo.shift;
387         tree->data.ainfo.indexreg = tree->left->data.ainfo.indexreg;
388 }
389
390 # we pass exception in ECX to catch handler
391 reg: EXCEPTION {
392         int offset = VARINFO (s, tree->data.i).offset;
393         int reg = VARINFO (s, tree->data.i).reg;
394
395         if (tree->reg1 != X86_ECX)
396                 x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
397         
398         /* store it so that we can RETHROW it later */
399         if (reg < 0)
400                 x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
401         else
402                 x86_mov_reg_reg (s->code, reg, tree->reg1, 4);
403 }
404
405 stmt: THROW (reg) {
406         gpointer target;
407
408         x86_push_reg (s->code, tree->left->reg1);
409         target = arch_get_throw_exception ();
410         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
411         x86_call_code (s->code, target);
412 }
413
414 stmt: RETHROW {
415         int off = VARINFO (s, tree->data.i).offset;
416         int reg = VARINFO (s, tree->data.i).reg;
417         gpointer target;
418
419         if (reg < 0)
420                 x86_push_membase (s->code, X86_EBP, off);
421         else
422                 x86_push_reg (s->code, reg);
423
424         target = arch_get_throw_exception ();
425         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
426         x86_call_code (s->code, target);
427 }
428
429 stmt: HANDLER {
430         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
431         x86_call_imm (s->code, 0); 
432 }
433
434 stmt: ENDFINALLY {
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, coni4) {
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, coni4) {
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_reg (s->code, X86_ESP);
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 # warning: this chain rule requires a register
1008 reg: coni4 1 {
1009         x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
1010 }
1011
1012 reg: CONV_I4 (reg) {
1013         if (tree->reg1 != tree->left->reg1)
1014                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1015         PRINT_REG ("CONV_I4", tree->left->reg1);
1016
1017
1018 reg: CONV_U4 (reg) {
1019         if (tree->reg1 != tree->left->reg1)
1020                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1021         PRINT_REG ("CONV_U4", tree->left->reg1);
1022
1023
1024 reg: CONV_OVF_I4 (reg) {
1025         if (tree->reg1 != tree->left->reg1)
1026                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1027         PRINT_REG ("CONV_OVF_I4", tree->left->reg1);
1028 }
1029
1030 reg: CONV_OVF_U4 (reg) {
1031         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
1032         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
1033         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
1034         if (tree->reg1 != tree->left->reg1)
1035                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1036 }
1037
1038 reg: CONV_OVF_I4_UN (reg) {
1039         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
1040         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
1041         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
1042         if (tree->reg1 != tree->left->reg1)
1043                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1044 }
1045
1046 reg: CONV_OVF_I1 (reg) {
1047         /* probe value to be within -128 to 127 */
1048         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 127);
1049         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
1050         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -128);
1051         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GT, TRUE, "OverflowException");      
1052         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
1053 }
1054
1055 reg: CONV_OVF_I1_UN (reg) {
1056         /* probe values between 0 to 128 */
1057         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff80);
1058         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1059         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1060 }
1061
1062 reg: CONV_OVF_U1 (reg) {
1063         /* Keep in sync with CONV_OVF_U1_UN routine below, they are the same on 32-bit machines */
1064         /* probe value to be within 0 to 255 */
1065         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
1066         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1067         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1068 }
1069
1070 reg: CONV_OVF_U1_UN (reg) {
1071         /* Keep in sync with CONV_OVF_U1 routine above, they are the same on 32-bit machines */
1072         /* probe value to be within 0 to 255 */
1073         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
1074         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1075         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
1076 }
1077
1078 reg: CONV_OVF_I2 (reg) {        
1079         /* Probe value to be within -32768 and 32767 */
1080         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 32767);
1081         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
1082         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -32768);
1083         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GE, TRUE, "OverflowException");      
1084         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
1085 }
1086
1087 reg: CONV_OVF_U2 (reg) {
1088         /* Keep in sync with CONV_OVF_U2_UN below, they are the same on 32-bit machines */
1089         /* Probe value to be within 0 and 65535 */
1090         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
1091         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");      
1092         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1093 }
1094
1095 reg: CONV_OVF_U2_UN (reg) {
1096         /* Keep in sync with CONV_OVF_U2 above, they are the same on 32-bit machines */
1097         /* Probe value to be within 0 and 65535 */
1098         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
1099         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1100         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1101 }
1102
1103 reg: CONV_OVF_I2_UN (reg) {
1104         /* Convert uint value into short, value within 0 and 32767 */
1105         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff8000);
1106         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
1107         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
1108 }
1109
1110 reg: MUL (reg, coni4) "MB_USE_OPT1(0)" {
1111         unsigned int i, j, k, v;
1112
1113         v = tree->right->data.i;
1114         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1115                 if (v & j)
1116                         break;
1117         }
1118
1119         if (v < 0 || i == 32 || v & k) {
1120                 switch (v) {
1121                 case 3:
1122                         /* LEA r1, [r2 + r2*2] */
1123                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1124                         break;
1125                 case 5:
1126                         /* LEA r1, [r2 + r2*4] */
1127                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1128                         break;
1129                 case 6:
1130                         /* LEA r1, [r2 + r2*2] */
1131                         /* ADD r1, r1          */
1132                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1133                         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
1134                         break;
1135                 case 9:
1136                         /* LEA r1, [r2 + r2*8] */
1137                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 3);
1138                         break;
1139                 case 10:
1140                         /* LEA r1, [r2 + r2*4] */
1141                         /* ADD r1, r1          */
1142                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1143                         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
1144                         break;
1145                 case 12:
1146                         /* LEA r1, [r2 + r2*2] */
1147                         /* SHL r1, 2           */
1148                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 1);
1149                         x86_shift_reg_imm (s->code, X86_SHL, tree->reg1, 2);
1150                         break;
1151                 case 25:
1152                         /* LEA r1, [r2 + r2*4] */
1153                         /* LEA r1, [r1 + r1*4] */
1154                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1155                         x86_lea_memindex (s->code, tree->reg1, tree->reg1, 0, tree->reg1, 2);
1156                         break;
1157                 case 100:
1158                         /* LEA r1, [r2 + r2*4] */
1159                         /* SHL r1, 2           */
1160                         /* LEA r1, [r1 + r1*4] */
1161                         x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 0, tree->left->reg1, 2);
1162                         x86_shift_reg_imm (s->code, X86_SHL, tree->reg1, 2);
1163                         x86_lea_memindex (s->code, tree->reg1, tree->reg1, 0, tree->reg1, 2);
1164                         break;
1165                 default:
1166                         x86_imul_reg_reg_imm (s->code, tree->reg1, tree->left->reg1, tree->right->data.i);
1167                         break;
1168                 }
1169         } else {
1170                 x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, i);
1171                 if (tree->reg1 != tree->left->reg1)
1172                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1173         }
1174 }
1175
1176 reg: MUL (reg, reg) {
1177         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
1178
1179         if (tree->reg1 != tree->left->reg1)
1180                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1181 }
1182
1183 reg: MUL_OVF (reg, reg) {
1184         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
1185         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1186
1187         if (tree->reg1 != tree->left->reg1)
1188                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1189 }
1190
1191 reg: MUL_OVF_UN (reg, reg) {
1192         mono_assert (tree->right->reg1 != X86_EAX);
1193         
1194         if (tree->left->reg1 != X86_EAX)
1195                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1196
1197         x86_mul_reg (s->code, tree->right->reg1, FALSE);
1198         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");
1199
1200         mono_assert (tree->reg1 == X86_EAX &&
1201                      tree->reg2 == X86_EDX);
1202 }
1203
1204 reg: DIV (reg, coni4) {
1205         unsigned int i, j, k, v;
1206
1207         v = tree->right->data.i;
1208         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1209                 if (v & j)
1210                         break;
1211         }
1212
1213         x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg1, i);
1214         if (tree->reg1 != tree->left->reg1)
1215                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1216
1217 } cost {
1218         unsigned int i, j, k, v;
1219
1220         if (v < 0) 
1221                 return MBMAXCOST;
1222
1223         v = tree->right->data.i;
1224         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1225                 if (v & j)
1226                         break;
1227         }
1228         
1229         if (i == 32 || v & k) 
1230                 return MBMAXCOST;
1231
1232         return 0;
1233
1234 }
1235
1236 reg: DIV (reg, reg) {
1237         mono_assert (tree->right->reg1 != X86_EAX);
1238
1239         if (tree->left->reg1 != X86_EAX)
1240                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1241
1242         x86_cdq (s->code);
1243         x86_div_reg (s->code, tree->right->reg1, TRUE);
1244
1245         mono_assert (tree->reg1 == X86_EAX &&
1246                      tree->reg2 == X86_EDX);
1247 }
1248
1249 reg: DIV_UN (reg, coni4) {
1250         unsigned int i, j, k, v;
1251         double f, r;
1252
1253         v = tree->right->data.i;
1254         for (i = 0, j = 1, k = 0xfffffffe; i < 32; i++, j = j << 1, k = k << 1) {
1255                 if (v & j)
1256                         break;
1257         }
1258
1259         if (i == 32 || v & k)  {
1260                 for (i = 32, j = 0x80000000; --i >= 0; j >>= 1) {
1261                         if (v & j) break;
1262                 }
1263
1264                 /* k = 32 + number of significant bits in v - 1 */
1265                 k = 32 + i;
1266
1267                 f = 1.0f / v;
1268                 for (i = 0; i < k; i++) f *= 2.0f;
1269
1270
1271                 r = f - floor(f);
1272
1273                 if (r == 0) {
1274                         x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, k - 32);
1275                         if (tree->reg1 != tree->left->reg1)
1276                                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1277                 } else if (r < 0.5f) {
1278                         if (tree->left->reg1 != X86_EAX)
1279                                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1280                         x86_mov_reg_imm (s->code, X86_EDX, (guint32) floor(f));
1281                         /* x86_inc_reg (s->code, X86_EAX); */
1282                         /* INC is faster but we have to check for overflow. */
1283                         x86_alu_reg_imm (s->code, X86_ADD, X86_EAX, 1);
1284                         x86_branch8(s->code, X86_CC_C, 2, FALSE);
1285                         x86_mul_reg (s->code, X86_EDX, FALSE);
1286                         x86_shift_reg_imm (s->code, X86_SHR, X86_EDX, k - 32);
1287                         if (tree->reg1 != X86_EDX)
1288                                 x86_mov_reg_reg (s->code, tree->reg1, X86_EDX, 4);
1289                 } else {
1290                         if (tree->left->reg1 != X86_EAX)
1291                                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1292                         x86_mov_reg_imm (s->code, X86_EDX, (guint32) ceil(f));
1293                         x86_mul_reg (s->code, X86_EDX, FALSE);
1294                         x86_shift_reg_imm (s->code, X86_SHR, X86_EDX, k - 32);
1295                         if (tree->reg1 != X86_EDX)
1296                                 x86_mov_reg_reg (s->code, tree->reg1, X86_EDX, 4);
1297                 }
1298         } else {
1299                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, i);
1300                 if (tree->reg1 != tree->left->reg1)
1301                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1302         }
1303
1304 }
1305
1306 reg: DIV_UN (reg, reg) {
1307         mono_assert (tree->right->reg1 != X86_EAX);
1308
1309         if (tree->left->reg1 != X86_EAX)
1310                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1311
1312         x86_mov_reg_imm (s->code, X86_EDX, 0);
1313         x86_div_reg (s->code, tree->right->reg1, FALSE);
1314
1315         mono_assert (tree->reg1 == X86_EAX &&
1316                      tree->reg2 == X86_EDX);
1317 }
1318
1319 reg: REM (reg, reg) {
1320         mono_assert (tree->right->reg1 != X86_EAX);
1321         mono_assert (tree->right->reg1 != X86_EDX);
1322
1323         if (tree->left->reg1 != X86_EAX)
1324                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1325
1326         /* sign extend to 64bit in EAX/EDX */
1327         x86_cdq (s->code);
1328         x86_div_reg (s->code, tree->right->reg1, TRUE);
1329         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
1330
1331         mono_assert (tree->reg1 == X86_EAX &&
1332                      tree->reg2 == X86_EDX);
1333 }
1334
1335 reg: REM_UN (reg, reg) {
1336         mono_assert (tree->right->reg1 != X86_EAX);
1337         mono_assert (tree->right->reg1 != X86_EDX);
1338
1339         if (tree->left->reg1 != X86_EAX)
1340                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1341
1342         /* zero extend to 64bit in EAX/EDX */
1343         x86_mov_reg_imm (s->code, X86_EDX, 0); 
1344         x86_div_reg (s->code, tree->right->reg1, FALSE);
1345         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
1346
1347         mono_assert (tree->reg1 == X86_EAX &&
1348                      tree->reg2 == X86_EDX);
1349 }
1350
1351 reg: ADD (reg, coni4) "MB_USE_OPT1(0)" {
1352         if (tree->right->data.i == 1)
1353                 x86_inc_reg (s->code, tree->left->reg1);
1354         else 
1355                 x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, tree->right->data.i);
1356
1357         if (tree->reg1 != tree->left->reg1)
1358                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1359
1360 }
1361
1362 reg: ADD (reg, LDIND_I4 (ADDR_L)) {
1363         int treg = VARINFO (s, tree->right->left->data.i).reg;
1364
1365         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, treg);
1366
1367         if (tree->reg1 != tree->left->reg1)
1368                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1369 } cost {
1370         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
1371         return 0;
1372 }
1373
1374 reg: ADD (reg, reg) {
1375         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1376
1377         if (tree->reg1 != tree->left->reg1)
1378                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1379 }
1380
1381 reg: ADD_OVF (reg, reg) {
1382         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1383         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1384
1385         if (tree->reg1 != tree->left->reg1)
1386                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1387 }
1388
1389 reg: ADD_OVF_UN (reg, reg) {
1390         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
1391         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
1392
1393         if (tree->reg1 != tree->left->reg1)
1394                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1395 }
1396
1397 reg: SUB (reg, coni4) "MB_USE_OPT1(0)" {
1398         if (tree->right->data.i == 1)
1399                 x86_dec_reg (s->code, tree->left->reg1);
1400         else
1401                 x86_alu_reg_imm (s->code, X86_SUB, tree->left->reg1, tree->right->data.i);
1402
1403         if (tree->reg1 != tree->left->reg1)
1404                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1405 }
1406
1407 reg: SUB (reg, LDIND_I4 (ADDR_L)) {
1408         int treg = VARINFO (s, tree->right->left->data.i).reg;
1409
1410         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, treg);
1411
1412         if (tree->reg1 != tree->left->reg1)
1413                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1414 } cost {
1415         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
1416         return 0;
1417 }
1418
1419 reg: SUB (reg, reg) {
1420         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1421
1422         if (tree->reg1 != tree->left->reg1)
1423                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1424 }
1425
1426 reg: SUB_OVF (reg, reg) {
1427         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1428         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
1429
1430         if (tree->reg1 != tree->left->reg1)
1431                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1432 }
1433
1434 reg: SUB_OVF_UN (reg, reg) {
1435         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
1436         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
1437
1438         if (tree->reg1 != tree->left->reg1)
1439                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1440 }
1441
1442 reg: CSET (cflags) {
1443
1444         switch (tree->data.i) {
1445         case CEE_CEQ:
1446                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
1447                 break;
1448         case CEE_CGT:
1449                 x86_set_reg (s->code, X86_CC_GT, tree->reg1, TRUE);
1450                 break;
1451         case CEE_CGT_UN:
1452                 x86_set_reg (s->code, X86_CC_GT, tree->reg1, FALSE);
1453                 break;
1454         case CEE_CLT:
1455                 x86_set_reg (s->code, X86_CC_LT, tree->reg1, TRUE);
1456                 break;
1457         case CEE_CLT_UN:
1458                 x86_set_reg (s->code, X86_CC_LT, tree->reg1, FALSE);
1459                 break;
1460         default:
1461                 g_assert_not_reached ();
1462         }
1463
1464         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
1465 }
1466
1467 reg: AND (reg, coni4) "MB_USE_OPT1(0)" {
1468         x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, tree->right->data.i);
1469
1470         if (tree->reg1 != tree->left->reg1)
1471                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1472 }
1473
1474 reg: AND (reg, reg) {
1475         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
1476
1477         if (tree->reg1 != tree->left->reg1)
1478                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1479 }
1480
1481 reg: OR (reg, coni4) "MB_USE_OPT1(0)" {
1482         x86_alu_reg_imm (s->code, X86_OR, tree->left->reg1, tree->right->data.i);
1483
1484         if (tree->reg1 != tree->left->reg1)
1485                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1486 }
1487
1488 reg: OR (reg, reg) {
1489         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
1490
1491         if (tree->reg1 != tree->left->reg1)
1492                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1493 }
1494
1495 reg: XOR (reg, coni4) "MB_USE_OPT1(0)" {
1496         x86_alu_reg_imm (s->code, X86_XOR, tree->left->reg1, tree->right->data.i);
1497
1498         if (tree->reg1 != tree->left->reg1)
1499                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1500 }
1501
1502 reg: XOR (reg, reg) {
1503         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->right->reg1);
1504
1505         if (tree->reg1 != tree->left->reg1)
1506                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1507 }
1508
1509 reg: NEG (reg) {
1510         x86_neg_reg (s->code, tree->left->reg1);
1511
1512         if (tree->reg1 != tree->left->reg1)
1513                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1514 }
1515
1516 reg: NOT (reg) {
1517         x86_not_reg (s->code, tree->left->reg1);
1518
1519         if (tree->reg1 != tree->left->reg1)
1520                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1521 }
1522
1523 reg: SHL (reg, coni4) {
1524         x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
1525
1526         if (tree->reg1 != tree->left->reg1)
1527                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1528 }
1529
1530 reg: SHL (reg, reg) {
1531         if (tree->right->reg1 != X86_ECX) {
1532                 x86_push_reg (s->code, X86_ECX);
1533                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1534         }
1535         x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
1536
1537         if (tree->reg1 != tree->left->reg1)
1538                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1539
1540         if (tree->right->reg1 != X86_ECX)
1541                 x86_pop_reg (s->code, X86_ECX);
1542
1543         mono_assert (tree->reg1 != X86_ECX &&
1544                      tree->left->reg1 != X86_ECX);
1545 }
1546
1547 reg: SHR (reg, coni4) {
1548         x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg1, tree->right->data.i);
1549
1550         if (tree->reg1 != tree->left->reg1)
1551                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1552 }
1553
1554 reg: SHR (reg, reg) {
1555         if (tree->right->reg1 != X86_ECX) {
1556                 x86_push_reg (s->code, X86_ECX);
1557                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1558         }
1559
1560         x86_shift_reg (s->code, X86_SAR, tree->left->reg1);
1561
1562         if (tree->reg1 != tree->left->reg1)
1563                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1564
1565         if (tree->right->reg1 != X86_ECX)
1566                 x86_pop_reg (s->code, X86_ECX);
1567
1568         mono_assert (tree->reg1 != X86_ECX &&
1569                      tree->left->reg1 != X86_ECX);
1570 }
1571
1572 reg: SHR_UN (reg, coni4) {
1573         x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, tree->right->data.i);
1574
1575         if (tree->reg1 != tree->left->reg1)
1576                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1577 }
1578
1579 reg: SHR_UN (reg, reg) {
1580         if (tree->right->reg1 != X86_ECX) {
1581                 x86_push_reg (s->code, X86_ECX);
1582                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1583         }
1584
1585         x86_shift_reg (s->code, X86_SHR, tree->left->reg1);
1586
1587         if (tree->reg1 != tree->left->reg1)
1588                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1589
1590         if (tree->right->reg1 != X86_ECX)
1591                 x86_pop_reg (s->code, X86_ECX);
1592
1593         mono_assert (tree->reg1 != X86_ECX &&
1594                      tree->left->reg1 != X86_ECX);
1595 }
1596
1597 reg: LDSFLDA (coni4) {
1598         if (tree->reg1 != X86_EAX)
1599                 x86_push_reg (s->code, X86_EAX);
1600         x86_push_reg (s->code, X86_ECX);
1601         x86_push_reg (s->code, X86_EDX);
1602
1603         x86_push_imm (s->code, tree->left->data.i);
1604         x86_push_imm (s->code, tree->data.klass);
1605         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldsflda);
1606         x86_call_code (s->code, 0);
1607         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1608         
1609         x86_pop_reg (s->code, X86_EDX);
1610         x86_pop_reg (s->code, X86_ECX);
1611         if (tree->reg1 != X86_EAX) {
1612                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1613                 x86_pop_reg (s->code, X86_EAX);
1614         }
1615 }
1616
1617 # array support
1618 reg: LDLEN (reg) {      
1619         x86_mov_reg_membase (s->code, tree->reg1, tree->left->reg1,  
1620                              G_STRUCT_OFFSET (MonoArray, max_length), 4);
1621 }
1622
1623 reg: LDELEMA (reg, coni4) {
1624         int ind;
1625
1626         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length), tree->right->data.i);
1627         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GT, FALSE, "IndexOutOfRangeException");
1628        
1629         ind = tree->data.i * tree->right->data.i + G_STRUCT_OFFSET (MonoArray, vector);
1630         
1631         x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, ind);
1632
1633         if (tree->reg1 != tree->left->reg1)
1634                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1635
1636 }
1637
1638 reg: LDELEMA (reg, reg) {
1639
1640         x86_alu_reg_membase (s->code, X86_CMP, tree->right->reg1, tree->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length));
1641         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LT, FALSE, "IndexOutOfRangeException");
1642
1643         if (tree->data.i == 1 || tree->data.i == 2 || 
1644             tree->data.i == 4 || tree->data.i == 8) {
1645                 static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
1646                 x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 
1647                                   G_STRUCT_OFFSET (MonoArray, vector), tree->right->reg1, 
1648                                   fast_log2 [tree->data.i]);
1649         } else {
1650                 x86_imul_reg_reg_imm (s->code, tree->right->reg1, tree->right->reg1, tree->data.i);
1651                 x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
1652                 x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, G_STRUCT_OFFSET (MonoArray, vector));
1653         }
1654 }
1655
1656 reg: LDSTR {
1657         if (tree->reg1 != X86_EAX)
1658                 x86_push_reg (s->code, X86_EAX);
1659         x86_push_reg (s->code, X86_ECX);
1660         x86_push_reg (s->code, X86_EDX);
1661
1662         x86_push_imm (s->code, tree->data.p);
1663         x86_push_imm (s->code, s->method->klass->image);
1664         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldstr_wrapper);
1665         x86_call_code (s->code, 0);
1666         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1667
1668         x86_pop_reg (s->code, X86_EDX);
1669         x86_pop_reg (s->code, X86_ECX);
1670         if (tree->reg1 != X86_EAX) {
1671                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1672                 x86_pop_reg (s->code, X86_EAX);
1673         }
1674
1675         PRINT_REG ("LDSTR", tree->reg1);        
1676 }
1677
1678 reg: NEWARR (reg) {
1679         if (tree->reg1 != X86_EAX)
1680                 x86_push_reg (s->code, X86_EAX);
1681         x86_push_reg (s->code, X86_ECX);
1682         x86_push_reg (s->code, X86_EDX);
1683
1684         x86_push_reg (s->code, tree->left->reg1);
1685         x86_push_imm (s->code, tree->data.p);
1686         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_wrapper);
1687         x86_call_code (s->code, 0);
1688         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
1689
1690         x86_pop_reg (s->code, X86_EDX);
1691         x86_pop_reg (s->code, X86_ECX);
1692         if (tree->reg1 != X86_EAX) {
1693                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1694                 x86_pop_reg (s->code, X86_EAX);
1695         }
1696
1697         PRINT_REG ("NEWARR", tree->reg1);
1698 }
1699
1700 reg: NEWARR_SPEC (reg) {
1701         if (tree->reg1 != X86_EAX)
1702                 x86_push_reg (s->code, X86_EAX);
1703         x86_push_reg (s->code, X86_ECX);
1704         x86_push_reg (s->code, X86_EDX);
1705
1706         x86_push_reg (s->code, tree->left->reg1);
1707         x86_push_imm (s->code, tree->data.p);
1708         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_specific);
1709         x86_call_code (s->code, 0);
1710         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
1711
1712         x86_pop_reg (s->code, X86_EDX);
1713         x86_pop_reg (s->code, X86_ECX);
1714         if (tree->reg1 != X86_EAX) {
1715                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1716                 x86_pop_reg (s->code, X86_EAX);
1717         }
1718
1719         PRINT_REG ("NEWARR_SPEC", tree->reg1);
1720 }
1721
1722 reg: NEWOBJ {
1723         if (tree->reg1 != X86_EAX)
1724                 x86_push_reg (s->code, X86_EAX);
1725         x86_push_reg (s->code, X86_ECX);
1726         x86_push_reg (s->code, X86_EDX);
1727
1728         x86_push_imm (s->code, tree->data.klass);
1729         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_wrapper);
1730         x86_call_code (s->code, 0);
1731         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1732
1733         x86_pop_reg (s->code, X86_EDX);
1734         x86_pop_reg (s->code, X86_ECX);
1735         if (tree->reg1 != X86_EAX) {
1736                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1737                 x86_pop_reg (s->code, X86_EAX);
1738         }
1739         PRINT_REG ("NEWOBJ", tree->reg1);
1740 }
1741
1742 reg: NEWOBJ_SPEC {
1743         if (tree->reg1 != X86_EAX)
1744                 x86_push_reg (s->code, X86_EAX);
1745         x86_push_reg (s->code, X86_ECX);
1746         x86_push_reg (s->code, X86_EDX);
1747
1748         x86_push_imm (s->code, tree->data.p);
1749         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_specific);
1750         x86_call_code (s->code, 0);
1751         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1752
1753         x86_pop_reg (s->code, X86_EDX);
1754         x86_pop_reg (s->code, X86_ECX);
1755         if (tree->reg1 != X86_EAX) {
1756                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1757                 x86_pop_reg (s->code, X86_EAX);
1758         }
1759         PRINT_REG ("NEWOBJ_SPEC", tree->reg1);
1760 }
1761
1762 reg: NEWSTRUCT {
1763         int size = tree->data.i;        
1764         int sa;
1765         
1766         mono_assert (size > 0);
1767
1768         sa = size + 3;
1769         sa &= ~3;
1770
1771         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
1772         x86_mov_reg_reg (s->code, tree->reg1, X86_ESP, 4);
1773 }
1774
1775 reg: UNBOX (reg) {
1776         if (tree->reg1 != tree->left->reg1)
1777                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1778
1779         x86_push_reg (s->code, tree->reg1);
1780         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1781         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1782         x86_alu_membase_imm (s->code, X86_CMP, tree->reg1, 
1783                              G_STRUCT_OFFSET (MonoClass, element_class), ((int)(tree->data.klass->element_class)));
1784         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "InvalidCastException");
1785         x86_pop_reg (s->code, tree->reg1);
1786         x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
1787 }
1788
1789 reg: CASTCLASS (reg) {
1790         MonoClass *klass = tree->data.klass;
1791         guint8 *br [2];
1792         int lreg = tree->left->reg1;
1793         
1794         x86_push_reg (s->code, lreg);
1795         x86_test_reg_reg (s->code, lreg, lreg);
1796         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
1797
1798         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1799                 /* lreg = obj->vtable */
1800                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1801
1802                 x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoVTable, max_interface_id), 
1803                                      klass->interface_id);
1804                 EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GE, FALSE, "InvalidCastException");
1805                 /* lreg = obj->vtable->interface_offsets */
1806                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1807                 x86_alu_membase_imm (s->code, X86_CMP, lreg, klass->interface_id << 2, 0);
1808                 EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, FALSE, "InvalidCastException");
1809         } else {
1810
1811                 /* lreg = obj->vtable */
1812                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1813                 /* lreg = obj->vtable->klass */
1814                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1815
1816                 if (klass->rank) {
1817
1818                         x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoClass, rank), klass->rank);
1819                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "InvalidCastException");
1820                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, element_class), 4);
1821                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1822                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->element_class->baseval);
1823                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->element_class->diffval);
1824                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, FALSE, "InvalidCastException");
1825
1826                 } else {
1827
1828                         if (klass->marshalbyref) {
1829                                 /* check for transparent_proxy */               
1830                                 x86_alu_reg_imm (s->code, X86_CMP, lreg, (int)mono_defaults.transparent_proxy_class);
1831                                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1832                 
1833                                 /* lreg = obj */
1834                                 x86_mov_reg_membase (s->code, lreg, X86_ESP, 0, 4);
1835                                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoTransparentProxy, 
1836                                                                                            klass), 4);
1837
1838                                 x86_patch (br [1], s->code);
1839                         }
1840
1841                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1842                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->baseval);
1843                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->diffval);
1844                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, FALSE, "InvalidCastException");          
1845                 }
1846         }
1847
1848         x86_patch (br [0], s->code);
1849         x86_pop_reg (s->code, tree->reg1);
1850 }
1851
1852 reg: ISINST (reg) {
1853         MonoClass *klass = tree->data.klass;
1854         guint8 *br [3];
1855         int lreg = tree->left->reg1;
1856         
1857         x86_push_reg (s->code, lreg);
1858         x86_test_reg_reg (s->code, lreg, lreg);
1859         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
1860
1861         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1862                 /* lreg = obj->vtable */
1863                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1864
1865                 x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoVTable, max_interface_id), 
1866                                      klass->interface_id);
1867                 br [1] = s->code; x86_branch8 (s->code, X86_CC_LT, 0, FALSE);
1868                 /* lreg = obj->vtable->interface_offsets */
1869                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1870                 x86_alu_membase_imm (s->code, X86_CMP, lreg, klass->interface_id << 2, 0);
1871                 br [2] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1872                 x86_patch (br [1], s->code);
1873                 x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1874                 x86_patch (br [2], s->code);
1875
1876         } else {
1877
1878                 /* lreg = obj->vtable */
1879                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1880                 /* lreg = obj->vtable->klass */
1881                 x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1882
1883                 if (klass->rank) {
1884
1885                         x86_alu_membase_imm (s->code, X86_CMP, lreg, G_STRUCT_OFFSET (MonoClass, rank), klass->rank);
1886                         br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1887                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, element_class), 4);
1888                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1889                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->element_class->baseval);
1890                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->element_class->diffval);
1891                         br [2] = s->code; x86_branch8 (s->code, X86_CC_LE, 0, FALSE);
1892                         x86_patch (br [1], s->code);
1893                         x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1894                         x86_patch (br [2], s->code);
1895
1896                 } else {
1897
1898                         if (klass->marshalbyref) {
1899                                 /* check for transparent_proxy */               
1900                                 x86_alu_reg_imm (s->code, X86_CMP, lreg, (int)mono_defaults.transparent_proxy_class);
1901                                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
1902                 
1903                                 /* lreg = obj */
1904                                 x86_mov_reg_membase (s->code, lreg, X86_ESP, 0, 4);
1905                                 x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoTransparentProxy, 
1906                                                                                            klass), 4);
1907                                 x86_patch (br [1], s->code);
1908                         }
1909
1910                         x86_mov_reg_membase (s->code, lreg, lreg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
1911                         x86_alu_reg_mem (s->code, X86_SUB, lreg, &klass->baseval);
1912                         x86_alu_reg_mem (s->code, X86_CMP, lreg, &klass->diffval);
1913                         br [2] = s->code; x86_branch8 (s->code, X86_CC_LE, 0, FALSE);
1914                         x86_mov_membase_imm (s->code, X86_ESP, 0, 0, 4);
1915                         x86_patch (br [2], s->code);
1916                 }
1917         }
1918
1919         x86_patch (br [0], s->code);
1920         x86_pop_reg (s->code, tree->reg1);
1921 }
1922
1923 stmt: INITOBJ (reg) {
1924         int i, j;
1925
1926         i = tree->data.i;
1927
1928         if (i == 1 || i == 2 || i == 4) {
1929                 x86_mov_membase_imm (s->code, tree->left->reg1, 0, 0, i);
1930                 return;
1931         }
1932
1933         i = tree->data.i / 4;
1934         j = tree->data.i % 4;
1935
1936         x86_push_reg (s->code, X86_EAX);
1937         
1938         if (tree->left->reg1 != X86_EDI) {
1939                 x86_push_reg (s->code, X86_EDI);
1940                 x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
1941         }
1942
1943         if (i) {
1944                 x86_push_reg (s->code, X86_ECX);
1945                 x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
1946                 x86_mov_reg_imm (s->code, X86_ECX, i);
1947                 x86_cld (s->code);
1948                 x86_prefix (s->code, X86_REP_PREFIX);
1949                 x86_stosl (s->code);
1950                 x86_pop_reg (s->code, X86_ECX);
1951
1952                 for (i = 0; i < j; i++)
1953                         x86_stosb (s->code);
1954
1955         } else {
1956                 g_assert (j == 3);
1957                 x86_mov_membase_imm (s->code, X86_EDI, 0, 0, 2);
1958                 x86_mov_membase_imm (s->code, X86_EDI, 2, 0, 1);
1959         }
1960
1961
1962
1963         if (tree->left->reg1 != X86_EDI)
1964                 x86_pop_reg (s->code, X86_EDI);
1965         
1966         x86_pop_reg (s->code, X86_EAX);
1967 }
1968
1969 stmt: NOP
1970
1971 stmt: POP (reg)
1972
1973 stmt: BR {
1974         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
1975         x86_jump32 (s->code, 0); 
1976 }
1977
1978 cflags: COMPARE (reg, LDIND_I4 (ADDR_L)) {
1979         int treg = VARINFO (s, tree->right->left->data.i).reg;
1980         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, treg);
1981 } cost {
1982         MBCOND ((VARINFO (data, tree->right->left->data.i).reg >= 0));
1983         return 0;
1984 }
1985
1986 cflags: COMPARE (LDIND_I4 (ADDR_L), coni4) {
1987         int treg = VARINFO (s, tree->left->left->data.i).reg;
1988         x86_alu_reg_imm (s->code, X86_CMP, treg, tree->right->data.i);
1989 } cost {
1990         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
1991         return 0;
1992 }
1993
1994 cflags: COMPARE (LDIND_I4 (ADDR_L), reg) {
1995         int treg = VARINFO (s, tree->left->left->data.i).reg;
1996         x86_alu_reg_reg (s->code, X86_CMP, treg, tree->right->reg1);
1997 } cost {
1998         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
1999         return 0;
2000 }
2001
2002 cflags: COMPARE (LDIND_I4 (ADDR_L), coni4) {
2003         int offset = VARINFO (s, tree->left->left->data.i).offset;
2004         x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset,  tree->right->data.i);
2005 } cost {
2006         MBCOND ((VARINFO (data, tree->left->left->data.i).reg < 0));
2007         return 0;
2008 }
2009
2010 cflags: COMPARE (reg, coni4) {
2011         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
2012 }
2013
2014 cflags: COMPARE (reg, reg) {
2015         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2016 }
2017
2018
2019 stmt: CBRANCH (cflags) {
2020         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
2021
2022         switch (tree->data.bi.cond) {
2023         case CEE_BLT:
2024                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE); 
2025                 break;
2026         case CEE_BLT_UN:
2027                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE); 
2028                 break;
2029         case CEE_BGT:
2030                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE); 
2031                 break;
2032         case CEE_BGT_UN:
2033                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE); 
2034                 break;
2035         case CEE_BEQ:
2036                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2037                 break;
2038         case CEE_BNE_UN:
2039                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
2040                 break;
2041         case CEE_BGE:
2042                 x86_branch32 (s->code, X86_CC_GE, 0, TRUE);
2043                 break;
2044         case CEE_BGE_UN:
2045                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
2046                 break;
2047         case CEE_BLE:
2048                 x86_branch32 (s->code, X86_CC_LE, 0, TRUE);
2049                 break;
2050         case CEE_BLE_UN:
2051                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
2052                 break;
2053         default:
2054                 g_assert_not_reached ();
2055         }
2056 }
2057
2058 stmt: BRTRUE (LDIND_I4 (ADDR_L)) {
2059         int treg = VARINFO (s, tree->left->left->data.i).reg;
2060         int offset = VARINFO (s, tree->left->left->data.i).offset;
2061
2062         if (treg >= 0)
2063                 x86_test_reg_reg (s->code, treg, treg);
2064         else
2065                 x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, 0);
2066
2067         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2068         x86_branch32 (s->code, X86_CC_NE, 0, TRUE);
2069 }
2070
2071 stmt: BRTRUE (reg) {
2072         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2073         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2074         x86_branch32 (s->code, X86_CC_NE, 0, TRUE);
2075 }
2076
2077 stmt: BRFALSE (LDIND_I4 (ADDR_L)) {
2078         int treg = VARINFO (s, tree->left->left->data.i).reg;
2079         int offset = VARINFO (s, tree->left->left->data.i).offset;
2080
2081         if (treg >= 0)
2082                 x86_test_reg_reg (s->code, treg, treg);
2083         else
2084                 x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, 0);
2085
2086         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2087         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2088
2089         //{static int cx= 0; printf ("CX1 %5d\n", cx++);}
2090 }
2091
2092 stmt: BRFALSE (reg) {
2093         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2094         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
2095         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2096 }
2097
2098 stmt: BREAK {
2099         x86_breakpoint (s->code);
2100 }
2101
2102 stmt: RET (reg) {
2103         if (tree->left->reg1 != X86_EAX)
2104                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
2105
2106         if (!tree->last_instr) {
2107                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
2108                 x86_jump32 (s->code, 0);      
2109         }
2110 }
2111
2112 stmt: RET_VOID {
2113         if (!tree->last_instr) {
2114                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
2115                 x86_jump32 (s->code, 0);      
2116         } 
2117 }
2118
2119
2120 stmt: ARG_I4 (LDIND_I4 (addr)) {
2121         MBTree *at = tree->left->left;
2122
2123         switch (at->data.ainfo.amode) {
2124
2125         case AMImmediate:
2126                 x86_push_mem (s->code, at->data.ainfo.offset);
2127                 break;
2128
2129         case AMBase:
2130                 x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
2131                 break;          
2132         case AMIndex:
2133                 x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
2134                                    at->data.ainfo.indexreg, at->data.ainfo.shift);
2135                 break;          
2136         case AMBaseIndex:
2137                 x86_push_memindex (s->code, at->data.ainfo.basereg, 
2138                                    at->data.ainfo.offset, at->data.ainfo.indexreg, 
2139                                    at->data.ainfo.shift);
2140                 break;          
2141         }
2142 }
2143
2144 stmt: ARG_I4 (LDIND_I4 (ADDR_L)) {
2145         int treg = VARINFO (s, tree->left->left->data.i).reg;
2146         x86_push_reg (s->code, treg);
2147 } cost {
2148         MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
2149         return 0;
2150 }
2151
2152 stmt: ARG_I4 (reg) {
2153         x86_push_reg (s->code, tree->left->reg1);
2154         PRINT_REG ("ARG_I4",  tree->left->reg1);
2155 }
2156
2157 # fixme: we must free the allocated strings somewhere
2158 stmt: ARG_STRING (reg) {
2159         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2160         x86_push_reg (s->code, X86_EAX);
2161         x86_push_reg (s->code, X86_ECX);
2162         x86_push_reg (s->code, X86_EDX);
2163
2164         x86_push_reg (s->code, tree->left->reg1);
2165         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_string_to_utf8);
2166         x86_call_code (s->code, 0);
2167         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
2168         
2169         x86_mov_membase_reg (s->code, X86_ESP, 12, X86_EAX, 4);
2170
2171         x86_pop_reg (s->code, X86_EDX);
2172         x86_pop_reg (s->code, X86_ECX);
2173         x86_pop_reg (s->code, X86_EAX);
2174 }
2175
2176 stmt: ARG_I4 (ADDR_G) {
2177         x86_push_imm (s->code, tree->left->data.p);
2178 }
2179
2180 stmt: ARG_I4 (coni4) "MB_USE_OPT1(0)" {
2181         x86_push_imm (s->code, tree->left->data.i);
2182 }
2183
2184 this: reg {
2185         PRINT_REG ("THIS", tree->reg1);
2186 }
2187
2188 reg: CHECKTHIS (reg) {
2189         /* try to access the vtable - this will raise an exception
2190          * if the object is NULL */
2191         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, 0, 0);
2192         if (tree->reg1 != tree->left->reg1)
2193                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2194 }
2195
2196 stmt: CHECKTHIS (reg) {
2197         x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, 0, 0);
2198 }
2199
2200 this: NOP
2201
2202 reg: CALL_I4 (this, reg) {
2203         int treg = X86_EAX;
2204         int lreg = tree->left->reg1;
2205         int rreg = tree->right->reg1;
2206         
2207         if (lreg == treg || rreg == treg) 
2208                 treg = X86_EDX;
2209         if (lreg == treg || rreg == treg) 
2210                 treg = X86_ECX;
2211         if (lreg == treg || rreg == treg) 
2212                 mono_assert_not_reached ();
2213
2214         if (tree->left->op != MB_TERM_NOP) {
2215                 mono_assert (lreg >= 0);
2216                 x86_push_reg (s->code, lreg);
2217         }
2218
2219         if (tree->data.ci.vtype_num) {
2220                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2221                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2222                 x86_push_reg (s->code, treg);
2223         }
2224
2225         x86_call_reg (s->code, rreg);
2226
2227         if (tree->data.ci.args_size)
2228                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2229         
2230         PRINT_REG ("CALL_I4", tree->reg1);
2231
2232         mono_assert (tree->reg1 == X86_EAX);
2233 }
2234
2235 reg: CALL_I4 (this, ADDR_G) {
2236         int lreg = tree->left->reg1;
2237         int treg = X86_EAX;
2238
2239         if (lreg == treg) 
2240                 treg = X86_EDX;
2241         
2242         if (tree->left->op != MB_TERM_NOP) {
2243                 mono_assert (lreg >= 0);
2244                 x86_push_reg (s->code, lreg);
2245                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2246         }
2247
2248         if (tree->data.ci.vtype_num) {
2249                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2250                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2251                 x86_push_reg (s->code, treg);
2252         }
2253
2254         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
2255         x86_call_code (s->code, 0);
2256
2257         if (tree->data.ci.args_size)
2258                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2259
2260         PRINT_REG ("CALL_I4", tree->reg1);
2261
2262         mono_assert (tree->reg1 == X86_EAX);
2263 }
2264
2265 reg: LDVIRTFTN (reg, INTF_ADDR) {
2266         int lreg = tree->left->reg1;
2267
2268         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2269         x86_mov_reg_membase (s->code, lreg, lreg, 
2270                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2271         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2272         x86_mov_reg_membase (s->code, tree->reg1, lreg, tree->right->data.m->slot << 2, 4);
2273 }
2274
2275 reg: CALL_I4 (this, INTF_ADDR) {
2276         int lreg = tree->left->reg1;
2277         int treg = X86_EAX;
2278
2279         if (lreg == treg) 
2280                 treg = X86_EDX;
2281
2282         if (tree->left->op != MB_TERM_NOP) {
2283                 mono_assert (lreg >= 0);
2284                 x86_push_reg (s->code, lreg);
2285         }
2286
2287         if (tree->data.ci.vtype_num) {
2288                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2289                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2290                 x86_push_reg (s->code, treg);
2291         }
2292
2293         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2294         x86_mov_reg_membase (s->code, lreg, lreg, 
2295                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2296         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2297         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2298
2299         if (tree->data.ci.args_size)
2300                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2301
2302         PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
2303
2304         mono_assert (tree->reg1 == X86_EAX);
2305 }
2306
2307 reg: LDVIRTFTN (reg, VFUNC_ADDR) {
2308         int lreg = tree->left->reg1;
2309         
2310         x86_mov_reg_membase (s->code, tree->reg1, lreg, 0, 4);
2311         
2312         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2), 4);
2313 }
2314
2315 reg: LDFTN {
2316         if (tree->reg1 != X86_EAX)
2317                 x86_push_reg (s->code, X86_EAX);
2318         x86_push_reg (s->code, X86_ECX);
2319         x86_push_reg (s->code, X86_EDX);
2320
2321         x86_push_imm (s->code, tree->data.m);
2322         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, arch_compile_method);
2323         x86_call_code (s->code, 0);
2324         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
2325
2326         x86_pop_reg (s->code, X86_EDX);
2327         x86_pop_reg (s->code, X86_ECX);
2328         if (tree->reg1 != X86_EAX) {
2329                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
2330                 x86_pop_reg (s->code, X86_EAX);
2331         }
2332         PRINT_REG ("LDFTN", tree->reg1);
2333 }
2334
2335
2336 reg: CALL_I4 (this, VFUNC_ADDR) {
2337         int lreg = tree->left->reg1;
2338         int treg = X86_EAX;
2339
2340         if (lreg == treg) 
2341                 treg = X86_EDX;
2342
2343         if (tree->left->op != MB_TERM_NOP) {
2344                 mono_assert (lreg >= 0);
2345                 x86_push_reg (s->code, lreg);
2346         }
2347
2348         if (tree->data.ci.vtype_num) {
2349                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2350                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2351                 x86_push_reg (s->code, treg);
2352         }
2353
2354         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);        
2355         x86_call_virtual (s->code, lreg, 
2356                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
2357
2358         if (tree->data.ci.args_size)
2359                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2360
2361         PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
2362
2363         mono_assert (tree->reg1 == X86_EAX);
2364 }
2365
2366 stmt: CALL_VOID (this, ADDR_G) {
2367         int lreg = tree->left->reg1;
2368         int treg = X86_EAX;
2369
2370         if (lreg == treg) 
2371                 treg = X86_EDX;
2372         
2373         if (tree->left->op != MB_TERM_NOP) {
2374                 mono_assert (lreg >= 0);
2375                 x86_push_reg (s->code, lreg);
2376                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
2377         }
2378
2379         if (tree->data.ci.vtype_num) {
2380                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2381                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2382                 x86_push_reg (s->code, treg);
2383         }
2384
2385         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
2386         x86_call_code (s->code, 0);
2387
2388         if (tree->data.ci.args_size)
2389                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2390 }
2391
2392 stmt: CALL_VOID (this, INTF_ADDR) {
2393         int lreg = tree->left->reg1;
2394         int treg = X86_EAX;
2395
2396         if (lreg == treg) 
2397                 treg = X86_EDX;
2398
2399         if (tree->left->op != MB_TERM_NOP) {
2400                 mono_assert (lreg >= 0);
2401                 x86_push_reg (s->code, lreg);
2402         }
2403
2404         if (tree->data.ci.vtype_num) {
2405                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2406                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2407                 x86_push_reg (s->code, treg);
2408         }
2409
2410         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2411         x86_mov_reg_membase (s->code, lreg, lreg, 
2412                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2413         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2414         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2415
2416         if (tree->data.ci.args_size)
2417                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2418 }
2419
2420 stmt: CALL_VOID (this, VFUNC_ADDR) {
2421         int lreg = tree->left->reg1;
2422         int treg = X86_EAX;
2423
2424         if (lreg == treg) 
2425                 treg = X86_EDX;
2426
2427         if (tree->left->op != MB_TERM_NOP) {
2428                 mono_assert (lreg >= 0);
2429                 x86_push_reg (s->code, lreg);
2430         }
2431
2432         if (tree->data.ci.vtype_num) {
2433                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
2434                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2435                 x86_push_reg (s->code, treg);
2436         }
2437
2438         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2439         x86_call_virtual (s->code, lreg, 
2440                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
2441
2442         if (tree->data.ci.args_size)
2443                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
2444 }
2445
2446 stmt: SWITCH (reg) {
2447         guint32 offset;
2448         guint32 *jt = (guint32 *)tree->data.p;
2449
2450         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, jt [0]);
2451         offset = 6 + (guint32)s->code;
2452         x86_branch32 (s->code, X86_CC_GE, jt [jt [0] + 1] - offset, FALSE);
2453
2454         x86_mov_reg_memindex (s->code, X86_EAX, X86_NOBASEREG, 
2455                               tree->data.i + 4, tree->left->reg1, 2, 4);        
2456         x86_jump_reg (s->code, X86_EAX);
2457 }
2458
2459 #
2460 # 64 bit integers
2461 #
2462
2463 reg: CONV_I1 (lreg) {
2464         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
2465
2466
2467 reg: CONV_U1 (lreg) {
2468         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
2469
2470
2471 reg: CONV_I2 (lreg) {
2472         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
2473
2474
2475 reg: CONV_U2 (lreg) {
2476         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
2477
2478
2479 reg: CONV_I4 (lreg) {
2480         if (tree->reg1 != tree->left->reg1)
2481                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2482
2483
2484 reg: CONV_U4 (lreg) {
2485         if (tree->reg1 != tree->left->reg1)
2486                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2487
2488
2489
2490 reg: CONV_OVF_I4 (lreg){
2491         guint8 *start = s->code;
2492         guchar* o1, *o2, *o3, *o4, *o5;
2493         int i;
2494
2495         /* 
2496          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2497          */
2498         for (i = 0; i < 2; i++) {
2499                 s->code = start;
2500
2501                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2502
2503                 /* If the low word top bit is set, see if we are negative */
2504                 x86_branch8 (s->code, X86_CC_LT, o3 - o1, TRUE);
2505                 o1 = s->code;
2506
2507                 /* We are not negative (no top bit set, check for our top word to be zero */
2508                 x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
2509                 x86_branch8 (s->code, X86_CC_EQ, o4 - o2, TRUE);
2510                 o2 = s->code;
2511
2512                 /* throw exception */
2513                 x86_push_imm (s->code, "OverflowException");
2514                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
2515                                     arch_get_throw_exception_by_name ());
2516                 x86_call_code (s->code, 0);
2517         
2518                 o3 = s->code;
2519                 /* our top bit is set, check that top word is 0xfffffff */
2520                 x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg2, 0xffffffff);
2521                 
2522                 o4 = s->code;
2523                 /* nope, emit exception */
2524                 x86_branch8 (s->code, X86_CC_NE, o2 - o5, TRUE);
2525                 o5 = s->code;
2526
2527                 if (tree->reg1 != tree->left->reg1)
2528                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2529         }
2530 }
2531 reg: CONV_OVF_I4 (lreg){
2532         guint8 *br [3], *label [1];
2533
2534         /* 
2535          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2536          */
2537         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2538
2539         /* If the low word top bit is set, see if we are negative */
2540         br [0] = s->code; x86_branch8 (s->code, X86_CC_LT, 0, TRUE);
2541
2542         /* We are not negative (no top bit set, check for our top word to be zero */
2543         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
2544         br [1] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, TRUE);
2545         label [0] = s->code;
2546
2547         /* throw exception */
2548         x86_push_imm (s->code, "OverflowException");
2549         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
2550                             arch_get_throw_exception_by_name ());
2551         x86_call_code (s->code, 0);
2552         
2553         x86_patch (br [0], s->code);
2554         /* our top bit is set, check that top word is 0xfffffff */
2555         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg2, 0xffffffff);
2556                 
2557         x86_patch (br [1], s->code);
2558         /* nope, emit exception */
2559         br [2] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
2560         x86_patch (br [2], label [0]);
2561
2562         if (tree->reg1 != tree->left->reg1)
2563                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2564 }
2565
2566 reg: CONV_OVF_U4 (lreg) {
2567         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
2568         /* top word must be 0 */
2569         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
2570         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
2571         if (tree->reg1 != tree->left->reg1)
2572                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2573 }
2574
2575 reg: CONV_OVF_I4_UN (lreg) {
2576         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
2577         /* top word must be 0 */
2578         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
2579         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
2580         if (tree->reg1 != tree->left->reg1)
2581                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2582 }
2583
2584 stmt: POP (lreg)
2585
2586 lreg: CONST_I8 1 {
2587         x86_mov_reg_imm (s->code, tree->reg1, *((gint32 *)&tree->data.p));
2588         x86_mov_reg_imm (s->code, tree->reg2, *((gint32 *)&tree->data.p + 1));
2589 }
2590
2591 lreg: CONV_I8 (coni4) {
2592         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
2593
2594         if (tree->left->data.i >= 0)
2595                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2596         else 
2597                 x86_mov_reg_imm (s->code, tree->reg2, -1);              
2598 }
2599
2600 lreg: CONV_I8 (reg) {
2601         guint8 *i1;
2602
2603         if (tree->reg1 != tree->left->reg1)
2604                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2605
2606         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2607         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
2608         x86_branch8 (s->code, X86_CC_GE, 5, TRUE);
2609         i1 = s->code;
2610         x86_mov_reg_imm (s->code, tree->reg2, -1); 
2611         mono_assert ((s->code - i1) == 5);
2612 }
2613
2614 lreg: CONV_U8 (coni4) 1 {
2615         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
2616         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2617 }
2618
2619 lreg: CONV_U8 (reg) {
2620         if (tree->reg1 != tree->left->reg1)
2621                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2622         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2623 }
2624
2625 lreg: CONV_OVF_U8 (coni4) {
2626         if (tree->left->data.i < 0){
2627                 x86_push_imm (s->code, "OverflowException");
2628                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, 
2629                                     arch_get_throw_exception_by_name ());
2630                 x86_call_code (s->code, 0);
2631         } else {
2632                 x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
2633                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2634         }
2635 }
2636
2637 lreg: CONV_OVF_I8_UN (coni4) {
2638         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
2639         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2640 }
2641
2642 lreg: CONV_OVF_U8 (reg) {
2643         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
2644         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
2645
2646         if (tree->reg1 != tree->left->reg1)
2647                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2648         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2649 }
2650
2651 lreg: CONV_OVF_I8_UN (reg) {
2652         /* Convert uint value into int64, we pass everything */
2653         if (tree->reg1 != tree->left->reg1)
2654                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2655         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
2656 }
2657
2658 stmt: STIND_I8 (addr, lreg) {
2659
2660         switch (tree->left->data.ainfo.amode) {
2661
2662         case AMImmediate:
2663                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
2664                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
2665                 break;
2666                 
2667         case AMBase:
2668                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
2669                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
2670                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
2671                                      tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
2672                 break;          
2673         case AMIndex:
2674                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
2675                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2676                                       tree->right->reg1, 4);
2677                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset + 4,
2678                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2679                                       tree->right->reg2, 4);
2680                 break;          
2681         case AMBaseIndex:
2682                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
2683                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2684                                       tree->right->reg1, 4);
2685                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset + 4,
2686                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2687                                       tree->right->reg2, 4);
2688                 break;          
2689         }
2690 }
2691
2692 stmt: REMOTE_STIND_I8 (reg, lreg) {
2693         guint8 *br[2];
2694         int offset;
2695
2696         x86_push_reg (s->code, tree->right->reg1);
2697         x86_mov_reg_membase (s->code, tree->right->reg1, tree->left->reg1, 0, 4);
2698         x86_alu_membase_imm (s->code, X86_CMP, tree->right->reg1, 0, ((int)mono_defaults.transparent_proxy_class));
2699         x86_pop_reg (s->code, tree->right->reg1);
2700         
2701         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
2702
2703         /* this is a transparent proxy - remote the call */
2704
2705         /* save value to stack */
2706         x86_push_reg (s->code, tree->right->reg2);
2707         x86_push_reg (s->code, tree->right->reg1);
2708
2709         x86_push_reg (s->code, X86_ESP);
2710         x86_push_imm (s->code, tree->data.fi.field);
2711         x86_push_imm (s->code, tree->data.fi.klass);
2712         x86_push_reg (s->code, tree->left->reg1);
2713         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
2714         x86_call_code (s->code, 0);
2715         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 24);
2716
2717         br [1] = s->code; x86_jump8 (s->code, 0);
2718
2719         x86_patch (br [0], s->code);
2720         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
2721                 tree->data.fi.field->offset;
2722         x86_mov_membase_reg (s->code, tree->left->reg1, offset, tree->right->reg1, 4);
2723         x86_mov_membase_reg (s->code, tree->left->reg1, offset + 4, tree->right->reg2, 4);
2724
2725         x86_patch (br [1], s->code);
2726 }
2727
2728
2729 # an addr can use two address register (base and index register). The must take care 
2730 # that we do not override them (thus the use of x86_lea)
2731 lreg: LDIND_I8 (addr) {
2732
2733         switch (tree->left->data.ainfo.amode) {
2734
2735         case AMImmediate:
2736                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
2737                 x86_mov_reg_mem (s->code, tree->reg2, tree->left->data.ainfo.offset + 4, 4);
2738                 break;
2739
2740         case AMBase:
2741                 x86_lea_membase (s->code, tree->reg2, tree->left->data.ainfo.basereg,
2742                                  tree->left->data.ainfo.offset);
2743                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2744                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2745                 break;          
2746         case AMIndex:
2747                 x86_lea_memindex (s->code, tree->reg2, X86_NOBASEREG, tree->left->data.ainfo.offset,
2748                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift);
2749                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2750                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2751                 break;          
2752         case AMBaseIndex:
2753                 x86_lea_memindex (s->code, tree->reg2, tree->left->data.ainfo.basereg, 
2754                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
2755                                   tree->left->data.ainfo.shift);
2756                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2757                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2758                 break;          
2759         }
2760         PRINT_REG ("LDIND_I8_0", tree->reg1);
2761         PRINT_REG ("LDIND_I8_1", tree->reg2);
2762 }
2763
2764 lreg: SHR (lreg, coni4) {
2765         if (tree->right->data.i < 32) {
2766                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
2767                 x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg2, tree->right->data.i);
2768                 if (tree->reg1 != tree->left->reg1)
2769                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2770                 if (tree->reg2 != tree->left->reg2)
2771                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2772         } else if (tree->right->data.i < 64) {
2773                 if (tree->reg1 != tree->left->reg2)
2774                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
2775                 if (tree->reg2 != tree->left->reg2)
2776                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2777                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);
2778                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg1, (tree->right->data.i - 32));
2779         } /* else unspecified result */
2780 }
2781
2782 lreg: SHR_UN (lreg, coni4) {
2783         if (tree->right->data.i < 32) {
2784                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
2785                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg2, tree->right->data.i);
2786                 if (tree->reg1 != tree->left->reg1)
2787                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2788                 if (tree->reg2 != tree->left->reg2)
2789                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2790         } else if (tree->right->data.i < 64) {
2791                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
2792                 x86_shift_reg_imm (s->code, X86_SHR, tree->reg1, (tree->right->data.i - 32));
2793                 x86_mov_reg_imm (s->code, tree->reg2, 0);
2794         } /* else unspecified result */
2795 }
2796
2797 lreg: SHR (lreg, reg) {
2798         guint8 *br [1];
2799
2800         if (tree->right->reg1 != X86_ECX)
2801                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2802
2803         x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
2804         x86_shift_reg (s->code, X86_SAR, tree->left->reg2);
2805         x86_test_reg_imm (s->code, X86_ECX, 32);
2806         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
2807         x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
2808         x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);           
2809         x86_patch (br [0], s->code);
2810
2811         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2812 }
2813
2814 lreg: SHR_UN (lreg, reg) {
2815         guint8 *br [1];
2816
2817         if (tree->right->reg1 != X86_ECX)
2818                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2819
2820         x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
2821         x86_shift_reg (s->code, X86_SHR, tree->left->reg2);
2822         x86_test_reg_imm (s->code, X86_ECX, 32);
2823         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
2824         x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
2825         x86_shift_reg_imm (s->code, X86_SHR, tree->reg2, 31);           
2826         x86_patch (br [0], s->code);
2827
2828         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2829 }
2830
2831 lreg: SHL (lreg, coni4) {
2832         if (tree->right->data.i < 32) {
2833                 x86_shld_reg_imm (s->code, tree->left->reg2, tree->left->reg1, tree->right->data.i);
2834                 x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
2835                 if (tree->reg1 != tree->left->reg1)
2836                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2837                 if (tree->reg2 != tree->left->reg2)
2838                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2839         } else if (tree->right->data.i < 64) {
2840                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg1, 4);
2841                 x86_shift_reg_imm (s->code, X86_SHL, tree->reg2, (tree->right->data.i - 32));
2842                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg1, tree->reg1);     
2843         } /* else unspecified result */
2844 }
2845
2846 lreg: SHL (lreg, reg) {
2847         guint8 *br [1];
2848
2849         if (tree->right->reg1 != X86_ECX)
2850                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2851
2852         x86_shld_reg (s->code, tree->left->reg2, tree->left->reg1);
2853         x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
2854         x86_test_reg_imm (s->code, X86_ECX, 32);
2855         br [0] = s->code; x86_branch8 (s->code, X86_CC_EQ, 0, FALSE);
2856         x86_mov_reg_reg (s->code, tree->left->reg2, tree->left->reg1, 4);
2857         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->left->reg1); 
2858         x86_patch (br [0], s->code);
2859
2860         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2861 }
2862
2863 lreg: ADD (lreg, lreg) {
2864         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2865         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2866
2867         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2868 }
2869
2870 lreg: ADD_OVF (lreg, lreg) {
2871         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2872         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2873         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
2874
2875         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2876 }
2877
2878 lreg: ADD_OVF_UN (lreg, lreg) {
2879         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2880         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2881         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
2882
2883         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2884 }
2885
2886 lreg: SUB (lreg, lreg) {
2887         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2888         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2889
2890         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2891 }
2892
2893 lreg: SUB_OVF (lreg, lreg) {
2894         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2895         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2896         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
2897
2898         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2899 }
2900
2901 lreg: SUB_OVF_UN (lreg, lreg) {
2902         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2903         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2904         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
2905
2906         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2907 }
2908
2909 lreg: AND (lreg, lreg) {
2910         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
2911         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg2, tree->right->reg2);
2912
2913         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2914 }
2915
2916 lreg: OR (lreg, lreg) {
2917         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
2918         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg2, tree->right->reg2);
2919
2920         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2921 }
2922
2923 lreg: XOR (lreg, lreg) {
2924         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->right->reg1);
2925         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg2, tree->right->reg2);
2926
2927         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2928 }
2929
2930 lreg: NEG (lreg) {
2931         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2932
2933         x86_neg_reg (s->code, tree->reg1);
2934         x86_alu_reg_imm (s->code, X86_ADC, tree->reg2, 0);
2935         x86_neg_reg (s->code, tree->reg2);
2936 }
2937
2938 lreg: NOT (lreg) {
2939         MOVE_LREG (tree->reg1, tree->reg2, tree->left->reg1, tree->left->reg2);
2940
2941         x86_not_reg (s->code, tree->reg1);
2942         x86_not_reg (s->code, tree->reg2);
2943 }
2944
2945 lreg: MUL (lreg, lreg) {
2946         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2947                 x86_push_reg (s->code, X86_ECX);
2948
2949         x86_push_reg (s->code, tree->right->reg2);
2950         x86_push_reg (s->code, tree->right->reg1);
2951         x86_push_reg (s->code, tree->left->reg2);
2952         x86_push_reg (s->code, tree->left->reg1);
2953         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult);
2954         x86_call_code (s->code, 0);
2955         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2956
2957         if (mono_regset_reg_used (s->rs, X86_ECX))
2958                 x86_pop_reg (s->code, X86_ECX);
2959
2960         mono_assert (tree->reg1 == X86_EAX &&
2961                   tree->reg2 == X86_EDX);
2962 }
2963
2964 lreg: MUL_OVF (lreg, lreg) {
2965         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2966                 x86_push_reg (s->code, X86_ECX);
2967
2968         x86_push_reg (s->code, tree->right->reg2);
2969         x86_push_reg (s->code, tree->right->reg1);
2970         x86_push_reg (s->code, tree->left->reg2);
2971         x86_push_reg (s->code, tree->left->reg1);
2972         /* pass a pointer to store the resulting exception -
2973          * ugly, but it works */
2974         x86_push_reg (s->code, X86_ESP); 
2975         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult_ovf);
2976         x86_call_code (s->code, 0);
2977         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
2978         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
2979         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
2980
2981         /* cond. emit exception */
2982         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
2983         x86_push_reg (s->code, X86_ECX);
2984         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
2985         x86_call_code (s->code, 0);
2986
2987         if (mono_regset_reg_used (s->rs, X86_ECX))
2988                 x86_pop_reg (s->code, X86_ECX);
2989
2990         mono_assert (tree->reg1 == X86_EAX &&
2991                      tree->reg2 == X86_EDX);
2992 }
2993
2994 lreg: MUL_OVF_UN (lreg, lreg) {
2995         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2996                 x86_push_reg (s->code, X86_ECX);
2997
2998         x86_push_reg (s->code, tree->right->reg2);
2999         x86_push_reg (s->code, tree->right->reg1);
3000         x86_push_reg (s->code, tree->left->reg2);
3001         x86_push_reg (s->code, tree->left->reg1);
3002         /* pass a pointer to store the resulting exception -
3003          * ugly, but it works */
3004         x86_push_reg (s->code, X86_ESP); 
3005         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llmult_ovf_un);
3006         x86_call_code (s->code, 0);
3007         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
3008         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
3009         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
3010
3011         /* cond. emit exception */
3012         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
3013         x86_push_reg (s->code, X86_ECX);                                 
3014         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
3015         x86_call_code (s->code, 0);
3016
3017         if (mono_regset_reg_used (s->rs, X86_ECX))
3018                 x86_pop_reg (s->code, X86_ECX);
3019
3020         mono_assert (tree->reg1 == X86_EAX &&
3021                      tree->reg2 == X86_EDX);
3022 }
3023
3024 lreg: DIV (lreg, lreg) {
3025         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3026                 x86_push_reg (s->code, X86_ECX);
3027
3028         x86_push_reg (s->code, tree->right->reg2);
3029         x86_push_reg (s->code, tree->right->reg1);
3030         x86_push_reg (s->code, tree->left->reg2);
3031         x86_push_reg (s->code, tree->left->reg1);
3032         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_lldiv);
3033         x86_call_code (s->code, 0);
3034         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3035
3036         if (mono_regset_reg_used (s->rs, X86_ECX))
3037                 x86_pop_reg (s->code, X86_ECX);
3038
3039         mono_assert (tree->reg1 == X86_EAX &&
3040                      tree->reg2 == X86_EDX);
3041 }
3042
3043 lreg: REM (lreg, lreg) {
3044         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3045                 x86_push_reg (s->code, X86_ECX);
3046
3047         x86_push_reg (s->code, tree->right->reg2);
3048         x86_push_reg (s->code, tree->right->reg1);
3049         x86_push_reg (s->code, tree->left->reg2);
3050         x86_push_reg (s->code, tree->left->reg1);
3051         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llrem);
3052         x86_call_code (s->code, 0);
3053         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3054
3055         if (mono_regset_reg_used (s->rs, X86_ECX))
3056                 x86_pop_reg (s->code, X86_ECX);
3057
3058         mono_assert (tree->reg1 == X86_EAX &&
3059                      tree->reg2 == X86_EDX);
3060 }
3061
3062 lreg: DIV_UN (lreg, lreg) {
3063         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3064                 x86_push_reg (s->code, X86_ECX);
3065
3066         x86_push_reg (s->code, tree->right->reg2);
3067         x86_push_reg (s->code, tree->right->reg1);
3068         x86_push_reg (s->code, tree->left->reg2);
3069         x86_push_reg (s->code, tree->left->reg1);
3070         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_lldiv_un);
3071         x86_call_code (s->code, 0);
3072         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3073
3074         if (mono_regset_reg_used (s->rs, X86_ECX))
3075                 x86_pop_reg (s->code, X86_ECX);
3076
3077         mono_assert (tree->reg1 == X86_EAX &&
3078                      tree->reg2 == X86_EDX);
3079 }
3080
3081 lreg: REM_UN (lreg, lreg) {
3082         if (mono_regset_reg_used (s->rs, X86_ECX)) 
3083                 x86_push_reg (s->code, X86_ECX);
3084
3085         x86_push_reg (s->code, tree->right->reg2);
3086         x86_push_reg (s->code, tree->right->reg1);
3087         x86_push_reg (s->code, tree->left->reg2);
3088         x86_push_reg (s->code, tree->left->reg1);
3089         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_llrem_un);
3090         x86_call_code (s->code, 0);
3091         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
3092
3093         if (mono_regset_reg_used (s->rs, X86_ECX))
3094                 x86_pop_reg (s->code, X86_ECX);
3095
3096         mono_assert (tree->reg1 == X86_EAX &&
3097                      tree->reg2 == X86_EDX);
3098 }
3099
3100 lreg: CALL_I8 (this, ADDR_G) {
3101         int lreg = tree->left->reg1;
3102         int treg = X86_EAX;
3103
3104         if (lreg == treg) 
3105                 treg = X86_EDX;
3106         
3107         if (tree->left->op != MB_TERM_NOP) {
3108                 mono_assert (lreg >= 0);
3109                 x86_push_reg (s->code, lreg);
3110                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
3111         }
3112
3113         if (tree->data.ci.vtype_num) {
3114                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3115                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3116                 x86_push_reg (s->code, treg);
3117         }
3118
3119         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
3120         x86_call_code (s->code, 0);
3121
3122         if (tree->data.ci.args_size)
3123                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3124
3125         mono_assert (tree->reg1 == X86_EAX);
3126         mono_assert (tree->reg2 == X86_EDX);
3127 }
3128
3129 lreg: CALL_I8 (this, VFUNC_ADDR) {
3130         int lreg = tree->left->reg1;
3131         int treg = X86_EAX;
3132
3133         if (lreg == treg) 
3134                 treg = X86_EDX;
3135
3136         if (tree->left->op != MB_TERM_NOP) {
3137                 mono_assert (lreg >= 0);
3138                 x86_push_reg (s->code, lreg);
3139         }
3140
3141         if (tree->data.ci.vtype_num) {
3142                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3143                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3144                 x86_push_reg (s->code, treg);
3145         }
3146
3147         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3148         x86_call_virtual (s->code, lreg, 
3149                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
3150
3151         if (tree->data.ci.args_size)
3152                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3153
3154         PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
3155         PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
3156
3157         mono_assert (tree->reg1 == X86_EAX);
3158         mono_assert (tree->reg2 == X86_EDX);
3159 }
3160
3161 lreg: CALL_I8 (this, INTF_ADDR) {
3162         int lreg = tree->left->reg1;
3163         int treg = X86_EAX;
3164
3165         if (lreg == treg) 
3166                 treg = X86_EDX;
3167
3168         if (tree->left->op != MB_TERM_NOP) {
3169                 mono_assert (lreg >= 0);
3170                 x86_push_reg (s->code, lreg);
3171         }
3172
3173         if (tree->data.ci.vtype_num) {
3174                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
3175                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3176                 x86_push_reg (s->code, treg);
3177         }
3178
3179         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3180         x86_mov_reg_membase (s->code, lreg, lreg, 
3181                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
3182         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
3183         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
3184
3185         if (tree->data.ci.args_size)
3186                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
3187
3188         PRINT_REG ("CALL_I8(INTERFACE)", tree->reg1);
3189
3190         mono_assert (tree->reg1 == X86_EAX);
3191         mono_assert (tree->reg2 == X86_EDX);
3192 }
3193
3194 stmt: RET (lreg) {
3195         if (tree->left->reg1 != X86_EAX) {
3196                 if (tree->left->reg2 != X86_EAX) {
3197                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
3198                         if (tree->left->reg2 != X86_EDX)
3199                                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
3200                 } else { 
3201                         x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg2, 4);
3202                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
3203                         x86_mov_reg_reg (s->code, X86_EDX, X86_ECX, 4);
3204                 }
3205         } else if (tree->left->reg2 != X86_EDX) {
3206                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
3207         }
3208
3209         if (!tree->last_instr) {
3210                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
3211                 x86_jump32 (s->code, 0);      
3212         }
3213 }
3214
3215
3216 stmt: ARG_I8 (lreg) {
3217         x86_push_reg (s->code, tree->left->reg2);
3218         x86_push_reg (s->code, tree->left->reg1);
3219 }
3220
3221 reg: CSET (COMPARE (lreg, lreg)) {
3222         guint8 *br [4];
3223         int lreg1, lreg2, rreg1, rreg2;
3224
3225         lreg1 = tree->left->left->reg1;
3226         lreg2 = tree->left->left->reg2;
3227         rreg1 = tree->left->right->reg1;
3228         rreg2 = tree->left->right->reg2;
3229
3230
3231         if (tree->data.i == CEE_CEQ) {
3232                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3233                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3234                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3235                 x86_patch (br [0], s->code);
3236                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, FALSE);
3237                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
3238                 return;
3239         }
3240
3241         switch (tree->data.i) {
3242         case CEE_CGT:
3243                 x86_alu_reg_reg (s->code, X86_CMP, rreg2, lreg2);
3244                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, TRUE);
3245                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3246                 x86_alu_reg_reg (s->code, X86_CMP, rreg1, lreg1);
3247                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3248                 break;
3249         case CEE_CGT_UN:
3250                 x86_alu_reg_reg (s->code, X86_CMP, rreg2, lreg2);
3251                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, FALSE);
3252                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3253                 x86_alu_reg_reg (s->code, X86_CMP, rreg1, lreg1);
3254                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3255                 break;
3256         case CEE_CLT:
3257                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3258                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, TRUE);
3259                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3260                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3261                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3262                 break;
3263         case CEE_CLT_UN:
3264                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3265                 br [0] = s->code; x86_branch8 (s->code, X86_CC_GT, 0, FALSE);
3266                 br [1] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3267                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3268                 br [2] = s->code; x86_branch8 (s->code, X86_CC_GE, 0, FALSE);
3269                 break;
3270         default:
3271                 g_assert_not_reached ();
3272         }
3273
3274         /* set result to 1 */
3275         x86_patch (br [1], s->code);
3276         x86_mov_reg_imm (s->code, tree->reg1, 1);
3277         br [3] = s->code; x86_jump8 (s->code, 0);
3278
3279         /* set result to 0 */
3280         x86_patch (br [0], s->code);
3281         x86_patch (br [2], s->code);
3282         x86_mov_reg_imm (s->code, tree->reg1, 0);       
3283
3284         x86_patch (br [3], s->code);
3285 }
3286
3287 stmt: CBRANCH (COMPARE (lreg, lreg)) {
3288         guint8 *br [1];
3289         int lreg1, lreg2, rreg1, rreg2;
3290
3291         lreg1 = tree->left->left->reg1;
3292         lreg2 = tree->left->left->reg2;
3293         rreg1 = tree->left->right->reg1;
3294         rreg2 = tree->left->right->reg2;
3295
3296         switch (tree->data.bi.cond) {
3297         case CEE_BLT:
3298                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3299                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3300                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
3301                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3302                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3303                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3304                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3305                 x86_patch (br [0], s->code);    
3306                 break;
3307         case CEE_BLT_UN:
3308                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3309                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3310                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3311                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3312                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3313                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3314                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3315                 x86_patch (br [0], s->code);    
3316                 break;
3317         case CEE_BGT:
3318                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3319                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3320                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
3321                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3322                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3323                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3324                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3325                 x86_patch (br [0], s->code);    
3326                 break;
3327         case CEE_BGT_UN:
3328                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3329                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3330                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3331                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3332                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3333                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3334                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3335                 x86_patch (br [0], s->code);    
3336                 break;
3337         case CEE_BEQ:
3338                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3339                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3340                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3341                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3342                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
3343                 x86_patch (br [0], s->code);
3344                 break;
3345         case CEE_BNE_UN:
3346                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3347                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3348                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3349                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3350                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3351                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3352                 break;
3353         case CEE_BGE:
3354                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3355                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3356                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
3357                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3358                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3359                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3360                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3361                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
3362                 x86_patch (br [0], s->code);
3363                 break;
3364         case CEE_BGE_UN:
3365                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3366                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3367                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
3368                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3369                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3370                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3371                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
3372                 x86_patch (br [0], s->code);    
3373                 break;
3374         case CEE_BLE:
3375                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3376                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3377                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
3378                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, TRUE);
3379                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3380                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3381                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
3382                 x86_patch (br [0], s->code);    
3383                 break;
3384         case CEE_BLE_UN:
3385                 x86_alu_reg_reg (s->code, X86_CMP, lreg2, rreg2);
3386                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3387                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
3388                 br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
3389                 x86_alu_reg_reg (s->code, X86_CMP, lreg1, rreg1);
3390                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3391                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
3392                 x86_patch (br [0], s->code);    
3393                 break;
3394         default:
3395                 g_assert_not_reached ();
3396         }       
3397 }
3398
3399 #
3400 # floating point 
3401
3402 #stmt: STLOC (CONV_I4 (freg)) {
3403 #       // fixme: set CW
3404 #       x86_fist_pop_membase (s->code, X86_EBP, tree->data.i, FALSE);
3405 #} 
3406
3407 reg: CONV_I1 (freg) {
3408         if (mono_use_fast_iconv) {
3409                 mono_emit_fast_iconv(s, tree);
3410                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, FALSE);
3411         } else {
3412                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3413                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3414                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3415                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3416                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3417                 x86_fldcw_membase (s->code, X86_ESP, 2);
3418                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3419                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3420                 x86_pop_reg (s->code, tree->reg1);
3421                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, FALSE);
3422                 x86_fldcw_membase (s->code, X86_ESP, 0);
3423                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3424         }
3425 }
3426
3427 reg: CONV_U1 (freg) {
3428         if (mono_use_fast_iconv) {
3429                 mono_emit_fast_iconv(s, tree);
3430                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
3431         } else {
3432                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3433                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3434                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3435                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3436                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3437                 x86_fldcw_membase (s->code, X86_ESP, 2);
3438                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3439                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3440                 x86_pop_reg (s->code, tree->reg1);
3441                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
3442                 x86_fldcw_membase (s->code, X86_ESP, 0);
3443                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3444         }
3445 }
3446
3447 reg: CONV_I2 (freg) {
3448         if (mono_use_fast_iconv) {
3449                 mono_emit_fast_iconv(s, tree);
3450                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, TRUE);
3451         } else {
3452                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3453                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3454                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3455                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3456                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3457                 x86_fldcw_membase (s->code, X86_ESP, 2);
3458                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3459                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3460                 x86_pop_reg (s->code, tree->reg1);
3461                 x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, TRUE);
3462                 x86_fldcw_membase (s->code, X86_ESP, 0);
3463                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3464         }
3465 }
3466
3467 reg: CONV_U2 (freg) {
3468         if (mono_use_fast_iconv) {
3469                 mono_emit_fast_iconv(s, tree);
3470                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, TRUE);
3471         } else {
3472                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3473                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3474                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3475                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3476                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3477                 x86_fldcw_membase (s->code, X86_ESP, 2);
3478                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3479                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3480                 x86_pop_reg (s->code, tree->reg1);
3481                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, TRUE);
3482                 x86_fldcw_membase (s->code, X86_ESP, 0);
3483                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3484         }
3485 }
3486
3487 reg: CONV_I4 (freg) {
3488         if (mono_use_fast_iconv) {
3489                 mono_emit_fast_iconv(s, tree);
3490         } else {
3491                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3492                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3493                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3494                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3495                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3496                 x86_fldcw_membase (s->code, X86_ESP, 2);
3497                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3498                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3499                 x86_pop_reg (s->code, tree->reg1);
3500                 x86_fldcw_membase (s->code, X86_ESP, 0);
3501                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3502         }
3503 }
3504
3505 reg: CONV_U4 (freg) {
3506         if (mono_use_fast_iconv) {
3507                 mono_emit_fast_iconv(s, tree);
3508         } else {
3509                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3510                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3511                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3512                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3513                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3514                 x86_fldcw_membase (s->code, X86_ESP, 2);
3515                 x86_push_reg (s->code, X86_EAX); // SP = SP - 4
3516                 x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
3517                 x86_pop_reg (s->code, tree->reg1);
3518                 x86_fldcw_membase (s->code, X86_ESP, 0);
3519                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3520         }
3521 }
3522
3523 lreg: CONV_I8 (freg) {
3524         if (mono_use_fast_iconv) {
3525                 mono_emit_fast_iconv_i8(s, tree);
3526         } else {
3527                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3528                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3529                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3530                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3531                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3532                 x86_fldcw_membase (s->code, X86_ESP, 2);
3533                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
3534                 x86_fist_pop_membase (s->code, X86_ESP, 0, TRUE);
3535                 x86_pop_reg (s->code, tree->reg1);
3536                 x86_pop_reg (s->code, tree->reg2);
3537                 x86_fldcw_membase (s->code, X86_ESP, 0);
3538                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3539         }
3540 }
3541
3542 lreg: CONV_U8 (freg) {
3543         if (mono_use_fast_iconv) {
3544                 mono_emit_fast_iconv_i8(s, tree);
3545         } else {
3546                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3547                 x86_fnstcw_membase(s->code, X86_ESP, 0);
3548                 x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
3549                 x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
3550                 x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
3551                 x86_fldcw_membase (s->code, X86_ESP, 2);
3552                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
3553                 x86_fist_pop_membase (s->code, X86_ESP, 0, TRUE);
3554                 x86_pop_reg (s->code, tree->reg1);
3555                 x86_pop_reg (s->code, tree->reg2);
3556                 x86_fldcw_membase (s->code, X86_ESP, 0);
3557                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3558         }
3559 }
3560
3561 reg: CSET (COMPARE (freg, freg)) {
3562         int treg = tree->reg1;
3563
3564         if (treg != X86_EAX)
3565                 x86_push_reg (s->code, X86_EAX);
3566
3567         x86_fcompp (s->code);
3568         x86_fnstsw (s->code);
3569         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3570
3571         switch (tree->data.i) {
3572         case CEE_CEQ:
3573                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
3574                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
3575                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
3576                 break;
3577         case CEE_CGT:
3578                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3579                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
3580                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
3581                 break;
3582         case CEE_CGT_UN:
3583                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3584                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
3585                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
3586                 break;
3587         case CEE_CLT:
3588                 x86_set_reg (s->code, X86_CC_EQ, treg, TRUE);
3589                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
3590                 break;
3591         case CEE_CLT_UN:
3592                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
3593                 x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
3594                 break;
3595         default:
3596                 g_assert_not_reached ();
3597         }
3598         
3599         if (treg != X86_EAX)
3600                 x86_pop_reg (s->code, X86_EAX);
3601 }
3602
3603 freg: CONV_R8 (freg) {
3604         /* nothing to do */
3605 }
3606
3607 freg: CONV_R4 (freg) {
3608         /* fixme: nothing to do ??*/
3609 }
3610
3611 freg: CONV_R8 (LDIND_I4 (ADDR_G)) {
3612         x86_fild (s->code, tree->left->left->data.p, FALSE);
3613 }
3614
3615 freg: CONV_R4 (reg) {
3616         x86_push_reg (s->code, tree->left->reg1);
3617         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
3618         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3619 }
3620
3621 freg: CONV_R8 (reg) {
3622         x86_push_reg (s->code, tree->left->reg1);
3623         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
3624         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
3625 }
3626
3627 freg: CONV_R_UN (reg) {
3628         x86_push_imm (s->code, 0);
3629         x86_push_reg (s->code, tree->left->reg1);
3630         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
3631         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
3632 }
3633
3634 freg: CONV_R_UN (lreg) {
3635         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3636         guint8 *br [1];
3637
3638         /* load 64bit integer to FP stack */
3639         x86_push_imm (s->code, 0);
3640         x86_push_reg (s->code, tree->left->reg2);
3641         x86_push_reg (s->code, tree->left->reg1);
3642         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
3643         /* store as 80bit FP value */
3644         x86_fst80_membase (s->code, X86_ESP, 0);
3645
3646         /* test if lreg is negative */
3647         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
3648         br [0] = s->code; x86_branch8 (s->code, X86_CC_GEZ, 0, TRUE);
3649
3650         /* add correction constant mn */
3651         x86_fld80_mem (s->code, mn);
3652         x86_fld80_membase (s->code, X86_ESP, 0);
3653         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
3654         x86_fst80_membase (s->code, X86_ESP, 0);
3655
3656         x86_patch (br [0], s->code);
3657
3658         x86_fld80_membase (s->code, X86_ESP, 0);
3659         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
3660 }
3661
3662 freg: CONV_R4 (lreg) {
3663         x86_push_reg (s->code, tree->left->reg2);
3664         x86_push_reg (s->code, tree->left->reg1);
3665         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
3666         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
3667 }
3668
3669 freg: CONV_R8 (lreg) {
3670         x86_push_reg (s->code, tree->left->reg2);
3671         x86_push_reg (s->code, tree->left->reg1);
3672         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
3673         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
3674 }
3675
3676 freg: CONST_R4 {
3677         float f = *(float *)tree->data.p;
3678
3679         if (f == 0.0)
3680                 x86_fldz (s->code);
3681         else if (f == 1.0)
3682                 x86_fld1(s->code);
3683         else
3684                 x86_fld (s->code, tree->data.p, FALSE);
3685 }
3686
3687 freg: CONST_R8 {
3688         double d = *(double *)tree->data.p;
3689
3690         if (d == 0.0)
3691                 x86_fldz (s->code);
3692         else if (d == 1.0)
3693                 x86_fld1(s->code);
3694         else
3695                 x86_fld (s->code, tree->data.p, TRUE);
3696 }
3697
3698 freg: LDIND_R4 (addr) {
3699
3700         switch (tree->left->data.ainfo.amode) {
3701
3702         case AMImmediate:
3703                 x86_fld (s->code, tree->left->data.ainfo.offset, FALSE);
3704                 break;
3705
3706         case AMBase:
3707                 x86_fld_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, FALSE);
3708                 break;          
3709         case AMIndex:
3710                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
3711                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3712                                   tree->left->data.ainfo.shift);
3713                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE);
3714                 break;          
3715         case AMBaseIndex:
3716                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
3717                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3718                                   tree->left->data.ainfo.shift);
3719                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE);
3720                 break;          
3721         }
3722 }
3723
3724 freg: LDIND_R8 (addr) {
3725
3726         switch (tree->left->data.ainfo.amode) {
3727
3728         case AMImmediate:
3729                 x86_fld (s->code, tree->left->data.ainfo.offset, TRUE);
3730                 break;
3731
3732         case AMBase:
3733                 x86_fld_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, TRUE);
3734                 break;          
3735         case AMIndex:
3736                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
3737                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3738                                   tree->left->data.ainfo.shift);
3739                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE);
3740                 break;          
3741         case AMBaseIndex:
3742                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
3743                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3744                                   tree->left->data.ainfo.shift);
3745                 x86_fld_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE);
3746                 break;          
3747         }
3748 }
3749
3750
3751 freg: ADD (freg, freg) {
3752         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
3753 }
3754
3755 freg: SUB (freg, freg) {
3756         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE);
3757 }
3758
3759 freg: MUL (freg, freg) {
3760         x86_fp_op_reg (s->code, X86_FMUL, 1, TRUE);
3761 }
3762
3763 freg: DIV (freg, freg) {
3764         x86_fp_op_reg (s->code, X86_FDIV, 1, TRUE);
3765 }
3766
3767 freg: REM (freg, freg) {
3768         guint8 *l1, *l2;
3769
3770         /* we need to exchange ST(0) with ST(1) */
3771         x86_fxch (s->code, 1);
3772
3773         /* this requires a loop, because fprem1 somtimes 
3774          * returns a partial remainder */
3775         l1 = s->code;
3776         x86_fprem1 (s->code);
3777         x86_fnstsw (s->code);
3778         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x0400);
3779         l2 = s->code + 2;
3780         x86_branch8 (s->code, X86_CC_NE, l1 - l2, FALSE);
3781
3782         /* pop result */
3783         x86_fstp (s->code, 1);
3784 }
3785
3786 freg: NEG (freg) {
3787         x86_fchs (s->code);
3788 }
3789
3790 stmt: POP (freg)
3791
3792 stmt: STIND_R4 (addr, freg) {
3793
3794         switch (tree->left->data.ainfo.amode) {
3795
3796         case AMImmediate:
3797                 x86_fst (s->code, tree->left->data.ainfo.offset, FALSE, TRUE);
3798                 break;
3799
3800         case AMBase:
3801                 x86_fst_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, 
3802                                  FALSE, TRUE);
3803                 break;          
3804         case AMIndex:
3805                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
3806                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3807                                   tree->left->data.ainfo.shift);
3808                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE, TRUE);
3809                 break;          
3810         case AMBaseIndex:
3811                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
3812                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3813                                   tree->left->data.ainfo.shift);
3814                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, FALSE, TRUE);
3815                 break;          
3816         }
3817 }
3818
3819 stmt: STIND_R8 (addr, freg) {
3820
3821         switch (tree->left->data.ainfo.amode) {
3822
3823         case AMImmediate:
3824                 x86_fst (s->code, tree->left->data.ainfo.offset, TRUE, TRUE);
3825                 break;
3826
3827         case AMBase:
3828                 x86_fst_membase (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset, 
3829                                  TRUE, TRUE);
3830                 break;          
3831         case AMIndex:
3832                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, X86_NOBASEREG, 
3833                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3834                                   tree->left->data.ainfo.shift);
3835                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE, TRUE);
3836                 break;          
3837         case AMBaseIndex:
3838                 x86_lea_memindex (s->code, tree->left->data.ainfo.indexreg, tree->left->data.ainfo.basereg, 
3839                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
3840                                   tree->left->data.ainfo.shift);
3841                 x86_fst_membase (s->code, tree->left->data.ainfo.indexreg, 0, TRUE, TRUE);
3842                 break;          
3843         }
3844 }
3845
3846 stmt: REMOTE_STIND_R4 (reg, freg) {
3847         guint8 *br[2];
3848         int treg = X86_EAX;
3849         int lreg = tree->left->reg1;
3850         int offset;
3851
3852         if (lreg == treg)
3853                 treg = X86_EDX;
3854
3855         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
3856         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
3857         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE); 
3858
3859         /* this is a transparent proxy - remote the call */
3860
3861         /* save value to stack */
3862         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3863         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
3864
3865         x86_push_reg (s->code, X86_ESP);
3866         x86_push_imm (s->code, tree->data.fi.field);
3867         x86_push_imm (s->code, tree->data.fi.klass);
3868         x86_push_reg (s->code, lreg);
3869         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
3870         x86_call_code (s->code, 0);
3871         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
3872
3873         br [1] = s->code; x86_jump8 (s->code, 0); 
3874
3875         x86_patch (br [0], s->code);
3876         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
3877                 tree->data.fi.field->offset;
3878         x86_fst_membase (s->code, lreg, offset, FALSE, TRUE);
3879
3880         x86_patch (br [1], s->code);
3881 }
3882
3883 stmt: REMOTE_STIND_R8 (reg, freg) {
3884         guint8 *br[2];
3885         int treg = X86_EAX;
3886         int lreg = tree->left->reg1;
3887         int offset;
3888
3889         if (lreg == treg)
3890                 treg = X86_EDX;
3891
3892         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
3893         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
3894         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE); 
3895
3896         /* this is a transparent proxy - remote the call */
3897
3898         /* save value to stack */
3899         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
3900         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
3901
3902         x86_push_reg (s->code, X86_ESP);
3903         x86_push_imm (s->code, tree->data.fi.field);
3904         x86_push_imm (s->code, tree->data.fi.klass);
3905         x86_push_reg (s->code, lreg);
3906         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
3907         x86_call_code (s->code, 0);
3908         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 24);
3909
3910         br [1] = s->code; x86_jump8 (s->code, 0);
3911
3912         x86_patch (br [0], s->code);
3913         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
3914                 tree->data.fi.field->offset;
3915         x86_fst_membase (s->code, lreg, offset, TRUE, TRUE);
3916
3917         x86_patch (br [1], s->code);
3918 }
3919
3920 stmt: ARG_R4 (freg) {
3921         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3922         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
3923 }
3924
3925 stmt: ARG_R8 (freg) {
3926         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
3927         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
3928 }
3929
3930 # fixme: we need to implement unordered and ordered compares
3931
3932 stmt: CBRANCH (COMPARE (freg, freg)) {
3933
3934         x86_fcompp (s->code);
3935         x86_fnstsw (s->code);
3936         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3937
3938         switch (tree->data.bi.cond) {
3939         case CEE_BLT:
3940                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3941                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3942                 break;
3943         case CEE_BLT_UN:
3944                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3945                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3946                 break;
3947         case CEE_BGT:
3948                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3949                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3950                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3951                 break;
3952         case CEE_BGT_UN:
3953                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3954                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3955                 x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3956                 break;
3957         case CEE_BEQ:
3958                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
3959                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3960                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
3961                 break;
3962         case CEE_BNE_UN:
3963                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
3964                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3965                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3966                 break;
3967         case CEE_BGE:
3968                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3969                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3970                 break;
3971         case CEE_BGE_UN:
3972                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3973                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3974                 break;
3975         case CEE_BLE:
3976                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3977                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3978                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3979                 break;
3980         case CEE_BLE_UN:
3981                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3982                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bi.target);
3983                 x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3984                 break;
3985         default:
3986                 g_assert_not_reached ();
3987         }
3988 }
3989
3990 freg: CALL_R8 (this, ADDR_G) {
3991         int lreg = tree->left->reg1;
3992         int treg = X86_EAX;
3993
3994         if (lreg == treg) 
3995                 treg = X86_EDX;
3996         
3997         if (tree->left->op != MB_TERM_NOP) {
3998                 mono_assert (lreg >= 0);
3999                 x86_push_reg (s->code, lreg);
4000                 x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
4001         }
4002
4003         if (tree->data.ci.vtype_num) {
4004                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4005                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4006                 x86_push_reg (s->code, treg);
4007         }
4008
4009         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
4010         x86_call_code (s->code, 0);
4011
4012         if (tree->data.ci.args_size)
4013                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4014 }
4015
4016 freg: CALL_R8 (this, INTF_ADDR) {
4017         int lreg = tree->left->reg1;
4018         int treg = X86_EAX;
4019
4020         if (lreg == treg) 
4021                 treg = X86_EDX;
4022
4023         if (tree->left->op != MB_TERM_NOP) {
4024                 mono_assert (lreg >= 0);
4025                 x86_push_reg (s->code, lreg);
4026         }
4027
4028         if (tree->data.ci.vtype_num) {
4029                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4030                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4031                 x86_push_reg (s->code, treg);
4032         }
4033
4034         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
4035         x86_mov_reg_membase (s->code, lreg, lreg, 
4036                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
4037         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
4038         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
4039
4040         if (tree->data.ci.args_size)
4041                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4042 }
4043
4044 freg: CALL_R8 (this, VFUNC_ADDR) {
4045         int lreg = tree->left->reg1;
4046         int treg = X86_EAX;
4047
4048         if (lreg == treg) 
4049                 treg = X86_EDX;
4050
4051         if (tree->left->op != MB_TERM_NOP) {
4052                 mono_assert (lreg >= 0);
4053                 x86_push_reg (s->code, lreg);
4054         }
4055
4056         if (tree->data.ci.vtype_num) {
4057                 int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
4058                 x86_lea_membase (s->code, treg, X86_EBP, offset);
4059                 x86_push_reg (s->code, treg);
4060         }
4061
4062         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
4063         x86_call_virtual (s->code, lreg, 
4064                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
4065
4066         if (tree->data.ci.args_size)
4067                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
4068 }
4069
4070 stmt: RET (freg) {
4071         if (!tree->last_instr) {
4072                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
4073                 x86_jump32 (s->code, 0);      
4074         }
4075 }
4076
4077 # support for value types
4078
4079 reg: LDIND_OBJ (reg) {
4080         if (tree->left->reg1 != tree->reg1)
4081                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
4082 }
4083
4084 stmt: STIND_OBJ (reg, reg) {
4085         mono_assert (tree->data.i > 0);
4086
4087         x86_push_imm (s->code, tree->data.i);
4088         x86_push_reg (s->code, tree->right->reg1);
4089         x86_push_reg (s->code, tree->left->reg1);
4090         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4091         x86_call_code (s->code, 0);
4092         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4093 }
4094
4095 stmt: REMOTE_STIND_OBJ (reg, reg) {
4096         guint8 *br[2];
4097         int treg = X86_EAX;
4098         int lreg = tree->left->reg1;
4099         int rreg = tree->right->reg1;
4100         int offset;
4101
4102         if (lreg == treg)
4103                 treg = X86_EDX;
4104
4105         if (rreg == treg)
4106                 treg = X86_ECX;
4107
4108         x86_mov_reg_membase (s->code, treg, lreg, 0, 4);
4109         x86_alu_membase_imm (s->code, X86_CMP, treg, 0, ((int)mono_defaults.transparent_proxy_class));
4110         br [0] = s->code; x86_branch8 (s->code, X86_CC_NE, 0, FALSE);
4111
4112         /* this is a transparent proxy - remote the call */
4113
4114         x86_push_reg (s->code, rreg);
4115         x86_push_imm (s->code, tree->data.fi.field);
4116         x86_push_imm (s->code, tree->data.fi.klass);
4117         x86_push_reg (s->code, lreg);
4118         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_store_remote_field);
4119         x86_call_code (s->code, 0);
4120         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
4121
4122         br [1] = s->code; x86_jump8 (s->code, 0);
4123
4124         x86_patch (br [0], s->code);
4125         offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
4126                 tree->data.fi.field->offset;
4127
4128         x86_push_imm (s->code, mono_class_value_size (tree->data.fi.klass, NULL));
4129         x86_push_reg (s->code, tree->right->reg1);
4130         x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, sizeof (MonoObject));      
4131         x86_push_reg (s->code, tree->left->reg1);
4132         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4133         x86_call_code (s->code, 0);
4134         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4135
4136         x86_patch (br [1], s->code);
4137 }
4138
4139 stmt: ARG_OBJ (coni4) {
4140         x86_push_imm (s->code, tree->left->data.i);     
4141 }
4142
4143 stmt: ARG_OBJ (reg) {
4144         int size = tree->data.i;
4145         int sa;
4146         
4147         mono_assert (size > 0);
4148
4149         sa = size + 3;
4150         sa &= ~3;
4151
4152         /* reserve space for the argument */
4153         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
4154
4155         x86_push_reg (s->code, X86_EAX);
4156         x86_push_reg (s->code, X86_EDX);
4157         x86_push_reg (s->code, X86_ECX);
4158
4159         x86_push_imm (s->code, size);
4160         x86_push_reg (s->code, tree->left->reg1);
4161         x86_lea_membase (s->code, X86_EAX, X86_ESP, 5*4);
4162         x86_push_reg (s->code, X86_EAX);
4163
4164         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4165         x86_call_code (s->code, 0);
4166         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4167
4168         x86_pop_reg (s->code, X86_ECX);
4169         x86_pop_reg (s->code, X86_EDX);
4170         x86_pop_reg (s->code, X86_EAX);
4171 }
4172
4173 stmt: RET_OBJ (reg) {
4174         int size = tree->data.i;
4175
4176         x86_push_imm (s->code, size);
4177         x86_push_reg (s->code, tree->left->reg1);
4178         x86_push_membase (s->code, X86_EBP, 8);
4179
4180
4181         mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
4182         x86_call_code (s->code, 0);
4183
4184         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
4185
4186         if (!tree->last_instr) {
4187                 mono_add_jump_info (s, s->code, MONO_JUMP_INFO_EPILOG, NULL);
4188                 x86_jump32 (s->code, 0);      
4189         }
4190 }
4191
4192 %% 
4193
4194 #include "jit.h"
4195
4196 gint64 
4197 mono_llmult (gint64 a, gint64 b)
4198 {
4199         return a * b;
4200 }
4201
4202 guint64  
4203 mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh)
4204 {
4205         guint64 res, t1;
4206
4207         // fixme: this is incredible slow
4208
4209         if (ah && bh)
4210                 goto raise_exception;
4211
4212         res = (guint64)al * (guint64)bl;
4213
4214         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
4215
4216         if (t1 > 0xffffffff)
4217                 goto raise_exception;
4218
4219         res += ((guint64)t1) << 32; 
4220
4221         *exc = NULL;
4222         return res;
4223
4224  raise_exception:
4225         *exc = mono_get_exception_overflow ();
4226         return 0;
4227 }
4228
4229 guint64  
4230 mono_llmult_ovf (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh)
4231 {
4232         gint64 res, t1;
4233
4234         // fixme: check for overflow
4235
4236         res = (gint64)al * (gint64)bl;
4237
4238         t1 = (gint64)ah * bl + al * (gint64)bh;
4239
4240         res += ((gint64)t1) << 32; 
4241
4242         *exc = NULL;
4243         return res;
4244 /*
4245  raise_exception:
4246         *exc = mono_get_exception_overflow ();
4247         return 0;
4248 */
4249 }
4250
4251 gint64 
4252 mono_lldiv (gint64 a, gint64 b)
4253 {
4254         return a / b;
4255 }
4256
4257 gint64 
4258 mono_llrem (gint64 a, gint64 b)
4259 {
4260         return a % b;
4261 }
4262
4263 guint64 
4264 mono_lldiv_un (guint64 a, guint64 b)
4265 {
4266         return a / b;
4267 }
4268
4269 guint64 
4270 mono_llrem_un (guint64 a, guint64 b)
4271 {
4272         return a % b;
4273 }
4274
4275 MBTree *
4276 mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
4277 {
4278         MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
4279
4280         t->op = op;
4281         t->left = left;
4282         t->right = right;
4283         t->reg1 = -1;
4284         t->reg2 = -1;
4285         t->reg3 = -1;
4286         t->svt = VAL_UNKNOWN;
4287         t->cli_addr = -1;
4288         return t;
4289 }
4290
4291 MBTree *
4292 mono_ctree_new_leaf (MonoMemPool *mp, int op)
4293 {
4294         return mono_ctree_new (mp, op, NULL, NULL);
4295 }
4296
4297 MonoArray*
4298 mono_array_new_wrapper  (MonoClass *eclass, guint32 n)
4299 {
4300         MonoDomain *domain = mono_domain_get ();
4301
4302         return mono_array_new (domain, eclass, n);
4303 }
4304
4305 MonoObject *
4306 mono_object_new_wrapper (MonoClass *klass)
4307 {
4308         MonoDomain *domain = mono_domain_get ();
4309
4310         return mono_object_new (domain, klass);
4311 }
4312
4313 MonoString*
4314 mono_ldstr_wrapper (MonoImage *image, guint32 ind)
4315 {
4316         MonoDomain *domain = mono_domain_get ();
4317
4318         return mono_ldstr (domain, image, ind);
4319 }
4320
4321 gpointer 
4322 mono_ldsflda (MonoClass *klass, int offset)
4323 {
4324         MonoDomain *domain = mono_domain_get ();
4325         MonoVTable *vt;
4326         gpointer addr;
4327         
4328         vt = mono_class_vtable (domain, klass);
4329         addr = (char*)(vt->data) + offset;
4330
4331         return addr;
4332 }
4333
4334 #ifdef DEBUG
4335 void *
4336 MEMCOPY (void *dest, const void *src, size_t n)
4337 {
4338         int i, l = n;
4339
4340         printf ("MEMCPY(%p to %p [%d]) ", src, dest, n);
4341
4342         for (i = 0; i < l; i++)
4343                 printf ("%02x ", *((guint8 *)src + i));
4344         printf ("\n");
4345         
4346         return memcpy (dest, src, n);
4347 }
4348 #endif
4349
4350 void mono_emit_fast_iconv (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
4351 {
4352         guint8* br [3];
4353         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 12);
4354         x86_fist_membase (s->code, X86_ESP, 8, TRUE); // rounded value
4355         x86_fst_membase (s->code, X86_ESP, 0, FALSE, FALSE); // float value
4356         x86_fp_int_op_membase (s->code, X86_FSUB, X86_ESP, 8, TRUE);
4357         x86_fst_membase (s->code, X86_ESP, 4, FALSE, TRUE); // diff
4358
4359         x86_pop_reg (s->code, tree->reg1); // float value
4360         x86_test_reg_reg (s->code, tree->reg1, tree->reg1);
4361         br[0] = s->code; x86_branch8 (s->code, X86_CC_S, 0, TRUE);
4362
4363         x86_pop_reg (s->code, tree->reg1); // diff
4364         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
4365         x86_pop_reg (s->code, tree->reg1); // rounded value
4366         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, 0);
4367         br[1] = s->code; x86_jump8 (s->code, 0);
4368
4369         // freg is negative
4370         x86_patch (br[0], s->code);
4371
4372         x86_pop_reg (s->code, tree->reg1); // diff
4373         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
4374         x86_pop_reg (s->code, tree->reg1); // rounded value
4375         br[2] = s->code; x86_branch8 (s->code, X86_CC_Z, 0, FALSE);
4376         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, -1);
4377         x86_patch (br[1], s->code);
4378         x86_patch (br[2], s->code);
4379 }
4380
4381 void mono_emit_fast_iconv_i8 (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
4382 {
4383         guint8* br [3];
4384         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 16);
4385         x86_fld_reg (s->code, 0);
4386         x86_fist_pop_membase (s->code, X86_ESP, 8, TRUE); // rounded value (qword)
4387         x86_fst_membase (s->code, X86_ESP, 0, FALSE, FALSE); // float value
4388         x86_fild_membase (s->code, X86_ESP, 8, TRUE);
4389         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE); // diff
4390         x86_fst_membase (s->code, X86_ESP, 4, FALSE, TRUE); // diff
4391
4392         x86_pop_reg (s->code, tree->reg1); // float value
4393         x86_test_reg_reg (s->code, tree->reg1, tree->reg1);
4394         br[0] = s->code; x86_branch8 (s->code, X86_CC_S, 0, TRUE);
4395
4396         x86_pop_reg (s->code, tree->reg1); // diff
4397         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
4398         x86_pop_reg (s->code, tree->reg1); // rounded value
4399         x86_pop_reg (s->code, tree->reg2);
4400         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, 0);
4401         x86_alu_reg_imm (s->code, X86_SBB, tree->reg2, 0);
4402         br[1] = s->code; x86_jump8 (s->code, 0);
4403
4404         // freg is negative
4405         x86_patch (br[0], s->code);
4406
4407         x86_pop_reg (s->code, tree->reg1); // diff
4408         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->reg1);
4409         x86_pop_reg (s->code, tree->reg1); // rounded value
4410         x86_pop_reg (s->code, tree->reg2);
4411         br[2] = s->code; x86_branch8 (s->code, X86_CC_Z, 0, FALSE);
4412         x86_alu_reg_imm (s->code, X86_SBB, tree->reg1, -1);
4413         x86_alu_reg_imm (s->code, X86_SBB, tree->reg2, -1);
4414         x86_patch (br[1], s->code);
4415         x86_patch (br[2], s->code);
4416 }