Alien-TinyCCx

 view release on metacpan or  search on metacpan

src/arm64-gen.c  view on Meta::CPAN

        // lab2:
        write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2);
    }
}

ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
                       int *align, int *regsize)
{
    return 0;
}

ST_FUNC void greturn(void)
{
    CType *t = &func_vt;
    unsigned long a;

    arm64_pcs(0, &t, &a);
    switch (a) {
    case -1:
        break;
    case 0:
        if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
            int align, size = type_size(&func_vt, &align);
            gaddrof();
            gv(RC_R(0));
            arm64_ldrs(0, size);
        }
        else
            gv(RC_IRET);
        break;
    case 1: {
        CType type = func_vt;
        mk_pointer(&type);
        vset(&type, VT_LOCAL | VT_LVAL, func_vc);
        indir();
        vswap();
        vstore();
        break;
    }
    case 16:
        if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
          uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz);
          gaddrof();
          gv(RC_R(0));
          for (j = 0; j < n; j++)
              o(0x3d400000 |
                (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
                j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)]
        }
        else
            gv(RC_FRET);
        break;
    default:
      assert(0);
    }
}

ST_FUNC void gfunc_epilog(void)
{
    if (loc) {
        // Insert instructions to subtract size of stack frame from SP.
        unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset;
        uint64_t diff = (-loc + 15) & ~15;
        if (!(diff >> 24)) {
            if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff)
                write32le(ptr, 0xd10003ff | (diff & 0xfff) << 10);
            if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12
                write32le(ptr + 4, 0xd14003ff | (diff >> 12) << 10);
        }
        else {
            // In this case we may subtract more than necessary,
            // but always less than 17/16 of what we were aiming for.
            int i = 0;
            int j = 0;
            while (diff >> 20) {
                diff = (diff + 0xffff) >> 16;
                ++i;
            }
            while (diff >> 16) {
                diff = (diff + 1) >> 1;
                ++j;
            }
            write32le(ptr, 0xd2800010 | diff << 5 | i << 21);
            // mov x16,#(diff),lsl #(16 * i)
            write32le(ptr + 4, 0xcb3063ff | j << 10);
            // sub sp,sp,x16,lsl #(j)
        }
    }
    o(0x910003bf); // mov sp,x29
    o(0xa8ce7bfd); // ldp x29,x30,[sp],#224

    o(0xd65f03c0); // ret
}

// Generate forward branch to label:
ST_FUNC int gjmp(int t)
{
    int r = ind;
    o(t);
    return r;
}

// Generate branch to known address:
ST_FUNC void gjmp_addr(int a)
{
    assert(a - ind + 0x8000000 < 0x10000000);
    o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
}

ST_FUNC int gtst(int inv, int t)
{
    int bt = vtop->type.t & VT_BTYPE;
    if (bt == VT_LDOUBLE) {
        uint32_t a, b, f = fltr(gv(RC_FLOAT));
        a = get_reg(RC_INT);
        vpushi(0);
        vtop[0].r = a;
        b = get_reg(RC_INT);
        a = intr(a);
        b = intr(b);
        o(0x4e083c00 | a | f << 5); // mov x(a),v(f).d[0]



( run in 1.111 second using v1.01-cache-2.11-cpan-df04353d9ac )