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