inline1.cs \
inline2.cs \
inline3.cs \
- muldiv.cs
+ muldiv.cs \
+ loops.cs
TESTSI=$(TESTSRC:.cs=.exe)
TESTBS=$(BENCHSRC:.cs=.exe)
--- /dev/null
+using System;
+
+public class NestedLoop {
+ static public int nest_test () {
+ int n = 16;
+ int x = 0;
+ int a = n;
+ while (a-- != 0) {
+ int b = n;
+ while (b-- != 0) {
+ int c = n;
+ while (c-- != 0) {
+ int d = n;
+ while (d-- != 0) {
+ int e = n;
+ while (e-- != 0) {
+ int f = n;
+ while (f-- != 0) {
+ x++;
+ }
+ }
+ }
+ }
+ }
+ }
+ return x;
+ }
+
+ public static int Main (string[] args) {
+ int repeat = 1;
+
+ if (args.Length == 1)
+ repeat = Convert.ToInt32 (args [0]);
+
+ Console.WriteLine ("Repeat = " + repeat);
+
+ for (int i = 0; i < repeat*10; i++)
+ if (nest_test () != 16777216)
+ return 1;
+
+ return 0;
+ }
+}
+
+
+2002-05-09 Dietmar Maurer <dietmar@ximian.com>
+
+ * linear-scan.c: linear scan reg. allocation and data flow analysis
+
+ * jit.c (arch_allocate_var): add live range info
+ (mono_cfg_add_successor): create list of successors for basic
+ blocks.
+
+ * mono.c (main): new option --ls to enable linear scan
+
+ * exception.c (arch_handle_exception): print instruction pointer
+ relative to method start address.
+
+ * jit.c (mono_print_ctree): print register number if locals are
+ allocate in registers.
+
+ * emit-x86.c (arch_emit_prologue): initialize reg. allocated locals
+ (arch_emit_epilogue): take care when restoring save registers,
+ because the stack pointer may has changed.
+
+ * x86.brg: s/VAROFFSET/VARINFO/
+ modified to support global register allocation
Mon May 6 15:38:15 CEST 2002 Paolo Molaro <lupus@ximian.com>
delegate.c \
exception.c \
invoke.c \
- message.c
+ message.c \
+ linear-scan.c
mono_SOURCES = mono.c
if (header->num_locals) {
if (header->init_locals) {
- int offset = g_array_index (cfg->varinfo, MonoVarInfo,
- cfg->locals_start_index + header->num_locals - 1).offset;
+ MonoVarInfo *vi = &VARINFO (cfg, cfg->locals_start_index + header->num_locals - 1);
+ int offset = vi->offset;
int size = - offset;
+ for (i = 0; i < header->num_locals; ++i) {
+ MonoVarInfo *rv = &VARINFO (cfg, cfg->locals_start_index + header->num_locals - 1);
+
+ if (rv->reg >= 0)
+ x86_alu_reg_imm (cfg->code, X86_XOR, rv->reg, rv->reg);
+ }
+
if (size == 1 || size == 2 || size == 4) {
x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, size);
return;
for (i = 0; i < header->num_locals; ++i) {
MonoType *t = header->locals [i];
- int offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;
+ int offset = VARINFO (cfg, cfg->locals_start_index + i).offset;
if (t->byref) {
x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
static void
arch_emit_epilogue (MonoFlowGraph *cfg)
{
+ int pos = 4;
/*
* note: with trace and profiling the value on the FP stack may get clobbered.
*/
x86_pop_reg (cfg->code, X86_EAX);
}
- if (mono_regset_reg_used (cfg->rs, X86_ESI))
- x86_pop_reg (cfg->code, X86_ESI);
-
- if (mono_regset_reg_used (cfg->rs, X86_EDI))
- x86_pop_reg (cfg->code, X86_EDI);
-
- if (mono_regset_reg_used (cfg->rs, X86_EBX))
- x86_pop_reg (cfg->code, X86_EBX);
+ if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+ x86_mov_reg_membase (cfg->code, X86_EBX, X86_EBP, - (cfg->locals_size + pos), 4);
+ pos += 4;
+ }
+ if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+ x86_mov_reg_membase (cfg->code, X86_EDI, X86_EBP, - (cfg->locals_size + pos), 4);
+ pos += 4;
+ }
+ if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+ x86_mov_reg_membase (cfg->code, X86_ESI, X86_EBP, - (cfg->locals_size + pos), 4);
+ pos += 4;
+ }
x86_leave (cfg->code);
x86_ret (cfg->code);
if (mono_debug_handle)
return;
g_warning ("tree does not match");
- mono_print_ctree (t1); printf ("\n\n");
+ mono_print_ctree (cfg, t1); printf ("\n\n");
- mono_print_forest (forest);
+ mono_print_forest (cfg, forest);
g_assert_not_reached ();
}
}
}
static gboolean
-tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs, guint8 exclude_mask, int *spillcount)
+tree_allocate_regs (MonoFlowGraph *cfg, MBTree *tree, int goal, MonoRegSet *rs,
+ guint8 exclude_mask, int *spillcount)
{
MBTree *kids[10];
int ern = mono_burg_rule (tree->state, goal);
if (nts [0] && kids [0] == tree) {
/* chain rule */
- if (!tree_allocate_regs (kids [0], nts [0], rs, exclude_mask, spillcount))
+ if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, exclude_mask, spillcount))
return FALSE;
/* special case reg: coni4 */
if (goal == MB_NTERM_reg) {
if (nts [0]) {
if (nts [1]) { /* two kids */
MonoRegSet saved_rs;
- if (nts [2]) /* we cant handle tree kids */
+ if (nts [2]) /* we cant handle three kids */
g_assert_not_reached ();
- if (!tree_allocate_regs (kids [0], nts [0], rs, left_exclude_mask, spillcount))
+ if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
return FALSE;
saved_rs = *rs;
- if (!tree_allocate_regs (kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+ if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
#ifdef DEBUG_REGALLOC
printf ("tree_allocate_regs try 1 failed %d %d %d %d\n",
kids [0]->spilled = 1;
- if (!tree_allocate_regs (kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+ if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
#ifdef DEBUG_REGALLOC
printf ("tree_allocate_regs try 2 failed\n");
#endif
}
} else { /* one kid */
- if (!tree_allocate_regs (kids [0], nts [0], rs, left_exclude_mask, spillcount))
+ if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
return FALSE;
}
}
#ifdef DEBUG_REGALLOC
printf ("arch_allocate_regs start %d:%d %08x\n", i, j, cfg->rs->free_mask);
#endif
- if (!tree_allocate_regs (t1, 1, cfg->rs, 0, &spillcount)) {
- mono_print_ctree (t1);
+ if (!tree_allocate_regs (cfg, t1, 1, cfg->rs, 0, &spillcount)) {
+ mono_print_ctree (cfg, t1);
g_error ("register allocation failed");
}
int spillvar;
spillvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer),
MONO_TEMPVAR, VAL_I32);
- cfg->spillvars [i] = VAROFFSET (cfg, spillvar);
+ cfg->spillvars [i] = VARINFO (cfg, spillvar).offset;
}
}
cfg->method->klass->name_space,
cfg->method->klass->name, cfg->method->name);
- mono_print_ctree (kids [0]);printf ("\n\n");
+ mono_print_ctree (cfg, kids [0]);printf ("\n\n");
#endif
spilloffset1 = 0;
spilloffset2 = 0;
tree->addr = offset = cfg->code - cfg->start;
- // we assume an instruction uses a maximum of 128 bytes
+ /* we assume an instruction uses a maximum of 128 bytes */
if ((cfg->code_size - offset) <= 128) {
int add = MIN (cfg->code_size, 128);
cfg->code_size += add;
MonoFlowGraph *cfg;
MonoMemPool *mp;
gulong code_size_ratio;
+ guint32 ls_used_mask = 0;
mono_profiler_method_jit (method);
if (mono_debug_insert_breakpoint > 0)
mono_debug_insert_breakpoint--;
+ if (mono_use_linear_scan) {
+ mono_linear_scan (cfg, &ls_used_mask);
+ cfg->rs->used_mask |= ls_used_mask;
+ }
+
if (mono_jit_dump_forest) {
int i;
printf ("FOREST %s.%s:%s\n", method->klass->name_space,
method->klass->name, method->name);
for (i = 0; i < cfg->block_count; i++) {
printf ("BLOCK %d:\n", i);
- mono_print_forest (cfg->bblocks [i].forest);
+ mono_print_forest (cfg, cfg->bblocks [i].forest);
}
}
-
+
mono_label_cfg (cfg);
+
if (cfg->invalid) {
mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
return NULL;
strace = g_strdup ("");
}
- tmp = g_strdup_printf ("%sin %s.%s:%s ()\n", strace, m->klass->name_space,
- m->klass->name, m->name);
+ tmp = g_strdup_printf ("%sin %03x %s.%s:%s ()\n", strace, ip - ji->code_start,
+ m->klass->name_space, m->klass->name, m->name);
g_free (strace);
/* Force jit to share code between application domains */
gboolean mono_jit_share_code = FALSE;
+/* use linear scan register allocation */
+gboolean mono_use_linear_scan = FALSE;
+
/* inline code */
gboolean mono_jit_inline_code = TRUE;
* prints the tree to stdout
*/
void
-mono_print_ctree (MBTree *tree)
+mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree)
{
int arity;
switch (tree->op) {
case MB_TERM_CONST_I4:
- case MB_TERM_ADDR_L:
printf ("[%d]", tree->data.i);
break;
+ case MB_TERM_ADDR_L:
+ if (VARINFO (cfg, tree->data.i).reg >= 0)
+ printf ("[R%d]", tree->data.i);
+ else
+ printf ("[%d]", tree->data.i);
+ break;
}
g_assert (!(tree->right && !tree->left));
- mono_print_ctree (tree->left);
- mono_print_ctree (tree->right);
+ mono_print_ctree (cfg, tree->left);
+ mono_print_ctree (cfg, tree->right);
if (arity)
printf (")");
* prints the whole forest to stdout
*/
void
-mono_print_forest (GPtrArray *forest)
+mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest)
{
const int top = forest->len;
int i;
for (i = 0; i < top; i++) {
MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
printf (" ");
- mono_print_ctree (t);
+ mono_print_ctree (cfg, t);
printf ("\n");
}
mono_jit_stats.allocate_var++;
+ vi.range.last_use.abs_pos = 0;
+ vi.range.first_use.pos.bid = 0xffff;
+ vi.range.first_use.pos.tid = 0;
+ vi.isvolatile = 0;
+ vi.reg = -1;
+ vi.varnum = cfg->varinfo->len;
+
+ if (size != sizeof (gpointer))
+ vi.isvolatile = 1;
+
switch (kind) {
case MONO_TEMPVAR:
case MONO_LOCALVAR: {
if (!cfg->bblocks [i].reached)
continue;
g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
+ g_list_free (cfg->bblocks [i].succ);
}
if (cfg->bcinfo)
return NULL;
}
+static void
+mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
+{
+ MonoBBlock *tbb;
+ GList *l;
+
+ g_assert (cfg->bcinfo [target].is_block_start);
+
+ tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
+ g_assert (tbb);
+
+ for (l = bb->succ; l; l = l->next) {
+ MonoBBlock *t = (MonoBBlock *)l->data;
+ if (t == tbb)
+ return;
+ }
+
+ bb->succ = g_list_prepend (bb->succ, tbb);
+}
+
+
#define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
void
for (i = 0; i < header->code_size; i++) {
if (bcinfo [i].is_block_start) {
bb->cli_addr = i;
+ bb->num = block_count;
if (block_count)
bb [-1].length = i - bb [-1].cli_addr;
bcinfo [i].block_id = block_count;
cfg->bcinfo = bcinfo;
cfg->bblocks = bblocks;
cfg->block_count = block_count;
+
+ ip = header->code;
+ end = ip + header->code_size;
+ bb = NULL;
+
+ while (ip < end) {
+ guint32 cli_addr = ip - header->code;
+
+ if (bcinfo [cli_addr].is_block_start) {
+ MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];
+ if (bb && !bb->succ)
+ bb->succ = g_list_prepend (bb->succ, tbb);
+ bb = tbb;
+ }
+ g_assert (bb);
+
+ if (*ip == 0xfe) {
+ ++ip;
+ i = *ip + 256;
+ } else {
+ i = *ip;
+ }
+
+ opcode = &mono_opcodes [i];
+
+ switch (opcode->argument) {
+ case MonoInlineNone:
+ ++ip;
+ break;
+ case MonoInlineString:
+ case MonoInlineType:
+ case MonoInlineField:
+ case MonoInlineMethod:
+ case MonoInlineTok:
+ case MonoInlineSig:
+ case MonoShortInlineR:
+ case MonoInlineI:
+ ip += 5;
+ break;
+ case MonoInlineVar:
+ ip += 3;
+ break;
+ case MonoShortInlineVar:
+ case MonoShortInlineI:
+ ip += 2;
+ break;
+ case MonoShortInlineBrTarget:
+ ip++;
+ i = (signed char)*ip;
+ ip++;
+ mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
+ if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+ mono_cfg_add_successor (cfg, bb, cli_addr + 2);
+ break;
+ case MonoInlineBrTarget:
+ ip++;
+ i = read32 (ip);
+ ip += 4;
+ mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
+ if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+ mono_cfg_add_successor (cfg, bb, cli_addr + 5);
+ break;
+ case MonoInlineSwitch: {
+ gint32 st, target, n;
+ ++ip;
+ n = read32 (ip);
+ ip += 4;
+ st = cli_addr + 5 + 4 * n;
+ mono_cfg_add_successor (cfg, bb, st);
+
+ for (i = 0; i < n; i++) {
+ target = read32 (ip) + st;
+ ip += 4;
+ mono_cfg_add_successor (cfg, bb, target);
+ }
+ break;
+ }
+ case MonoInlineR:
+ case MonoInlineI8:
+ ip += 9;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
}
/**
int size, align;
for (i = 0; i < header->num_locals; ++i) {
+ MonoValueType svt;
size = mono_type_size (header->locals [i], &align);
- varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
+ map_ldind_type (header->locals [i], &svt);
+ varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
if (i == 0)
cfg->locals_start_index = varnum;
}
cfg->args_start_index = firstarg = varnum + 1;
if (signature->hasthis) {
- arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+ int thisvar;
+ thisvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+ VARINFO (cfg, thisvar).isvolatile = 1;
}
if (signature->param_count) {
int align, size;
for (i = 0; i < signature->param_count; ++i) {
+ int argvar;
size = mono_type_stack_size (signature->params [i], &align);
- arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+ argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+ VARINFO (cfg, argvar).isvolatile = 1;
}
}
}
if (csig->hasthis) {
- this = *(--sp);
+ this = *(--sp);
args_size += sizeof (gpointer);
} else
this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = LOCAL_POS (*ip);
+ VARINFO (cfg, t1->data.i).isvolatile = 1;
++ip;
PUSH_TREE (t1, VAL_POINTER);
break;
if (sp > stack) {
g_warning ("more values on stack at IL_%04x: %d", ip - header->code, sp - stack);
- mono_print_ctree (sp [-1]);
+ mono_print_ctree (cfg, sp [-1]);
printf ("\n");
}
superblock_end = TRUE;
t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
t1->data.i = LOCAL_POS (read16 (ip));
+ VARINFO (cfg, t1->data.i).isvolatile = 1;
ip += 2;
PUSH_TREE (t1, VAL_POINTER);
break;
cfg->invalid = 1;
return;
}
- mono_print_forest (forest);
+ mono_print_forest (cfg, forest);
g_assert_not_reached ();
}
}
if ((depth = sp - stack)) {
//printf ("DEPTH %d %d\n", depth, sp [0]->op);
- //mono_print_forest (forest);
+ //mono_print_forest (cfg, forest);
create_outstack (cfg, bb, stack, sp - stack);
}
//printf ("unreached block %d\n", i);
repeat = TRUE;
if (repeat_count >= 10) {
- /*mono_print_forest (forest);
+ /*mono_print_forest (cfg, forest);
g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
repeat = FALSE;
}
#define ISSTRUCT(t) (!t->byref && t->type == MONO_TYPE_VALUETYPE && !t->data.klass->enumtype)
-#define VAROFFSET(cfg,num) (g_array_index (cfg->varinfo, MonoVarInfo, num).offset)
+#define VARINFO(cfg,num) (g_array_index (cfg->varinfo, MonoVarInfo, num))
typedef struct _MBTree MBTree;
guint32 eip;
} MonoLMF;
+typedef union {
+ struct {
+ guint16 tid; /* tree number */
+ guint16 bid; /* block number */
+ } pos ;
+ guint32 abs_pos;
+} MonoPosition;
+
+typedef struct {
+ MonoPosition first_use, last_use;
+} MonoLiveRange;
+
typedef struct {
MonoValueType type;
MonoValueKind kind;
int offset;
int size;
+ MonoLiveRange range;
+ unsigned isvolatile:1;
+ int reg;
+ int varnum; /* only for debugging */
} MonoVarInfo;
typedef struct {
unsigned is_block_start:1;
} MonoBytecodeInfo;
+typedef guint32 * MonoBitSet;
+
typedef struct {
unsigned reached:1;
unsigned finished:1;
MBTree **outstack;
gint32 outdepth;
gint32 addr;
+ guint16 num;
+
+ MonoBitSet gen_set;
+ MonoBitSet kill_set;
+ MonoBitSet live_in_set;
+ MonoBitSet live_out_set;
+
+ GList *succ;
} MonoBBlock;
typedef enum {
extern gboolean mono_jit_profile;
extern gboolean mono_jit_share_code;
extern gboolean mono_jit_inline_code;
+extern gboolean mono_use_linear_scan;
+
extern gpointer mono_end_of_stack;
extern int mono_worker_threads;
extern guint32 lmf_thread_id;
arch_allocate_var (MonoFlowGraph *cfg, int size, int align,
MonoValueKind kind, MonoValueType type);
+void
+mono_linear_scan (MonoFlowGraph *cfg, guint32 *used_mask);
+
/* delegate support functions */
void
/* some handy debugging functions */
void
-mono_print_ctree (MBTree *tree);
+mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree);
void
-mono_print_forest (GPtrArray *forest);
+mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest);
#endif
--- /dev/null
+/*
+ * linear-scan.c: linbear scan register allocation
+ *
+ * Authors:
+ * Dietmar Maurer (dietmar@ximian.com)
+ * Miguel de Icaza (miguel@ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "jit.h"
+#include "codegen.h"
+#include "debug.h"
+
+//#define MNAME "nest_test"
+
+#ifdef MNAME
+#define DEGUG_LIVENESS
+#define DEBUG_LSCAN
+#endif
+
+inline static MonoBitSet
+mono_bitset_alloc (MonoFlowGraph *cfg, int n, gboolean use_mempool)
+{
+ if (use_mempool)
+ return (MonoBitSet)mono_mempool_alloc0 (cfg->mp, ((n + 31) >> 5) << 2);
+ else
+ return (MonoBitSet)g_malloc0 (((n + 31) >> 5) << 2);
+}
+
+static void
+mono_bitset_set (MonoBitSet set, int n)
+{
+ int ind = n >> 5;
+ int pos = n & 0x1f;
+ set [ind] |= 1<<pos;
+}
+
+static gboolean
+mono_bitset_inset (MonoBitSet set, int n)
+{
+ int ind = n >> 5;
+ int pos = n & 0x1f;
+
+ if (set [ind] & (1<<pos))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+mono_bitset_unset (MonoBitSet set, int n)
+{
+ int ind = n >> 5;
+ int pos = n & 0x1f;
+
+ set [ind] &= ~(1<<pos);
+}
+
+static void
+mono_bitset_add (MonoBitSet set1, MonoBitSet set2, int len)
+{
+ int i, ind = (len + 31) >> 5;
+
+ for (i = 0; i < ind; i++)
+ set1 [i] |= set2 [i];
+}
+
+static void
+mono_bitset_sub (MonoBitSet set1, MonoBitSet set2, int len)
+{
+ int i, ind = (len + 31) >> 5;
+
+ for (i = 0; i < ind; i++)
+ set1 [i] &= ~(set2 [i]);
+}
+
+static void
+mono_bitset_copy (MonoBitSet set1, MonoBitSet set2, int len)
+{
+ memcpy (set1, set2, (len + 7) >> 3);
+}
+
+static int
+mono_bitset_cmp (MonoBitSet set1, MonoBitSet set2, int len)
+{
+ return memcmp (set1, set2, (len + 7) >> 3);
+}
+
+static void
+mono_bitset_clear (MonoBitSet set, int len)
+{
+ memset (set, 0, (len + 7) >> 3);
+}
+
+static void
+mono_bitset_print (MonoBitSet set, int len)
+{
+ int i;
+
+ printf ("{");
+ for (i = 0; i < len; i++) {
+ int ind = i >> 5;
+ int pos = i & 0x1f;
+
+ if (set [ind] & (1<<pos))
+ printf ("%d, ", i);
+
+ }
+ printf ("}");
+}
+
+static void
+update_live_range (MonoFlowGraph *cfg, int varnum, int block_num, int tree_pos)
+{
+ MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, varnum);
+ guint32 abs_pos = (block_num << 16) | tree_pos;
+
+ if (vi->range.first_use.abs_pos > abs_pos)
+ vi->range.first_use.abs_pos = abs_pos;
+
+ if (vi->range.last_use.abs_pos < abs_pos)
+ vi->range.last_use.abs_pos = abs_pos;
+}
+
+static void
+mono_update_live_info (MonoFlowGraph *cfg)
+{
+ int i, j;
+
+ for (i = 0; i < cfg->block_count; i++) {
+ MonoBBlock *bb = &cfg->bblocks [i];
+
+ for (j = cfg->varinfo->len; j > 0; j--) {
+
+ if (mono_bitset_inset (bb->live_in_set, j))
+ update_live_range (cfg, j, bb->num, 0);
+
+ if (mono_bitset_inset (bb->live_out_set, j))
+ update_live_range (cfg, j, bb->num, bb->forest->len);
+ }
+ }
+}
+
+static void
+update_tree_live_info (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree *tree)
+{
+ if (tree->left)
+ update_tree_live_info (cfg, bb, tree->left);
+ if (tree->right)
+ update_tree_live_info (cfg, bb, tree->right);
+
+ if (tree->op == MB_TERM_ADDR_L)
+ update_live_range (cfg, tree->data.i, bb->num, bb->forest->len);
+}
+
+static void
+update_gen_set (MBTree *tree, MonoBitSet set)
+{
+ if (tree->left) {
+ switch (tree->op) {
+ case MB_TERM_REMOTE_STIND_I1:
+ case MB_TERM_REMOTE_STIND_I2:
+ case MB_TERM_REMOTE_STIND_I4:
+ case MB_TERM_REMOTE_STIND_I8:
+ case MB_TERM_REMOTE_STIND_R4:
+ case MB_TERM_REMOTE_STIND_R8:
+ case MB_TERM_REMOTE_STIND_REF:
+ case MB_TERM_REMOTE_STIND_OBJ:
+ case MB_TERM_STIND_I1:
+ case MB_TERM_STIND_I2:
+ case MB_TERM_STIND_I4:
+ case MB_TERM_STIND_I8:
+ case MB_TERM_STIND_R4:
+ case MB_TERM_STIND_R8:
+ case MB_TERM_STIND_REF:
+ case MB_TERM_STIND_OBJ:
+ if (tree->left->op != MB_TERM_ADDR_L)
+ update_gen_set (tree->left, set);
+ break;
+ default:
+ update_gen_set (tree->left, set);
+ break;
+ }
+ }
+
+ if (tree->right)
+ update_gen_set (tree->right, set);
+
+ if (tree->op == MB_TERM_ADDR_L)
+ mono_bitset_set (set, tree->data.i);
+}
+
+static void
+mono_analyze_liveness (MonoFlowGraph *cfg)
+{
+ MonoBitSet old_live_in_set, old_live_out_set;
+ gboolean changes;
+ GList *l;
+ int i, j , max_vars = cfg->varinfo->len;
+
+#ifdef DEGUG_LIVENESS
+ int debug = !strcmp (cfg->method->name, MNAME);
+ if (debug)
+ printf ("LIVENLESS %s.%s:%s\n", cfg->method->klass->name_space,
+ cfg->method->klass->name, cfg->method->name);
+#endif
+
+ old_live_in_set = mono_bitset_alloc (cfg, max_vars, FALSE);
+ old_live_out_set = mono_bitset_alloc (cfg, max_vars, FALSE);
+
+ for (i = 0; i < cfg->block_count; i++) {
+ MonoBBlock *bb = &cfg->bblocks [i];
+
+ bb->gen_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+ bb->kill_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+ bb->live_in_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+ bb->live_out_set = mono_bitset_alloc (cfg, max_vars, TRUE);
+
+ for (j = 0; j < bb->forest->len; j++) {
+ MBTree *t1 = (MBTree *) g_ptr_array_index (bb->forest, j);
+
+ update_tree_live_info (cfg, bb, t1);
+
+ mono_bitset_clear (old_live_in_set, max_vars);
+ update_gen_set (t1, old_live_in_set);
+ mono_bitset_sub (old_live_in_set, bb->kill_set, max_vars);
+ mono_bitset_add (bb->gen_set, old_live_in_set, max_vars);
+
+ switch (t1->op) {
+ case MB_TERM_REMOTE_STIND_I1:
+ case MB_TERM_REMOTE_STIND_I2:
+ case MB_TERM_REMOTE_STIND_I4:
+ case MB_TERM_REMOTE_STIND_I8:
+ case MB_TERM_REMOTE_STIND_R4:
+ case MB_TERM_REMOTE_STIND_R8:
+ case MB_TERM_REMOTE_STIND_REF:
+ case MB_TERM_REMOTE_STIND_OBJ:
+ case MB_TERM_STIND_I1:
+ case MB_TERM_STIND_I2:
+ case MB_TERM_STIND_I4:
+ case MB_TERM_STIND_I8:
+ case MB_TERM_STIND_R4:
+ case MB_TERM_STIND_R8:
+ case MB_TERM_STIND_REF:
+ case MB_TERM_STIND_OBJ:
+ if (t1->left->op == MB_TERM_ADDR_L)
+ mono_bitset_set (bb->kill_set, t1->left->data.i);
+ break;
+ }
+ }
+
+#ifdef DEGUG_LIVENESS
+ if (debug) {
+ printf ("BLOCK %d (", bb->num);
+ for (l = bb->succ; l; l = l->next) {
+ MonoBBlock *t = (MonoBBlock *)l->data;
+ printf ("%d, ", t->num);
+ }
+ printf (")\n");
+ printf ("GEN %d: ", i); mono_bitset_print (bb->gen_set, max_vars); printf ("\n");
+ printf ("KILL %d: ", i); mono_bitset_print (bb->kill_set, max_vars); printf ("\n");
+ }
+#endif
+ }
+
+ do {
+ changes = FALSE;
+ for (i = 0; i < cfg->block_count; i++) {
+ MonoBBlock *bb = &cfg->bblocks [i];
+
+ mono_bitset_copy (old_live_in_set, bb->live_in_set, max_vars);
+ mono_bitset_copy (old_live_out_set, bb->live_out_set, max_vars);
+
+ mono_bitset_copy (bb->live_in_set, bb->live_out_set, max_vars);
+ mono_bitset_sub (bb->live_in_set, bb->kill_set, max_vars);
+ mono_bitset_add (bb->live_in_set, bb->gen_set, max_vars);
+
+ mono_bitset_clear (bb->live_out_set, max_vars);
+
+ for (l = bb->succ; l; l = l->next) {
+ MonoBBlock *t = (MonoBBlock *)l->data;
+ mono_bitset_add (bb->live_out_set, t->live_in_set, max_vars);
+ }
+
+ if (mono_bitset_cmp (old_live_in_set, bb->live_in_set, max_vars) ||
+ mono_bitset_cmp (old_live_out_set, bb->live_out_set, max_vars))
+ changes = TRUE;
+
+ }
+
+ } while (changes);
+
+ g_free (old_live_in_set);
+ g_free (old_live_out_set);
+
+
+#ifdef DEGUG_LIVENESS
+ if (debug) {
+ for (i = 0; i < cfg->block_count; i++) {
+ MonoBBlock *bb = &cfg->bblocks [i];
+
+ printf ("LIVE IN %d: ", i);
+ mono_bitset_print (bb->live_in_set, max_vars);
+ printf ("\n");
+ printf ("LIVE OUT %d: ", i);
+ mono_bitset_print (bb->live_out_set, max_vars);
+ printf ("\n");
+ }
+ }
+#endif
+}
+
+static GList *
+mono_varlist_insert_sorted (GList *list, MonoVarInfo *vi, gboolean sort_end)
+{
+ GList *l;
+
+ if (!list)
+ return g_list_prepend (NULL, vi);
+
+ for (l = list; l; l = l->next) {
+ MonoVarInfo *v = (MonoVarInfo *)l->data;
+
+ if (sort_end) {
+ if (vi->range.last_use.abs_pos <= v->range.last_use.abs_pos) {
+ list = g_list_insert_before (list, l, vi);
+ break;
+ }
+ } else {
+ if (vi->range.first_use.abs_pos <= v->range.first_use.abs_pos) {
+ list = g_list_insert_before (list, l, vi);
+ break;
+ }
+ }
+ }
+ if (!l)
+ list = g_list_append (list, vi);
+
+ return list;
+}
+
+void
+mono_linear_scan (MonoFlowGraph *cfg, guint32 *used_mask)
+{
+ GList *l, *ranges = NULL;
+ GList *active = NULL;
+ GList *regs = NULL;
+ int i, max_regs;
+
+#ifdef DEBUG_LSCAN
+ MonoMethod *m = cfg->method;
+ int debug = !strcmp (cfg->method->name, MNAME);
+
+ if (debug)
+ printf ("VARINFO for %s.%s:%s\n", m->klass->name_space, m->klass->name, m->name);
+#endif
+
+ mono_analyze_liveness (cfg);
+ mono_update_live_info (cfg);
+
+ for (i = 1; i < cfg->varinfo->len; i++) {
+ MonoVarInfo *vi = &g_array_index (cfg->varinfo, MonoVarInfo, i);
+
+ /* unused vars */
+ if (vi->range.first_use.abs_pos > vi->range.last_use.abs_pos)
+ continue;
+
+ /* we can only allocate 32 bit values */
+ if (vi->isvolatile || (vi->type != VAL_I32 && vi->type != VAL_POINTER))
+ continue;
+
+ ranges = mono_varlist_insert_sorted (ranges, vi, FALSE);
+
+ }
+
+#ifdef DEBUG_LSCAN
+ if (debug) {
+ for (l = ranges; l; l = l->next) {
+ MonoVarInfo *vi = (MonoVarInfo *)l->data;
+
+ printf ("VAR %d %08x %08x\n", vi->varnum, vi->range.first_use.abs_pos,
+ vi->range.last_use.abs_pos);
+ }
+ }
+#endif
+
+ /* we can use 2 registers for global allocation */
+ regs = g_list_prepend (regs, (gpointer)X86_EBX);
+ regs = g_list_prepend (regs, (gpointer)X86_ESI);
+
+ max_regs = g_list_length (regs);
+
+ /* linear scan */
+
+ for (l = ranges; l; l = l->next) {
+ MonoVarInfo *vi = (MonoVarInfo *)l->data;
+
+#ifdef DEBUG_LSCAN
+ if (debug)
+ printf ("START %2d %08x %08x\n", vi->varnum, vi->range.first_use.abs_pos,
+ vi->range.last_use.abs_pos);
+#endif
+ /* expire old intervals in active */
+ while (active) {
+ MonoVarInfo *v = (MonoVarInfo *)active->data;
+
+ if (v->range.last_use.abs_pos >= vi->range.first_use.abs_pos)
+ break;
+
+#ifdef DEBUG_LSCAN
+ if (debug)
+ printf ("EXPIR %2d %08x %08x\n", v->varnum,
+ v->range.first_use.abs_pos, v->range.last_use.abs_pos);
+#endif
+ active = g_list_remove_link (active, active);
+ regs = g_list_prepend (regs, (gpointer)v->reg);
+ }
+
+ if (active && g_list_length (active) == max_regs) {
+ /* Spill */
+
+ GList *a = g_list_nth (active, max_regs - 1);
+ MonoVarInfo *v = (MonoVarInfo *)a->data;
+
+ if (v->range.last_use.abs_pos > vi->range.last_use.abs_pos) {
+ vi->reg = v->reg;
+ v->reg = -1;
+ active = g_list_remove_link (active, a);
+ active = mono_varlist_insert_sorted (active, vi, TRUE);
+#ifdef DEBUG_LSCAN
+ if (debug)
+ printf ("SPILL0 %2d %08x %08x\n", v->varnum,
+ v->range.first_use.abs_pos, v->range.last_use.abs_pos);
+#endif
+ } else {
+#ifdef DEBUG_LSCAN
+ if (debug)
+ printf ("SPILL1 %2d %08x %08x\n", vi->varnum,
+ vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
+#endif
+ vi->reg = -1;
+ }
+ } else {
+ /* assign register */
+
+ g_assert (regs);
+
+ vi->reg = (int)regs->data;
+
+ *used_mask |= 1 << vi->reg;
+
+ regs = g_list_remove_link (regs, regs);
+
+#ifdef DEBUG_LSCAN
+ if (debug)
+ printf ("ADD %2d %08x %08x\n", vi->varnum,
+ vi->range.first_use.abs_pos, vi->range.last_use.abs_pos);
+#endif
+ active = mono_varlist_insert_sorted (active, vi, TRUE);
+ }
+
+
+#ifdef DEBUG_LSCAN
+ if (debug) {
+ GList *a;
+ for (a = active; a; a = a->next) {
+ MonoVarInfo *v = (MonoVarInfo *)a->data;
+
+ printf ("ACT %2d %08x %08x %d\n", v->varnum,
+ v->range.first_use.abs_pos, v->range.last_use.abs_pos, v->reg);
+ }
+ printf ("NEXT\n");
+ }
+#endif
+ }
+
+ g_list_free (regs);
+ g_list_free (active);
+ g_list_free (ranges);
+
+}
+
"--dwarf-plus write extended dwarf2 debug information\n"
"--stats print statistics about the jit operations\n"
"--noinline do not inline code\n"
+ "--ls use linear scan register allocation\n"
"--compile cname compile methods in given class (namespace.name[:methodname])\n"
"--ncompile num compile methods num times (default: 1000)\n"
"--debug name insert a breakpoint at the start of method name\n"
mono_jit_share_code = TRUE;
else if (strcmp (argv [i], "--noinline") == 0)
mono_jit_inline_code = FALSE;
+ else if (strcmp (argv [i], "--ls") == 0)
+ mono_use_linear_scan = TRUE;
else if (strcmp (argv [i], "--print-vtable") == 0)
mono_print_vtable = TRUE;
else if (strcmp (argv [i], "--debug") == 0) {
if (!vc) {
vc = buf = g_malloc (256);
-
/* save caller save regs because we need to do a call */
x86_push_reg (buf, X86_EDX);
x86_push_reg (buf, X86_EAX);
x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 3*4); \
x86_pop_reg (s->code, X86_ECX); \
x86_pop_reg (s->code, X86_EDX); \
-x86_pop_reg (s->code, X86_EAX);
+x86_pop_reg (s->code, X86_EAX);
#ifdef DEBUG
#define MEMCOPY debug_memcpy
}
base: ADDR_L {
- tree->data.ainfo.offset = VAROFFSET (s, tree->data.i);
+ tree->data.ainfo.offset = VARINFO (s, tree->data.i).offset;
tree->data.ainfo.basereg = X86_EBP;
tree->data.ainfo.amode = AMBase;
+} cost {
+ MBCOND (VARINFO (data, tree->data.i).reg < 0);
+ return 0;
}
index: reg {
# we pass exception in ECX to catch handler
reg: EXCEPTION {
- int offset = VAROFFSET (s, tree->data.i);
+ int offset = VARINFO (s, tree->data.i).offset;
if (tree->reg1 != X86_ECX)
x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
}
stmt: RETHROW {
- int off = VAROFFSET (s, tree->data.i);
+ int off = VARINFO (s, tree->data.i).offset;
gpointer target;
x86_push_membase (s->code, X86_EBP, off);
x86_patch (br [1], s->code);
}
+stmt: STIND_I4 (ADDR_L, reg) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->right->reg1)
+ x86_mov_reg_reg (s->code, treg, tree->right->reg1, 4);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+stmt: STIND_I4 (ADDR_L, coni4) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ x86_mov_reg_imm (s->code, treg, tree->right->data.i);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+reg: LDIND_I4 (ADDR_L) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+reg: LDIND_U4 (ADDR_L) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+stmt: STIND_REF (ADDR_L, reg) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->right->reg1)
+ x86_mov_reg_reg (s->code, treg, tree->right->reg1, 4);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+stmt: STIND_REF (ADDR_L, coni4) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->right->reg1)
+ x86_mov_reg_imm (s->code, treg, tree->right->data.i);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
+reg: LDIND_REF (ADDR_L) {
+ int treg = VARINFO (s, tree->left->data.i).reg;
+
+ if (treg != tree->reg1)
+ x86_mov_reg_reg (s->code, tree->reg1, treg, 4);
+
+} cost {
+ MBCOND ((VARINFO (data, tree->left->data.i).reg >= 0));
+ return 0;
+}
+
reg: LDIND_I4 (addr) {
switch (tree->left->data.ainfo.amode) {
x86_pop_reg (s->code, treg);
}
-reg: ADDR_L 5 {
- int offset = VAROFFSET (s, tree->data.i);
+reg: ADDR_L {
+ int offset = VARINFO (s, tree->data.i).offset;
x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
PRINT_REG ("ADDR_L", tree->reg1);
+} cost {
+ MBCOND (VARINFO (data, tree->data.i).reg < 0);
+ return 5;
}
x86_alu_reg_imm (s->code, X86_CMP, tree->left->reg1, tree->right->data.i);
}
-cflags: COMPARE (LDIND_I4 (ADDR_L), coni4) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (LDIND_U4 (ADDR_L), coni4) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (LDIND_REF (ADDR_L), coni4) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_imm (s->code, X86_CMP, X86_EBP, offset, tree->right->data.i);
-}
-
-cflags: COMPARE (reg, LDIND_I4 (ADDR_L)) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->right->left->data.i);
- x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (reg, LDIND_U4 (ADDR_L)) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->right->left->data.i);
- x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (reg, LDIND_REF (ADDR_L)) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->right->left->data.i);
- x86_alu_reg_membase (s->code, X86_CMP, tree->left->reg1, X86_EBP, offset);
-}
-
-cflags: COMPARE (LDIND_I4 (ADDR_L), reg) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
-cflags: COMPARE (LDIND_U4 (ADDR_L), reg) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
-cflags: COMPARE (LDIND_REF (ADDR_L), reg) "MB_USE_OPT1(0)" {
- int offset = VAROFFSET (s, tree->left->left->data.i);
- x86_alu_membase_reg (s->code, X86_CMP, X86_EBP, offset, tree->right->reg1);
-}
-
cflags: COMPARE (reg, reg) {
x86_alu_reg_reg (s->code, X86_CMP, tree->left->reg1, tree->right->reg1);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
tree->right->reg2, 4);
break;
}
-
}
stmt: REMOTE_STIND_I8 (reg, lreg) {
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
stmt: POP (freg)
stmt: STIND_R4 (ADDR_L, freg) {
- int offset = VAROFFSET (s, tree->left->data.i);
+ int offset = VARINFO (s, tree->left->data.i).offset;
x86_fst_membase (s->code, X86_EBP, offset, FALSE, TRUE);
}
}
stmt: STIND_R8 (ADDR_L, freg) {
- int offset = VAROFFSET (s, tree->left->data.i);
+ int offset = VARINFO (s, tree->left->data.i).offset;
x86_fst_membase (s->code, X86_EBP, offset, TRUE, TRUE);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
}
if (tree->data.ci.vtype_num) {
- int offset = VAROFFSET (s, tree->data.ci.vtype_num);
+ int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
x86_lea_membase (s->code, treg, X86_EBP, offset);
x86_push_reg (s->code, treg);
}
stmt: STIND_OBJ (reg, reg) {
mono_assert (tree->data.i > 0);
+
x86_push_imm (s->code, tree->data.i);
x86_push_reg (s->code, tree->right->reg1);
x86_push_reg (s->code, tree->left->reg1);