2001-12-03 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mono / jit / x86.brg
1 /*
2  * x86.brg: X86 code generator
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <glib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <sys/syscall.h>
15
16 #include <mono/metadata/blob.h>
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/arch/x86/x86-codegen.h>
22
23 #include "regset.h"
24 #include "mempool.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         MBTree   *left, *right;
50         gpointer  state;
51         gpointer  emit;
52
53         gint32    addr;
54         gint32    cli_addr;
55
56         unsigned      is_jump:1;
57         unsigned      last_instr:1;
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 gint64  mono_lldiv     (gint64 a, gint64 b);
81 gint64  mono_llrem     (gint64 a, gint64 b);
82 guint64 mono_lldiv_un  (guint64 a, guint64 b);
83 guint64 mono_llrem_un  (guint64 a, guint64 b);
84
85 gpointer 
86 get_throw_exception    (void);
87
88 gpointer
89 get_mono_object_isinst (void);
90
91 #define MB_OPT_LEVEL 1
92
93 #if MB_OPT_LEVEL == 0
94 #define MB_USE_OPT1(c) 65535
95 #define MB_USE_OPT2(c) 65535
96 #endif
97 #if MB_OPT_LEVEL == 1
98 #define MB_USE_OPT1(c) c
99 #define MB_USE_OPT2(c) 65535
100 #endif
101 #if MB_OPT_LEVEL >= 2
102 #define MB_USE_OPT1(c) c
103 #define MB_USE_OPT2(c) c
104 #endif
105
106 //#define DEBUG
107
108 #ifdef DEBUG
109 #define MEMCOPY debug_memcpy
110 void *MEMCOPY (void *dest, const void *src, size_t n);
111
112 #define PRINT_REG(text,reg) \
113 g_assert (reg >= 0); \
114 x86_push_reg (s->code, X86_EAX); \
115 x86_push_reg (s->code, X86_EDX); \
116 x86_push_reg (s->code, X86_ECX); \
117 x86_push_reg (s->code, reg); \
118 x86_push_imm (s->code, reg); \
119 x86_push_imm (s->code, text " %d %p\n"); \
120 x86_call_code (s->code, printf); \
121 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
122 x86_pop_reg (s->code, X86_ECX); \
123 x86_pop_reg (s->code, X86_EDX); \
124 x86_pop_reg (s->code, X86_EAX); 
125 #else
126
127 #define MEMCOPY memcpy
128
129 #define PRINT_REG(x,y)
130
131 #endif
132
133 /* The call instruction for virtual functions must have a known
134  * size (used by x86_magic_trampoline)
135  */
136 #define x86_call_virtual(inst,basereg,disp)                    \
137         do {                                                   \
138                 *(inst)++ = (unsigned char)0xff;               \
139                 x86_address_byte ((inst), 2, 2, (basereg));    \
140                 x86_imm_emit32 ((inst), (disp));               \
141         } while (0)
142
143 %%
144
145 #
146 # terminal definitions
147 #
148
149 # constatnts
150 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
151 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8
152 %term LDIND_U4 LDIND_OBJ
153 %term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
154 %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
155 %term BREAK SWITCH BR RET RETV ENDFINALLY
156 %term ADD SUB MUL DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
157 %term BLT BLT_UN BEQ BNE_UN BRTRUE BRFALSE BGE BGE_UN BLE BLE_UN BGT BGT_UN 
158 %term CEQ CLT
159 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U8 CONV_R4 CONV_R8
160 %term CONV_OVF_U4 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U8
161 %term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWOBJ CPOBJ POP INITOBJ VTYPE ISINST CASTCLASS
162 %term EXCEPTION THROW RETHROW HANDLER 
163 %term LDLEN
164
165 #
166 # we start at stmt
167 #
168 %start stmt
169
170 #
171 # tree definitions
172 #
173
174 #
175 # x86 adressing mode
176 #
177
178 acon: CONST_I4 {
179         tree->data.ainfo.offset = tree->data.i;
180         tree->data.ainfo.amode = AMImmediate;
181 }
182
183 acon: ADDR_G {
184         tree->data.ainfo.offset = tree->data.i;
185         tree->data.ainfo.amode = AMImmediate;
186 }
187
188 acon: ADD (ADDR_G, CONST_I4) {
189         tree->data.ainfo.offset = (unsigned)tree->left->data.p + tree->right->data.i;
190         tree->data.ainfo.amode = AMImmediate;
191 }
192
193 base: acon
194
195 base: reg {
196         tree->data.ainfo.offset = 0;
197         tree->data.ainfo.basereg = tree->reg1;
198         tree->data.ainfo.amode = AMBase;
199 }
200
201 base: ADD (reg, acon) {
202         tree->data.ainfo.offset = tree->right->data.i;
203         tree->data.ainfo.basereg = tree->left->reg1;
204         tree->data.ainfo.amode = AMBase;
205 }
206
207 base: ADDR_L {
208         tree->data.ainfo.offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
209         tree->data.ainfo.basereg = X86_EBP;
210         tree->data.ainfo.amode = AMBase;
211 }
212
213 index: reg {
214         tree->data.ainfo.offset = 0;
215         tree->data.ainfo.indexreg = tree->reg1;
216         tree->data.ainfo.shift = 0;
217         tree->data.ainfo.amode = AMIndex;
218 }
219
220 index: SHL (reg, CONST_I4) {
221         tree->data.ainfo.offset = 0;
222         tree->data.ainfo.amode = AMIndex;
223         tree->data.ainfo.indexreg = tree->left->reg1;
224         tree->data.ainfo.shift = tree->right->data.i;
225 } cost {
226         MBCOND (tree->right->data.i == 0 ||
227                 tree->right->data.i == 1 ||
228                 tree->right->data.i == 2 ||
229                 tree->right->data.i == 3);
230
231         return 0;
232 }
233
234 index: MUL (reg, CONST_I4) {
235         static int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
236   
237         tree->data.ainfo.offset = 0;
238         tree->data.ainfo.amode = AMIndex;
239         tree->data.ainfo.indexreg = tree->left->reg1;
240         tree->data.ainfo.shift = fast_log2 [tree->right->data.i];
241 } cost {
242         MBCOND (tree->right->data.i == 1 ||
243                 tree->right->data.i == 2 ||
244                 tree->right->data.i == 4 ||
245                 tree->right->data.i == 8);
246
247         return 0;
248 }
249
250 addr: base
251
252 addr: index
253
254 addr: ADD (index, base) {
255         tree->data.ainfo.offset = tree->right->data.ainfo.offset;
256         tree->data.ainfo.basereg = tree->right->data.ainfo.basereg;
257         tree->data.ainfo.amode = tree->left->data.ainfo.amode | 
258                 tree->right->data.ainfo.amode;
259         tree->data.ainfo.shift = tree->left->data.ainfo.shift;
260         tree->data.ainfo.indexreg = tree->left->data.ainfo.indexreg;
261 }
262
263 # we pass exception in ECX to catch handler
264 reg: EXCEPTION {
265         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
266
267         if (tree->reg1 != X86_ECX)
268                 x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
269         
270         /* store it so that we can RETHROW it later */
271         x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
272 }
273
274 stmt: THROW (reg) {
275         if (tree->left->reg1 != X86_ECX)
276                 x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg1, 4);
277
278         x86_call_code (s->code, get_throw_exception ());
279 }
280
281 stmt: RETHROW {
282         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
283
284         x86_mov_reg_membase (s->code, X86_ECX, X86_EBP, offset, 4);
285
286         x86_call_code (s->code, get_throw_exception ());
287 }
288
289 stmt: HANDLER {
290         gint32 addr = tree->data.bb->addr - tree->addr - 5;
291         tree->is_jump = 1;    
292         x86_call_imm (s->code, addr); 
293 }
294
295 stmt: ENDFINALLY {
296         x86_ret (s->code);
297 }
298
299 stmt: STIND_I4 (addr, reg) {
300         PRINT_REG ("STIND_I4", tree->right->reg1);
301
302         switch (tree->left->data.ainfo.amode) {
303
304         case AMImmediate:
305                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
306                 break;
307                 
308         case AMBase:
309                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
310                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
311                 break;          
312         case AMIndex:
313                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
314                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
315                                       tree->right->reg1, 4);
316                 break;          
317         case AMBaseIndex:
318                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
319                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
320                                       tree->right->reg1, 4);
321                 break;          
322         }
323 }
324
325 stmt: STIND_I1 (addr, reg) {
326         PRINT_REG ("STIND_I1", tree->right->reg1);
327
328         switch (tree->left->data.ainfo.amode) {
329
330         case AMImmediate:
331                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 1);
332                 break;
333                 
334         case AMBase:
335                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
336                                      tree->left->data.ainfo.offset, tree->right->reg1, 1);
337                 break;          
338         case AMIndex:
339                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
340                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
341                                       tree->right->reg1, 1);
342                 break;          
343         case AMBaseIndex:
344                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
345                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
346                                       tree->right->reg1, 1);
347                 break;          
348         }
349 }
350
351 stmt: STIND_I2 (addr, reg) {
352         PRINT_REG ("STIND_I2", tree->right->reg1);
353
354         switch (tree->left->data.ainfo.amode) {
355
356         case AMImmediate:
357                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 2);
358                 break;
359                 
360         case AMBase:
361                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
362                                      tree->left->data.ainfo.offset, tree->right->reg1, 2);
363                 break;          
364         case AMIndex:
365                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
366                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
367                                       tree->right->reg1, 2);
368                 break;          
369         case AMBaseIndex:
370                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
371                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
372                                       tree->right->reg1, 2);
373                 break;          
374         }
375 }
376
377 reg: LDIND_I4 (addr) {
378
379         switch (tree->left->data.ainfo.amode) {
380
381         case AMImmediate:
382                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
383                 break;
384
385         case AMBase:
386                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
387                                      tree->left->data.ainfo.offset, 4);
388                 break;          
389         case AMIndex:
390                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
391                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
392                 break;          
393         case AMBaseIndex:
394                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
395                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
396                                       tree->left->data.ainfo.shift, 4);
397                 break;          
398         }
399
400         
401         PRINT_REG ("LDIND_I4", tree->reg1);
402 }
403
404 reg: LDIND_I1 (addr) {
405         switch (tree->left->data.ainfo.amode) {
406
407         case AMImmediate:
408                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, FALSE);
409                 break;
410
411         case AMBase:
412                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
413                                    tree->left->data.ainfo.offset, TRUE, FALSE);
414                 break;          
415         case AMIndex:
416                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
417                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, FALSE);
418                 break;          
419         case AMBaseIndex:
420                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
421                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
422                                     tree->left->data.ainfo.shift, TRUE, FALSE);
423                 break;          
424         }
425
426         PRINT_REG ("LDIND_I1", tree->reg1);
427 }
428
429 reg: LDIND_U1 (addr) {
430         switch (tree->left->data.ainfo.amode) {
431
432         case AMImmediate:
433                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, FALSE);
434                 break;
435
436         case AMBase:
437                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
438                                    tree->left->data.ainfo.offset, FALSE, FALSE);
439                 break;          
440         case AMIndex:
441                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
442                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, FALSE);
443                 break;          
444         case AMBaseIndex:
445                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
446                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
447                                     tree->left->data.ainfo.shift, FALSE, FALSE);
448                 break;          
449         }
450
451         PRINT_REG ("LDIND_U1", tree->reg1);
452 }
453
454 reg: LDIND_I2 (addr) {
455         switch (tree->left->data.ainfo.amode) {
456
457         case AMImmediate:
458                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, TRUE, TRUE);
459                 break;
460
461         case AMBase:
462                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
463                                    tree->left->data.ainfo.offset, TRUE, TRUE);
464                 break;          
465         case AMIndex:
466                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
467                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, TRUE, TRUE);
468                 break;          
469         case AMBaseIndex:
470                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
471                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
472                                     tree->left->data.ainfo.shift, TRUE, TRUE);
473                 break;          
474         }
475
476         PRINT_REG ("LDIND_U2", tree->reg1);
477 }
478
479 reg: LDIND_U2 (addr) {
480         switch (tree->left->data.ainfo.amode) {
481
482         case AMImmediate:
483                 x86_widen_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, FALSE, TRUE);
484                 break;
485
486         case AMBase:
487                 x86_widen_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
488                                    tree->left->data.ainfo.offset, FALSE, TRUE);
489                 break;          
490         case AMIndex:
491                 x86_widen_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
492                                     tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, FALSE, TRUE);
493                 break;          
494         case AMBaseIndex:
495                 x86_widen_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
496                                     tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
497                                     tree->left->data.ainfo.shift, FALSE, TRUE);
498                 break;          
499         }
500
501         PRINT_REG ("LDIND_U2", tree->reg1);
502 }
503
504 reg: LDIND_U4 (addr) {
505         switch (tree->left->data.ainfo.amode) {
506
507         case AMImmediate:
508                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
509                 break;
510
511         case AMBase:
512                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
513                                      tree->left->data.ainfo.offset, 4);
514                 break;          
515         case AMIndex:
516                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
517                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
518                 break;          
519         case AMBaseIndex:
520                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
521                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
522                                       tree->left->data.ainfo.shift, 4);
523                 break;          
524         }
525
526         PRINT_REG ("LDIND_U4", tree->reg1);
527 }
528
529 locaddr: ADDR_L 10 {
530         tree->data.i = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
531 }
532
533 reg: ADDR_L 5 {
534         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;  
535         x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
536 }
537
538
539 reg: ADDR_G 5 {
540         x86_mov_reg_imm (s->code, tree->reg1, tree->data.p);
541 }
542
543 reg: CONV_I1 (reg) {
544         if (tree->reg1 != tree->left->reg1)
545                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
546         x86_alu_reg_imm (s->code, X86_AND, tree->reg1, 0xff);
547 }
548
549 reg: CONV_I2 (reg) {
550         if (tree->reg1 != tree->left->reg1)
551                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
552         x86_alu_reg_imm (s->code, X86_AND, tree->reg1, 0xffff);
553 }
554
555 reg: CONST_I4 1 {
556         x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
557 }
558
559 reg: CONV_I4 (reg) {
560         if (tree->reg1 != tree->left->reg1)
561                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
562         PRINT_REG ("CONV_I4", tree->left->reg1);
563
564
565 reg: CONV_OVF_U4 (reg) {
566         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
567         x86_branch8 (s->code, X86_CC_EQ, 10, TRUE);
568         x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
569         x86_call_code (s->code, get_throw_exception ());
570         if (tree->reg1 != tree->left->reg1)
571                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
572 }
573
574 reg: CONV_OVF_I2 (reg) {
575         /* Probe value to be within -32768 and 32767 */
576
577         x86_alu_reg_imm (s->code, X86_CMP, tree->reg1, 32767);
578         x86_branch8 (s->code, X86_CC_LE, 10, TRUE);
579         x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
580         x86_call_code (s->code, get_throw_exception ());
581
582         x86_alu_reg_imm (s->code, X86_CMP, tree->reg1, -32768);
583         x86_branch8 (s->code, X86_CC_LT, -17, TRUE);
584         if (tree->reg1 != tree->left->reg1)
585                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
586 }
587
588 reg: CONV_OVF_U2 (reg) {
589         /* Probe value to be within 0 and 65535 */
590         x86_test_reg_imm (s->code, tree->left->reg1, 0xffff0000);
591         x86_branch8 (s->code, X86_CC_EQ, 10, TRUE);
592         x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
593         x86_call_code (s->code, get_throw_exception ());
594         if (tree->reg1 != tree->left->reg1)
595                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);     
596 }
597
598 reg: MUL (reg, reg) {
599         if (tree->reg1 != tree->left->reg1)
600                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
601         x86_imul_reg_reg (s->code, tree->reg1, tree->right->reg1);
602 }
603
604 reg: DIV (reg, reg) {
605         if (tree->left->reg1 != X86_EAX)
606                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
607
608         x86_cdq (s->code);
609         x86_div_reg (s->code, tree->right->reg1, TRUE);
610
611         g_assert (tree->reg1 == X86_EAX &&
612                   tree->reg2 == X86_EDX);
613 }
614
615 reg: DIV_UN (reg, reg) {
616         if (tree->left->reg1 != X86_EAX)
617                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
618
619         x86_cdq (s->code);
620         x86_div_reg (s->code, tree->right->reg1, FALSE);
621
622         g_assert (tree->reg1 == X86_EAX &&
623                   tree->reg2 == X86_EDX);
624 }
625
626 reg: REM (reg, reg) {
627         if (tree->left->reg1 != X86_EAX)
628                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
629
630         x86_cdq (s->code);
631         x86_div_reg (s->code, tree->right->reg1, TRUE);
632         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
633
634         g_assert (tree->reg1 == X86_EAX &&
635                   tree->reg2 == X86_EDX);
636 }
637
638 reg: REM_UN (reg, reg) {
639         if (tree->left->reg1 != X86_EAX)
640                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
641
642         x86_cdq (s->code);
643         x86_div_reg (s->code, tree->right->reg1, FALSE);
644         x86_mov_reg_reg (s->code, X86_EAX, X86_EDX, 4);
645
646         g_assert (tree->reg1 == X86_EAX &&
647                   tree->reg2 == X86_EDX);
648 }
649
650 reg: ADD (reg, CONST_I4) "MB_USE_OPT1(0)" {
651         if (tree->reg1 != tree->left->reg1)
652                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
653         x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, tree->right->data.i);
654 }
655
656 reg: ADD (reg, reg) {
657         if (tree->reg1 != tree->left->reg1)
658                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
659         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
660 }
661
662 reg: SUB (reg, CONST_I4) "MB_USE_OPT1(0)" {
663         if (tree->reg1 != tree->left->reg1)
664                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
665         x86_alu_reg_imm (s->code, X86_SUB, tree->reg1, tree->right->data.i);
666 }
667
668 reg: SUB (reg, reg) {
669         if (tree->reg1 != tree->left->reg1)
670                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
671         x86_alu_reg_reg (s->code, X86_SUB, tree->reg1, tree->right->reg1);
672 }
673
674 reg: CEQ (reg, reg) {
675         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
676         x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
677         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
678 }
679
680 reg: CLT (reg, reg) {
681         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
682         x86_set_reg (s->code, X86_CC_LT, tree->reg1, TRUE);
683         x86_widen_reg (s->code, tree->reg1, tree->reg1, FALSE, FALSE);
684 }
685
686 reg: AND (reg, reg) {
687         if (tree->reg1 != tree->left->reg1)
688                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
689         x86_alu_reg_reg (s->code, X86_AND, tree->reg1, tree->right->reg1);
690 }
691
692 reg: OR (reg, reg) {
693         if (tree->reg1 != tree->left->reg1)
694                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
695         x86_alu_reg_reg (s->code, X86_OR, tree->reg1, tree->right->reg1);
696 }
697
698 reg: XOR (reg, reg) {
699         if (tree->reg1 != tree->left->reg1)
700                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
701         x86_alu_reg_reg (s->code, X86_XOR, tree->reg1, tree->right->reg1);
702 }
703
704 reg: NEG (reg) {
705         if (tree->reg1 != tree->left->reg1)
706                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
707          x86_neg_reg (s->code, tree->reg1);
708 }
709
710 reg: NOT (reg) {
711         if (tree->reg1 != tree->left->reg1)
712                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
713          x86_not_reg (s->code, tree->reg1);
714 }
715
716 reg: SHL (reg, CONST_I4) {
717         if (tree->reg1 != tree->left->reg1)
718                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
719         x86_shift_reg_imm (s->code, X86_SHL, tree->reg1, tree->right->data.i);
720 }
721
722 reg: SHL (reg, reg) {
723         if (tree->reg1 != tree->left->reg1)
724                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
725         if (tree->right->reg1 != X86_ECX)
726                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
727         x86_shift_reg (s->code, X86_SHL, tree->reg1);
728
729         g_assert (tree->reg1 != X86_ECX &&
730                   tree->left->reg1 != X86_ECX);
731 }
732
733 reg: SHR (reg, CONST_I4) {
734         if (tree->reg1 != tree->left->reg1)
735                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
736         x86_shift_reg_imm (s->code, X86_SAR, tree->reg1, tree->right->data.i);
737 }
738
739 reg: SHR (reg, reg) {
740         if (tree->reg1 != tree->left->reg1)
741                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
742         if (tree->right->reg1 != X86_ECX)
743                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
744         x86_shift_reg (s->code, X86_SAR, tree->reg1);
745
746         g_assert (tree->reg1 != X86_ECX &&
747                   tree->left->reg1 != X86_ECX);
748 }
749
750 reg: SHR_UN (reg, CONST_I4) {
751         if (tree->reg1 != tree->left->reg1)
752                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
753         x86_shift_reg_imm (s->code, X86_SHR, tree->reg1, tree->right->data.i);
754 }
755
756 reg: SHR_UN (reg, reg) {
757         if (tree->reg1 != tree->left->reg1)
758                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
759         if (tree->right->reg1 != X86_ECX)
760                 x86_mov_reg_reg (s->code, X86_ECX, tree->right->reg1, 4);
761         x86_shift_reg (s->code, X86_SHR, tree->reg1);
762
763         g_assert (tree->reg1 != X86_ECX &&
764                   tree->left->reg1 != X86_ECX);
765 }
766
767 # array support
768 reg: LDLEN (reg) {
769         x86_mov_reg_membase (s->code, tree->reg1, tree->left->reg1,  
770                              G_STRUCT_OFFSET (MonoArray, bounds), 4);
771         x86_mov_reg_membase (s->code, tree->reg1, tree->reg1,  
772                              G_STRUCT_OFFSET (MonoArrayBounds, length), 4);
773 }
774
775 #reg: LDELEMA (reg, reg) {
776 #       x86_imul_reg_reg_imm (s->code, tree->right->reg1, tree->right->reg1, tree->data.i);
777 #       x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
778 #       x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, G_STRUCT_OFFSET (MonoArray, vector));
779 #}
780
781 reg: NEWARR (reg) {
782         if (tree->reg1 != X86_EAX)
783                 x86_push_reg (s->code, X86_EAX);
784         x86_push_reg (s->code, X86_ECX);
785         x86_push_reg (s->code, X86_EDX);
786
787         x86_push_reg (s->code, tree->left->reg1);
788         x86_push_imm (s->code, tree->data.p);
789         x86_call_code (s->code, mono_array_new);
790         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
791
792         x86_pop_reg (s->code, X86_EDX);
793         x86_pop_reg (s->code, X86_ECX);
794         if (tree->reg1 != X86_EAX) {
795                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
796                 x86_pop_reg (s->code, X86_EAX);
797         }
798 }
799
800 reg: NEWOBJ {
801         if (tree->reg1 != X86_EAX)
802                 x86_push_reg (s->code, X86_EAX);
803         x86_push_reg (s->code, X86_ECX);
804         x86_push_reg (s->code, X86_EDX);
805
806         x86_push_imm (s->code, tree->data.p);
807         x86_call_code (s->code, mono_object_new);
808         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
809
810         x86_pop_reg (s->code, X86_EDX);
811         x86_pop_reg (s->code, X86_ECX);
812         if (tree->reg1 != X86_EAX) {
813                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
814                 x86_pop_reg (s->code, X86_EAX);
815         }
816 }
817
818 reg: CASTCLASS (reg) {
819         guint8 *start = s->code, *l1, *l2, *l3, *l4, *le;
820         int i;
821
822         tree->is_jump = TRUE;
823         l1 = l2 = l3 = l4 = le = NULL;
824
825         for (i = 0; i < 2; i++) {
826                 s->code = start;
827
828                 if (tree->reg1 != X86_EAX)
829                         x86_push_reg (s->code, X86_EAX);
830
831                 x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
832                 x86_branch8 (s->code, X86_CC_EQ, le - l2, FALSE);
833                 l2 = s->code;
834                 x86_push_reg (s->code, X86_ECX);
835                 x86_push_reg (s->code, X86_EDX);
836
837                 x86_push_imm (s->code, tree->data.klass);
838                 x86_push_reg (s->code, tree->left->reg1);
839                 x86_call_code (s->code, mono_object_isinst);
840                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
841                 x86_pop_reg (s->code, X86_EDX);
842                 x86_pop_reg (s->code, X86_ECX);
843
844                 x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0);
845                 x86_branch8 (s->code, X86_CC_NE, le - l3, FALSE);
846                 l3 = s->code;
847
848                 x86_mov_reg_imm (s->code, X86_ECX, get_exception_invalid_cast ());
849                 x86_call_code (s->code, get_throw_exception ());
850
851                 le = s->code;
852
853         }
854 }
855
856 reg: ISINST (reg) {
857         if (tree->reg1 != X86_EAX)
858                 x86_push_reg (s->code, X86_EAX);
859         x86_push_reg (s->code, X86_ECX);
860         x86_push_reg (s->code, X86_EDX);
861
862         x86_push_imm (s->code, tree->data.klass);
863         x86_push_reg (s->code, tree->left->reg1);
864         x86_call_code (s->code, mono_object_isinst);
865         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
866
867         x86_pop_reg (s->code, X86_EDX);
868         x86_pop_reg (s->code, X86_ECX);
869         if (tree->reg1 != X86_EAX) {
870                 x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
871                 x86_pop_reg (s->code, X86_EAX);
872         }
873
874 }
875
876 #reg: ISINST (reg) {
877 #       guint8 *start = s->code, *l1, *l2, *l3, *l4, *le;
878 #       MonoClass *k = tree->data.klass;
879 #       int treg = tree->reg1;
880 #       gint32 i;
881 #
882 #       tree->is_jump = TRUE;
883 #       l1 = l2 = l3 = l4 = le = NULL;
884 #
885 #       for (i = 0; i < 2; i++) {
886 #               s->code = start;
887 #
888 #               x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
889 #               x86_branch8 (s->code, X86_CC_EQ, le - l1, FALSE);
890 #               l1 = s->code;
891 #       
892 #               x86_push_reg (s->code, tree->left->reg1);
893 #
894 #               if (k->flags & TYPE_ATTRIBUTE_INTERFACE) {
895 #                       x86_mov_reg_membase (s->code, treg, treg, 0, 4); // treg = o->klass
896 #                       x86_mov_reg_membase (s->code, treg, treg, G_STRUCT_OFFSET (MonoClass, max_interface_id), 4);
897 #                       x86_alu_reg_imm (s->code, X86_CMP, treg, k->interface_id);
898 #                       x86_branch8 (s->code, X86_CC_GE, l3 - l2, FALSE);
899 #                       l2 = s->code;
900 #                       x86_pop_reg (s->code, treg);
901 #                       x86_alu_reg_reg (s->code, X86_XOR, treg, treg);
902 #                       x86_jump8 (s->code, le - l3);
903 #                       l3 = s->code;
904 #                       x86_mov_reg_membase (s->code, treg, X86_ESP, 0, 4); // treg = o
905 #                       x86_mov_reg_membase (s->code, treg, treg, 0, 4); // treg = o->klass
906 #                       x86_mov_reg_membase (s->code, treg, treg, G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
907 #                       x86_mov_reg_membase (s->code, treg, treg, (k->interface_id << 2), 4);
908 #                       x86_alu_reg_imm (s->code, X86_CMP, treg, 0);
909 #                       x86_pop_reg (s->code, treg);
910 #                       x86_branch8 (s->code, X86_CC_NE, le - l4, FALSE);
911 #                       l4 = s->code;
912 #                       x86_alu_reg_reg (s->code, X86_XOR, treg, treg);
913 #               } else {
914 #                       x86_mov_reg_membase (s->code, treg, treg, 0, 4); // treg = o->klass
915 #                       x86_mov_reg_membase (s->code, treg, treg, G_STRUCT_OFFSET (MonoClass, baseval), 4);
916 #                       x86_alu_reg_imm (s->code, X86_SUB, treg, k->baseval);
917 #                       x86_alu_reg_imm (s->code, X86_CMP, treg, k->diffval);
918 #                       x86_pop_reg (s->code, treg);
919 #                       x86_branch8 (s->code, X86_CC_LE, le - l2, FALSE);
920 #                       l2 = s->code;
921 #                       x86_alu_reg_reg (s->code, X86_XOR, treg, treg);
922 #               }
923 #               
924 #               le = s->code;
925 #               //x86_breakpoint (s->code);
926 #       }
927 #}
928
929 stmt: INITOBJ (reg) {
930         int i, j;
931
932         i = tree->data.i;
933
934         if (i == 1 || i == 2 || i == 4) {
935                 int t = X86_ECX;
936
937                 if (tree->left->reg1 != X86_EAX) 
938                         t = X86_EAX;
939
940                 x86_push_reg (s->code, t);
941                 x86_alu_reg_reg (s->code, X86_XOR, t, t);
942
943                 switch (tree->data.i) {
944                 case 4:
945                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
946                         break;
947                 case 2:
948                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
949                         break;
950                 case 1:
951                         x86_mov_regp_reg (s->code, tree->left->reg1, t, 4);
952                         break;
953                 }
954                 x86_pop_reg (s->code, t);
955
956                 return;
957         }
958
959         i = tree->data.i / 4;
960         j = tree->data.i % 4;
961
962         x86_push_reg (s->code, X86_EAX);
963         
964         if (tree->left->reg1 != X86_EDI) {
965                 x86_push_reg (s->code, X86_EDI);
966                 x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
967         }
968
969         if (i) {
970                 x86_push_reg (s->code, X86_ECX);
971                 x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
972                 x86_mov_reg_imm (s->code, X86_ECX, i);
973                 x86_cld (s->code);
974                 x86_prefix (s->code, X86_REP_PREFIX);
975                 x86_stosl (s->code);
976                 x86_pop_reg (s->code, X86_ECX);
977         }
978
979
980         for (i = 0; i < j; i++)
981                 x86_stosb (s->code);
982
983         if (tree->left->reg1 != X86_EDI)
984                 x86_pop_reg (s->code, X86_EDI);
985         
986         x86_pop_reg (s->code, X86_EAX);
987 }
988
989 stmt: NOP
990
991 stmt: POP (reg)
992
993 stmt: STIND_I4 (reg, CONST_I4) "MB_USE_OPT1(0)" {
994         x86_mov_membase_imm (s->code, tree->left->reg1, 0,
995                              tree->right->data.i, 4);
996 }
997
998 stmt: STIND_I4 (reg, reg) {
999         x86_mov_membase_reg (s->code, tree->left->reg1, 0,
1000                              tree->right->reg1, 4);
1001 }
1002
1003 stmt: STIND_I4 (locaddr, CONST_I4) "MB_USE_OPT1(0)" {
1004         x86_mov_membase_imm (s->code, X86_EBP, tree->left->data.i,
1005                              tree->right->data.i, 4);
1006 }
1007
1008 stmt: STIND_I1 (locaddr, reg) {
1009         x86_mov_membase_reg (s->code, X86_EBP, tree->left->data.i,
1010                              tree->right->reg1, 1);
1011 }
1012
1013 stmt: STIND_I2 (locaddr, reg) {
1014         x86_mov_membase_reg (s->code, X86_EBP, tree->left->data.i,
1015                              tree->right->reg1, 2);
1016 }
1017
1018 stmt: STIND_I4 (locaddr, reg) {
1019         x86_mov_membase_reg (s->code, X86_EBP, tree->left->data.i,
1020                              tree->right->reg1, 4);
1021 }
1022
1023 stmt: STIND_I4 (ADDR_G, reg) {
1024         x86_mov_mem_reg (s->code, tree->left->data.p,
1025                          tree->right->reg1, 4);
1026 }
1027
1028 stmt: BR {
1029         gint32 addr = tree->data.bb->addr - tree->addr - 5;
1030         tree->is_jump = 1;    
1031         
1032         x86_jump32 (s->code, addr); 
1033 }
1034
1035 stmt: BLT (reg, reg) 1 {
1036         gint32 offset;
1037
1038         tree->is_jump = 1;
1039         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1040         offset = 6 + s->code - s->start;
1041         x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - offset, TRUE); 
1042 }
1043
1044 stmt: BLT (reg, CONST_I4) "MB_USE_OPT1(0)" {
1045         gint32 offset;
1046
1047         tree->is_jump = 1;
1048         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1049         offset = 6 + s->code - s->start;
1050         x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - offset, TRUE); 
1051 }
1052
1053 stmt: BLT_UN (reg, reg) 1 {
1054         gint32 offset;
1055
1056         tree->is_jump = 1;
1057         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1058         offset = 6 + s->code - s->start;
1059         x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - offset, FALSE); 
1060 }
1061
1062 stmt: BLT_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1063         gint32 offset;
1064
1065         tree->is_jump = 1;
1066         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1067         offset = 6 + s->code - s->start;
1068         x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - offset, FALSE); 
1069 }
1070
1071 stmt: BGT (reg, reg) 1 {
1072         gint32 offset;
1073
1074         tree->is_jump = 1;
1075         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1076         offset = 6 + s->code - s->start;
1077         x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - offset, TRUE); 
1078 }
1079
1080 stmt: BGT (reg, CONST_I4) "MB_USE_OPT1(0)" {
1081         gint32 offset;
1082
1083         tree->is_jump = 1;
1084         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1085         offset = 6 + s->code - s->start;
1086         x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - offset, TRUE); 
1087 }
1088
1089 stmt: BGT_UN (reg, reg) 1 {
1090         gint32 offset;
1091
1092         tree->is_jump = 1;
1093         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1094         offset = 6 + s->code - s->start;
1095         x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - offset, FALSE); 
1096 }
1097
1098 stmt: BGT_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1099         gint32 offset;
1100
1101         tree->is_jump = 1;
1102         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1103         offset = 6 + s->code - s->start;
1104         x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - offset, FALSE); 
1105 }
1106
1107 stmt: BEQ (reg, CONST_I4) "MB_USE_OPT1(0)" {
1108         gint32 offset;
1109
1110         tree->is_jump = 1;
1111         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1112         offset = 6 + s->code - s->start;
1113         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, TRUE);
1114 }
1115
1116 stmt: BEQ (reg, reg) 1 {
1117         gint32 offset;
1118
1119         tree->is_jump = 1;
1120         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1121         offset = 6 + s->code - s->start;
1122         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, TRUE);
1123 }
1124
1125 stmt: BNE_UN (reg, reg) 1 {
1126         gint32 offset;
1127
1128         tree->is_jump = 1;
1129         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1130         offset = 6 + s->code - s->start;
1131         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
1132 }
1133
1134 stmt: BNE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1135         gint32 offset;
1136
1137         tree->is_jump = 1;
1138         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1139         offset = 6 + s->code - s->start;
1140         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
1141 }
1142
1143 stmt: BGE (reg, reg) 1 {
1144         gint32 offset;
1145
1146         tree->is_jump = 1;
1147         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1148         offset = 6 + s->code - s->start;
1149         x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - offset, TRUE);
1150 }
1151
1152 stmt: BGE (reg, CONST_I4) "MB_USE_OPT1(0)" {
1153         gint32 offset;
1154
1155         tree->is_jump = 1;
1156         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1157         offset = 6 + s->code - s->start;
1158         x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - offset, TRUE);
1159 }
1160
1161 stmt: BGE_UN (reg, reg) 1 {
1162         gint32 offset;
1163
1164         tree->is_jump = 1;
1165         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1166         offset = 6 + s->code - s->start;
1167         x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - offset, FALSE);
1168 }
1169
1170 stmt: BGE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1171         gint32 offset;
1172
1173         tree->is_jump = 1;
1174         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1175         offset = 6 + s->code - s->start;
1176         x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - offset, FALSE);
1177 }
1178
1179 stmt: BLE (reg, reg) 1 {
1180         gint32 offset;
1181
1182         tree->is_jump = 1;
1183         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1184         offset = 6 + s->code - s->start;
1185         x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - offset, TRUE);
1186 }
1187
1188 stmt: BLE (reg, CONST_I4) "MB_USE_OPT1(0)" {
1189         gint32 offset;
1190
1191         tree->is_jump = 1;
1192         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1193         offset = 6 + s->code - s->start;
1194         x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - offset, TRUE);
1195 }
1196
1197 stmt: BLE_UN (reg, reg) 1 {
1198         gint32 offset;
1199
1200         tree->is_jump = 1;
1201         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1202         offset = 6 + s->code - s->start;
1203         x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - offset, FALSE);
1204 }
1205
1206 stmt: BLE_UN (reg, CONST_I4) "MB_USE_OPT1(0)" {
1207         gint32 offset;
1208
1209         tree->is_jump = 1;
1210         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
1211         offset = 6 + s->code - s->start;
1212         x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - offset, FALSE);
1213 }
1214
1215 stmt: BRTRUE (reg) {
1216         gint32 offset;
1217
1218         tree->is_jump = 1;
1219         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
1220         offset = 6 + s->code - s->start;
1221         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, TRUE);
1222 }
1223
1224 stmt: BRFALSE (reg) {
1225         gint32 offset;
1226
1227         tree->is_jump = 1;
1228         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
1229         offset = 6 + s->code - s->start;
1230         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, TRUE);
1231 }
1232
1233 stmt: BREAK {
1234         x86_breakpoint (s->code);
1235 }
1236
1237 stmt: RETV (reg) {
1238         if (tree->left->reg1 != X86_EAX)
1239                 x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1240
1241         if (!tree->last_instr) {
1242                 tree->is_jump = 1;
1243                 x86_jump32 (s->code, s->epilog - 5);      
1244         }
1245 }
1246
1247 stmt: RET {
1248         if (!tree->last_instr) {
1249                 tree->is_jump = 1;
1250                 x86_jump32 (s->code, s->epilog - 5);
1251         } 
1252 }
1253
1254 stmt: ARG_I4 (reg) {
1255         x86_push_reg (s->code, tree->left->reg1);
1256 }
1257
1258 # fixme: we must free the allocated strings somewhere
1259 stmt: ARG_STRING (reg) {
1260         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
1261         x86_push_reg (s->code, X86_EAX);
1262         x86_push_reg (s->code, X86_ECX);
1263         x86_push_reg (s->code, X86_EDX);
1264
1265         x86_push_reg (s->code, tree->left->reg1);
1266         x86_call_code (s->code, mono_string_to_utf8);
1267         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
1268         
1269         x86_mov_membase_reg (s->code, X86_ESP, 12, X86_EAX, 4);
1270
1271         x86_pop_reg (s->code, X86_EDX);
1272         x86_pop_reg (s->code, X86_ECX);
1273         x86_pop_reg (s->code, X86_EAX);
1274 }
1275
1276 stmt: ARG_I4 (ADDR_G) {
1277         x86_push_imm (s->code, tree->left->data.p);
1278 }
1279
1280 stmt: ARG_I4 (CONST_I4) "MB_USE_OPT1(0)" {
1281         x86_push_imm (s->code, tree->left->data.i);
1282 }
1283
1284 this: reg
1285
1286 this: NOP
1287
1288 reg: CALL_I4 (this, reg) {
1289         MethodCallInfo *ci = tree->data.ci;
1290         int treg = X86_EAX;
1291         int lreg = tree->left->reg1;
1292         int rreg = tree->right->reg1;
1293         
1294         if (lreg == treg || rreg == treg) 
1295                 treg = X86_EDX;
1296         if (lreg == treg || rreg == treg) 
1297                 treg = X86_ECX;
1298         if (lreg == treg || rreg == treg) 
1299                 g_assert_not_reached ();
1300
1301         if (ci->vtype_num) {
1302                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1303                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1304                 x86_push_reg (s->code, treg);
1305         }
1306
1307         if (tree->left->op != MB_TERM_NOP) {
1308                 g_assert (lreg >= 0);
1309                 x86_push_reg (s->code, lreg);
1310         }
1311
1312         x86_call_reg (s->code, rreg);
1313
1314         if (ci->args_size)
1315                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1316         
1317         PRINT_REG ("CALL_I4", tree->reg1);
1318
1319         g_assert (tree->reg1 == X86_EAX);
1320 }
1321
1322 reg: CALL_I4 (this, LDIND_I4 (ADDR_G)) {
1323         MethodCallInfo *ci = tree->data.ci;
1324         int lreg = tree->left->reg1;
1325         int treg = X86_EAX;
1326
1327         if (lreg == treg) 
1328                 treg = X86_EDX;
1329         
1330         if (ci->vtype_num) {
1331                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1332                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1333                 x86_push_reg (s->code, treg);
1334         }
1335
1336         if (tree->left->op != MB_TERM_NOP) {
1337                 g_assert (lreg >= 0);
1338                 x86_push_reg (s->code, lreg);
1339         }
1340
1341         x86_call_mem (s->code, tree->right->left->data.p);
1342
1343         if (ci->args_size)
1344                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1345
1346         PRINT_REG ("CALL_I4", tree->reg1);
1347
1348         g_assert (tree->reg1 == X86_EAX);
1349 }
1350
1351 reg: CALL_I4 (this, INTF_ADDR) {
1352         MethodCallInfo *ci = tree->data.ci;
1353         int lreg = tree->left->reg1;
1354         int treg = X86_EAX;
1355
1356         if (lreg == treg) 
1357                 treg = X86_EDX;
1358
1359         if (ci->vtype_num) {
1360                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1361                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1362                 x86_push_reg (s->code, treg);
1363         }
1364
1365         if (tree->left->op != MB_TERM_NOP) {
1366                 g_assert (lreg >= 0);
1367                 x86_push_reg (s->code, lreg);
1368         }
1369
1370         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1371         x86_mov_reg_membase (s->code, lreg, lreg, 
1372                 G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
1373         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
1374         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
1375
1376         if (ci->args_size)
1377                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1378
1379         PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
1380
1381         g_assert (tree->reg1 == X86_EAX);
1382 }
1383
1384 reg: CALL_I4 (this, VFUNC_ADDR) {
1385         MethodCallInfo *ci = tree->data.ci;
1386         int lreg = tree->left->reg1;
1387         int treg = X86_EAX;
1388
1389         if (lreg == treg) 
1390                 treg = X86_EDX;
1391
1392         if (ci->vtype_num) {
1393                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1394                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1395                 x86_push_reg (s->code, treg);
1396         }
1397
1398         if (tree->left->op != MB_TERM_NOP) {
1399                 g_assert (lreg >= 0);
1400                 x86_push_reg (s->code, lreg);
1401         }
1402
1403         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1404         x86_call_virtual (s->code, lreg, 
1405                 G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
1406
1407         if (ci->args_size)
1408                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1409
1410         PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
1411
1412         g_assert (tree->reg1 == X86_EAX);
1413 }
1414
1415 stmt: CALL_VOID (this, LDIND_I4 (ADDR_G)) {
1416         MethodCallInfo *ci = tree->data.ci;
1417         int lreg = tree->left->reg1;
1418         int treg = X86_EAX;
1419
1420         if (lreg == treg) 
1421                 treg = X86_EDX;
1422         
1423         if (ci->vtype_num) {
1424                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1425                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1426                 x86_push_reg (s->code, treg);
1427         }
1428
1429         if (tree->left->op != MB_TERM_NOP) {
1430                 g_assert (lreg >= 0);
1431                 x86_push_reg (s->code, lreg);
1432         }
1433
1434         x86_call_mem (s->code, tree->right->left->data.p);
1435
1436         if (ci->args_size)
1437                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1438 }
1439
1440 stmt: CALL_VOID (this, INTF_ADDR) {
1441         MethodCallInfo *ci = tree->data.ci;
1442         int lreg = tree->left->reg1;
1443         int treg = X86_EAX;
1444
1445         if (lreg == treg) 
1446                 treg = X86_EDX;
1447
1448         if (ci->vtype_num) {
1449                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1450                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1451                 x86_push_reg (s->code, treg);
1452         }
1453
1454         if (tree->left->op != MB_TERM_NOP) {
1455                 g_assert (lreg >= 0);
1456                 x86_push_reg (s->code, lreg);
1457         }
1458
1459         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1460         x86_mov_reg_membase (s->code, lreg, lreg, 
1461                 G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
1462         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
1463         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
1464
1465         if (ci->args_size)
1466                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1467 }
1468
1469 stmt: CALL_VOID (this, VFUNC_ADDR) {
1470         MethodCallInfo *ci = tree->data.ci;
1471         int lreg = tree->left->reg1;
1472         int treg = X86_EAX;
1473
1474         if (lreg == treg) 
1475                 treg = X86_EDX;
1476
1477         if (ci->vtype_num) {
1478                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1479                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1480                 x86_push_reg (s->code, treg);
1481         }
1482
1483         if (tree->left->op != MB_TERM_NOP) {
1484                 g_assert (lreg >= 0);
1485                 x86_push_reg (s->code, lreg);
1486         }
1487
1488         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
1489         x86_call_virtual (s->code, lreg, 
1490                 G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
1491
1492         if (ci->args_size)
1493                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1494 }
1495
1496 stmt: SWITCH (reg) {
1497         guint32 offset;
1498         guint32 *jt = (guint32 *)tree->data.p;
1499
1500         tree->is_jump = 1;
1501
1502         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, jt [0]);
1503         offset = 6 + (guint32)s->code;
1504         x86_branch32 (s->code, X86_CC_GE, jt [jt [0] + 1] - offset, FALSE);
1505
1506         x86_mov_reg_memindex (s->code, X86_EAX, X86_NOBASEREG, 
1507                               tree->data.i + 4, tree->left->reg1, 2, 4);        
1508         x86_jump_reg (s->code, X86_EAX);
1509 }
1510
1511 #
1512 # 64 bit integers
1513 #
1514
1515 reg: CONV_I4 (lreg) {
1516         if (tree->reg1 != tree->left->reg1)
1517                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1518
1519
1520 stmt: POP (lreg)
1521
1522 lreg: CONST_I8 1 {
1523         x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
1524         x86_mov_reg_imm (s->code, tree->reg2, *(gint32 *)(&tree->data.p + 4));
1525 }
1526
1527 lreg: CONV_I8 (CONST_I4) {
1528         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1529
1530         if (tree->left->data.i >= 0)
1531                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1532         else 
1533                 x86_mov_reg_imm (s->code, tree->reg2, -1);              
1534 }
1535
1536 lreg: CONV_I8 (reg) {
1537         guint8 *i1;
1538
1539         if (tree->reg1 != tree->left->reg1)
1540                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1541
1542         x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, 0);
1543         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1544         x86_branch8 (s->code, X86_CC_GE, 5, TRUE);
1545         i1 = s->code;
1546         x86_mov_reg_imm (s->code, tree->reg2, -1); 
1547         g_assert ((s->code - i1) == 5);
1548 }
1549
1550 lreg: CONV_U8 (CONST_I4) 1 {
1551         x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1552         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1553 }
1554
1555 lreg: CONV_OVF_U8 (CONST_I4) {
1556         if (tree->left->data.i < 0){
1557                 x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
1558                 x86_call_code (s->code, get_throw_exception ());
1559         } else {
1560                 x86_mov_reg_imm (s->code, tree->reg1, tree->left->data.i);
1561                 x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1562         }
1563 }
1564
1565 lreg: CONV_OVF_U8 (reg) {
1566         /* 
1567          * Buggy: notice that this assumes reg is an int, maybe I should
1568          * generate a CONV_I8 node when the value on the stack is an int?
1569          */
1570         x86_test_reg_imm (s->code, tree->left->reg1, 0x8000000);
1571         x86_branch8 (s->code, X86_CC_EQ, 10, TRUE);
1572         x86_mov_reg_imm (s->code, X86_ECX, get_exception_overflow ());
1573         x86_call_code (s->code, get_throw_exception ());
1574
1575         if (tree->reg1 != tree->left->reg1)
1576                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1577         x86_alu_reg_reg (s->code, X86_XOR, tree->reg2, tree->reg2);
1578 }
1579
1580 stmt: STIND_I8 (locaddr, lreg) {
1581         x86_mov_membase_reg (s->code, X86_EBP, tree->left->data.i,
1582                              tree->right->reg1, 4);
1583         x86_mov_membase_reg (s->code, X86_EBP, tree->left->data.i + 4,
1584                              tree->right->reg2, 4);
1585 }
1586 stmt: STIND_I8 (addr, lreg) {
1587        
1588         switch (tree->left->data.ainfo.amode) {
1589
1590         case AMImmediate:
1591                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset, tree->right->reg1, 4);
1592                 x86_mov_mem_reg (s->code, tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
1593                 break;
1594                 
1595         case AMBase:
1596                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
1597                                      tree->left->data.ainfo.offset, tree->right->reg1, 4);
1598                 x86_mov_membase_reg (s->code, tree->left->data.ainfo.basereg, 
1599                                      tree->left->data.ainfo.offset + 4, tree->right->reg2, 4);
1600                 break;          
1601         case AMIndex:
1602                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset,
1603                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
1604                                       tree->right->reg1, 4);
1605                 x86_mov_memindex_reg (s->code, X86_NOBASEREG, tree->left->data.ainfo.offset + 4,
1606                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
1607                                       tree->right->reg2, 4);
1608                 break;          
1609         case AMBaseIndex:
1610                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset,
1611                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
1612                                       tree->right->reg1, 4);
1613                 x86_mov_memindex_reg (s->code, tree->left->data.ainfo.basereg, tree->left->data.ainfo.offset + 4,
1614                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift,
1615                                       tree->right->reg2, 4);
1616                 break;          
1617         }
1618 }
1619
1620 lreg: LDIND_I8 (locaddr) {
1621         x86_mov_reg_membase (s->code, tree->reg1, X86_EBP,
1622                              tree->left->data.i, 4);
1623         x86_mov_reg_membase (s->code, tree->reg2, X86_EBP,
1624                              tree->left->data.i + 4, 4);
1625 }
1626
1627 lreg: LDIND_I8 (addr) {
1628         switch (tree->left->data.ainfo.amode) {
1629
1630         case AMImmediate:
1631                 x86_mov_reg_mem (s->code, tree->reg1, tree->left->data.ainfo.offset, 4);
1632                 x86_mov_reg_mem (s->code, tree->reg2, tree->left->data.ainfo.offset + 4, 4);
1633                 break;
1634
1635         case AMBase:
1636                 x86_mov_reg_membase (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
1637                                      tree->left->data.ainfo.offset, 4);
1638                 x86_mov_reg_membase (s->code, tree->reg2, tree->left->data.ainfo.basereg, 
1639                                      tree->left->data.ainfo.offset + 4, 4);
1640                 break;          
1641         case AMIndex:
1642                 x86_mov_reg_memindex (s->code, tree->reg1, X86_NOBASEREG, tree->left->data.ainfo.offset,
1643                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
1644                 x86_mov_reg_memindex (s->code, tree->reg2, X86_NOBASEREG, tree->left->data.ainfo.offset + 4,
1645                                       tree->left->data.ainfo.indexreg, tree->left->data.ainfo.shift, 4);
1646                 break;          
1647         case AMBaseIndex:
1648                 x86_mov_reg_memindex (s->code, tree->reg1, tree->left->data.ainfo.basereg, 
1649                                       tree->left->data.ainfo.offset, tree->left->data.ainfo.indexreg, 
1650                                       tree->left->data.ainfo.shift, 4);
1651                 x86_mov_reg_memindex (s->code, tree->reg2, tree->left->data.ainfo.basereg, 
1652                                       tree->left->data.ainfo.offset + 4, tree->left->data.ainfo.indexreg, 
1653                                       tree->left->data.ainfo.shift, 4);
1654                 break;          
1655         }
1656 }
1657
1658 lreg: ADD (lreg, lreg) {
1659         if (tree->reg1 != tree->left->reg1)
1660                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1661         if (tree->reg2 != tree->left->reg2)
1662                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1663         x86_alu_reg_reg (s->code, X86_ADD, tree->reg1, tree->right->reg1);
1664         x86_alu_reg_reg (s->code, X86_ADC, tree->reg2, tree->right->reg2);
1665 }
1666
1667 lreg: SUB (lreg, lreg) {
1668         if (tree->reg1 != tree->left->reg1)
1669                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1670         if (tree->reg2 != tree->left->reg2)
1671                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1672         x86_alu_reg_reg (s->code, X86_SUB, tree->reg1, tree->right->reg1);
1673         x86_alu_reg_reg (s->code, X86_SUB, tree->reg2, tree->right->reg2);
1674 }
1675
1676 lreg: AND (lreg, lreg) {
1677         if (tree->reg1 != tree->left->reg1)
1678                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1679         if (tree->reg2 != tree->left->reg2)
1680                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1681         x86_alu_reg_reg (s->code, X86_AND, tree->reg1, tree->right->reg1);
1682         x86_alu_reg_reg (s->code, X86_AND, tree->reg2, tree->right->reg2);
1683 }
1684
1685 lreg: OR (lreg, lreg) {
1686         if (tree->reg1 != tree->left->reg1)
1687                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1688         if (tree->reg2 != tree->left->reg2)
1689                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1690         x86_alu_reg_reg (s->code, X86_OR, tree->reg1, tree->right->reg1);
1691         x86_alu_reg_reg (s->code, X86_OR, tree->reg2, tree->right->reg2);
1692 }
1693
1694 lreg: NEG (lreg) {
1695         if (tree->reg1 != tree->left->reg1)
1696                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1697         if (tree->reg2 != tree->left->reg2)
1698                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1699         x86_neg_reg (s->code, tree->reg1);
1700         x86_alu_reg_imm (s->code, X86_ADC, tree->reg2, 0);
1701         x86_neg_reg (s->code, tree->reg2);
1702 }
1703
1704 lreg: NOT (lreg) {
1705         if (tree->reg1 != tree->left->reg1)
1706                 x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
1707         if (tree->reg2 != tree->left->reg2)
1708                 x86_mov_reg_reg (s->code, tree->reg2, tree->left->reg2, 4);
1709          x86_not_reg (s->code, tree->reg1);
1710          x86_not_reg (s->code, tree->reg2);
1711 }
1712
1713 lreg: MUL (lreg, lreg) {
1714         if (mono_regset_reg_used (s->rs, X86_ECX)) 
1715                 x86_push_reg (s->code, X86_ECX);
1716
1717         x86_push_reg (s->code, tree->right->reg2);
1718         x86_push_reg (s->code, tree->right->reg1);
1719         x86_push_reg (s->code, tree->left->reg2);
1720         x86_push_reg (s->code, tree->left->reg1);
1721         x86_call_code (s->code, mono_llmult);
1722         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
1723
1724         if (mono_regset_reg_used (s->rs, X86_ECX))
1725                 x86_pop_reg (s->code, X86_ECX);
1726 }
1727
1728 lreg: DIV (lreg, lreg) {
1729         if (mono_regset_reg_used (s->rs, X86_ECX)) 
1730                 x86_push_reg (s->code, X86_ECX);
1731
1732         x86_push_reg (s->code, tree->right->reg2);
1733         x86_push_reg (s->code, tree->right->reg1);
1734         x86_push_reg (s->code, tree->left->reg2);
1735         x86_push_reg (s->code, tree->left->reg1);
1736         x86_call_code (s->code, mono_lldiv);
1737         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
1738
1739         if (mono_regset_reg_used (s->rs, X86_ECX))
1740                 x86_pop_reg (s->code, X86_ECX);
1741 }
1742
1743 lreg: REM (lreg, lreg) {
1744         if (mono_regset_reg_used (s->rs, X86_ECX)) 
1745                 x86_push_reg (s->code, X86_ECX);
1746
1747         x86_push_reg (s->code, tree->right->reg2);
1748         x86_push_reg (s->code, tree->right->reg1);
1749         x86_push_reg (s->code, tree->left->reg2);
1750         x86_push_reg (s->code, tree->left->reg1);
1751         x86_call_code (s->code, mono_llrem);
1752         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
1753
1754         if (mono_regset_reg_used (s->rs, X86_ECX))
1755                 x86_pop_reg (s->code, X86_ECX);
1756 }
1757
1758 lreg: DIV_UN (lreg, lreg) {
1759         if (mono_regset_reg_used (s->rs, X86_ECX)) 
1760                 x86_push_reg (s->code, X86_ECX);
1761
1762         x86_push_reg (s->code, tree->right->reg2);
1763         x86_push_reg (s->code, tree->right->reg1);
1764         x86_push_reg (s->code, tree->left->reg2);
1765         x86_push_reg (s->code, tree->left->reg1);
1766         x86_call_code (s->code, mono_lldiv_un);
1767         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
1768
1769         if (mono_regset_reg_used (s->rs, X86_ECX))
1770                 x86_pop_reg (s->code, X86_ECX);
1771 }
1772
1773 lreg: REM_UN (lreg, lreg) {
1774         if (mono_regset_reg_used (s->rs, X86_ECX)) 
1775                 x86_push_reg (s->code, X86_ECX);
1776
1777         x86_push_reg (s->code, tree->right->reg2);
1778         x86_push_reg (s->code, tree->right->reg1);
1779         x86_push_reg (s->code, tree->left->reg2);
1780         x86_push_reg (s->code, tree->left->reg1);
1781         x86_call_code (s->code, mono_llrem_un);
1782         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 16);
1783
1784         if (mono_regset_reg_used (s->rs, X86_ECX))
1785                 x86_pop_reg (s->code, X86_ECX);
1786 }
1787
1788 lreg: CALL_I8 (this, LDIND_I4 (ADDR_G)) {
1789         MethodCallInfo *ci = tree->data.ci;
1790         int lreg = tree->left->reg1;
1791         int treg = X86_EAX;
1792
1793         if (lreg == treg) 
1794                 treg = X86_EDX;
1795         
1796         if (ci->vtype_num) {
1797                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
1798                 x86_lea_membase (s->code, treg, X86_EBP, offset);
1799                 x86_push_reg (s->code, treg);
1800         }
1801
1802         if (tree->left->op != MB_TERM_NOP) {
1803                 g_assert (lreg >= 0);
1804                 x86_push_reg (s->code, lreg);
1805         }
1806
1807         x86_call_mem (s->code, tree->right->left->data.p);
1808
1809         if (ci->args_size)
1810                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
1811
1812         g_assert (tree->reg1 == X86_EAX);
1813         g_assert (tree->reg2 == X86_EDX);
1814 }
1815
1816 stmt: RETV (lreg) {
1817         if (tree->left->reg1 != X86_EAX) {
1818                 if (tree->left->reg2 != X86_EAX) {
1819                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1820                         if (tree->left->reg2 != X86_EDX)
1821                                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
1822                 } else { 
1823                         x86_mov_reg_reg (s->code, X86_ECX, tree->left->reg2, 4);
1824                         x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
1825                         x86_mov_reg_reg (s->code, X86_EDX, X86_ECX, 4);
1826                 }
1827         } else if (tree->left->reg2 != X86_EDX) {
1828                 x86_mov_reg_reg (s->code, X86_EDX, tree->left->reg2, 4);
1829         }
1830
1831         if (!tree->last_instr) {
1832                 tree->is_jump = 1;
1833                 x86_jump32 (s->code, s->epilog - 5);      
1834         }
1835 }
1836
1837
1838 stmt: ARG_I8 (lreg) {
1839         x86_push_reg (s->code, tree->left->reg2);
1840         x86_push_reg (s->code, tree->left->reg1);
1841 }
1842
1843 stmt: BEQ (lreg, lreg) {
1844         guint8 *start = s->code;
1845         gint32 o1, o2, i;
1846
1847         tree->is_jump = 1;
1848
1849         for (i = 0; i < 2; i ++) {
1850                 s->code = start;
1851                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1852                 o1 = 2 + s->code - s->start;
1853                 x86_branch8 (s->code, X86_CC_NE, o2 - o1, FALSE);
1854                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1855                 o2 = 6 + s->code - s->start;
1856                 x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - o2, TRUE);
1857         }
1858 }
1859
1860 stmt: BNE_UN (lreg, lreg) {
1861         gint32 offset;
1862
1863         tree->is_jump = 1;
1864
1865         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1866         offset = 6 + s->code - s->start;
1867         x86_branch8 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
1868         x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1869         offset = 6 + s->code - s->start;
1870         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
1871 }
1872
1873 stmt: BGE (lreg, lreg) {
1874         guint8 *start = s->code;
1875         gint32 o1, o2, oe, i;
1876
1877         tree->is_jump = 1;
1878
1879         for (i = 0; i < 2; i ++) {
1880                 s->code = start;
1881                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1882                 o1 = 6 + s->code - s->start;
1883                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - o1, TRUE);
1884                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1885                 o2 = 2 + s->code - s->start;
1886                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
1887                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1888                 oe = 6 + s->code - s->start;
1889                 x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - oe, FALSE);
1890         }
1891 }
1892
1893 stmt: BGE_UN (lreg, lreg) {
1894         guint8 *start = s->code;
1895         gint32 o1, o2, oe, i;
1896
1897         tree->is_jump = 1;
1898
1899         for (i = 0; i < 2; i ++) {
1900                 s->code = start;
1901                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1902                 o1 = 6 + s->code - s->start;
1903                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - o1, FALSE);
1904                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1905                 o2 = 2 + s->code - s->start;
1906                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
1907                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1908                 oe = 6 + s->code - s->start;
1909                 x86_branch32 (s->code, X86_CC_GE, tree->data.bb->addr - oe, FALSE);
1910         }
1911 }
1912
1913 stmt: BGT (lreg, lreg) {
1914         guint8 *start = s->code;
1915         gint32 o1, o2, oe, i;
1916
1917         tree->is_jump = 1;
1918
1919         for (i = 0; i < 2; i ++) {
1920                 s->code = start;
1921                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1922                 o1 = 6 + s->code - s->start;
1923                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - o1, TRUE);
1924                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1925                 o2 = 2 + s->code - s->start;
1926                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
1927                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1928                 oe = 6 + s->code - s->start;
1929                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - oe, FALSE);
1930         }
1931 }
1932
1933 stmt: BGT_UN (lreg, lreg) {
1934         guint8 *start = s->code;
1935         gint32 o1, o2, oe, i;
1936
1937         tree->is_jump = 1;
1938
1939         for (i = 0; i < 2; i ++) {
1940                 s->code = start;
1941                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1942                 o1 = 6 + s->code - s->start;
1943                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - o1, FALSE);
1944                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1945                 o2 = 2 + s->code - s->start;
1946                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
1947                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1948                 oe = 6 + s->code - s->start;
1949                 x86_branch32 (s->code, X86_CC_GT, tree->data.bb->addr - oe, FALSE);
1950         }
1951 }
1952
1953 stmt: BLT (lreg, lreg) {
1954         guint8 *start = s->code;
1955         gint32 o1, o2, oe, i;
1956
1957         tree->is_jump = 1;
1958
1959         for (i = 0; i < 2; i ++) {
1960                 s->code = start;
1961                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1962                 o1 = 6 + s->code - s->start;
1963                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - o1, TRUE);
1964                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1965                 o2 = 2 + s->code - s->start;
1966                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
1967                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1968                 oe = 6 + s->code - s->start;
1969                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - oe, FALSE);
1970         }
1971 }
1972
1973 stmt: BLT_UN (lreg, lreg) {
1974         guint8 *start = s->code;
1975         gint32 o1, o2, oe, i;
1976
1977         tree->is_jump = 1;
1978
1979         for (i = 0; i < 2; i ++) {
1980                 s->code = start;
1981                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1982                 o1 = 6 + s->code - s->start;
1983                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - o1, FALSE);
1984                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
1985                 o2 = 2 + s->code - s->start;
1986                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
1987                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
1988                 oe = 6 + s->code - s->start;
1989                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - oe, FALSE);
1990         }
1991 }
1992
1993 stmt: BLE (lreg, lreg) {
1994         guint8 *start = s->code;
1995         gint32 o1, o2, oe, i;
1996
1997         tree->is_jump = 1;
1998
1999         for (i = 0; i < 2; i ++) {
2000                 s->code = start;
2001                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2002                 o1 = 6 + s->code - s->start;
2003                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - o1, TRUE);
2004                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2005                 o2 = 2 + s->code - s->start;
2006                 x86_branch8 (s->code, X86_CC_NE, oe - o2, TRUE);
2007                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2008                 oe = 6 + s->code - s->start;
2009                 x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - oe, FALSE);
2010         }
2011 }
2012
2013 stmt: BLE_UN (lreg, lreg) {
2014         guint8 *start = s->code;
2015         gint32 o1, o2, oe, i;
2016
2017         tree->is_jump = 1;
2018
2019         for (i = 0; i < 2; i ++) {
2020                 s->code = start;
2021                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2022                 o1 = 6 + s->code - s->start;
2023                 x86_branch32 (s->code, X86_CC_LT, tree->data.bb->addr - o1, FALSE);
2024                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg2, tree->right->reg2);
2025                 o2 = 2 + s->code - s->start;
2026                 x86_branch8 (s->code, X86_CC_NE, oe - o2, FALSE);
2027                 x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
2028                 oe = 6 + s->code - s->start;
2029                 x86_branch32 (s->code, X86_CC_LE, tree->data.bb->addr - oe, FALSE);
2030         }
2031 }
2032
2033 #
2034 # floating point 
2035
2036 #stmt: STLOC (CONV_I4 (freg)) {
2037 #       // fixme: set CW
2038 #       x86_fist_pop_membase (s->code, X86_EBP, tree->data.i, FALSE);
2039 #} 
2040
2041 reg: CONV_I4 (freg) {
2042         x86_push_reg (s->code, X86_EAX); // SP = SP - 4
2043         x86_fist_pop_membase (s->code, X86_ESP, 0, FALSE);
2044         x86_pop_reg (s->code, tree->reg1);
2045 }
2046
2047 freg: CONV_R8 (freg) {
2048         /* nothing to do */
2049 }
2050
2051 freg: CONV_R8 (LDIND_I4 (ADDR_G)) {
2052         x86_fild (s->code, tree->left->left->data.p, FALSE);
2053 }
2054
2055 freg: CONV_R8 (reg) {
2056         /* I found no direct way to move an integer register to 
2057          * the floating point stack, so we need to store the register
2058          * to memory
2059          */
2060         x86_push_reg (s->code, tree->left->reg1);
2061         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
2062         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2063 }
2064
2065 freg: CONV_R4 (reg) {
2066         /* I found no direct way to move an integer register to 
2067          * the floating point stack, so we need to store the register
2068          * to memory
2069          */
2070         x86_push_reg (s->code, tree->left->reg1);
2071         x86_fild_membase (s->code, X86_ESP, 0, FALSE);
2072         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2073 }
2074
2075 freg: CONST_R4 {
2076         float f = *(float *)tree->data.p;
2077
2078         if (f == 0.0)
2079                 x86_fldz (s->code);
2080         else if (f == 1.0)
2081                 x86_fld1(s->code);
2082         else
2083                 x86_fld (s->code, tree->data.p, FALSE);
2084 }
2085
2086 freg: CONST_R8 {
2087         double d = *(double *)tree->data.p;
2088
2089         if (d == 0.0)
2090                 x86_fldz (s->code);
2091         else if (d == 1.0)
2092                 x86_fld1(s->code);
2093         else
2094                 x86_fld (s->code, tree->data.p, TRUE);
2095 }
2096
2097 freg: LDIND_R4 (reg) {
2098         x86_fld_membase (s->code, tree->left->reg1, 0, FALSE);
2099 }
2100
2101 freg: LDIND_R8 (reg) {
2102         x86_fld_membase (s->code, tree->left->reg1, 0, TRUE);
2103 }
2104
2105 freg: LDIND_R8 (reg) {
2106         x86_fld_membase (s->code, tree->left->reg1, 0, TRUE);
2107 }
2108
2109 freg: ADD (freg, freg) {
2110         x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
2111 }
2112
2113 freg: SUB (freg, freg) {
2114         x86_fp_op_reg (s->code, X86_FSUB, 1, TRUE);
2115 }
2116
2117 freg: MUL (freg, freg) {
2118         x86_fp_op_reg (s->code, X86_FMUL, 1, TRUE);
2119 }
2120
2121 freg: DIV (freg, freg) {
2122         x86_fp_op_reg (s->code, X86_FDIV, 1, TRUE);
2123 }
2124
2125 #freg: REM (freg, freg) {
2126 # this does not work, since it does not pop a value from the stack,
2127 # and we need to test if the instruction is ready
2128 #       x86_fprem1 (s->code);
2129 #}
2130
2131 freg: NEG (freg) {
2132         x86_fchs (s->code);
2133 }
2134
2135 stmt: POP (freg)
2136
2137 stmt: STIND_R4 (reg, freg) {
2138         x86_fst_membase (s->code, tree->left->reg1, 0, FALSE, TRUE);
2139 }
2140
2141 stmt: STIND_R8 (reg, freg) {
2142         x86_fst_membase (s->code, tree->left->reg1, 0, TRUE, TRUE);
2143 }
2144
2145 stmt: ARG_R4 (freg) {
2146         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
2147         x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
2148 }
2149
2150 stmt: ARG_R8 (freg) {
2151         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
2152         x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
2153 }
2154
2155 stmt: BEQ (freg, freg) {
2156         gint32 offset;
2157
2158         tree->is_jump = 1;
2159         x86_fcompp (s->code);
2160         x86_fnstsw (s->code);
2161         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2162         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
2163         offset = 6 + s->code - s->start;
2164         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, TRUE);
2165 }
2166
2167 stmt: BNE_UN (freg, freg) {
2168         gint32 offset;
2169
2170         tree->is_jump = 1;
2171         x86_fcompp (s->code);
2172         x86_fnstsw (s->code);
2173         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2174         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
2175         offset = 6 + s->code - s->start;
2176         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
2177 }
2178
2179 stmt: BLT (freg, freg) {
2180         gint32 offset;
2181
2182         tree->is_jump = 1;
2183         x86_fcompp (s->code);
2184         x86_fnstsw (s->code);
2185         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2186         offset = 6 + s->code - s->start;
2187         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, TRUE);
2188 }
2189
2190 stmt: BLT_UN (freg, freg) {
2191         gint32 offset;
2192
2193         tree->is_jump = 1;
2194         x86_fcompp (s->code);
2195         x86_fnstsw (s->code);
2196         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2197         offset = 6 + s->code - s->start;
2198         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, FALSE);
2199 }
2200
2201 stmt: BGE_UN (freg, freg) {
2202         gint32 offset;
2203
2204         tree->is_jump = 1;
2205         x86_fcompp (s->code);
2206         x86_fnstsw (s->code);
2207         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2208         offset = 6 + s->code - s->start;
2209         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
2210 }
2211
2212 stmt: BGT_UN (freg, freg) {
2213         gint32 offset;
2214
2215         tree->is_jump = 1;
2216         x86_fcompp (s->code);
2217         x86_fnstsw (s->code);
2218         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2219         x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
2220         offset = 6 + s->code - s->start;
2221         x86_branch32 (s->code, X86_CC_EQ, tree->data.bb->addr - offset, FALSE);
2222 }
2223
2224 stmt: BLE_UN (freg, freg) {
2225         gint32 offset;
2226
2227         tree->is_jump = 1;
2228         x86_fcompp (s->code);
2229         x86_fnstsw (s->code);
2230         x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
2231         offset = 6 + s->code - s->start;
2232         x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
2233 }
2234
2235 freg: CALL_R8 (this, LDIND_I4 (ADDR_G)) {
2236         MethodCallInfo *ci = tree->data.ci;
2237         int lreg = tree->left->reg1;
2238         int treg = X86_EAX;
2239
2240         if (lreg == treg) 
2241                 treg = X86_EDX;
2242         
2243         if (ci->vtype_num) {
2244                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2245                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2246                 x86_push_reg (s->code, treg);
2247         }
2248
2249         if (tree->left->op != MB_TERM_NOP) {
2250                 g_assert (lreg >= 0);
2251                 x86_push_reg (s->code, lreg);
2252         }
2253
2254         x86_call_mem (s->code, tree->right->left->data.p);
2255
2256         if (ci->args_size)
2257                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2258 }
2259
2260 freg: CALL_R8 (this, INTF_ADDR) {
2261         MethodCallInfo *ci = tree->data.ci;
2262         int lreg = tree->left->reg1;
2263         int treg = X86_EAX;
2264
2265         if (lreg == treg) 
2266                 treg = X86_EDX;
2267
2268         if (ci->vtype_num) {
2269                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2270                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2271                 x86_push_reg (s->code, treg);
2272         }
2273
2274         if (tree->left->op != MB_TERM_NOP) {
2275                 g_assert (lreg >= 0);
2276                 x86_push_reg (s->code, lreg);
2277         }
2278
2279         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2280         x86_mov_reg_membase (s->code, lreg, lreg, 
2281                 G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
2282         x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
2283         x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
2284
2285         if (ci->args_size)
2286                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2287 }
2288
2289 freg: CALL_R8 (this, VFUNC_ADDR) {
2290         MethodCallInfo *ci = tree->data.ci;
2291         int lreg = tree->left->reg1;
2292         int treg = X86_EAX;
2293
2294         if (lreg == treg) 
2295                 treg = X86_EDX;
2296
2297         if (ci->vtype_num) {
2298                 int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
2299                 x86_lea_membase (s->code, treg, X86_EBP, offset);
2300                 x86_push_reg (s->code, treg);
2301         }
2302
2303         if (tree->left->op != MB_TERM_NOP) {
2304                 g_assert (lreg >= 0);
2305                 x86_push_reg (s->code, lreg);
2306         }
2307
2308         x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
2309         x86_call_virtual (s->code, lreg, 
2310                 G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
2311
2312         if (ci->args_size)
2313                 x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
2314 }
2315
2316 stmt: RETV (freg) {
2317
2318         if (!tree->last_instr) {
2319                 tree->is_jump = 1;
2320                 x86_jump32 (s->code, s->epilog - 5);      
2321         }
2322 }
2323
2324 # support for value types
2325
2326 vtype: VTYPE
2327
2328 vtype: LDIND_OBJ (reg) {
2329         int treg = X86_EAX;
2330         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).offset;
2331         int size = g_array_index (s->varinfo, MonoVarInfo, tree->data.i).size;
2332
2333         if (tree->left->reg1 == X86_EAX)
2334                 treg = X86_ECX;
2335
2336         x86_push_reg (s->code, X86_EAX);
2337         x86_push_reg (s->code, X86_EDX);
2338         x86_push_reg (s->code, X86_ECX);
2339
2340         x86_push_imm (s->code, size);
2341         x86_push_reg (s->code, tree->left->reg1);
2342         x86_lea_membase (s->code, treg, X86_EBP, offset);
2343         x86_push_reg (s->code, treg);
2344         x86_call_code (s->code, MEMCOPY);
2345         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2346
2347         x86_pop_reg (s->code, X86_ECX);
2348         x86_pop_reg (s->code, X86_EDX);
2349         x86_pop_reg (s->code, X86_EAX);
2350 }
2351
2352 stmt: STIND_OBJ (reg, vtype) {
2353         int treg = X86_EAX;
2354         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->right->data.i).offset;
2355         int size = g_array_index (s->varinfo, MonoVarInfo, tree->right->data.i).size;
2356
2357         if (tree->left->reg1 == X86_EAX)
2358                 treg = X86_ECX;
2359
2360         x86_push_reg (s->code, X86_EAX);
2361         x86_push_reg (s->code, X86_EDX);
2362         x86_push_reg (s->code, X86_ECX);
2363
2364         x86_push_imm (s->code, size);
2365         x86_lea_membase (s->code, treg, X86_EBP, offset);
2366         x86_push_reg (s->code, treg);
2367         x86_push_reg (s->code, tree->left->reg1);
2368         x86_call_code (s->code, MEMCOPY);
2369         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2370
2371         x86_pop_reg (s->code, X86_ECX);
2372         x86_pop_reg (s->code, X86_EDX);
2373         x86_pop_reg (s->code, X86_EAX);
2374 }
2375
2376 stmt: ARG_OBJ (vtype) {
2377         int treg = X86_EAX;
2378         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).offset;
2379         int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
2380         int sa;
2381         
2382         sa = size + 3;
2383         sa &= ~3;
2384
2385         /* reserve space for the argument */
2386         x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
2387
2388         x86_push_reg (s->code, X86_EAX);
2389         x86_push_reg (s->code, X86_EDX);
2390         x86_push_reg (s->code, X86_ECX);
2391
2392         x86_push_imm (s->code, size);
2393
2394         x86_lea_membase (s->code, treg, X86_EBP, offset);
2395         x86_push_reg (s->code, treg);
2396
2397         x86_lea_membase (s->code, treg, X86_ESP, 5*4);
2398         x86_push_reg (s->code, treg);
2399
2400         x86_call_code (s->code, MEMCOPY);
2401         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2402
2403         x86_pop_reg (s->code, X86_ECX);
2404         x86_pop_reg (s->code, X86_EDX);
2405         x86_pop_reg (s->code, X86_EAX);
2406 }
2407
2408 stmt: RETV (vtype) {
2409         int treg = X86_EAX;
2410         int offset = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).offset;
2411         int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
2412
2413         x86_push_imm (s->code, size);
2414         x86_lea_membase (s->code, treg, X86_EBP, offset);
2415         x86_push_reg (s->code, treg);
2416         x86_push_membase (s->code, X86_EBP, 8);
2417
2418         x86_call_code (s->code, MEMCOPY);
2419         x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
2420
2421         if (!tree->last_instr) {
2422                 tree->is_jump = 1;
2423                 x86_jump32 (s->code, s->epilog - 5);      
2424         }
2425 }
2426
2427 %% 
2428
2429 #include "jit.h"
2430
2431 gint64 
2432 mono_llmult (gint64 a, gint64 b)
2433 {
2434         return a * b;
2435 }
2436
2437 gint64 
2438 mono_lldiv (gint64 a, gint64 b)
2439 {
2440         return a / b;
2441 }
2442
2443 gint64 
2444 mono_llrem (gint64 a, gint64 b)
2445 {
2446         return a % b;
2447 }
2448
2449 guint64 
2450 mono_lldiv_un (guint64 a, guint64 b)
2451 {
2452         return a / b;
2453 }
2454
2455 guint64 
2456 mono_llrem_un (guint64 a, guint64 b)
2457 {
2458         return a % b;
2459 }
2460
2461 MBTree *
2462 mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
2463 {
2464         MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
2465
2466         t->op = op;
2467         t->left = left;
2468         t->right = right;
2469         t->reg1 = -1;
2470         t->reg2 = -1;
2471         t->reg3 = -1;
2472         t->svt = VAL_UNKNOWN;
2473         t->cli_addr = -1;
2474         return t;
2475 }
2476
2477 MBTree *
2478 mono_ctree_new_leaf (MonoMemPool *mp, int op)
2479 {
2480         return mono_ctree_new (mp, op, NULL, NULL);
2481 }
2482
2483 static void
2484 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
2485                  unsigned long esi, unsigned long edi, unsigned long ebp, unsigned long eip,
2486                  unsigned long esp)
2487 {
2488         MonoObject *exc = (gpointer)ecx;
2489         struct sigcontext ctx;
2490         
2491         ctx.esp = esp;
2492         ctx.eip = eip;
2493         ctx.ebp = ebp;
2494         ctx.edi = edi;
2495         ctx.esi = esi;
2496         ctx.ebx = ebx;
2497         ctx.edx = edx;
2498         ctx.ecx = ecx;
2499         ctx.eax = eax;
2500         
2501         arch_handle_exception (&ctx, exc);
2502
2503         g_assert_not_reached ();
2504 }
2505
2506 gpointer 
2507 get_throw_exception (void)
2508 {
2509         static guint8 *start = NULL;
2510         guint8 *code;
2511
2512         if (start)
2513                 return start;
2514
2515         code = start = g_malloc (1024);
2516
2517         x86_push_reg (code, X86_ESP);
2518         x86_push_membase (code, X86_ESP, 4); /* IP */
2519         x86_push_reg (code, X86_EBP);
2520         x86_push_reg (code, X86_EDI);
2521         x86_push_reg (code, X86_ESI);
2522         x86_push_reg (code, X86_EBX);
2523         x86_push_reg (code, X86_EDX);
2524         x86_push_reg (code, X86_ECX);
2525         x86_push_reg (code, X86_EAX);
2526         x86_call_code (code, throw_exception);
2527         /* we should never reach this breakpoint */
2528         x86_breakpoint (code);
2529
2530         return start;
2531 }
2532
2533 #ifdef DEBUG
2534 void *
2535 MEMCOPY (void *dest, const void *src, size_t n)
2536 {
2537         int i, l = n;
2538
2539         printf ("MEMCPY(%p to %p [%d]) ", src, dest, n);
2540
2541         for (i = 0; i < l; i++)
2542                 printf ("%02x ", *((guint8 *)src + i));
2543         printf ("\n");
2544         
2545         return memcpy (dest, src, n);
2546 }
2547 #endif
2548