2002-03-07 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / jit / x86.brg
1 /*
2  * x86.brg: X86 code generator
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <glib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <sys/syscall.h>
15
16 #include <mono/metadata/blob.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/arch/x86/x86-codegen.h>
23
24 #include "regset.h"
25 #include "jit.h"
26
27
28 void print_lmf ();
29
30 #define MBTREE_TYPE  MBTree
31 #define MBCGEN_TYPE  MonoFlowGraph
32 #define MBCOST_DATA  MonoFlowGraph
33 #define MBALLOC_STATE mono_mempool_alloc (data->mp, sizeof (MBState))
34
35 typedef enum {
36         AMImmediate       = 0,  // ptr
37         AMBase            = 1,  // V[REG]  
38         AMIndex           = 2,  // V[REG*X] 
39         AMBaseIndex       = 3,  // V[REG*X][REG] 
40 } X86AddMode;
41
42 typedef struct {
43         int           offset;
44         X86AddMode    amode:2;
45         unsigned int  shift:2;
46         gint8         basereg;
47         gint8         indexreg;
48 } X86AddressInfo;
49
50 struct _MBTree {
51         guint16   op;
52         unsigned      last_instr:1;
53         
54         MBTree   *left, *right;
55         gpointer  state;
56         gpointer  emit;
57
58         gint32    addr;
59         gint32    cli_addr;
60
61         guint8    exclude_mask;
62
63         gint8     reg1;
64         gint8     reg2;
65         gint8     reg3;
66         
67         MonoValueType svt;
68
69         union {
70                 gint32 i;
71                 gint64 l;
72                 gpointer p;
73                 MonoBBlock *bb;
74                 MonoMethod *m;
75                 MethodCallInfo *ci;
76                 MonoClass *klass;
77                 X86AddressInfo ainfo;
78         } data;
79 };
80
81 gint64   mono_llmult        (gint64 a, gint64 b);
82 guint64  mono_llmult_ovf    (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh);
83 guint64  mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh);
84 gint64   mono_lldiv         (gint64 a, gint64 b);
85 gint64   mono_llrem         (gint64 a, gint64 b);
86 guint64  mono_lldiv_un      (guint64 a, guint64 b);
87 guint64  mono_llrem_un      (guint64 a, guint64 b);
88 gpointer mono_ldsflda       (MonoClass *klass, int offset);
89
90 gpointer arch_get_lmf_addr (void);
91
92 MonoArray*
93 mono_array_new_wrapper  (MonoClass *eclass, guint32 n);
94 MonoObject *
95 mono_object_new_wrapper (MonoClass *klass);
96 MonoString*
97 mono_string_new_wrapper (const char *text);
98 MonoString*
99 mono_ldstr_wrapper      (MonoImage *image, guint32 index);
100
101 gpointer
102 get_mono_object_isinst (void);
103
104 #define MB_OPT_LEVEL 1
105
106 #if MB_OPT_LEVEL == 0
107 #define MB_USE_OPT1(c) 65535
108 #define MB_USE_OPT2(c) 65535
109 #endif
110 #if MB_OPT_LEVEL == 1
111 #define MB_USE_OPT1(c) c
112 #define MB_USE_OPT2(c) 65535
113 #endif
114 #if MB_OPT_LEVEL >= 2
115 #define MB_USE_OPT1(c) c
116 #define MB_USE_OPT2(c) c
117 #endif
118
119 //#define DEBUG
120
121 #define REAL_PRINT_REG(text,reg) \
122 mono_assert (reg >= 0); \
123 x86_push_reg (s->code, X86_EAX); \
124 x86_push_reg (s->code, X86_EDX); \
125 x86_push_reg (s->code, X86_ECX); \
126 x86_push_reg (s->code, reg); \
127 x86_push_imm (s->code, reg); \
128 x86_push_imm (s->code, text " %d %p\n"); \
129 x86_mov_reg_imm (s->code, X86_EAX, printf); \
130 x86_call_reg (s->code, X86_EAX); \
131 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
132 x86_pop_reg (s->code, X86_ECX); \
133 x86_pop_reg (s->code, X86_EDX); \
134 x86_pop_reg (s->code, X86_EAX); 
135
136 #ifdef DEBUG
137 #define MEMCOPY debug_memcpy
138 void *MEMCOPY (void *dest, const void *src, size_t n);
139
140 #define PRINT_REG(text,reg) REAL_PRINT_REG(text,reg)
141 #else
142
143 #define MEMCOPY memcpy
144
145 #define PRINT_REG(x,y)
146
147 #endif
148
149 /* The call instruction for virtual functions must have a known
150  * size (used by x86_magic_trampoline)
151  */
152 #define x86_call_virtual(inst,basereg,disp)                    \
153         do {                                                   \
154                 *(inst)++ = (unsigned char)0xff;               \
155                 x86_address_byte ((inst), 2, 2, (basereg));    \
156                 x86_imm_emit32 ((inst), (disp));               \
157         } while (0)
158
159 /* emit an exception if condition is fail */
160 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)       \
161         do {                                                   \
162                 gpointer t;                                    \
163                 x86_branch8 (s->code, cond, 10, signed);       \
164                 x86_push_imm (s->code, exc_name);              \
165                 t = arch_get_throw_exception_by_name ();       \
166                 mono_add_jump_info (s, s->code + 1,            \
167                                     MONO_JUMP_INFO_ABS, t);    \
168                 x86_call_code (s->code, 0);                    \
169         } while (0); 
170
171 %%
172
173 #
174 # terminal definitions
175 #
176
177 # constatnts
178 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
179 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_REF LDIND_I8 LDIND_R4 LDIND_R8
180 %term LDIND_U4 LDIND_OBJ 
181 %term STIND_I1 STIND_I2 STIND_I4 STIND_REF STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
182 %term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ ARG_STRING CALL_I4 CALL_I8 CALL_R8 CALL_VOID
183 %term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY
184 %term ADD ADD_OVF ADD_OVF_UN SUB SUB_OVF SUB_OVF_UN MUL MUL_OVF MUL_OVF_UN 
185 %term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
186 %term BLT BLT_UN BEQ BNE_UN BRTRUE BRFALSE BGE BGE_UN BLE BLE_UN BGT BGT_UN 
187 %term CEQ CLT CLT_UN CGT CGT_UN
188 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U8 CONV_R4 CONV_R8 CONV_R_UN
189 %term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWOBJ NEWSTRUCT CPOBJ POP INITOBJ
190 %term ISINST CASTCLASS UNBOX
191 %term CONV_OVF_I1 CONV_OVF_U1 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U4 CONV_OVF_U8 CONV_OVF_I4
192 %term CONV_OVF_I4_UN CONV_OVF_U1_UN CONV_OVF_U2_UN
193 %term CONV_OVF_I2_UN CONV_OVF_I8_UN CONV_OVF_I1_UN 
194 %term EXCEPTION THROW RETHROW HANDLER SAVE_LMF RESTORE_LMF
195 %term LDLEN LDELEMA LDFTN TOSTRING LDSTR LDSFLDA
196
197 #
198 # we start at stmt
199 #
200 %start stmt
201
202 #
203 # tree definitions
204 #
205
206 #
207 # x86 adressing mode
208 #
209
210 acon: CONST_I4 {
211         tree->data.ainfo.offset = tree->data.i;
212         tree->data.ainfo.amode = AMImmediate;
213 }
214
215 acon: ADDR_G {
216         tree->data.ainfo.offset = tree->data.i;
217         tree->data.ainfo.amode = AMImmediate;
218 }
219
220 acon: ADD (ADDR_G, CONST_I4) {
221         tree->data.ainfo.offset = (unsigned)tree->left->data.p + tree->right->data.i;
222         tree->data.ainfo.amode = AMImmediate;
223 }
224
225 base: acon
226
227 base: reg {
228         tree->data.ainfo.offset = 0;
229         tree->data.ainfo.basereg = tree->reg1;
230         tree->data.ainfo.amode = AMBase;
231 }
232
233 base: ADD (reg, acon) {
234         tree->data.ainfo.offset = tree->right->data.i;
235         tree->data.ainfo.basereg = tree->left->reg1;
236         tree->data.ainfo.amode = AMBase;
237 }
238
239 base: ADDR_L {
240         tree->data.ainfo.offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
241         tree->data.ainfo.basereg = X86_EBP;
242         tree->data.ainfo.amode = AMBase;
243 }
244
245 index: reg {
246         tree->data.ainfo.offset = 0;
247         tree->data.ainfo.indexreg = tree->reg1;
248         tree->data.ainfo.shift = 0;
249         tree->data.ainfo.amode = AMIndex;
250 }
251
252 index: SHL (reg, CONST_I4) {
253         tree->data.ainfo.offset = 0;
254         tree->data.ainfo.amode = AMIndex;
255         tree->data.ainfo.indexreg = tree->left->reg1;
256         tree->data.ainfo.shift = tree->right->data.i;
257 } cost {
258         MBCOND (tree->right->data.i == 0 ||
259                 tree->right->data.i == 1 ||
260                 tree->right->data.i == 2 ||
261                 tree->right->data.i == 3);
262
263         return 0;
264 }
265
266 index: MUL (reg, CONST_I4) {
267         static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
268   
269         tree->data.ainfo.offset = 0;
270         tree->data.ainfo.amode = AMIndex;
271         tree->data.ainfo.indexreg = tree->left->reg1;
272         tree->data.ainfo.shift = fast_log2 [tree->right->data.i];
273 } cost {
274         MBCOND (tree->right->data.i == 1 ||
275                 tree->right->data.i == 2 ||
276                 tree->right->data.i == 4 ||
277                 tree->right->data.i == 8);
278
279         return 0;
280 }
281
282 addr: base
283
284 addr: index
285
286 addr: ADD (index, base) {
287         tree->data.ainfo.offset = tree->right->data.ainfo.offset;
288         tree->data.ainfo.basereg = tree->right->data.ainfo.basereg;
289         tree->data.ainfo.amode = tree->left->data.ainfo.amode | 
290                 tree->right->data.ainfo.amode;
291         tree->data.ainfo.shift = tree->left->data.ainfo.shift;
292         tree->data.ainfo.indexreg = tree->left->data.ainfo.indexreg;
293 }
294
295 # we pass exception in ECX to catch handler
296 reg: EXCEPTION {
297         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
298
299         if (tree->reg1 != X86_ECX)
300                 x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
301         
302         /* store it so that we can RETHROW it later */
303         x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
304 }
305
306 stmt: THROW (reg) {
307         gpointer target;
308
309         x86_push_reg (s->code, tree->left->reg1);
310         target = arch_get_throw_exception ();
311         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, target);
312         x86_call_code (s->code, target);
313 }
314
315 stmt: RETHROW {
316         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
317         gpointer target;
318
319         x86_push_membase (s->code, X86_EBP, offset);
320         target = arch_get_throw_exception ();
321         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, target);
322         x86_call_code (s->code, target);
323 }
324
325 stmt: HANDLER {
326         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_BB, tree->data.bb);
327         x86_call_imm (s->code, 0); 
328 }
329
330 stmt: ENDFINALLY {
331         x86_ret (s->code);
332 }
333
334 stmt: SAVE_LMF {
335         /* save all caller saved regs */
336         x86_push_reg (s->code, X86_EBX);
337         x86_push_reg (s->code, X86_EDI);
338         x86_push_reg (s->code, X86_ESI);
339         x86_push_reg (s->code, X86_EBP);
340         
341         /* save the IP */
342         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_IP, NULL);
343         x86_push_imm (s->code, s->code);
344
345         /* save method info */
346         x86_push_imm (s->code, tree->data.m);
347         /* get the address of lmf for the current thread */
348         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, arch_get_lmf_addr);
349         x86_call_code (s->code, arch_get_lmf_addr);
350         /* push lmf */
351         x86_push_reg (s->code, X86_EAX); 
352         /* push *lfm (previous_lmf) */
353         x86_push_membase (s->code, X86_EAX, 0);
354         /* *(lmf) = ESP */
355         x86_mov_membase_reg (s->code, X86_EAX, 0, X86_ESP, 4);
356 }
357
358 stmt: RESTORE_LMF {
359         /* ebx = previous_lmf */
360         x86_pop_reg (s->code, X86_EBX);
361         /* edi = lmf */
362         x86_pop_reg (s->code, X86_EDI);
363         /* *(lmf) = previous_lmf */
364         x86_mov_membase_reg (s->code, X86_EDI, 0, X86_EBX, 4);
365
366         /* discard method info */
367         x86_pop_reg (s->code, X86_ESI);
368
369         /* discard save IP */
370         x86_pop_reg (s->code, X86_ESI);
371
372         /* restore caller saved regs */
373         x86_pop_reg (s->code, X86_EBP);
374         x86_pop_reg (s->code, X86_ESI);
375         x86_pop_reg (s->code, X86_EDI);
376         x86_pop_reg (s->code, X86_EBX);
377 }
378
379 stmt: STIND_I4 (addr, reg) {
380         PRINT_REG ("STIND_I4", tree->right->reg1);
381
382         switch (tree->left->data.ainfo.amode) {
383
384         case AMImmediate:
385                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
386                 break;
387                 
388         case AMBase:
389                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
390                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
391                 break;          
392         case AMIndex:
393                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
394                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
395                                       tree->right->reg1, 4);
396                 break;          
397         case AMBaseIndex:
398                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
399                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
400                                       tree->right->reg1, 4);
401                 break;          
402         }
403 }
404
405 stmt: STIND_REF (addr, reg) {
406         PRINT_REG ("STIND_REF", tree->right->reg1);
407
408         switch (tree->left->data.ainfo.amode) {
409
410         case AMImmediate:
411                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
412                 break;
413                 
414         case AMBase:
415                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
416                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
417                 break;          
418         case AMIndex:
419                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
420                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
421                                       tree->right->reg1, 4);
422                 break;          
423         case AMBaseIndex:
424                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
425                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
426                                       tree->right->reg1, 4);
427                 break;          
428         }
429 }
430
431 stmt: STIND_I1 (addr, reg) {
432         PRINT_REG ("STIND_I1", tree->right->reg1);
433
434         switch (tree->left->data.ainfo.amode) {
435
436         case AMImmediate:
437                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 1);
438                 break;
439                 
440         case AMBase:
441                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
442                                      tree->left->data.ainfo.offset, tree->right->reg1, 1);
443                 break;          
444         case AMIndex:
445                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
446                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
447                                       tree->right->reg1, 1);
448                 break;          
449         case AMBaseIndex:
450                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
451                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
452                                       tree->right->reg1, 1);
453                 break;          
454         }
455 }
456
457 stmt: STIND_I2 (addr, reg) {
458         PRINT_REG ("STIND_I2", tree->right->reg1);
459
460         switch (tree->left->data.ainfo.amode) {
461
462         case AMImmediate:
463                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 2);
464                 break;
465                 
466         case AMBase:
467                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
468                                      tree->left->data.ainfo.offset, tree->right->reg1, 2);
469                 break;          
470         case AMIndex:
471                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
472                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
473                                       tree->right->reg1, 2);
474                 break;          
475         case AMBaseIndex:
476                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
477                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
478                                       tree->right->reg1, 2);
479                 break;          
480         }
481 }
482
483 reg: LDIND_I4 (addr) {
484
485         switch (tree->left->data.ainfo.amode) {
486
487         case AMImmediate:
488                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
489                 break;
490
491         case AMBase:
492                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
493                                      tree->left->data.ainfo.offset, 4);
494                 break;          
495         case AMIndex:
496                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
497                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
498                 break;          
499         case AMBaseIndex:
500                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
501                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
502                                       tree->left->data.ainfo.shift, 4);
503                 break;          
504         }
505
506
507         PRINT_REG ("LDIND_I4", tree->reg1);
508 }
509
510 reg: LDIND_REF (addr) {
511
512         switch (tree->left->data.ainfo.amode) {
513
514         case AMImmediate:
515                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
516                 break;
517
518         case AMBase:
519                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
520                                      tree->left->data.ainfo.offset, 4);
521                 break;          
522         case AMIndex:
523                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
524                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
525                 break;          
526         case AMBaseIndex:
527                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
528                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
529                                       tree->left->data.ainfo.shift, 4);
530                 break;          
531         }
532
533
534         PRINT_REG ("LDIND_REF", tree->reg1);
535 }
536
537 reg: LDIND_I1 (addr) {
538         switch (tree->left->data.ainfo.amode) {
539
540         case AMImmediate:
541                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, FALSE);
542                 break;
543
544         case AMBase:
545                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
546                                    tree->left->data.ainfo.offset, TRUE, FALSE);
547                 break;          
548         case AMIndex:
549                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
550                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, FALSE);
551                 break;          
552         case AMBaseIndex:
553                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
554                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
555                                     tree->left->data.ainfo.shift, TRUE, FALSE);
556                 break;          
557         }
558
559         PRINT_REG ("LDIND_I1", tree->reg1);
560 }
561
562 reg: LDIND_U1 (addr) {
563         switch (tree->left->data.ainfo.amode) {
564
565         case AMImmediate:
566                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, FALSE);
567                 break;
568
569         case AMBase:
570                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
571                                    tree->left->data.ainfo.offset, FALSE, FALSE);
572                 break;          
573         case AMIndex:
574                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
575                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, FALSE);
576                 break;          
577         case AMBaseIndex:
578                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
579                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
580                                     tree->left->data.ainfo.shift, FALSE, FALSE);
581                 break;          
582         }
583
584         PRINT_REG ("LDIND_U1", tree->reg1);
585 }
586
587 reg: LDIND_I2 (addr) {
588         switch (tree->left->data.ainfo.amode) {
589
590         case AMImmediate:
591                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, TRUE);
592                 break;
593
594         case AMBase:
595                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
596                                    tree->left->data.ainfo.offset, TRUE, TRUE);
597                 break;          
598         case AMIndex:
599                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
600                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, TRUE);
601                 break;          
602         case AMBaseIndex:
603                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
604                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
605                                     tree->left->data.ainfo.shift, TRUE, TRUE);
606                 break;          
607         }
608
609         PRINT_REG ("LDIND_U2", tree->reg1);
610 }
611
612 reg: LDIND_U2 (addr) {
613         switch (tree->left->data.ainfo.amode) {
614
615         case AMImmediate:
616                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, TRUE);
617                 break;
618
619         case AMBase:
620                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
621                                    tree->left->data.ainfo.offset, FALSE, TRUE);
622                 break;          
623         case AMIndex:
624                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
625                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, TRUE);
626                 break;          
627         case AMBaseIndex:
628                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
629                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
630                                     tree->left->data.ainfo.shift, FALSE, TRUE);
631                 break;          
632         }
633
634         PRINT_REG ("LDIND_U2", tree->reg1);
635 }
636
637 reg: LDIND_U4 (addr) {
638         switch (tree->left->data.ainfo.amode) {
639
640         case AMImmediate:
641                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
642                 break;
643
644         case AMBase:
645                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
646                                      tree->left->data.ainfo.offset, 4);
647                 break;          
648         case AMIndex:
649                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
650                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
651                 break;          
652         case AMBaseIndex:
653                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
654                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
655                                       tree->left->data.ainfo.shift, 4);
656                 break;          
657         }
658
659         PRINT_REG ("LDIND_U4", tree->reg1);
660 }
661
662 reg: ADDR_L 5 {
663         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;  
664         x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
665         
666         PRINT_REG ("ADDR_L",  tree->reg1);
667 }
668
669
670 reg: ADDR_G 5 {
671         x86_mov_reg_imm (s->code, tree->reg1, tree->data.p);
672 }
673
674 reg: CONV_I1 (reg) {
675         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
676 }
677
678 reg: CONV_I2 (reg) {
679         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
680 }
681
682 reg: CONST_I4 1 {
683         x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
684 }
685
686 reg: CONV_I4 (reg) {
687         if (tree->reg1 != tree->left->reg1)
688                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
689         PRINT_REG ("CONV_I4", tree->left->reg1);
690
691
692 reg: CONV_OVF_U4 (reg) {
693         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
694         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
695         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
696         if (tree->reg1 != tree->left->reg1)
697                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
698 }
699
700 reg: CONV_OVF_I4_UN (reg) {
701         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
702         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
703         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");
704         if (tree->reg1 != tree->left->reg1)
705                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
706 }
707
708 reg: CONV_OVF_I1 (reg) {
709         /* probe value to be within -128 to 127 */
710         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 127);
711         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
712         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -128);
713         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GT, TRUE, "OverflowException");      
714         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
715 }
716
717 reg: CONV_OVF_I1_UN (reg) {
718         /* probe values between 0 to 128 */
719         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff80);
720         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
721         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
722 }
723
724 reg: CONV_OVF_U1 (reg) {
725         /* Keep in sync with CONV_OVF_U1_UN routine below, they are the same on 32-bit machines */
726         /* probe value to be within 0 to 255 */
727         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
728         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
729         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
730 }
731
732 reg: CONV_OVF_U1_UN (reg) {
733         /* Keep in sync with CONV_OVF_U1 routine above, they are the same on 32-bit machines */
734         /* probe value to be within 0 to 255 */
735         x86_test_reg_imm (s->code, tree->left->reg1, 0xffffff00);
736         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
737         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, FALSE);
738 }
739
740 reg: CONV_OVF_I2 (reg) {        
741         /* Probe value to be within -32768 and 32767 */
742         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 32767);
743         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LE, TRUE, "OverflowException");      
744         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, -32768);
745         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_GE, TRUE, "OverflowException");      
746         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
747 }
748
749 reg: CONV_OVF_U2 (reg) {
750         /* Keep in sync with CONV_OVF_U2_UN below, they are the same on 32-bit machines */
751         /* Probe value to be within 0 and 65535 */
752         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
753         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");      
754         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
755 }
756
757 reg: CONV_OVF_U2_UN (reg) {
758         /* Keep in sync with CONV_OVF_U2 above, they are the same on 32-bit machines */
759         /* Probe value to be within 0 and 65535 */
760         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
761         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
762         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
763 }
764
765 reg: CONV_OVF_I2_UN (reg) {
766         /* Convert uint value into short, value within 0 and 32767 */
767         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff8000);
768         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "OverflowException");     
769         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
770 }
771
772 reg: MUL (reg, reg) {
773         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
774
775         if (tree->reg1 != tree->left->reg1)
776                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
777 }
778
779 reg: MUL_OVF (reg, reg) {
780         x86_imul_reg_reg (s->code, tree->left->reg1, tree->right->reg1);
781         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
782
783         if (tree->reg1 != tree->left->reg1)
784                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
785 }
786
787 reg: MUL_OVF_UN (reg, reg) {
788         mono_assert (tree->right->reg1 != X86_EAX);
789         
790         if (tree->left->reg1 != X86_EAX)
791                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
792
793         x86_mul_reg (s->code, tree->right->reg1, FALSE);
794         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");
795
796         mono_assert (tree->reg1 == X86_EAX &&
797                      tree->reg2 == X86_EDX);
798 }
799
800 reg: DIV (reg, reg) {
801         mono_assert (tree->right->reg1 != X86_EAX);
802
803         if (tree->left->reg1 != X86_EAX)
804                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
805
806         x86_cdq (s->code);
807         x86_div_reg (s->code, tree->right->reg1, TRUE);
808
809         mono_assert (tree->reg1 == X86_EAX &&
810                      tree->reg2 == X86_EDX);
811 }
812
813 reg: DIV_UN (reg, reg) {
814         mono_assert (tree->right->reg1 != X86_EAX);
815
816         if (tree->left->reg1 != X86_EAX)
817                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
818
819         x86_cdq (s->code);
820         x86_div_reg (s->code, tree->right->reg1, FALSE);
821
822         mono_assert (tree->reg1 == X86_EAX &&
823                      tree->reg2 == X86_EDX);
824 }
825
826 reg: REM (reg, reg) {
827         mono_assert (tree->right->reg1 != X86_EAX);
828         mono_assert (tree->right->reg1 != X86_EDX);
829
830         if (tree->left->reg1 != X86_EAX)
831                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
832
833         /* sign extend to 64bit in EAX/EDX */
834         x86_cdq (s->code);
835         x86_div_reg (s->code, tree->right->reg1, TRUE);
836         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
837
838         mono_assert (tree->reg1 == X86_EAX &&
839                      tree->reg2 == X86_EDX);
840 }
841
842 reg: REM_UN (reg, reg) {
843         mono_assert (tree->right->reg1 != X86_EAX);
844         mono_assert (tree->right->reg1 != X86_EDX);
845
846         if (tree->left->reg1 != X86_EAX)
847                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
848
849         /* zero extend to 64bit in EAX/EDX */
850         x86_mov_reg_imm (s->code, X86_EDX, 0); 
851         x86_div_reg (s->code, tree->right->reg1, FALSE);
852         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
853
854         mono_assert (tree->reg1 == X86_EAX &&
855                      tree->reg2 == X86_EDX);
856 }
857
858 reg: ADD (reg, CONST_I4) "MB_USE_OPT1(0)" {
859         if (tree->right->data.i == 1)
860                 x86_inc_reg (s->code, tree->left->reg1);
861         else 
862                 x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, tree->right->data.i);
863
864         if (tree->reg1 != tree->left->reg1)
865                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
866
867 }
868
869 reg: ADD (reg, reg) {
870         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
871
872         if (tree->reg1 != tree->left->reg1)
873                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
874 }
875
876 reg: ADD_OVF (reg, reg) {
877         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
878         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
879
880         if (tree->reg1 != tree->left->reg1)
881                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
882 }
883
884 reg: ADD_OVF_UN (reg, reg) {
885         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
886         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
887
888         if (tree->reg1 != tree->left->reg1)
889                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
890 }
891
892 reg: SUB (reg, CONST_I4) "MB_USE_OPT1(0)" {
893         if (tree->right->data.i == 1)
894                 x86_dec_reg (s->code, tree->left->reg1);
895         else
896                 x86_alu_reg_imm (s->code, X86_SUB, tree->left->reg1, tree->right->data.i);
897
898         if (tree->reg1 != tree->left->reg1)
899                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
900 }
901
902 reg: SUB (reg, reg) {
903         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
904
905         if (tree->reg1 != tree->left->reg1)
906                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
907 }
908
909 reg: SUB_OVF (reg, reg) {
910         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
911         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
912
913         if (tree->reg1 != tree->left->reg1)
914                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
915 }
916
917 reg: SUB_OVF_UN (reg, reg) {
918         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
919         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
920
921         if (tree->reg1 != tree->left->reg1)
922                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
923 }
924
925 reg: CEQ (reg, reg) {
926         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
927         x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
928         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
929 }
930
931 reg: CGT (reg, reg) {
932         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
933         x86_set_reg (s->code, X86_CC_GT, tree->reg1, TRUE);
934         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
935 }
936
937 reg: CGT_UN (reg, reg) {
938         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
939         x86_set_reg (s->code, X86_CC_GT, tree->reg1, FALSE);
940         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
941 }
942
943 reg: CLT (reg, reg) {
944         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
945         x86_set_reg (s->code, X86_CC_LT, tree->reg1, TRUE);
946         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
947 }
948
949 reg: CLT_UN (reg, reg) {
950         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
951         x86_set_reg (s->code, X86_CC_LT, tree->reg1, FALSE);
952         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
953 }
954
955 reg: AND (reg, reg) {
956         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
957
958         if (tree->reg1 != tree->left->reg1)
959                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
960 }
961
962 reg: OR (reg, reg) {
963         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
964
965         if (tree->reg1 != tree->left->reg1)
966                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
967 }
968
969 reg: XOR (reg, reg) {
970         x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->right->reg1);
971
972         if (tree->reg1 != tree->left->reg1)
973                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
974 }
975
976 reg: NEG (reg) {
977         x86_neg_reg (s->code, tree->left->reg1);
978
979         if (tree->reg1 != tree->left->reg1)
980                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
981 }
982
983 reg: NOT (reg) {
984         x86_not_reg (s->code, tree->left->reg1);
985
986         if (tree->reg1 != tree->left->reg1)
987                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
988 }
989
990 reg: SHL (reg, CONST_I4) {
991         x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
992
993         if (tree->reg1 != tree->left->reg1)
994                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
995 }
996
997 reg: SHL (reg, reg) {
998         if (tree->right->reg1 != X86_ECX)
999                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1000         x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
1001
1002         if (tree->reg1 != tree->left->reg1)
1003                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1004
1005         mono_assert (tree->reg1 != X86_ECX &&
1006                   tree->left->reg1 != X86_ECX);
1007 }
1008
1009 reg: SHR (reg, CONST_I4) {
1010         x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg1, tree->right->data.i);
1011
1012         if (tree->reg1 != tree->left->reg1)
1013                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1014 }
1015
1016 reg: SHR (reg, reg) {
1017         if (tree->right->reg1 != X86_ECX)
1018                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1019         x86_shift_reg (s->code, X86_SAR, tree->left->reg1);
1020
1021         if (tree->reg1 != tree->left->reg1)
1022                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1023
1024         mono_assert (tree->reg1 != X86_ECX &&
1025                   tree->left->reg1 != X86_ECX);
1026 }
1027
1028 reg: SHR_UN (reg, CONST_I4) {
1029         x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, tree->right->data.i);
1030
1031         if (tree->reg1 != tree->left->reg1)
1032                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1033 }
1034
1035 reg: SHR_UN (reg, reg) {
1036         if (tree->right->reg1 != X86_ECX)
1037                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
1038         x86_shift_reg (s->code, X86_SHR, tree->left->reg1);
1039
1040         if (tree->reg1 != tree->left->reg1)
1041                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1042
1043         mono_assert (tree->reg1 != X86_ECX &&
1044                   tree->left->reg1 != X86_ECX);
1045 }
1046
1047 reg: LDSFLDA (CONST_I4) {
1048         if (tree->reg1 != X86_EAX)
1049                 x86_push_reg (s->code, X86_EAX);
1050         x86_push_reg (s->code, X86_ECX);
1051         x86_push_reg (s->code, X86_EDX);
1052
1053         x86_push_imm (s->code, tree->left->data.i);
1054         x86_push_imm (s->code, tree->data.klass);
1055         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_ldsflda);
1056         x86_call_code (s->code, 0);
1057         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1058         
1059         x86_pop_reg (s->code, X86_EDX);
1060         x86_pop_reg (s->code, X86_ECX);
1061         if (tree->reg1 != X86_EAX) {
1062                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1063                 x86_pop_reg (s->code, X86_EAX);
1064         }
1065 }
1066
1067 # array support
1068 reg: LDLEN (reg) {      
1069         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1070         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, TRUE, "NullReferenceException");
1071
1072         x86_mov_reg_membase (s->code, tree->reg1, tree->left->reg1,  
1073                              G_STRUCT_OFFSET (MonoArray, bounds), 4);
1074         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1,  
1075                              G_STRUCT_OFFSET (MonoArrayBounds, length), 4);
1076 }
1077
1078 reg: LDELEMA (reg, reg) {
1079         x86_alu_reg_membase (s->code, X86_CMP, tree->right->reg1, tree->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length));
1080         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_LT, FALSE, "IndexOutOfRangeException");
1081
1082         if (tree->data.i == 1 || tree->data.i == 2 || 
1083             tree->data.i == 4 || tree->data.i == 8) {
1084                 static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
1085                 x86_lea_memindex (s->code, tree->reg1, tree->left->reg1, 
1086                                   G_STRUCT_OFFSET (MonoArray, vector), tree->right->reg1, 
1087                                   fast_log2 [tree->data.i]);
1088         } else {
1089                 x86_imul_reg_reg_imm (s->code, tree->right->reg1, tree->right->reg1, tree->data.i);
1090                 x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
1091                 x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, G_STRUCT_OFFSET (MonoArray, vector));
1092         }
1093 }
1094
1095 reg: LDSTR {
1096         if (tree->reg1 != X86_EAX)
1097                 x86_push_reg (s->code, X86_EAX);
1098         x86_push_reg (s->code, X86_ECX);
1099         x86_push_reg (s->code, X86_EDX);
1100
1101         x86_push_imm (s->code, tree->data.p);
1102         x86_push_imm (s->code, s->method->klass->image);
1103         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_ldstr_wrapper);
1104         x86_call_code (s->code, 0);
1105         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1106
1107         x86_pop_reg (s->code, X86_EDX);
1108         x86_pop_reg (s->code, X86_ECX);
1109         if (tree->reg1 != X86_EAX) {
1110                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1111                 x86_pop_reg (s->code, X86_EAX);
1112         }
1113
1114         PRINT_REG ("LDSTR", tree->reg1);        
1115 }
1116
1117 reg: TOSTRING (reg) {
1118         guint8 *start = s->code, *l1, *le;
1119         int i;
1120
1121         l1 = le = NULL;
1122
1123         for (i = 0; i < 2; i++) {
1124                 s->code = start;
1125
1126                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1127                 x86_branch8 (s->code, X86_CC_EQ, le - l1, FALSE);
1128                 l1 = s->code;
1129
1130                 if (tree->reg1 != X86_EAX)
1131                         x86_push_reg (s->code, X86_EAX);
1132                 x86_push_reg (s->code, X86_ECX);
1133                 x86_push_reg (s->code, X86_EDX);
1134
1135                 x86_push_reg (s->code, tree->left->reg1);
1136                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_string_new_wrapper);
1137                 x86_call_code (s->code, 0);
1138                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1139
1140                 x86_pop_reg (s->code, X86_EDX);
1141                 x86_pop_reg (s->code, X86_ECX);
1142                 if (tree->reg1 != X86_EAX) {
1143                         x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1144                         x86_pop_reg (s->code, X86_EAX);
1145                 }
1146
1147                 le = s->code;
1148         }
1149 }
1150
1151 reg: NEWARR (reg) {
1152         if (tree->reg1 != X86_EAX)
1153                 x86_push_reg (s->code, X86_EAX);
1154         x86_push_reg (s->code, X86_ECX);
1155         x86_push_reg (s->code, X86_EDX);
1156
1157         x86_push_reg (s->code, tree->left->reg1);
1158         x86_push_imm (s->code, tree->data.p);
1159         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_array_new_wrapper);
1160         x86_call_code (s->code, 0);
1161         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
1162
1163         x86_pop_reg (s->code, X86_EDX);
1164         x86_pop_reg (s->code, X86_ECX);
1165         if (tree->reg1 != X86_EAX) {
1166                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1167                 x86_pop_reg (s->code, X86_EAX);
1168         }
1169
1170         PRINT_REG ("NEWARR", tree->reg1);
1171 }
1172
1173 reg: NEWOBJ {
1174         if (tree->reg1 != X86_EAX)
1175                 x86_push_reg (s->code, X86_EAX);
1176         x86_push_reg (s->code, X86_ECX);
1177         x86_push_reg (s->code, X86_EDX);
1178
1179         x86_push_imm (s->code, tree->data.klass);
1180         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_object_new_wrapper);
1181         x86_call_code (s->code, 0);
1182         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
1183
1184         x86_pop_reg (s->code, X86_EDX);
1185         x86_pop_reg (s->code, X86_ECX);
1186         if (tree->reg1 != X86_EAX) {
1187                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1188                 x86_pop_reg (s->code, X86_EAX);
1189         }
1190         PRINT_REG ("NEWOBJ", tree->reg1);
1191 }
1192
1193 reg: NEWSTRUCT {
1194         int size = tree->data.i;        
1195         int sa;
1196         
1197         mono_assert (size > 0);
1198
1199         sa = size + 3;
1200         sa &= ~3;
1201
1202         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
1203         x86_mov_reg_reg (s->code, tree->reg1, X86_ESP, 4);
1204 }
1205
1206 reg: UNBOX (reg) {
1207         if (tree->reg1 != tree->left->reg1)
1208                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1209
1210         x86_test_reg_reg (s->code, tree->reg1, tree->reg1);
1211         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, TRUE, "NullReferenceException"); 
1212
1213         x86_push_reg (s->code, tree->reg1);
1214         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1215         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, 0, 4); 
1216         x86_alu_membase_imm (s->code, X86_CMP, tree->reg1, 
1217                              G_STRUCT_OFFSET (MonoClass, element_class), ((int)(tree->data.klass->element_class)));
1218         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "InvalidCastException");
1219         x86_pop_reg (s->code, tree->reg1);
1220         x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
1221 }
1222
1223 reg: CASTCLASS (reg) {
1224         guint8 *start = s->code, *l1, *l2, *le;
1225         int i;
1226
1227         l1 = l2 = le = NULL;
1228
1229         for (i = 0; i < 2; i++) {
1230                 s->code = start;
1231
1232                 if (tree->reg1 != X86_EAX)
1233                         x86_push_reg (s->code, X86_EAX);
1234
1235                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1236                 x86_branch8 (s->code, X86_CC_EQ, le - l2, FALSE);
1237                 l2 = s->code;
1238                 x86_push_reg (s->code, X86_ECX);
1239                 x86_push_reg (s->code, X86_EDX);
1240
1241                 x86_push_imm (s->code, tree->data.klass);
1242                 x86_push_reg (s->code, tree->left->reg1);
1243                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_object_isinst);
1244                 x86_call_code (s->code, 0);
1245                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1246
1247                 x86_pop_reg (s->code, X86_EDX);
1248                 x86_pop_reg (s->code, X86_ECX);
1249
1250                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0);
1251                 EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, TRUE, "InvalidCastException");   
1252                 if (tree->reg1 != X86_EAX) {
1253                         x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1254                         x86_pop_reg (s->code, X86_EAX);
1255                 }
1256
1257                 le = s->code;
1258
1259         }
1260 }
1261
1262 reg: ISINST (reg) {
1263         if (tree->reg1 != X86_EAX)
1264                 x86_push_reg (s->code, X86_EAX);
1265         x86_push_reg (s->code, X86_ECX);
1266         x86_push_reg (s->code, X86_EDX);
1267
1268         x86_push_imm (s->code, tree->data.klass);
1269         x86_push_reg (s->code, tree->left->reg1);
1270         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_object_isinst);
1271         x86_call_code (s->code, 0);
1272         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
1273
1274         x86_pop_reg (s->code, X86_EDX);
1275         x86_pop_reg (s->code, X86_ECX);
1276         if (tree->reg1 != X86_EAX) {
1277                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
1278                 x86_pop_reg (s->code, X86_EAX);
1279         }
1280
1281 }
1282
1283 stmt: INITOBJ (reg) {
1284         int i, j;
1285
1286         i = tree->data.i;
1287
1288         if (i == 1 || i == 2 || i == 4) {
1289                 int t = X86_ECX;
1290
1291                 if (tree->left->reg1 != X86_EAX) 
1292                         t = X86_EAX;
1293
1294                 x86_push_reg (s->code, t);
1295                 x86_alu_reg_reg (s->code, X86_XOR, t, t);
1296
1297                 switch (tree->data.i) {
1298                 case 4:
1299                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
1300                         break;
1301                 case 2:
1302                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
1303                         break;
1304                 case 1:
1305                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
1306                         break;
1307                 }
1308                 x86_pop_reg (s->code, t);
1309
1310                 return;
1311         }
1312
1313         i = tree->data.i / 4;
1314         j = tree->data.i % 4;
1315
1316         x86_push_reg (s->code, X86_EAX);
1317         
1318         if (tree->left->reg1 != X86_EDI) {
1319                 x86_push_reg (s->code, X86_EDI);
1320                 x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
1321         }
1322
1323         if (i) {
1324                 x86_push_reg (s->code, X86_ECX);
1325                 x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
1326                 x86_mov_reg_imm (s->code, X86_ECX, i);
1327                 x86_cld (s->code);
1328                 x86_prefix (s->code, X86_REP_PREFIX);
1329                 x86_stosl (s->code);
1330                 x86_pop_reg (s->code, X86_ECX);
1331         }
1332
1333
1334         for (i = 0; i < j; i++)
1335                 x86_stosb (s->code);
1336
1337         if (tree->left->reg1 != X86_EDI)
1338                 x86_pop_reg (s->code, X86_EDI);
1339         
1340         x86_pop_reg (s->code, X86_EAX);
1341 }
1342
1343 stmt: NOP
1344
1345 stmt: POP (reg)
1346
1347 stmt: BR {
1348         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_BB, tree->data.bb);
1349         x86_jump32 (s->code, 0); 
1350 }
1351
1352 stmt: BLT (reg, reg) 1 {
1353         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1354         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1355         x86_branch32 (s->code, X86_CC_LT, 0, TRUE); 
1356 }
1357
1358 stmt: BLT (reg, CONST_I4) "MB_USE_OPT1(0)" {
1359         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1360         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1361         x86_branch32 (s->code, X86_CC_LT, 0, TRUE); 
1362 }
1363
1364 stmt: BLT_UN (reg, reg) 1 {
1365         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1366         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1367         x86_branch32 (s->code, X86_CC_LT, 0, FALSE); 
1368 }
1369
1370 stmt: BLT_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1371         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1372         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1373         x86_branch32 (s->code, X86_CC_LT, 0, FALSE); 
1374 }
1375
1376 stmt: BGT (reg, reg) 1 {
1377         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1378         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1379         x86_branch32 (s->code, X86_CC_GT, 0, TRUE); 
1380 }
1381
1382 stmt: BGT (reg, CONST_I4) "MB_USE_OPT1(0)" {
1383         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1384         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1385         x86_branch32 (s->code, X86_CC_GT, 0, TRUE); 
1386 }
1387
1388 stmt: BGT_UN (reg, reg) 1 {
1389         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1390         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1391         x86_branch32 (s->code, X86_CC_GT, 0, FALSE); 
1392 }
1393
1394 stmt: BGT_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1395         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1396         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1397         x86_branch32 (s->code, X86_CC_GT, 0, FALSE); 
1398 }
1399
1400 stmt: BEQ (reg, CONST_I4) "MB_USE_OPT1(0)" {
1401         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1402         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1403         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
1404 }
1405
1406 stmt: BEQ (reg, reg) 1 {
1407         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1408         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1409         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
1410 }
1411
1412 stmt: BNE_UN (reg, reg) 1 {
1413         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1414         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1415         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
1416 }
1417
1418 stmt: BNE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1419         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1420         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1421         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
1422 }
1423
1424 stmt: BGE (reg, reg) 1 {
1425         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1426         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1427         x86_branch32 (s->code, X86_CC_GE, 0, TRUE);
1428 }
1429
1430 stmt: BGE (reg, CONST_I4) "MB_USE_OPT1(0)" {
1431         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1432         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1433         x86_branch32 (s->code, X86_CC_GE, 0, TRUE);
1434 }
1435
1436 stmt: BGE_UN (reg, reg) 1 {
1437         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1438         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1439         x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
1440 }
1441
1442 stmt: BGE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1443         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1444         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1445         x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
1446 }
1447
1448 stmt: BLE (reg, reg) 1 {
1449         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1450         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1451         x86_branch32 (s->code, X86_CC_LE, 0, TRUE);
1452 }
1453
1454 stmt: BLE (reg, CONST_I4) "MB_USE_OPT1(0)" {
1455         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1456         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1457         x86_branch32 (s->code, X86_CC_LE, 0, TRUE);
1458 }
1459
1460 stmt: BLE_UN (reg, reg) 1 {
1461         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1462         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1463         x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
1464 }
1465
1466 stmt: BLE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1467         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1468         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1469         x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
1470 }
1471
1472 stmt: BRTRUE (reg) {
1473         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1474         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1475         x86_branch32 (s->code, X86_CC_NE, 0, TRUE);
1476 }
1477
1478 stmt: BRFALSE (reg) {
1479         x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1480         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
1481         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
1482 }
1483
1484 stmt: BREAK {
1485         x86_breakpoint (s->code);
1486 }
1487
1488 stmt: RET (reg) {
1489         if (tree->left->reg1 != X86_EAX)
1490                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1491
1492         if (!tree->last_instr) {
1493                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_EPILOG, NULL);
1494                 x86_jump32 (s->code, 0);      
1495         }
1496 }
1497
1498 stmt: RET_VOID {
1499         if (!tree->last_instr) {
1500                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_EPILOG, NULL);
1501                 x86_jump32 (s->code, 0);      
1502         } 
1503 }
1504
1505
1506 stmt: ARG_I4 (LDIND_I4 (addr)) {
1507         MBTree *at = tree->left->left;
1508
1509         switch (at->data.ainfo.amode) {
1510
1511         case AMImmediate:
1512                 x86_push_mem (s->code, at->data.ainfo.offset);
1513                 break;
1514
1515         case AMBase:
1516                 x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
1517                 break;          
1518         case AMIndex:
1519                 x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
1520                                    at->data.ainfo.indexreg, at->data.ainfo.shift);
1521                 break;          
1522         case AMBaseIndex:
1523                 x86_push_memindex (s->code, at->data.ainfo.basereg, 
1524                                    at->data.ainfo.offset, at->data.ainfo.indexreg, 
1525                                    at->data.ainfo.shift);
1526                 break;          
1527         }
1528 }
1529
1530 stmt: ARG_I4 (LDIND_U4 (addr)) {
1531         MBTree *at = tree->left->left;
1532
1533         switch (at->data.ainfo.amode) {
1534
1535         case AMImmediate:
1536                 x86_push_mem (s->code, at->data.ainfo.offset);
1537                 break;
1538
1539         case AMBase:
1540                 x86_push_membase (s->code, at->data.ainfo.basereg, at->data.ainfo.offset);
1541                 break;          
1542         case AMIndex:
1543                 x86_push_memindex (s->code, X86_NOBASEREG, at->data.ainfo.offset,
1544                                    at->data.ainfo.indexreg, at->data.ainfo.shift);
1545                 break;          
1546         case AMBaseIndex:
1547                 x86_push_memindex (s->code, at->data.ainfo.basereg, 
1548                                    at->data.ainfo.offset, at->data.ainfo.indexreg, 
1549                                    at->data.ainfo.shift);
1550                 break;          
1551         }
1552 }
1553
1554 stmt: ARG_I4 (reg) {
1555         x86_push_reg (s->code, tree->left->reg1);
1556         PRINT_REG ("ARG_I4",  tree->left->reg1);
1557 }
1558
1559 # fixme: we must free the allocated strings somewhere
1560 stmt: ARG_STRING (reg) {
1561         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
1562         x86_push_reg (s->code, X86_EAX);
1563         x86_push_reg (s->code, X86_ECX);
1564         x86_push_reg (s->code, X86_EDX);
1565
1566         x86_push_reg (s->code, tree->left->reg1);
1567         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_string_to_utf8);
1568         x86_call_code (s->code, 0);
1569         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
1570         
1571         x86_mov_membase_reg (s->code, X86_ESP, 12, X86_EAX, 4);
1572
1573         x86_pop_reg (s->code, X86_EDX);
1574         x86_pop_reg (s->code, X86_ECX);
1575         x86_pop_reg (s->code, X86_EAX);
1576 }
1577
1578 stmt: ARG_I4 (ADDR_G) {
1579         x86_push_imm (s->code, tree->left->data.p);
1580 }
1581
1582 stmt: ARG_I4 (CONST_I4) "MB_USE_OPT1(0)" {
1583         x86_push_imm (s->code, tree->left->data.i);
1584 }
1585
1586 this: reg {
1587         PRINT_REG ("THIS", tree->reg1);
1588 }
1589
1590 this: NOP
1591
1592 reg: CALL_I4 (this, reg) {
1593         MethodCallInfo *ci = tree->data.ci;
1594         int treg = X86_EAX;
1595         int lreg = tree->left->reg1;
1596         int rreg = tree->right->reg1;
1597         
1598         if (lreg == treg || rreg == treg) 
1599                 treg = X86_EDX;
1600         if (lreg == treg || rreg == treg) 
1601                 treg = X86_ECX;
1602         if (lreg == treg || rreg == treg) 
1603                 mono_assert_not_reached ();
1604
1605         if (tree->left->op != MB_TERM_NOP) {
1606                 mono_assert (lreg >= 0);
1607                 x86_push_reg (s->code, lreg);
1608         }
1609
1610         if (ci->vtype_num) {
1611                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1612                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1613                 x86_push_reg (s->code, treg);
1614         }
1615
1616         x86_call_reg (s->code, rreg);
1617
1618         if (ci->args_size)
1619                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1620         
1621         PRINT_REG ("CALL_I4", tree->reg1);
1622
1623         mono_assert (tree->reg1 == X86_EAX);
1624 }
1625
1626 reg: CALL_I4 (this, ADDR_G) {
1627         MethodCallInfo *ci = tree->data.ci;
1628         int lreg = tree->left->reg1;
1629         int treg = X86_EAX;
1630
1631         if (lreg == treg) 
1632                 treg = X86_EDX;
1633         
1634         if (tree->left->op != MB_TERM_NOP) {
1635                 mono_assert (lreg >= 0);
1636                 x86_push_reg (s->code, lreg);
1637         }
1638
1639         if (ci->vtype_num) {
1640                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1641                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1642                 x86_push_reg (s->code, treg);
1643         }
1644
1645         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, tree->right->data.p);
1646         x86_call_code (s->code, 0);
1647
1648         if (ci->args_size)
1649                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1650
1651         PRINT_REG ("CALL_I4", tree->reg1);
1652
1653         mono_assert (tree->reg1 == X86_EAX);
1654 }
1655
1656 reg: LDFTN (reg, INTF_ADDR) {
1657         int lreg = tree->left->reg1;
1658
1659         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1660         x86_mov_reg_membase (s->code, lreg, lreg, 
1661                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1662         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
1663         x86_mov_reg_membase (s->code, tree->reg1, lreg, tree->right->data.m->slot << 2, 4);
1664 }
1665
1666 reg: CALL_I4 (this, INTF_ADDR) {
1667         MethodCallInfo *ci = tree->data.ci;
1668         int lreg = tree->left->reg1;
1669         int treg = X86_EAX;
1670
1671         if (lreg == treg) 
1672                 treg = X86_EDX;
1673
1674         if (tree->left->op != MB_TERM_NOP) {
1675                 mono_assert (lreg >= 0);
1676                 x86_push_reg (s->code, lreg);
1677         }
1678
1679         if (ci->vtype_num) {
1680                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1681                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1682                 x86_push_reg (s->code, treg);
1683         }
1684
1685         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1686         x86_mov_reg_membase (s->code, lreg, lreg, 
1687                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1688         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
1689         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
1690
1691         if (ci->args_size)
1692                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1693
1694         PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
1695
1696         mono_assert (tree->reg1 == X86_EAX);
1697 }
1698
1699 reg: LDFTN (reg, VFUNC_ADDR) {
1700         int lreg = tree->left->reg1;
1701         
1702         x86_mov_reg_membase (s->code, tree->reg1, lreg, 0, 4);
1703         
1704         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2), 4);
1705 }
1706
1707 reg: CALL_I4 (this, VFUNC_ADDR) {
1708         MethodCallInfo *ci = tree->data.ci;
1709         int lreg = tree->left->reg1;
1710         int treg = X86_EAX;
1711
1712         if (lreg == treg) 
1713                 treg = X86_EDX;
1714
1715         if (tree->left->op != MB_TERM_NOP) {
1716                 mono_assert (lreg >= 0);
1717                 x86_push_reg (s->code, lreg);
1718         }
1719
1720         if (ci->vtype_num) {
1721                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1722                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1723                 x86_push_reg (s->code, treg);
1724         }
1725
1726         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);        
1727         x86_call_virtual (s->code, lreg, 
1728                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
1729
1730         if (ci->args_size)
1731                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1732
1733         PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
1734
1735         mono_assert (tree->reg1 == X86_EAX);
1736 }
1737
1738 stmt: CALL_VOID (this, ADDR_G) {
1739         MethodCallInfo *ci = tree->data.ci;
1740         int lreg = tree->left->reg1;
1741         int treg = X86_EAX;
1742
1743         if (lreg == treg) 
1744                 treg = X86_EDX;
1745         
1746         if (tree->left->op != MB_TERM_NOP) {
1747                 mono_assert (lreg >= 0);
1748                 x86_push_reg (s->code, lreg);
1749         }
1750
1751         if (ci->vtype_num) {
1752                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1753                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1754                 x86_push_reg (s->code, treg);
1755         }
1756
1757         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, tree->right->data.p);
1758         x86_call_code (s->code, 0);
1759
1760         if (ci->args_size)
1761                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1762 }
1763
1764 stmt: CALL_VOID (this, INTF_ADDR) {
1765         MethodCallInfo *ci = tree->data.ci;
1766         int lreg = tree->left->reg1;
1767         int treg = X86_EAX;
1768
1769         if (lreg == treg) 
1770                 treg = X86_EDX;
1771
1772         if (tree->left->op != MB_TERM_NOP) {
1773                 mono_assert (lreg >= 0);
1774                 x86_push_reg (s->code, lreg);
1775         }
1776
1777         if (ci->vtype_num) {
1778                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1779                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1780                 x86_push_reg (s->code, treg);
1781         }
1782
1783         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1784         x86_mov_reg_membase (s->code, lreg, lreg, 
1785                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
1786         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
1787         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
1788
1789         if (ci->args_size)
1790                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1791 }
1792
1793 stmt: CALL_VOID (this, VFUNC_ADDR) {
1794         MethodCallInfo *ci = tree->data.ci;
1795         int lreg = tree->left->reg1;
1796         int treg = X86_EAX;
1797
1798         if (lreg == treg) 
1799                 treg = X86_EDX;
1800
1801         if (tree->left->op != MB_TERM_NOP) {
1802                 mono_assert (lreg >= 0);
1803                 x86_push_reg (s->code, lreg);
1804         }
1805
1806         if (ci->vtype_num) {
1807                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1808                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1809                 x86_push_reg (s->code, treg);
1810         }
1811
1812         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1813         x86_call_virtual (s->code, lreg, 
1814                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
1815
1816         if (ci->args_size)
1817                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1818 }
1819
1820 stmt: SWITCH (reg) {
1821         guint32 offset;
1822         guint32 *jt = (guint32 *)tree->data.p;
1823
1824         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, jt [0]);
1825         offset = 6 + (guint32)s->code;
1826         x86_branch32 (s->code, X86_CC_GE, jt [jt [0] + 1] - offset, FALSE);
1827
1828         x86_mov_reg_memindex (s->code, X86_EAX, X86_NOBASEREG, 
1829                               tree->data.i + 4, tree->left->reg1, 2, 4);        
1830         x86_jump_reg (s->code, X86_EAX);
1831 }
1832
1833 #
1834 # 64 bit integers
1835 #
1836
1837 reg: CONV_I1 (lreg) {
1838         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, FALSE);
1839
1840
1841 reg: CONV_I2 (lreg) {
1842         x86_widen_reg (s->code, tree->reg1, tree->left->reg1, TRUE, TRUE);
1843
1844
1845 reg: CONV_I4 (lreg) {
1846         if (tree->reg1 != tree->left->reg1)
1847                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1848
1849
1850
1851 reg: CONV_OVF_I4 (lreg){
1852         guint8 *start = s->code;
1853         gpointer o1, o2, o3, o4, o5;
1854         int i;
1855
1856         /* 
1857          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
1858          */
1859         for (i = 0; i < 2; i++) {
1860                 s->code = start;
1861
1862                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
1863
1864                 /* If the low word top bit is set, see if we are negative */
1865                 x86_branch8 (s->code, X86_CC_LT, o3 - o1, TRUE);
1866                 o1 = s->code;
1867
1868                 /* We are not negative (no top bit set, check for our top word to be zero */
1869                 x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
1870                 x86_branch8 (s->code, X86_CC_EQ, o4 - o2, TRUE);
1871                 o2 = s->code;
1872
1873                 /* throw exception */
1874                 x86_push_imm (s->code, "OverflowException");
1875                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, 
1876                                     arch_get_throw_exception_by_name ());
1877                 x86_call_code (s->code, 0);
1878         
1879                 o3 = s->code;
1880                 /* our top bit is set, check that top word is 0xfffffff */
1881                 x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg2, 0xffffffff);
1882                 
1883                 o4 = s->code;
1884                 /* nope, emit exception */
1885                 x86_branch8 (s->code, X86_CC_NE, o2 - o5, TRUE);
1886                 o5 = s->code;
1887
1888                 if (tree->reg1 != tree->left->reg1)
1889                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1890         }
1891 }
1892
1893 reg: CONV_OVF_U4 (lreg) {
1894         /* Keep in sync with CONV_OVF_I4_UN below, they are the same on 32-bit machines */
1895         /* top word must be 0 */
1896         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
1897         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
1898         if (tree->reg1 != tree->left->reg1)
1899                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1900 }
1901
1902 reg: CONV_OVF_I4_UN (lreg) {
1903         /* Keep in sync with CONV_OVF_U4 above, they are the same on 32-bit machines */
1904         /* top word must be 0 */
1905         x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
1906         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
1907         if (tree->reg1 != tree->left->reg1)
1908                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1909 }
1910
1911 stmt: POP (lreg)
1912
1913 lreg: CONST_I8 1 {
1914         x86_mov_reg_imm (s->code, tree->reg1, *((gint32 *)&tree->data.p));
1915         x86_mov_reg_imm (s->code, tree->reg2, *((gint32 *)&tree->data.p + 1));
1916 }
1917
1918 lreg: CONV_I8 (CONST_I4) {
1919         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1920
1921         if (tree->left->data.i >= 0)
1922                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1923         else 
1924                 x86_mov_reg_imm (s->code, tree->reg2, -1);              
1925 }
1926
1927 lreg: CONV_I8 (reg) {
1928         guint8 *i1;
1929
1930         if (tree->reg1 != tree->left->reg1)
1931                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1932
1933         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
1934         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1935         x86_branch8 (s->code, X86_CC_GE, 5, TRUE);
1936         i1 = s->code;
1937         x86_mov_reg_imm (s->code, tree->reg2, -1); 
1938         mono_assert ((s->code - i1) == 5);
1939 }
1940
1941 lreg: CONV_U8 (CONST_I4) 1 {
1942         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1943         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1944 }
1945
1946 lreg: CONV_OVF_U8 (CONST_I4) {
1947         if (tree->left->data.i < 0){
1948                 x86_push_imm (s->code, "OverflowException");
1949                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, 
1950                                     arch_get_throw_exception_by_name ());
1951                 x86_call_code (s->code, 0);
1952         } else {
1953                 x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1954                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1955         }
1956 }
1957
1958 lreg: CONV_OVF_I8_UN (CONST_I4) {
1959         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1960         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1961 }
1962
1963 lreg: CONV_OVF_U8 (reg) {
1964         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
1965         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "OverflowException");
1966
1967         if (tree->reg1 != tree->left->reg1)
1968                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1969         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1970 }
1971
1972 lreg: CONV_OVF_I8_UN (reg) {
1973         /* Convert uint value into int64, we pass everything */
1974         if (tree->reg1 != tree->left->reg1)
1975                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1976         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1977 }
1978
1979 stmt: STIND_I8 (addr, lreg) {
1980        
1981         switch (tree->left->data.ainfo.amode) {
1982
1983         case AMImmediate:
1984                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
1985                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
1986                 break;
1987                 
1988         case AMBase:
1989                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
1990                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
1991                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
1992                                      tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
1993                 break;          
1994         case AMIndex:
1995                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
1996                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
1997                                       tree->right->reg1, 4);
1998                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset + 4,
1999                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2000                                       tree->right->reg2, 4);
2001                 break;          
2002         case AMBaseIndex:
2003                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
2004                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2005                                       tree->right->reg1, 4);
2006                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset + 4,
2007                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
2008                                       tree->right->reg2, 4);
2009                 break;          
2010         }
2011
2012 }
2013
2014 # an addr can use two address register (base and index register). The must take care 
2015 # that we do not override them (thus the use of x86_lea)
2016 lreg: LDIND_I8 (addr) {
2017
2018         switch (tree->left->data.ainfo.amode) {
2019
2020         case AMImmediate:
2021                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
2022                 x86_mov_reg_mem (s->code, tree->reg2, tree->left->data.ainfo.offset + 4, 4);
2023                 break;
2024
2025         case AMBase:
2026                 x86_lea_membase (s->code, tree->reg2, tree->left->data.ainfo.basereg,
2027                                  tree->left->data.ainfo.offset);
2028                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2029                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2030                 break;          
2031         case AMIndex:
2032                 x86_lea_memindex (s->code, tree->reg2, X86_NOBASEREG, tree->left->data.ainfo.offset,
2033                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift);
2034                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2035                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2036                 break;          
2037         case AMBaseIndex:
2038                 x86_lea_memindex (s->code, tree->reg2, tree->left->data.ainfo.basereg, 
2039                                   tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
2040                                   tree->left->data.ainfo.shift);
2041                 x86_mov_reg_membase (s->code, tree->reg1, tree->reg2, 0, 4);
2042                 x86_mov_reg_membase (s->code, tree->reg2, tree->reg2, 4, 4);
2043                 break;          
2044         }
2045         PRINT_REG ("LDIND_I8_0", tree->reg1);
2046         PRINT_REG ("LDIND_I8_1", tree->reg2);
2047 }
2048
2049 lreg: SHR (lreg, CONST_I4) {
2050         if (tree->right->data.i < 32) {
2051                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
2052                 x86_shift_reg_imm (s->code, X86_SAR, tree->left->reg2, tree->right->data.i);
2053                 if (tree->reg1 != tree->left->reg1)
2054                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2055                 if (tree->reg2 != tree->left->reg2)
2056                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2057         } else if (tree->right->data.i < 64) {
2058                 if (tree->reg1 != tree->left->reg2)
2059                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
2060                 if (tree->reg2 != tree->left->reg2)
2061                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2062                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);
2063                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg1, (tree->right->data.i - 32));
2064         } /* else unspecified result */
2065 }
2066
2067 lreg: SHR_UN (lreg, CONST_I4) {
2068         if (tree->right->data.i < 32) {
2069                 x86_shrd_reg_imm (s->code, tree->left->reg1, tree->left->reg2, tree->right->data.i);
2070                 x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg2, tree->right->data.i);
2071                 if (tree->reg1 != tree->left->reg1)
2072                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2073                 if (tree->reg2 != tree->left->reg2)
2074                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2075         } else if (tree->right->data.i < 64) {
2076                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg2, 4);
2077                 x86_shift_reg_imm (s->code, X86_SHR, tree->reg1, (tree->right->data.i - 32));
2078                 x86_mov_reg_imm (s->code, tree->reg2, 0);
2079         } /* else unspecified result */
2080 }
2081
2082 lreg: SHR (lreg, reg) {
2083         guint8 *start = s->code;
2084         gint32 o1, o2, i;
2085
2086         if (tree->right->reg1 != X86_ECX)
2087                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2088
2089         for (i = 0; i < 2; i ++) {
2090                 s->code = start;
2091                 x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
2092                 x86_shift_reg (s->code, X86_SAR, tree->left->reg2);
2093                 x86_test_reg_imm (s->code, X86_ECX, 32);
2094                 o1 = 2 + s->code - s->start;
2095                 x86_branch8 (s->code, X86_CC_EQ, o2 - o1, FALSE);
2096                 x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
2097                 x86_shift_reg_imm (s->code, X86_SAR, tree->reg2, 31);           
2098                 o2 = s->code - s->start;
2099         }
2100
2101         if (tree->reg1 != tree->left->reg1)
2102                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2103         if (tree->reg2 != tree->left->reg2)
2104                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2105 }
2106
2107 lreg: SHR_UN (lreg, reg) {
2108         guint8 *start = s->code;
2109         gint32 o1, o2, i;
2110
2111         if (tree->right->reg1 != X86_ECX)
2112                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2113
2114         for (i = 0; i < 2; i ++) {
2115                 s->code = start;
2116                 x86_shrd_reg (s->code, tree->left->reg1, tree->left->reg2);
2117                 x86_shift_reg (s->code, X86_SHR, tree->left->reg2);
2118                 x86_test_reg_imm (s->code, X86_ECX, 32);
2119                 o1 = 2 + s->code - s->start;
2120                 x86_branch8 (s->code, X86_CC_EQ, o2 - o1, FALSE);
2121                 x86_mov_reg_reg (s->code, tree->left->reg1, tree->left->reg2, 4);
2122                 x86_shift_reg_imm (s->code, X86_SHR, tree->reg2, 31);           
2123                 o2 = s->code - s->start;
2124         }
2125
2126         if (tree->reg1 != tree->left->reg1)
2127                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2128         if (tree->reg2 != tree->left->reg2)
2129                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2130 }
2131
2132 lreg: SHL (lreg, CONST_I4) {
2133         if (tree->right->data.i < 32) {
2134                 x86_shld_reg_imm (s->code, tree->left->reg2, tree->left->reg1, tree->right->data.i);
2135                 x86_shift_reg_imm (s->code, X86_SHL, tree->left->reg1, tree->right->data.i);
2136                 if (tree->reg1 != tree->left->reg1)
2137                         x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2138                 if (tree->reg2 != tree->left->reg2)
2139                         x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2140         } else if (tree->right->data.i < 64) {
2141                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg1, 4);
2142                 x86_shift_reg_imm (s->code, X86_SHL, tree->reg2, (tree->right->data.i - 32));
2143                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg1, tree->reg1);     
2144         } /* else unspecified result */
2145 }
2146
2147 lreg: SHL (lreg, reg) {
2148         guint8 *start = s->code;
2149         gint32 o1, o2, i;
2150
2151         if (tree->right->reg1 != X86_ECX)
2152                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
2153
2154         for (i = 0; i < 2; i ++) {
2155                 s->code = start;
2156                 x86_shld_reg (s->code, tree->left->reg2, tree->left->reg1);
2157                 x86_shift_reg (s->code, X86_SHL, tree->left->reg1);
2158                 x86_test_reg_imm (s->code, X86_ECX, 32);
2159                 o1 = 2 + s->code - s->start;
2160                 x86_branch8 (s->code, X86_CC_EQ, o2 - o1, FALSE);
2161                 x86_mov_reg_reg (s->code, tree->left->reg2, tree->left->reg1, 4);
2162                 x86_alu_reg_reg (s->code, X86_XOR, tree->left->reg1, tree->left->reg1); 
2163                 o2 = s->code - s->start;
2164         }
2165
2166         if (tree->reg1 != tree->left->reg1)
2167                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2168         if (tree->reg2 != tree->left->reg2)
2169                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2170 }
2171
2172 lreg: ADD (lreg, lreg) {
2173         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2174         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2175
2176         if (tree->reg1 != tree->left->reg1)
2177                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2178         if (tree->reg2 != tree->left->reg2)
2179                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2180 }
2181
2182 lreg: ADD_OVF (lreg, lreg) {
2183         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2184         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2185         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
2186
2187         if (tree->reg1 != tree->left->reg1)
2188                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2189         if (tree->reg2 != tree->left->reg2)
2190                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2191 }
2192
2193 lreg: ADD_OVF_UN (lreg, lreg) {
2194         x86_alu_reg_reg (s->code, X86_ADD, tree->left->reg1, tree->right->reg1);
2195         x86_alu_reg_reg (s->code, X86_ADC, tree->left->reg2, tree->right->reg2);
2196         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
2197
2198         if (tree->reg1 != tree->left->reg1)
2199                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2200         if (tree->reg2 != tree->left->reg2)
2201                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2202 }
2203
2204 lreg: SUB (lreg, lreg) {
2205         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2206         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2207
2208         if (tree->reg1 != tree->left->reg1)
2209                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2210         if (tree->reg2 != tree->left->reg2)
2211                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2212 }
2213
2214 lreg: SUB_OVF (lreg, lreg) {
2215         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2216         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2217         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NO, TRUE, "OverflowException");      
2218
2219         if (tree->reg1 != tree->left->reg1)
2220                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2221         if (tree->reg2 != tree->left->reg2)
2222                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2223 }
2224
2225 lreg: SUB_OVF_UN (lreg, lreg) {
2226         x86_alu_reg_reg (s->code, X86_SUB, tree->left->reg1, tree->right->reg1);
2227         x86_alu_reg_reg (s->code, X86_SBB, tree->left->reg2, tree->right->reg2);
2228         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NC, FALSE, "OverflowException");     
2229
2230         if (tree->reg1 != tree->left->reg1)
2231                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2232         if (tree->reg2 != tree->left->reg2)
2233                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2234 }
2235
2236 lreg: AND (lreg, lreg) {
2237         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg1, tree->right->reg1);
2238         x86_alu_reg_reg (s->code, X86_AND, tree->left->reg2, tree->right->reg2);
2239
2240         if (tree->reg1 != tree->left->reg1)
2241                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2242         if (tree->reg2 != tree->left->reg2)
2243                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2244 }
2245
2246 lreg: OR (lreg, lreg) {
2247         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg1, tree->right->reg1);
2248         x86_alu_reg_reg (s->code, X86_OR, tree->left->reg2, tree->right->reg2);
2249
2250         if (tree->reg1 != tree->left->reg1)
2251                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2252         if (tree->reg2 != tree->left->reg2)
2253                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2254 }
2255
2256 lreg: NEG (lreg) {
2257         if (tree->reg1 != tree->left->reg1)
2258                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2259         if (tree->reg2 != tree->left->reg2)
2260                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2261
2262         x86_neg_reg (s->code, tree->reg1);
2263         x86_alu_reg_imm (s->code, X86_ADC, tree->reg2, 0);
2264         x86_neg_reg (s->code, tree->reg2);
2265 }
2266
2267 lreg: NOT (lreg) {
2268         if (tree->reg1 != tree->left->reg1)
2269                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
2270         if (tree->reg2 != tree->left->reg2)
2271                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
2272
2273          x86_not_reg (s->code, tree->reg1);
2274          x86_not_reg (s->code, tree->reg2);
2275 }
2276
2277 lreg: MUL (lreg, lreg) {
2278         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2279                 x86_push_reg (s->code, X86_ECX);
2280
2281         x86_push_reg (s->code, tree->right->reg2);
2282         x86_push_reg (s->code, tree->right->reg1);
2283         x86_push_reg (s->code, tree->left->reg2);
2284         x86_push_reg (s->code, tree->left->reg1);
2285         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_llmult);
2286         x86_call_code (s->code, 0);
2287         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2288
2289         if (mono_regset_reg_used (s->rs, X86_ECX))
2290                 x86_pop_reg (s->code, X86_ECX);
2291
2292         mono_assert (tree->reg1 == X86_EAX &&
2293                   tree->reg2 == X86_EDX);
2294 }
2295
2296 lreg: MUL_OVF (lreg, lreg) {
2297         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2298                 x86_push_reg (s->code, X86_ECX);
2299
2300         x86_push_reg (s->code, tree->right->reg2);
2301         x86_push_reg (s->code, tree->right->reg1);
2302         x86_push_reg (s->code, tree->left->reg2);
2303         x86_push_reg (s->code, tree->left->reg1);
2304         /* pass a pointer to store the resulting exception -
2305          * ugly, but it works */
2306         x86_push_reg (s->code, X86_ESP); 
2307         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_llmult_ovf);
2308         x86_call_code (s->code, 0);
2309         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
2310         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
2311         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
2312
2313         /* cond. emit exception */
2314         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
2315         x86_push_reg (s->code, X86_ECX);
2316         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
2317         x86_call_code (s->code, 0);
2318
2319         if (mono_regset_reg_used (s->rs, X86_ECX))
2320                 x86_pop_reg (s->code, X86_ECX);
2321
2322         mono_assert (tree->reg1 == X86_EAX &&
2323                   tree->reg2 == X86_EDX);
2324 }
2325
2326 lreg: MUL_OVF_UN (lreg, lreg) {
2327         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2328                 x86_push_reg (s->code, X86_ECX);
2329
2330         x86_push_reg (s->code, tree->right->reg2);
2331         x86_push_reg (s->code, tree->right->reg1);
2332         x86_push_reg (s->code, tree->left->reg2);
2333         x86_push_reg (s->code, tree->left->reg1);
2334         /* pass a pointer to store the resulting exception -
2335          * ugly, but it works */
2336         x86_push_reg (s->code, X86_ESP); 
2337         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_llmult_ovf_un);
2338         x86_call_code (s->code, 0);
2339         x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, 4, 4);
2340         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 20);
2341         x86_alu_reg_imm (s->code, X86_CMP, X86_ECX, 0);
2342
2343         /* cond. emit exception */
2344         x86_branch8 (s->code, X86_CC_EQ, 7, FALSE);                     
2345         x86_push_reg (s->code, X86_ECX);                                 
2346         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, arch_get_throw_exception ());
2347         x86_call_code (s->code, 0);
2348
2349         if (mono_regset_reg_used (s->rs, X86_ECX))
2350                 x86_pop_reg (s->code, X86_ECX);
2351
2352         mono_assert (tree->reg1 == X86_EAX &&
2353                   tree->reg2 == X86_EDX);
2354 }
2355
2356 lreg: DIV (lreg, lreg) {
2357         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2358                 x86_push_reg (s->code, X86_ECX);
2359
2360         x86_push_reg (s->code, tree->right->reg2);
2361         x86_push_reg (s->code, tree->right->reg1);
2362         x86_push_reg (s->code, tree->left->reg2);
2363         x86_push_reg (s->code, tree->left->reg1);
2364         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_lldiv);
2365         x86_call_code (s->code, 0);
2366         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2367
2368         if (mono_regset_reg_used (s->rs, X86_ECX))
2369                 x86_pop_reg (s->code, X86_ECX);
2370
2371         mono_assert (tree->reg1 == X86_EAX &&
2372                   tree->reg2 == X86_EDX);
2373 }
2374
2375 lreg: REM (lreg, lreg) {
2376         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2377                 x86_push_reg (s->code, X86_ECX);
2378
2379         x86_push_reg (s->code, tree->right->reg2);
2380         x86_push_reg (s->code, tree->right->reg1);
2381         x86_push_reg (s->code, tree->left->reg2);
2382         x86_push_reg (s->code, tree->left->reg1);
2383         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_llrem);
2384         x86_call_code (s->code, 0);
2385         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2386
2387         if (mono_regset_reg_used (s->rs, X86_ECX))
2388                 x86_pop_reg (s->code, X86_ECX);
2389
2390         mono_assert (tree->reg1 == X86_EAX &&
2391                   tree->reg2 == X86_EDX);
2392 }
2393
2394 lreg: DIV_UN (lreg, lreg) {
2395         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2396                 x86_push_reg (s->code, X86_ECX);
2397
2398         x86_push_reg (s->code, tree->right->reg2);
2399         x86_push_reg (s->code, tree->right->reg1);
2400         x86_push_reg (s->code, tree->left->reg2);
2401         x86_push_reg (s->code, tree->left->reg1);
2402         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_lldiv_un);
2403         x86_call_code (s->code, 0);
2404         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2405
2406         if (mono_regset_reg_used (s->rs, X86_ECX))
2407                 x86_pop_reg (s->code, X86_ECX);
2408
2409         mono_assert (tree->reg1 == X86_EAX &&
2410                   tree->reg2 == X86_EDX);
2411 }
2412
2413 lreg: REM_UN (lreg, lreg) {
2414         if (mono_regset_reg_used (s->rs, X86_ECX)) 
2415                 x86_push_reg (s->code, X86_ECX);
2416
2417         x86_push_reg (s->code, tree->right->reg2);
2418         x86_push_reg (s->code, tree->right->reg1);
2419         x86_push_reg (s->code, tree->left->reg2);
2420         x86_push_reg (s->code, tree->left->reg1);
2421         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, mono_llrem_un);
2422         x86_call_code (s->code, 0);
2423         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
2424
2425         if (mono_regset_reg_used (s->rs, X86_ECX))
2426                 x86_pop_reg (s->code, X86_ECX);
2427
2428         mono_assert (tree->reg1 == X86_EAX &&
2429                   tree->reg2 == X86_EDX);
2430 }
2431
2432 lreg: CALL_I8 (this, ADDR_G) {
2433         MethodCallInfo *ci = tree->data.ci;
2434         int lreg = tree->left->reg1;
2435         int treg = X86_EAX;
2436
2437         if (lreg == treg) 
2438                 treg = X86_EDX;
2439         
2440         if (tree->left->op != MB_TERM_NOP) {
2441                 mono_assert (lreg >= 0);
2442                 x86_push_reg (s->code, lreg);
2443         }
2444
2445         if (ci->vtype_num) {
2446                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2447                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2448                 x86_push_reg (s->code, treg);
2449         }
2450
2451         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, tree->right->data.p);
2452         x86_call_code (s->code, 0);
2453
2454         if (ci->args_size)
2455                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2456
2457         mono_assert (tree->reg1 == X86_EAX);
2458         mono_assert (tree->reg2 == X86_EDX);
2459 }
2460
2461 lreg: CALL_I8 (this, VFUNC_ADDR) {
2462         MethodCallInfo *ci = tree->data.ci;
2463         int lreg = tree->left->reg1;
2464         int treg = X86_EAX;
2465
2466         if (lreg == treg) 
2467                 treg = X86_EDX;
2468
2469         if (tree->left->op != MB_TERM_NOP) {
2470                 mono_assert (lreg >= 0);
2471                 x86_push_reg (s->code, lreg);
2472         }
2473
2474         if (ci->vtype_num) {
2475                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2476                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2477                 x86_push_reg (s->code, treg);
2478         }
2479
2480         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2481         x86_call_virtual (s->code, lreg, 
2482                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
2483
2484         if (ci->args_size)
2485                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2486
2487         PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
2488         PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
2489
2490         mono_assert (tree->reg1 == X86_EAX);
2491         mono_assert (tree->reg2 == X86_EDX);
2492 }
2493
2494 lreg: CALL_I8 (this, INTF_ADDR) {
2495         MethodCallInfo *ci = tree->data.ci;
2496         int lreg = tree->left->reg1;
2497         int treg = X86_EAX;
2498
2499         if (lreg == treg) 
2500                 treg = X86_EDX;
2501
2502         if (tree->left->op != MB_TERM_NOP) {
2503                 mono_assert (lreg >= 0);
2504                 x86_push_reg (s->code, lreg);
2505         }
2506
2507         if (ci->vtype_num) {
2508                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2509                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2510                 x86_push_reg (s->code, treg);
2511         }
2512
2513         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2514         x86_mov_reg_membase (s->code, lreg, lreg, 
2515                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
2516         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2517         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2518
2519         if (ci->args_size)
2520                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2521
2522         PRINT_REG ("CALL_I8(INTERFACE)", tree->reg1);
2523
2524         mono_assert (tree->reg1 == X86_EAX);
2525         mono_assert (tree->reg2 == X86_EDX);
2526 }
2527
2528 stmt: RET (lreg) {
2529         if (tree->left->reg1 != X86_EAX) {
2530                 if (tree->left->reg2 != X86_EAX) {
2531                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
2532                         if (tree->left->reg2 != X86_EDX)
2533                                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
2534                 } else { 
2535                         x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg2, 4);
2536                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
2537                         x86_mov_reg_reg (s->code, X86_EDX, X86_ECX, 4);
2538                 }
2539         } else if (tree->left->reg2 != X86_EDX) {
2540                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
2541         }
2542
2543         if (!tree->last_instr) {
2544                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_EPILOG, NULL);
2545                 x86_jump32 (s->code, 0);      
2546         }
2547 }
2548
2549
2550 stmt: ARG_I8 (lreg) {
2551         x86_push_reg (s->code, tree->left->reg2);
2552         x86_push_reg (s->code, tree->left->reg1);
2553 }
2554
2555 reg: CEQ (lreg, lreg) {
2556         guint8 *start = s->code;
2557         gint32 o1, o2, i;
2558
2559         for (i = 0; i < 2; i ++) {
2560                 s->code = start;
2561                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2562                 o1 = 2 + s->code - s->start;
2563                 x86_branch8 (s->code, X86_CC_NE, o2 - o1, FALSE);
2564                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2565                 o2 = s->code - s->start;                
2566                 x86_set_reg (s->code, X86_CC_EQ, tree->reg1, FALSE);
2567                 x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
2568         }
2569 }
2570
2571 reg: CLT (lreg, lreg) {
2572         guint8 *start = s->code;
2573         gpointer o1, o2, o3, o4, o5;
2574         int i;
2575
2576         for (i = 0; i < 2; i ++) {
2577                 s->code = start;
2578                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2579                 x86_branch8 (s->code, X86_CC_GT, o4 - o1, TRUE);
2580                 o1 = s->code;
2581                 x86_branch8 (s->code, X86_CC_NE, o4 - o2, TRUE);
2582                 o2 = s->code;
2583                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2584                 x86_branch8 (s->code, X86_CC_GE, o4 - o3, FALSE);
2585
2586                 /* set result to 1 */
2587                 o3 = s->code;
2588                 x86_mov_reg_imm (s->code, tree->reg1, 1);
2589                 x86_jump8 (s->code, (o4 - o3));
2590                 /* set result to 0 */
2591                 o4 = s->code;
2592                 x86_mov_reg_imm (s->code, tree->reg1, 0);       
2593                 o5 = s->code;
2594         }
2595 }
2596
2597 stmt: BEQ (lreg, lreg) {
2598         guint8 *start = s->code;
2599         int i;
2600         gpointer o1, o2;
2601
2602         for (i = 0; i < 2; i ++) {
2603                 s->code = start;
2604                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2605                 x86_branch8 (s->code, X86_CC_NE, o2 - o1, FALSE);
2606                 o1 = s->code;
2607                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2608                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2609                 x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
2610                 o2 = s->code;
2611         }
2612 }
2613
2614 stmt: BNE_UN (lreg, lreg) {
2615         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2616         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2617         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
2618         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2619         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2620         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
2621 }
2622
2623 stmt: BGE (lreg, lreg) {
2624         guint8 *start = s->code;
2625         gpointer o2, oe;
2626         int i;
2627
2628         for (i = 0; i < 2; i ++) {
2629                 s->code = start;
2630                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2631                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2632                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
2633                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2634                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
2635                 o2 = s->code;
2636                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2637                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2638                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
2639                 oe = s->code;
2640         }
2641 }
2642
2643 stmt: BGE_UN (lreg, lreg) {
2644         guint8 *start = s->code;
2645         gpointer o2, oe;
2646         int i;
2647
2648         for (i = 0; i < 2; i ++) {
2649                 s->code = start;
2650                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2651                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2652                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
2653                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2654                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
2655                 o2 = s->code;
2656                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2657                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2658                 x86_branch32 (s->code, X86_CC_GE, 0, FALSE);
2659                 oe = s->code;
2660         }
2661 }
2662
2663 stmt: BGT (lreg, lreg) {
2664         guint8 *start = s->code;
2665         gpointer o2, oe;
2666         int i;
2667
2668         for (i = 0; i < 2; i ++) {
2669                 s->code = start;
2670                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2671                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2672                 x86_branch32 (s->code, X86_CC_GT, 0, TRUE);
2673                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2674                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
2675                 o2 = s->code;
2676                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2677                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2678                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
2679                 oe = s->code;
2680         }
2681 }
2682
2683 stmt: BGT_UN (lreg, lreg) {
2684         guint8 *start = s->code;
2685         gpointer o2, oe;
2686         int i;
2687
2688         for (i = 0; i < 2; i ++) {
2689                 s->code = start;
2690                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2691                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2692                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
2693                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2694                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
2695                 o2 = s->code;
2696                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2697                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2698                 x86_branch32 (s->code, X86_CC_GT, 0, FALSE);
2699                 oe = s->code;
2700         }
2701 }
2702
2703 stmt: BLT (lreg, lreg) {
2704         guint8 *start = s->code;
2705         gpointer o2, oe;
2706         int i;
2707
2708         for (i = 0; i < 2; i ++) {
2709                 s->code = start;
2710                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2711                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2712                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
2713                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2714                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
2715                 o2 = s->code;
2716                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2717                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2718                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
2719                 oe = s->code;
2720         }
2721 }
2722
2723 stmt: BLT_UN (lreg, lreg) {
2724         guint8 *start = s->code;
2725         gpointer o2, oe;
2726         int i;
2727
2728         for (i = 0; i < 2; i ++) {
2729                 s->code = start;
2730                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2731                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2732                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
2733                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2734                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
2735                 o2 = s->code;
2736                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2737                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2738                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
2739                 oe = s->code;
2740         }
2741 }
2742
2743 stmt: BLE (lreg, lreg) {
2744         guint8 *start = s->code;
2745         gpointer o2, oe;
2746         int i;
2747
2748         for (i = 0; i < 2; i ++) {
2749                 s->code = start;
2750                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2751                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2752                 x86_branch32 (s->code, X86_CC_LT, 0, TRUE);
2753                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2754                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
2755                 o2 = s->code;
2756                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2757                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2758                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
2759                 oe = s->code;
2760         }
2761 }
2762
2763 stmt: BLE_UN (lreg, lreg) {
2764         guint8 *start = s->code;
2765         gpointer o2, oe;
2766         int i;
2767
2768         for (i = 0; i < 2; i ++) {
2769                 s->code = start;
2770                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2771                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2772                 x86_branch32 (s->code, X86_CC_LT, 0, FALSE);
2773                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2774                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
2775                 o2 = s->code;
2776                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2777                 if (i) mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
2778                 x86_branch32 (s->code, X86_CC_LE, 0, FALSE);
2779                 oe = s->code;
2780         }
2781 }
2782
2783 #
2784 # floating point 
2785
2786 #stmt: STLOC (CONV_I4 (freg)) {
2787 #       // fixme: set CW
2788 #       x86_fist_pop_membase (s->code, X86_EBP, tree->data.i, FALSE);
2789 #} 
2790
2791 reg: CONV_I1 (freg) {
2792         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2793         x86_fnstcw_membase(s->code, X86_ESP, 0);
2794         x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
2795         x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
2796         x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
2797         x86_fldcw_membase (s->code, X86_ESP, 2);
2798         x86_push_reg (s->code, X86_EAX); // SP = SP - 4
2799         x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
2800         x86_pop_reg (s->code, tree->reg1);
2801         x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, FALSE);
2802         x86_fldcw_membase (s->code, X86_ESP, 0);
2803         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
2804 }
2805
2806 reg: CONV_I2 (freg) {
2807         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2808         x86_fnstcw_membase(s->code, X86_ESP, 0);
2809         x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
2810         x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
2811         x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
2812         x86_fldcw_membase (s->code, X86_ESP, 2);
2813         x86_push_reg (s->code, X86_EAX); // SP = SP - 4
2814         x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
2815         x86_pop_reg (s->code, tree->reg1);
2816         x86_widen_reg (s->code, tree->reg1, tree->reg1, TRUE, TRUE);
2817         x86_fldcw_membase (s->code, X86_ESP, 0);
2818         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
2819 }
2820
2821 reg: CONV_I4 (freg) {
2822         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2823         x86_fnstcw_membase(s->code, X86_ESP, 0);
2824         x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
2825         x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
2826         x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
2827         x86_fldcw_membase (s->code, X86_ESP, 2);
2828         x86_push_reg (s->code, X86_EAX); // SP = SP - 4
2829         x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
2830         x86_pop_reg (s->code, tree->reg1);
2831         x86_fldcw_membase (s->code, X86_ESP, 0);
2832         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
2833 }
2834
2835 lreg: CONV_I8 (freg) {
2836         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2837         x86_fnstcw_membase(s->code, X86_ESP, 0);
2838         x86_mov_reg_membase (s->code, tree->reg1, X86_ESP, 0, 2);
2839         x86_alu_reg_imm (s->code, X86_OR, tree->reg1, 0xc00);
2840         x86_mov_membase_reg (s->code, X86_ESP, 2, tree->reg1, 2);
2841         x86_fldcw_membase (s->code, X86_ESP, 2);
2842         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
2843         x86_fist_pop_membase (s->code, X86_ESP, 0, TRUE);
2844         x86_pop_reg (s->code, tree->reg1);
2845         x86_pop_reg (s->code, tree->reg2);
2846         x86_fldcw_membase (s->code, X86_ESP, 0);
2847         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
2848 }
2849
2850 reg: CEQ (freg, freg) {
2851         int treg = tree->reg1;
2852         
2853         if (treg != X86_EAX)
2854                 x86_push_reg (s->code, X86_EAX); // save EAX
2855                 
2856         x86_fcompp (s->code);
2857         x86_fnstsw (s->code);
2858         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2859         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
2860         x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
2861         x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
2862
2863         if (treg != X86_EAX)
2864                 x86_pop_reg (s->code, X86_EAX); // save EAX
2865 }
2866
2867 freg: CONV_R8 (freg) {
2868         /* nothing to do */
2869 }
2870
2871 freg: CONV_R4 (freg) {
2872         /* fixme: nothing to do ??*/
2873 }
2874
2875 freg: CONV_R8 (LDIND_I4 (ADDR_G)) {
2876         x86_fild (s->code, tree->left->left->data.p, FALSE);
2877 }
2878
2879 freg: CONV_R4 (reg) {
2880         x86_push_reg (s->code, tree->left->reg1);
2881         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
2882         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2883 }
2884
2885 freg: CONV_R8 (reg) {
2886         x86_push_reg (s->code, tree->left->reg1);
2887         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
2888         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2889 }
2890
2891 freg: CONV_R_UN (reg) {
2892         x86_push_imm (s->code, 0);
2893         x86_push_reg (s->code, tree->left->reg1);
2894         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
2895         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
2896 }
2897
2898 freg: CONV_R_UN (lreg) {
2899         guint8 *start = s->code, *l1, *l2;
2900         int i;
2901
2902         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
2903
2904         for (i = 0; i < 2; i++) {
2905                 s->code = start;
2906
2907                 /* load 64bit integer to FP stack */
2908                 x86_push_imm (s->code, 0);
2909                 x86_push_reg (s->code, tree->left->reg2);
2910                 x86_push_reg (s->code, tree->left->reg1);
2911                 x86_fild_membase (s->code, X86_ESP, 0, TRUE);
2912                 /* store as 80bit FP value */
2913                 x86_fst80_membase (s->code, X86_ESP, 0);
2914
2915                 /* test if lreg is negative */
2916                 x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
2917                 x86_branch8 (s->code, X86_CC_GEZ, l2 - l1, TRUE);
2918                 l1 = s->code;
2919
2920                 /* add correction constant mn */
2921                 x86_fld80_mem (s->code, mn);
2922                 x86_fld80_membase (s->code, X86_ESP, 0);
2923                 x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
2924                 x86_fst80_membase (s->code, X86_ESP, 0);
2925
2926                 l2 = s->code;
2927
2928                 x86_fld80_membase (s->code, X86_ESP, 0);
2929                 x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 12);
2930         }
2931 }
2932
2933 freg: CONV_R4 (lreg) {
2934         x86_push_reg (s->code, tree->left->reg2);
2935         x86_push_reg (s->code, tree->left->reg1);
2936         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
2937         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
2938 }
2939
2940 freg: CONV_R8 (lreg) {
2941         x86_push_reg (s->code, tree->left->reg2);
2942         x86_push_reg (s->code, tree->left->reg1);
2943         x86_fild_membase (s->code, X86_ESP, 0, TRUE);
2944         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
2945 }
2946
2947 freg: CONST_R4 {
2948         float f = *(float *)tree->data.p;
2949
2950         if (f == 0.0)
2951                 x86_fldz (s->code);
2952         else if (f == 1.0)
2953                 x86_fld1(s->code);
2954         else
2955                 x86_fld (s->code, tree->data.p, FALSE);
2956 }
2957
2958 freg: CONST_R8 {
2959         double d = *(double *)tree->data.p;
2960
2961         if (d == 0.0)
2962                 x86_fldz (s->code);
2963         else if (d == 1.0)
2964                 x86_fld1(s->code);
2965         else
2966                 x86_fld (s->code, tree->data.p, TRUE);
2967 }
2968
2969 freg: LDIND_R4 (reg) {
2970         x86_fld_membase (s->code, tree->left->reg1, 0, FALSE);
2971 }
2972
2973 freg: LDIND_R8 (reg) {
2974         x86_fld_membase (s->code, tree->left->reg1, 0, TRUE);
2975 }
2976
2977 freg: ADD (freg, freg) {
2978         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
2979 }
2980
2981 freg: SUB (freg, freg) {
2982         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE);
2983 }
2984
2985 freg: MUL (freg, freg) {
2986         x86_fp_op_reg (s->code, X86_FMUL, 1, TRUE);
2987 }
2988
2989 freg: DIV (freg, freg) {
2990         x86_fp_op_reg (s->code, X86_FDIV, 1, TRUE);
2991 }
2992
2993 #freg: REM (freg, freg) {
2994 # this does not work, since it does not pop a value from the stack,
2995 # and we need to test if the instruction is ready
2996 #       x86_fprem1 (s->code);
2997 #}
2998
2999 freg: NEG (freg) {
3000         x86_fchs (s->code);
3001 }
3002
3003 stmt: POP (freg)
3004
3005 stmt: STIND_R4 (ADDR_L, freg) {
3006         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).offset;  
3007         x86_fst_membase (s->code, X86_EBP, offset, FALSE, TRUE);
3008 }
3009
3010 stmt: STIND_R4 (reg, freg) {
3011         x86_fst_membase (s->code, tree->left->reg1, 0, FALSE, TRUE);
3012 }
3013
3014 stmt: STIND_R8 (ADDR_L, freg) {
3015         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).offset;  
3016         x86_fst_membase (s->code, X86_EBP, offset, TRUE, TRUE);
3017 }
3018
3019 stmt: STIND_R8 (reg, freg) {
3020         x86_fst_membase (s->code, tree->left->reg1, 0, TRUE, TRUE);
3021 }
3022
3023 stmt: ARG_R4 (freg) {
3024         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
3025         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
3026 }
3027
3028 stmt: ARG_R8 (freg) {
3029         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
3030         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
3031 }
3032
3033 # fixme: we need to implement unordered and ordered compares
3034
3035 stmt: BEQ (freg, freg) {
3036         x86_fcompp (s->code);
3037         x86_fnstsw (s->code);
3038         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3039         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
3040         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3041         x86_branch32 (s->code, X86_CC_EQ, 0, TRUE);
3042 }
3043
3044 stmt: BNE_UN (freg, freg) {
3045         x86_fcompp (s->code);
3046         x86_fnstsw (s->code);
3047         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3048         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
3049         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3050         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3051 }
3052
3053 stmt: BLT (freg, freg) {
3054         x86_fcompp (s->code);
3055         x86_fnstsw (s->code);
3056         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3057         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3058         x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3059 }
3060
3061 stmt: BLT_UN (freg, freg) {
3062         x86_fcompp (s->code);
3063         x86_fnstsw (s->code);
3064         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3065         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3066         x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3067 }
3068
3069 stmt: BGE (freg, freg) {
3070         x86_fcompp (s->code);
3071         x86_fnstsw (s->code);
3072         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3073         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3074         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3075 }
3076
3077 stmt: BGE_UN (freg, freg) {
3078         x86_fcompp (s->code);
3079         x86_fnstsw (s->code);
3080         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3081         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3082         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3083 }
3084
3085 stmt: BGT (freg, freg) {
3086         x86_fcompp (s->code);
3087         x86_fnstsw (s->code);
3088         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3089         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3090         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3091         x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3092 }
3093
3094 stmt: BGT_UN (freg, freg) {
3095         x86_fcompp (s->code);
3096         x86_fnstsw (s->code);
3097         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3098         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3099         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3100         x86_branch32 (s->code, X86_CC_EQ, 0, FALSE);
3101 }
3102
3103 stmt: BLE (freg, freg) {
3104         x86_fcompp (s->code);
3105         x86_fnstsw (s->code);
3106         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3107         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3108         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3109         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3110 }
3111
3112 stmt: BLE_UN (freg, freg) {
3113         x86_fcompp (s->code);
3114         x86_fnstsw (s->code);
3115         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
3116         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
3117         mono_add_jump_info (s, s->code + 2, MONO_JUMP_INFO_BB, tree->data.bb);
3118         x86_branch32 (s->code, X86_CC_NE, 0, FALSE);
3119 }
3120
3121 freg: CALL_R8 (this, ADDR_G) {
3122         MethodCallInfo *ci = tree->data.ci;
3123         int lreg = tree->left->reg1;
3124         int treg = X86_EAX;
3125
3126         if (lreg == treg) 
3127                 treg = X86_EDX;
3128         
3129         if (tree->left->op != MB_TERM_NOP) {
3130                 mono_assert (lreg >= 0);
3131                 x86_push_reg (s->code, lreg);
3132         }
3133
3134         if (ci->vtype_num) {
3135                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
3136                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3137                 x86_push_reg (s->code, treg);
3138         }
3139
3140         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, tree->right->data.p);
3141         x86_call_code (s->code, 0);
3142
3143         if (ci->args_size)
3144                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
3145 }
3146
3147 freg: CALL_R8 (this, INTF_ADDR) {
3148         MethodCallInfo *ci = tree->data.ci;
3149         int lreg = tree->left->reg1;
3150         int treg = X86_EAX;
3151
3152         if (lreg == treg) 
3153                 treg = X86_EDX;
3154
3155         if (tree->left->op != MB_TERM_NOP) {
3156                 mono_assert (lreg >= 0);
3157                 x86_push_reg (s->code, lreg);
3158         }
3159
3160         if (ci->vtype_num) {
3161                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
3162                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3163                 x86_push_reg (s->code, treg);
3164         }
3165
3166         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3167         x86_mov_reg_membase (s->code, lreg, lreg, 
3168                 G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
3169         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
3170         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
3171
3172         if (ci->args_size)
3173                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
3174 }
3175
3176 freg: CALL_R8 (this, VFUNC_ADDR) {
3177         MethodCallInfo *ci = tree->data.ci;
3178         int lreg = tree->left->reg1;
3179         int treg = X86_EAX;
3180
3181         if (lreg == treg) 
3182                 treg = X86_EDX;
3183
3184         if (tree->left->op != MB_TERM_NOP) {
3185                 mono_assert (lreg >= 0);
3186                 x86_push_reg (s->code, lreg);
3187         }
3188
3189         if (ci->vtype_num) {
3190                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
3191                 x86_lea_membase (s->code, treg, X86_EBP, offset);
3192                 x86_push_reg (s->code, treg);
3193         }
3194
3195         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
3196         x86_call_virtual (s->code, lreg, 
3197                 G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
3198
3199         if (ci->args_size)
3200                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
3201 }
3202
3203 stmt: RET (freg) {
3204         if (!tree->last_instr) {
3205                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_EPILOG, NULL);
3206                 x86_jump32 (s->code, 0);      
3207         }
3208 }
3209
3210 # support for value types
3211
3212 reg: LDIND_OBJ (reg) {
3213         if (tree->left->reg1 != tree->reg1)
3214                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
3215 }
3216
3217 stmt: STIND_OBJ (reg, reg) {
3218         x86_push_reg (s->code, X86_EAX);
3219         x86_push_reg (s->code, X86_EDX);
3220         x86_push_reg (s->code, X86_ECX);
3221
3222         mono_assert (tree->data.i > 0);
3223         x86_push_imm (s->code, tree->data.i);
3224         x86_push_reg (s->code, tree->right->reg1);
3225         x86_push_reg (s->code, tree->left->reg1);
3226         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, MEMCOPY);
3227         x86_call_code (s->code, 0);
3228         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
3229
3230         x86_pop_reg (s->code, X86_ECX);
3231         x86_pop_reg (s->code, X86_EDX);
3232         x86_pop_reg (s->code, X86_EAX);
3233 }
3234
3235 stmt: ARG_OBJ (CONST_I4) {
3236         x86_push_imm (s->code, tree->left->data.i);     
3237 }
3238
3239 stmt: ARG_OBJ (reg) {
3240         int size = tree->data.i;
3241         int sa;
3242         
3243         mono_assert (size > 0);
3244
3245         sa = size + 3;
3246         sa &= ~3;
3247
3248         /* reserve space for the argument */
3249         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
3250
3251         x86_push_reg (s->code, X86_EAX);
3252         x86_push_reg (s->code, X86_EDX);
3253         x86_push_reg (s->code, X86_ECX);
3254
3255         x86_push_imm (s->code, size);
3256         x86_push_reg (s->code, tree->left->reg1);
3257         x86_lea_membase (s->code, X86_EAX, X86_ESP, 5*4);
3258         x86_push_reg (s->code, X86_EAX);
3259
3260         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, MEMCOPY);
3261         x86_call_code (s->code, 0);
3262         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
3263
3264         x86_pop_reg (s->code, X86_ECX);
3265         x86_pop_reg (s->code, X86_EDX);
3266         x86_pop_reg (s->code, X86_EAX);
3267 }
3268
3269 stmt: RET_OBJ (reg) {
3270         int size = tree->data.i;
3271
3272         x86_push_imm (s->code, size);
3273         x86_push_reg (s->code, tree->left->reg1);
3274         x86_push_membase (s->code, X86_EBP, 8);
3275
3276
3277         mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_ABS, MEMCOPY);
3278         x86_call_code (s->code, 0);
3279
3280         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
3281
3282         if (!tree->last_instr) {
3283                 mono_add_jump_info (s, s->code + 1, MONO_JUMP_INFO_EPILOG, NULL);
3284                 x86_jump32 (s->code, 0);      
3285         }
3286 }
3287
3288 %% 
3289
3290 #include "jit.h"
3291
3292 gint64 
3293 mono_llmult (gint64 a, gint64 b)
3294 {
3295         return a * b;
3296 }
3297
3298 guint64  
3299 mono_llmult_ovf_un (gpointer *exc, guint32 al, guint32 ah, guint32 bl, guint32 bh)
3300 {
3301         guint64 res, t1;
3302
3303         // fixme: this is incredible slow
3304
3305         if (ah && bh)
3306                 goto raise_exception;
3307
3308         res = (guint64)al * (guint64)bl;
3309
3310         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
3311
3312         if (t1 > 0xffffffff)
3313                 goto raise_exception;
3314
3315         res += ((guint64)t1) << 32; 
3316
3317         *exc = NULL;
3318         return res;
3319
3320  raise_exception:
3321         *exc = mono_get_exception_overflow ();
3322         return 0;
3323 }
3324
3325 guint64  
3326 mono_llmult_ovf (gpointer *exc, guint32 al, gint32 ah, guint32 bl, gint32 bh)
3327 {
3328         gint64 res, t1;
3329
3330         // fixme: check for overflow
3331
3332         res = (gint64)al * (gint64)bl;
3333
3334         t1 = (gint64)ah * bl + al * (gint64)bh;
3335
3336         res += ((gint64)t1) << 32; 
3337
3338         *exc = NULL;
3339         return res;
3340
3341  raise_exception:
3342         *exc = mono_get_exception_overflow ();
3343         return 0;
3344 }
3345
3346 gint64 
3347 mono_lldiv (gint64 a, gint64 b)
3348 {
3349         return a / b;
3350 }
3351
3352 gint64 
3353 mono_llrem (gint64 a, gint64 b)
3354 {
3355         return a % b;
3356 }
3357
3358 guint64 
3359 mono_lldiv_un (guint64 a, guint64 b)
3360 {
3361         return a / b;
3362 }
3363
3364 guint64 
3365 mono_llrem_un (guint64 a, guint64 b)
3366 {
3367         return a % b;
3368 }
3369
3370 MBTree *
3371 mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
3372 {
3373         MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
3374
3375         t->op = op;
3376         t->left = left;
3377         t->right = right;
3378         t->reg1 = -1;
3379         t->reg2 = -1;
3380         t->reg3 = -1;
3381         t->svt = VAL_UNKNOWN;
3382         t->cli_addr = -1;
3383         return t;
3384 }
3385
3386 MBTree *
3387 mono_ctree_new_leaf (MonoMemPool *mp, int op)
3388 {
3389         return mono_ctree_new (mp, op, NULL, NULL);
3390 }
3391
3392 gpointer 
3393 arch_get_lmf_addr (void)
3394 {
3395         gpointer *lmf;
3396
3397         if ((lmf = TlsGetValue (lmf_thread_id)))
3398                 return lmf;
3399
3400         lmf = g_malloc (sizeof (gpointer));
3401         *lmf = NULL;
3402
3403         TlsSetValue (lmf_thread_id, lmf);
3404
3405         return lmf;
3406 }
3407
3408 MonoArray*
3409 mono_array_new_wrapper  (MonoClass *eclass, guint32 n)
3410 {
3411         MonoDomain *domain = mono_domain_get ();
3412
3413         return mono_array_new (domain, eclass, n);
3414 }
3415
3416 MonoObject *
3417 mono_object_new_wrapper (MonoClass *klass)
3418 {
3419         MonoDomain *domain = mono_domain_get ();
3420
3421         return mono_object_new (domain, klass);
3422 }
3423
3424 MonoString*
3425 mono_string_new_wrapper (const char *text)
3426 {
3427         MonoDomain *domain = mono_domain_get ();
3428
3429         return mono_string_new (domain, text);
3430 }
3431
3432 MonoString*
3433 mono_ldstr_wrapper (MonoImage *image, guint32 index)
3434 {
3435         MonoDomain *domain = mono_domain_get ();
3436
3437         return mono_ldstr (domain, image, index);
3438 }
3439
3440 gpointer 
3441 mono_ldsflda (MonoClass *klass, int offset)
3442 {
3443         MonoDomain *domain = mono_domain_get ();
3444         MonoVTable *vt;
3445         gpointer addr;
3446         
3447         vt = mono_class_vtable (domain, klass);
3448         addr = (char*)(vt->data) + offset;
3449
3450         return addr;
3451 }
3452
3453 #ifdef DEBUG
3454 void *
3455 MEMCOPY (void *dest, const void *src, size_t n)
3456 {
3457         int i, l = n;
3458
3459         printf ("MEMCPY(%p to %p [%d]) ", src, dest, n);
3460
3461         for (i = 0; i < l; i++)
3462                 printf ("%02x ", *((guint8 *)src + i));
3463         printf ("\n");
3464         
3465         return memcpy (dest, src, n);
3466 }
3467 #endif
3468