Alien-TinyCCx
view release on metacpan or search on metacpan
src/arm64-gen.c view on Meta::CPAN
ST_FUNC void gen_va_arg(CType *t)
{
int align, size = type_size(t, &align);
int fsize, hfa = arm64_hfa(t, &fsize);
uint32_t r0, r1;
if (is_float(t->t)) {
hfa = 1;
fsize = size;
}
gaddrof();
r0 = intr(gv(RC_INT));
r1 = get_reg(RC_INT);
vtop[0].r = r1 | lvalue_type(t->t);
r1 = intr(r1);
if (!hfa) {
uint32_t n = size > 16 ? 8 : (size + 7) & -8;
o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs
if (align == 16) {
assert(0); // this path untested but needed for __uint128_t
o(0x11003fde); // add w30,w30,#15
o(0x121c6fde); // and w30,w30,#-16
}
o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n)
o(0x540000ad); // b.le .+20
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
o(0x14000004); // b .+16
o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs
o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top
o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw
if (size > 16)
o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)]
}
else {
uint32_t rsz = hfa << 4;
uint32_t ssz = (size + 7) & -(uint32_t)8;
uint32_t b1, b2;
o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs
o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz)
b1 = ind; o(0x5400000d); // b.le lab1
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
if (fsize == 16) {
o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
}
o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
b2 = ind; o(0x14000000); // b lab2
// lab1:
write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3);
o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs
o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top
if (hfa == 1 || fsize == 16)
o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw
else {
// We need to change the layout of this HFA.
// Get some space on the stack using global variable "loc":
loc = (loc - size) & -(uint32_t)align;
o(0x8b3ec000 | 30 | r1 << 5); // add x30,x(r1),w30,sxtw
arm64_movimm(r1, loc);
o(0x8b0003a0 | r1 | r1 << 16); // add x(r1),x29,x(r1)
o(0x4c402bdc | (uint32_t)fsize << 7 |
(uint32_t)(hfa == 2) << 15 |
(uint32_t)(hfa == 3) << 14); // ld1 {v28.(4s|2d),...},[x30]
o(0x0d00801c | r1 << 5 | (fsize == 8) << 10 |
(uint32_t)(hfa != 2) << 13 |
(uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)]
}
// 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)]
}
src/arm64-gen.c view on Meta::CPAN
o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv
break;
case TOK_UGE:
o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
o(0x1a9f37e0 | x); // cset wA,cs
break;
case TOK_UGT:
o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
o(0x1a9f97e0 | x); // cset wA,hi
break;
case TOK_ULT:
o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
o(0x1a9f27e0 | x); // cset wA,cc
break;
case TOK_ULE:
o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
o(0x1a9f87e0 | x); // cset wA,ls
break;
case TOK_UMOD:
// Use x30 for quotient:
o(0x1ac00800 | l << 31 | 30 | a << 5 | b << 16); // udiv
o(0x1b008000 | l << 31 | x | (uint32_t)30 << 5 |
b << 16 | a << 10); // msub
break;
default:
assert(0);
}
}
ST_FUNC void gen_opi(int op)
{
arm64_gen_opil(op, 0);
}
ST_FUNC void gen_opl(int op)
{
arm64_gen_opil(op, 1);
}
ST_FUNC void gen_opf(int op)
{
uint32_t x, a, b, dbl;
if (vtop[0].type.t == VT_LDOUBLE) {
CType type = vtop[0].type;
int func = 0;
int cond = -1;
switch (op) {
case '*': func = TOK___multf3; break;
case '+': func = TOK___addtf3; break;
case '-': func = TOK___subtf3; break;
case '/': func = TOK___divtf3; break;
case TOK_EQ: func = TOK___eqtf2; cond = 1; break;
case TOK_NE: func = TOK___netf2; cond = 0; break;
case TOK_LT: func = TOK___lttf2; cond = 10; break;
case TOK_GE: func = TOK___getf2; cond = 11; break;
case TOK_LE: func = TOK___letf2; cond = 12; break;
case TOK_GT: func = TOK___gttf2; cond = 13; break;
default: assert(0); break;
}
vpush_global_sym(&func_old_type, func);
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = cond < 0 ? REG_FRET : REG_IRET;
if (cond < 0)
vtop->type = type;
else {
o(0x7100001f); // cmp w0,#0
o(0x1a9f07e0 | (uint32_t)cond << 12); // cset w0,(cond)
}
return;
}
dbl = vtop[0].type.t != VT_FLOAT;
gv2(RC_FLOAT, RC_FLOAT);
assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
a = fltr(vtop[-1].r);
b = fltr(vtop[0].r);
vtop -= 2;
switch (op) {
case TOK_EQ: case TOK_NE:
case TOK_LT: case TOK_GE: case TOK_LE: case TOK_GT:
x = get_reg(RC_INT);
++vtop;
vtop[0].r = x;
x = intr(x);
break;
default:
x = get_reg(RC_FLOAT);
++vtop;
vtop[0].r = x;
x = fltr(x);
break;
}
switch (op) {
case '*':
o(0x1e200800 | dbl << 22 | x | a << 5 | b << 16); // fmul
break;
case '+':
o(0x1e202800 | dbl << 22 | x | a << 5 | b << 16); // fadd
break;
case '-':
o(0x1e203800 | dbl << 22 | x | a << 5 | b << 16); // fsub
break;
case '/':
o(0x1e201800 | dbl << 22 | x | a << 5 | b << 16); // fdiv
break;
case TOK_EQ:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9f17e0 | x); // cset w(x),eq
break;
case TOK_GE:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9fb7e0 | x); // cset w(x),ge
break;
case TOK_GT:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9fd7e0 | x); // cset w(x),gt
break;
case TOK_LE:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9f87e0 | x); // cset w(x),ls
break;
case TOK_LT:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9f57e0 | x); // cset w(x),mi
break;
case TOK_NE:
o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
o(0x1a9f07e0 | x); // cset w(x),ne
break;
default:
assert(0);
}
}
// Generate sign extension from 32 to 64 bits:
ST_FUNC void gen_cvt_sxtw(void)
{
uint32_t r = intr(gv(RC_INT));
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
}
ST_FUNC void gen_cvt_itof(int t)
{
if (t == VT_LDOUBLE) {
int f = vtop->type.t;
int func = (f & VT_BTYPE) == VT_LLONG ?
(f & VT_UNSIGNED ? TOK___floatunditf : TOK___floatditf) :
(f & VT_UNSIGNED ? TOK___floatunsitf : TOK___floatsitf);
vpush_global_sym(&func_old_type, func);
vrott(2);
gfunc_call(1);
vpushi(0);
vtop->type.t = t;
vtop->r = REG_FRET;
return;
}
else {
int d, n = intr(gv(RC_INT));
int s = !(vtop->type.t & VT_UNSIGNED);
uint32_t l = ((vtop->type.t & VT_BTYPE) == VT_LLONG);
--vtop;
d = get_reg(RC_FLOAT);
++vtop;
vtop[0].r = d;
o(0x1e220000 | (uint32_t)!s << 16 |
(uint32_t)(t != VT_FLOAT) << 22 | fltr(d) |
l << 31 | n << 5); // [us]cvtf [sd](d),[wx](n)
}
}
ST_FUNC void gen_cvt_ftoi(int t)
{
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
int func = (t & VT_BTYPE) == VT_LLONG ?
(t & VT_UNSIGNED ? TOK___fixunstfdi : TOK___fixtfdi) :
(t & VT_UNSIGNED ? TOK___fixunstfsi : TOK___fixtfsi);
vpush_global_sym(&func_old_type, func);
vrott(2);
gfunc_call(1);
vpushi(0);
vtop->type.t = t;
vtop->r = REG_IRET;
return;
}
else {
int d, n = fltr(gv(RC_FLOAT));
uint32_t l = ((vtop->type.t & VT_BTYPE) != VT_FLOAT);
--vtop;
d = get_reg(RC_INT);
++vtop;
vtop[0].r = d;
o(0x1e380000 |
(uint32_t)!!(t & VT_UNSIGNED) << 16 |
(uint32_t)((t & VT_BTYPE) == VT_LLONG) << 31 | intr(d) |
l << 22 | n << 5); // fcvtz[su] [wx](d),[sd](n)
}
}
ST_FUNC void gen_cvt_ftof(int t)
{
int f = vtop[0].type.t;
assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE);
assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE);
if (t == f)
return;
if (t == VT_LDOUBLE || f == VT_LDOUBLE) {
int func = (t == VT_LDOUBLE) ?
(f == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) :
(t == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2);
vpush_global_sym(&func_old_type, func);
vrott(2);
gfunc_call(1);
vpushi(0);
vtop->type.t = t;
vtop->r = REG_FRET;
}
else {
int x, a;
gv(RC_FLOAT);
assert(vtop[0].r < VT_CONST);
a = fltr(vtop[0].r);
--vtop;
x = get_reg(RC_FLOAT);
++vtop;
vtop[0].r = x;
x = fltr(x);
if (f == VT_FLOAT)
o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a)
else
o(0x1e624000 | x | a << 5); // fcvt s(x),d(a)
}
}
ST_FUNC void ggoto(void)
{
arm64_gen_bl_or_b(1);
--vtop;
}
ST_FUNC void gen_clear_cache(void)
{
uint32_t beg, end, dsz, isz, p, lab1, b1;
gv2(RC_INT, RC_INT);
vpushi(0);
vtop->r = get_reg(RC_INT);
vpushi(0);
vtop->r = get_reg(RC_INT);
vpushi(0);
vtop->r = get_reg(RC_INT);
beg = intr(vtop[-4].r); // x0
end = intr(vtop[-3].r); // x1
dsz = intr(vtop[-2].r); // x2
isz = intr(vtop[-1].r); // x3
p = intr(vtop[0].r); // x4
vtop -= 5;
o(0xd53b0020 | isz); // mrs x(isz),ctr_el0
o(0x52800080 | p); // mov w(p),#4
o(0x53104c00 | dsz | isz << 5); // ubfx w(dsz),w(isz),#16,#4
o(0x1ac02000 | dsz | p << 5 | dsz << 16); // lsl w(dsz),w(p),w(dsz)
o(0x12000c00 | isz | isz << 5); // and w(isz),w(isz),#15
o(0x1ac02000 | isz | p << 5 | isz << 16); // lsl w(isz),w(p),w(isz)
o(0x51000400 | p | dsz << 5); // sub w(p),w(dsz),#1
o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p)
b1 = ind; o(0x14000000); // b
lab1 = ind;
o(0xd50b7b20 | p); // dc cvau,x(p)
o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz)
write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2);
( run in 0.697 second using v1.01-cache-2.11-cpan-13bb782fe5a )