Hello Zoltan,
Here is another patch for mono on Linux/Alpha.
Changes are:
- Implemented passing of valuetypes in registers (taken from ia64
version) as requred by ABI
(invoking of native methods works, invoking of managed methods from
native code - fails)
- Enable inline optimization for arch
- Implemented generics handling
- Code cleanup
Now mono on Linux/Alpha builds libraries for both profiles (1.1, 2.0).
I was able to build gtk-sharp/gtk-sharp2 RPM packages and run sample
programs from them.
Suprisely, they worked. :)
Thank you,
--
Sergey Tikhonov
Solvo Ltd.
Saint-Petersburg, Russia
[EMAIL PROTECTED]
Index: mono/mono/mini/mini-alpha.c
===================================================================
--- mono/mono/mini/mini-alpha.c (revision 65696)
+++ mono/mono/mini/mini-alpha.c (working copy)
@@ -34,7 +34,14 @@
insert_after_ins (bb, last_ins, (dest)); \
} while (0)
+#define NEW_ICONST(cfg,dest,val) do { \
+ (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ (dest)->opcode = OP_ICONST;
\
+ (dest)->inst_c0 = (val); \
+ (dest)->type = STACK_I4; \
+ } while (0)
+
#undef DEBUG
#define DEBUG(a) if (cfg->verbose_level > 1) a
@@ -95,24 +102,23 @@
typedef enum {
ArgInIReg,
- ArgInFloatSSEReg,
- ArgInDoubleSSEReg,
+ ArgInFloatReg,
+ ArgInDoubleReg,
ArgOnStack,
- ArgValuetypeInReg,
-// ArgOnFloatFpStack,
-// ArgOnDoubleFpStack,
+ ArgValuetypeInReg, // ??
+ ArgAggregate,
ArgNone
} ArgStorage;
typedef struct {
- gint16 offset;
- gint8 reg;
- ArgStorage storage;
+ gint16 offset;
+ gint8 reg;
+ ArgStorage storage;
- /* Only if storage == ArgValuetypeInReg */
- ArgStorage pair_storage [2];
- gint8 pair_regs [2];
+ /* Only if storage == ArgAggregate */
+ int nregs, nslots;
+ //AggregateType atype; // So far use only AggregateNormal
} ArgInfo;
typedef struct {
@@ -180,9 +186,10 @@
{
/* A double register */
if (is_double)
- ainfo->storage = ArgInDoubleSSEReg;
+ ainfo->storage = ArgInDoubleReg;
else
- ainfo->storage = ArgInFloatSSEReg;
+ ainfo->storage = ArgInFloatReg;
+
ainfo->reg = fparam_regs [*gr];
(*gr) += 1;
}
@@ -207,7 +214,7 @@
else
size = mono_type_stack_size (&klass->byval_arg, NULL);
- if (!sig->pinvoke || (size == 0)) {
+ if (!sig->pinvoke || (size == 0) || is_return) {
/* Allways pass in memory */
ainfo->offset = *stack_size;
*stack_size += ALIGN_TO (size, 8);
@@ -216,18 +223,40 @@
return;
}
- info = mono_marshal_load_type_info (klass);
- g_assert (info);
- if (info->native_size/* > 16*/) {
- ainfo->offset = *stack_size;
- *stack_size += ALIGN_TO (info->native_size, 8);
- ainfo->storage = ArgOnStack;
+ info = mono_marshal_load_type_info (klass);
+ g_assert (info);
- return;
- }
+ ainfo->storage = ArgAggregate;
+ //ainfo->atype = AggregateNormal;
+#if 0
+ /* This also handles returning of TypedByRef used by some icalls */
+ if (is_return) {
+ if (size <= 32) {
+ ainfo->reg = IA64_R8;
+ ainfo->nregs = (size + 7) / 8;
+ ainfo->nslots = ainfo->nregs;
+ return;
+ }
+ NOT_IMPLEMENTED;
+ }
+#endif
- NOT_IMPLEMENTED("add_valuetype: more");
+ ainfo->reg = param_regs [*gr];
+ ainfo->offset = *stack_size;
+ ainfo->nslots = (size + 7) / 8;
+
+ if (((*gr) + ainfo->nslots) <= 6) {
+ /* Fits entirely in registers */
+ ainfo->nregs = ainfo->nslots;
+ (*gr) += ainfo->nregs;
+ return;
+ }
+
+ ainfo->nregs = 6 - (*gr);
+ (*gr) = 6;
+ (*stack_size) += (ainfo->nslots - ainfo->nregs) * 8;
+
}
// This function is called from mono_arch_call_opcode and
@@ -237,7 +266,7 @@
// that will be used in calls
static void
add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg,
- ArgStorage storage, int reg, MonoInst *tree)
+ ArgStorage storage, int reg, MonoInst *tree)
{
switch (storage)
{
@@ -248,14 +277,14 @@
arg->unused = reg;
call->used_iregs |= 1 << reg;
break;
- case ArgInFloatSSEReg:
+ case ArgInFloatReg:
arg->opcode = OP_OUTARG_FREG;
arg->inst_left = tree;
arg->inst_right = (MonoInst*)call;
arg->unused = reg;
call->used_fregs |= 1 << reg;
break;
- case ArgInDoubleSSEReg:
+ case ArgInDoubleReg:
arg->opcode = OP_OUTARG_FREG;
arg->inst_left = tree;
arg->inst_right = (MonoInst*)call;
@@ -1344,8 +1373,8 @@
}
//}
break;
- case ArgInDoubleSSEReg:
- case ArgInFloatSSEReg:
+ case ArgInDoubleReg:
+ case ArgInFloatReg:
// We need to save all used af0-af5 params
//for (i=0; i<PARAM_REGS; i++)
// {
@@ -1353,11 +1382,11 @@
{
switch(cinfo->args[i].storage)
{
- case ArgInFloatSSEReg:
+ case ArgInFloatReg:
//alpha_sts(code, ainfo->reg, alpha_fp, offset);
alpha_lds(code, ainfo->reg, inst->inst_basereg,
inst->inst_offset);
break;
- case ArgInDoubleSSEReg:
+ case ArgInDoubleReg:
//alpha_stt(code, ainfo->reg, alpha_fp, offset);
alpha_ldt(code, ainfo->reg, inst->inst_basereg,
inst->inst_offset);
break;
@@ -1495,8 +1524,8 @@
}
//}
break;
- case ArgInDoubleSSEReg:
- case ArgInFloatSSEReg:
+ case ArgInDoubleReg:
+ case ArgInFloatReg:
// We need to save all used af0-af5 params
//for (i=0; i<PARAM_REGS; i++)
// {
@@ -1504,11 +1533,11 @@
{
switch(cinfo->args[i].storage)
{
- case ArgInFloatSSEReg:
+ case ArgInFloatReg:
//alpha_sts(code, ainfo->reg, alpha_fp, offset);
alpha_sts(code, ainfo->reg, inst->inst_basereg,
inst->inst_offset);
break;
- case ArgInDoubleSSEReg:
+ case ArgInDoubleReg:
//alpha_stt(code, ainfo->reg, alpha_fp, offset);
alpha_stt(code, ainfo->reg, inst->inst_basereg,
inst->inst_offset);
break;
@@ -3789,8 +3818,8 @@
/*----------------------------------------------------------*/
/* no alpha-specific optimizations yet */
/*----------------------------------------------------------*/
- *exclude_mask = MONO_OPT_INLINE|MONO_OPT_LINEARS;
- // *exclude_mask = MONO_OPT_INLINE;
+ *exclude_mask = MONO_OPT_LINEARS;
+ // *exclude_mask = MONO_OPT_INLINE|MONO_OPT_INLINE;
return opts;
}
@@ -4186,7 +4215,7 @@
static CallInfo*
get_call_info (MonoMethodSignature *sig, gboolean is_pinvoke)
{
- guint32 i, gr, fr;
+ guint32 i, gr, fr, *pgr, *pfr;
MonoType *ret_type;
int n = sig->hasthis + sig->param_count;
guint32 stack_size = 0;
@@ -4197,6 +4226,14 @@
gr = 0;
fr = 0;
+ if (is_pinvoke)
+ pgr = pfr = &gr;
+ else
+ {
+ pgr = &gr;
+ pfr = &fr;
+ }
+
/* return value */
{
ret_type = mono_type_get_underlying_type (sig->ret);
@@ -4227,13 +4264,21 @@
cinfo->ret.reg = alpha_r0;
break;
case MONO_TYPE_R4:
- cinfo->ret.storage = ArgInFloatSSEReg;
+ cinfo->ret.storage = ArgInFloatReg;
cinfo->ret.reg = alpha_f0;
break;
case MONO_TYPE_R8:
- cinfo->ret.storage = ArgInDoubleSSEReg;
+ cinfo->ret.storage = ArgInDoubleReg;
cinfo->ret.reg = alpha_f0;
break;
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (sig->ret))
+ {
+ cinfo->ret.storage = ArgInIReg;
+ cinfo->ret.reg = alpha_r0;
+ break;
+ }
+ /* Fall through */
case MONO_TYPE_VALUETYPE:
{
guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
@@ -4244,25 +4289,24 @@
if (cinfo->ret.storage == ArgOnStack)
/* The caller passes the address where the value
is stored */
- add_general (&gr, &stack_size, &cinfo->ret);
+ add_general (pgr, &stack_size, &cinfo->ret);
break;
}
case MONO_TYPE_TYPEDBYREF:
/* Same as a valuetype with size 24 */
- add_general (&gr, &stack_size, &cinfo->ret);
+ add_general (pgr, &stack_size, &cinfo->ret);
;
break;
case MONO_TYPE_VOID:
break;
default:
- g_error ("Can't handle as return value 0x%x", sig->ret->
- type);
+ g_error ("Can't handle as return value 0x%x", sig->ret->type);
}
}
/* this */
if (sig->hasthis)
- add_general (&gr, &stack_size, cinfo->args + 0);
+ add_general (pgr, &stack_size, cinfo->args + 0);
if (!sig->pinvoke &&
(sig->call_convention == MONO_CALL_VARARG) && (n == 0))
@@ -4272,7 +4316,7 @@
/* Emit the signature cookie just before the implicit arguments
*/
- add_general (&gr, &stack_size, &cinfo->sig_cookie);
+ add_general (pgr, &stack_size, &cinfo->sig_cookie);
}
for (i = 0; i < sig->param_count; ++i)
@@ -4294,11 +4338,11 @@
fr = FLOAT_PARAM_REGS;
/* Emit the signature cookie just before the implicit arguments */
- add_general (&gr, &stack_size, &cinfo->sig_cookie);
+ add_general (pgr, &stack_size, &cinfo->sig_cookie);
}
if (sig->params [i]->byref) {
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
continue;
}
@@ -4308,16 +4352,16 @@
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_I1:
case MONO_TYPE_U1:
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
break;
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
break;
case MONO_TYPE_I4:
case MONO_TYPE_U4:
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
break;
case MONO_TYPE_I:
case MONO_TYPE_U:
@@ -4328,11 +4372,20 @@
case MONO_TYPE_STRING:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
break;
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (sig->params [i]))
+ {
+ add_general (pgr, &stack_size, ainfo);
+ break;
+ }
+ /* Fall through */
case MONO_TYPE_VALUETYPE:
+ /* FIXME: */
+ /* We allways pass valuetypes on the stack */
add_valuetype (sig, ainfo, sig->params [i],
- FALSE, &gr, &fr, &stack_size);
+ FALSE, pgr, pfr, &stack_size);
break;
case MONO_TYPE_TYPEDBYREF:
stack_size += sizeof (MonoTypedRef);
@@ -4340,13 +4393,13 @@
break;
case MONO_TYPE_U8:
case MONO_TYPE_I8:
- add_general (&gr, &stack_size, ainfo);
+ add_general (pgr, &stack_size, ainfo);
break;
case MONO_TYPE_R4:
- add_float (&fr, &stack_size, ainfo, FALSE);
+ add_float (pfr, &stack_size, ainfo, FALSE);
break;
case MONO_TYPE_R8:
- add_float (&fr, &stack_size, ainfo, TRUE);
+ add_float (pfr, &stack_size, ainfo, TRUE);
break;
default:
g_assert_not_reached ();
@@ -4361,7 +4414,7 @@
/* Emit the signature cookie just before the implicit arguments
*/
- add_general (&gr, &stack_size, &cinfo->sig_cookie);
+ add_general (pgr, &stack_size, &cinfo->sig_cookie);
}
cinfo->stack_usage = stack_size;
@@ -4584,27 +4637,126 @@
else
size = mono_type_stack_size (&in->klass->byval_arg, &align);
- {
- MonoInst *stack_addr;
+ if (ainfo->storage == ArgAggregate)
+ {
+ MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
+ int slot, j;
- CFG_DEBUG(3) g_print("value type, size:%d\n", size);
+ CFG_DEBUG(3) g_print("aggregate value type, size:%d\n", size);
- MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
- stack_addr->inst_basereg = alpha_sp;
- //stack_addr->inst_offset = -(cinfo->stack_usage -
ainfo->offset);
- stack_addr->inst_offset = ainfo->offset;
- //stack_addr->inst_offset = 16 + ainfo->offset;
- stack_addr->inst_imm = size;
+ vtaddr = mono_compile_create_var (cfg,
+ &mono_defaults.int_class->byval_arg, OP_LOCAL);
- arg->opcode = OP_OUTARG_VT;
- arg->inst_right = stack_addr;
- }
+ /*
+ * Part of the structure is passed in registers.
+ */
+ for (j = 0; j < ainfo->nregs; ++j)
+ {
+ int offset, load_op, dest_reg, arg_storage;
+ slot = ainfo->reg + j;
+ load_op = CEE_LDIND_I;
+ offset = j * 8;
+ dest_reg = ainfo->reg + j;
+ arg_storage = ArgInIReg;
+
+ MONO_INST_NEW (cfg, load, CEE_LDIND_I);
+ load->ssa_op = MONO_SSA_LOAD;
+ load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
+
+ NEW_ICONST (cfg, offset_ins, offset);
+ MONO_INST_NEW (cfg, load2, CEE_ADD);
+ load2->inst_left = load;
+ load2->inst_right = offset_ins;
+
+ MONO_INST_NEW (cfg, load, load_op);
+ load->inst_left = load2;
+
+ if (j == 0)
+ set_reg = arg;
+ else
+ MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
+
+ add_outarg_reg (cfg, call, set_reg, arg_storage,
+ dest_reg, load);
+ if (set_reg != call->out_args)
+ {
+ set_reg->next = call->out_args;
+ call->out_args = set_reg;
+ }
+ }
+
+ /*
+ * Part of the structure is passed on the stack.
+ */
+ for (j = ainfo->nregs; j < ainfo->nslots; ++j)
+ {
+ MonoInst *outarg;
+
+ slot = ainfo->reg + j;
+
+ MONO_INST_NEW (cfg, load, CEE_LDIND_I);
+ load->ssa_op = MONO_SSA_LOAD;
+ load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
+
+ NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
+ MONO_INST_NEW (cfg, load2, CEE_ADD);
+ load2->inst_left = load;
+ load2->inst_right = offset_ins;
+
+ MONO_INST_NEW (cfg, load, CEE_LDIND_I);
+ load->inst_left = load2;
+
+ if (j == 0)
+ outarg = arg;
+ else
+ MONO_INST_NEW (cfg, outarg, OP_OUTARG);
+
+ outarg->inst_left = load;
+ //outarg->inst_imm = 16 + ainfo->offset + (slot - 8) * 8;
+ outarg->dreg = ainfo->offset + (slot - 22) * 8;
+
+ if (outarg != call->out_args)
+ {
+ outarg->next = call->out_args;
+ call->out_args = outarg;
+ }
+ }
+
+ /* Trees can't be shared so make a copy*/
+ MONO_INST_NEW (cfg, arg, CEE_STIND_I);
+ arg->cil_code = in->cil_code;
+ arg->ssa_op = MONO_SSA_STORE;
+ arg->inst_left = vtaddr;
+ arg->inst_right = in;
+ arg->type = in->type;
+
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
+ }
+ else
+ {
+ MonoInst *stack_addr;
+
+ CFG_DEBUG(3) g_print("value type, size:%d\n", size);
+
+ MONO_INST_NEW (cfg, stack_addr, OP_REGOFFSET);
+ stack_addr->inst_basereg = alpha_sp;
+ //stack_addr->inst_offset = -(cinfo->stack_usage -
ainfo->offset);
+ stack_addr->inst_offset = ainfo->offset;
+ //stack_addr->inst_offset = 16 + ainfo->offset;
+ stack_addr->inst_imm = size;
+
+ arg->opcode = OP_OUTARG_VT;
+ arg->inst_right = stack_addr;
+ }
+
/*
- arg->opcode = OP_OUTARG_VT;
- arg->klass = in->klass;
- arg->unused = sig->pinvoke;
- arg->inst_imm = size; */
+ arg->opcode = OP_OUTARG_VT;
+ arg->klass = in->klass;
+ arg->unused = sig->pinvoke;
+ arg->inst_imm = size; */
}
else
{
@@ -4630,8 +4782,8 @@
arg->opcode = OP_OUTARG_R8;
}
break;
- case ArgInFloatSSEReg:
- case ArgInDoubleSSEReg:
+ case ArgInFloatReg:
+ case ArgInDoubleReg:
add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg,
in);
break;
default:
@@ -4641,35 +4793,36 @@
}
}
- if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
- if (cinfo->ret.storage == ArgValuetypeInReg) {
- MonoInst *zero_inst;
- /*
- * After the call, the struct is in registers, but needs to be saved to
the
- memory pointed
- * to by vt_arg in this_vret_args. This means that vt_ar
- g needs to be saved somewhere
- * before calling the function. So we add a dummy instru
- ction to represent pushing the
- * struct return address to the stack. The return addres
- s will be saved to this stack slot
- * by the code emitted in this_vret_args.
- */
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
- zero_inst->inst_p0 = 0;
- arg->inst_left = zero_inst;
- arg->type = STACK_PTR;
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
+ if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
+ {
+ if (cinfo->ret.storage == ArgValuetypeInReg) {
+ MonoInst *zero_inst;
+ /*
+ * After the call, the struct is in registers, but needs to be saved
+ to the memory pointed
+ * to by vt_arg in this_vret_args. This means that vt_ar
+ g needs to be saved somewhere
+ * before calling the function. So we add a dummy instru
+ ction to represent pushing the
+ * struct return address to the stack. The return addres
+ s will be saved to this stack slot
+ * by the code emitted in this_vret_args.
+ */
+ MONO_INST_NEW (cfg, arg, OP_OUTARG);
+ MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
+ zero_inst->inst_p0 = 0;
+ arg->inst_left = zero_inst;
+ arg->type = STACK_PTR;
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
+ }
+ else
+ /* if the function returns a struct, the called method a
+ lready does a ret $0x4 */
+ if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
+ ; //cinfo->stack_usage -= 4;
}
- else
- /* if the function returns a struct, the called method a
- lready does a ret $0x4 */
- if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
- ; //cinfo->stack_usage -= 4;
- }
// stack_usage shows how much stack we would need to do the call
// (for example for params that we pass on stack
@@ -5004,10 +5157,10 @@
{
switch(cinfo->args[i].storage)
{
- case ArgInDoubleSSEReg:
+ case ArgInDoubleReg:
alpha_stt(code, inst->dreg, alpha_sp, (i*8));
break;
- case ArgInFloatSSEReg:
+ case ArgInFloatReg:
alpha_sts(code, inst->dreg, alpha_sp, (i*8));
break;
default:
@@ -5280,8 +5433,8 @@
switch (cinfo->ret.storage)
{
case ArgInIReg:
- case ArgInFloatSSEReg:
- case ArgInDoubleSSEReg:
+ case ArgInFloatReg:
+ case ArgInDoubleReg:
if ((MONO_TYPE_ISSTRUCT (sig->ret) &&
!mono_class_from_mono_type (sig->ret)->enumtype) ||
(sig->ret->type == MONO_TYPE_TYPEDBYREF))
@@ -5393,7 +5546,8 @@
CFG_DEBUG(3) g_print ("ALPHA: args_save_area_offset at %d(%x)\n", offset,
offset);
- for (i = 0; i < PARAM_REGS; ++i)
+ // Consider floats passed in regs too
+ for (i = 0; i < (PARAM_REGS*2); ++i)
if (i < (sig->param_count + sig->hasthis))
//(cfg->used_int_regs & (1 << param_regs[i])))
{
@@ -5436,8 +5590,8 @@
inreg = FALSE;
if (//(ainfo->storage == ArgInIReg) ||
- (ainfo->storage == ArgInFloatSSEReg) ||
- (ainfo->storage == ArgInDoubleSSEReg) ||
+ (ainfo->storage == ArgInFloatReg) ||
+ (ainfo->storage == ArgInDoubleReg) ||
(ainfo->storage == ArgValuetypeInReg))
inreg = FALSE;
@@ -5446,8 +5600,8 @@
switch (ainfo->storage)
{
case ArgInIReg:
- case ArgInFloatSSEReg:
- case ArgInDoubleSSEReg:
+ case ArgInFloatReg:
+ case ArgInDoubleReg:
inst->opcode = OP_REGVAR;
inst->dreg = ainfo->reg;
break;
@@ -5463,6 +5617,10 @@
break;
case ArgValuetypeInReg:
break;
+ case ArgAggregate:
+ inreg = FALSE;
+ break;
+
default:
NOT_IMPLEMENTED("");
}
@@ -5483,8 +5641,14 @@
// 2 * sizeof (gpointer) : sizeof (gpointer);
inst->inst_offset = cfg->arch.args_save_area_offset + a_off;
- a_off += 8;
-
+ switch(ainfo->storage)
+ {
+ case ArgAggregate:
+ a_off += ainfo->nslots * 8;
+ break;
+ default:
+ a_off += sizeof (gpointer);
+ }
// (/*(ainfo->reg - 16)*/ i * 8);
}
}
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list