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