static List <Reg> get_push_list(CilNode.IRNode n, Code c, metadata.MethodSpec call_ms, out metadata.TypeSpec rt, ref Reg dest, out int rct, bool want_return = true) { /* Determine which registers we need to save */ var caller_preserves = c.t.cc_caller_preserves_map[call_ms.CallingConvention]; ulong defined = 0; foreach (var si in n.stack_after) { defined |= si.reg.mask; } foreach (var si in n.stack_before) { defined |= si.reg.mask; } var rt_idx = call_ms.m.GetMethodDefSigRetTypeIndex(call_ms.msig); rt = call_ms.m.GetTypeSpec(ref rt_idx, call_ms.gtparams, call_ms.gmparams); rct = ir.Opcode.ct_unknown; if (rt != null && want_return) { defined &= ~n.stack_after.Peek().reg.mask; if (dest == null) { dest = n.stack_after.Peek().reg; } rct = ir.Opcode.GetCTFromType(rt); } var to_push = new util.Set(); to_push.Union(defined); to_push.Intersect(caller_preserves); List <Reg> push_list = new List <Reg>(); while (!to_push.Empty) { var first_set = to_push.get_first_set(); push_list.Add(c.t.regs[first_set]); to_push.unset(first_set); } return(push_list); }
internal static List <MCInst> handle_enter( Target t, List <CilNode.IRNode> nodes, int start, int count, Code c) { List <MCInst> r = new List <MCInst>(); var n = nodes[start]; var lv_size = c.lv_total_size + c.stack_total_size; if (ir.Opcode.GetCTFromType(c.ret_ts) == ir.Opcode.ct_vt) { throw new NotImplementedException(); } /* standard ARM prologue is: * * mov ip, sp * stmdb sp!, {fp, ip, lr, pc} (push fp, ip, lr and pc) * sub fp, ip, #4 */ r.Add(inst(n, arm_mov_reg, Rd: r_ip, Rm: r_sp)); r.Add(inst(n, arm_stmdb, Rn: r_sp, W: 1, register_list: new Param[] { r_fp, r_ip, r_lr, r_pc })); r.Add(inst(n, arm_sub_imm, Rd: r_fp, Rn: r_ip, imm: 4)); /* Move incoming arguments to the appropriate locations */ for (int i = 0; i < c.la_needs_assign.Length; i++) { if (c.la_needs_assign[i]) { var from = c.incoming_args[i]; var to = c.la_locs[i]; handle_move(to, from, r, n, c); } } /* Save clobbered registers */ var regs_to_save = c.regs_used & c.t.cc_callee_preserves_map[c.ms.CallingConvention]; var regs_set = new util.Set(); regs_set.Union(regs_to_save); int y = 0; while (regs_set.Empty == false) { var reg = regs_set.get_first_set(); regs_set.unset(reg); var cur_reg = t.regs[reg]; handle_push(cur_reg, ref y, r, n, c); c.regs_saved.Add(cur_reg); } if (ir.Opcode.GetCTFromType(c.ret_ts) == ir.Opcode.ct_vt) { throw new NotImplementedException(); //handle_move(new ContentsReg { basereg = r_ebp, disp = -t.psize, size = t.psize }, // t.psize == 4 ? r_eax : r_edi, r, n, c); } return(r); }
protected internal override Code AssembleBoxRetTypeMethod(MethodSpec ms, TysilaState s) { // Move all parameters up one - this will require knowledge of the param locs // if the return type is an object (to get the 'from' locations) and // knowledge of the param locs in the target method (the 'to' locations) // Allocate space on heap (boxed return object) var cc = cc_map[ms.CallingConvention]; var cc_class_map = cc_classmap[ms.CallingConvention]; int stack_loc = 0; var from_locs = GetRegLocs(new ir.Param { m = ms.m, ms = ms, }, ref stack_loc, cc, cc_class_map, ms.CallingConvention, out var from_sizes, out var from_types, null); stack_loc = 0; var to_locs = GetRegLocs(new ir.Param { m = ms.m, ms = ms, }, ref stack_loc, cc, cc_class_map, ms.CallingConvention, out var to_sizes, out var to_types, ms.m.SystemIntPtr); // Generate code var c = new Code(); c.mc = new List <MCInst>(); c.s = s; var n = new cil.CilNode(ms, 0); var ir = new cil.CilNode.IRNode { parent = n, mc = c.mc }; ir.opcode = Opcode.oc_nop; n.irnodes.Add(ir); c.starts = new List <cil.CilNode>(); c.starts.Add(n); c.ms = ms; c.t = this; // copy from[0:n] to to[1:n+1] in reverse order so // we don't overwrite the previous registers ulong defined = 0; for (int i = from_locs.Length - 1; i >= 0; i--) { handle_move(to_locs[i + 1], from_locs[i], c.mc, ir, c, x86_64.x86_64_Assembler.r_rax, from_sizes[i]); defined |= to_locs[i + 1].mask; } // call gcmalloc with the size of the boxed version of the return // type var ts = ms.ReturnType; var tsize = GetSize(ts); var sysobj_size = layout.Layout.GetTypeSize(c.ms.m.SystemObject, c.t); var boxed_size = util.util.align(sysobj_size + tsize, psize); // decide on the registers we need to save around gcmalloc var caller_preserves = cc_caller_preserves_map[ms.CallingConvention]; var to_push = new util.Set(); to_push.Union(defined); to_push.Intersect(caller_preserves); List <Reg> push_list = new List <Reg>(); while (!to_push.Empty) { var first_set = to_push.get_first_set(); push_list.Add(c.t.regs[first_set]); to_push.unset(first_set); } int push_length = 0; foreach (var r in push_list) { handle_push(r, ref push_length, c.mc, ir, c); } c.mc.Add(inst(x86_call_rel32, new Param { t = Opcode.vl_call_target, str = "gcmalloc" }, new Param { t = Opcode.vl_c32, v = boxed_size }, ir)); for (int i = push_list.Count - 1; i >= 0; i--) { handle_pop(push_list[i], ref push_length, c.mc, ir, c); } // put vtable pointer into gcmalloc result c.mc.Add(inst(x86_mov_rm32_lab, new ContentsReg { basereg = r_eax, size = 4 }, new Param { t = Opcode.vl_str, str = ts.MangleType() }, ir)); // put rax into to[0] handle_move(to_locs[0], r_eax, c.mc, ir, c); // unbox to[0] (i.e. increment pointer so it points to the inner data) c.mc.Add(inst(psize == 4 ? x86_add_rm32_imm8 : x86_add_rm64_imm8, to_locs[0], sysobj_size, ir)); // call the actual function (see AssembleBoxedMethod below) var unboxed = ms.Unbox; var act_meth = unboxed.MangleMethod(); s.r.MethodRequestor.Request(unboxed); // Save rax around the call and return it // We do this because the actual method returns the address of a value type in rax // and we want to return the address of the boxed object instead c.mc.Add(inst(x86_push_r32, r_eax, ir)); c.mc.Add(inst(x86_call_rel32, new Param { t = Opcode.vl_str, str = act_meth }, ir)); c.mc.Add(inst(x86_pop_r32, r_eax, ir)); c.mc.Add(inst(x86_ret, ir)); return(c); }