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