Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }