This source file includes following definitions.
- cgen64
- cmp64
#include <u.h>
#include <libc.h>
#include "gg.h"
void
cgen64(Node *n, Node *res)
{
Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
Node lo1, lo2, hi1, hi2;
Prog *p1, *p2;
uint64 v;
uint32 lv, hv;
if(res->op != OINDREG && res->op != ONAME) {
dump("n", n);
dump("res", res);
fatal("cgen64 %O of %O", n->op, res->op);
}
switch(n->op) {
default:
fatal("cgen64 %O", n->op);
case OMINUS:
cgen(n->left, res);
split64(res, &lo1, &hi1);
gins(ANEGL, N, &lo1);
gins(AADCL, ncon(0), &hi1);
gins(ANEGL, N, &hi1);
splitclean();
return;
case OCOM:
cgen(n->left, res);
split64(res, &lo1, &hi1);
gins(ANOTL, N, &lo1);
gins(ANOTL, N, &hi1);
splitclean();
return;
case OADD:
case OSUB:
case OMUL:
case OLROT:
case OLSH:
case ORSH:
case OAND:
case OOR:
case OXOR:
break;
}
l = n->left;
r = n->right;
if(!l->addable) {
tempname(&t1, l->type);
cgen(l, &t1);
l = &t1;
}
if(r != N && !r->addable) {
tempname(&t2, r->type);
cgen(r, &t2);
r = &t2;
}
nodreg(&ax, types[TINT32], D_AX);
nodreg(&cx, types[TINT32], D_CX);
nodreg(&dx, types[TINT32], D_DX);
split64(l, &lo1, &hi1);
if(is64(r->type))
split64(r, &lo2, &hi2);
switch(n->op) {
case OADD:
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
gins(AADDL, &lo2, &ax);
gins(AADCL, &hi2, &dx);
break;
case OSUB:
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
gins(ASUBL, &lo2, &ax);
gins(ASBBL, &hi2, &dx);
break;
case OMUL:
regalloc(&ex, types[TPTR32], N);
regalloc(&fx, types[TPTR32], N);
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
gins(AMOVL, &lo2, &cx);
gins(AMOVL, &hi2, &ex);
gins(AMOVL, &dx, &fx);
gins(AORL, &ex, &fx);
p1 = gbranch(AJNE, T, 0);
gins(AMULL, &cx, N);
p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
gins(AIMULL, &cx, &dx);
gins(AMOVL, &ax, &fx);
gins(AIMULL, &ex, &fx);
gins(AADDL, &dx, &fx);
gins(AMOVL, &cx, &dx);
gins(AMULL, &dx, N);
gins(AADDL, &fx, &dx);
patch(p2, pc);
regfree(&ex);
regfree(&fx);
break;
case OLROT:
v = mpgetfix(r->val.u.xval);
if(v >= 32) {
v -= 32;
gins(AMOVL, &lo1, &dx);
gins(AMOVL, &hi1, &ax);
} else {
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
}
if(v == 0) {
} else {
gins(AMOVL, &dx, &cx);
p1 = gins(ASHLL, ncon(v), &dx);
p1->from.index = D_AX;
p1->from.scale = 0;
p1 = gins(ASHLL, ncon(v), &ax);
p1->from.index = D_CX;
p1->from.scale = 0;
}
break;
case OLSH:
if(r->op == OLITERAL) {
v = mpgetfix(r->val.u.xval);
if(v >= 64) {
if(is64(r->type))
splitclean();
splitclean();
split64(res, &lo2, &hi2);
gins(AMOVL, ncon(0), &lo2);
gins(AMOVL, ncon(0), &hi2);
splitclean();
goto out;
}
if(v >= 32) {
if(is64(r->type))
splitclean();
split64(res, &lo2, &hi2);
gmove(&lo1, &hi2);
if(v > 32) {
gins(ASHLL, ncon(v - 32), &hi2);
}
gins(AMOVL, ncon(0), &lo2);
splitclean();
splitclean();
goto out;
}
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
p1 = gins(ASHLL, ncon(v), &dx);
p1->from.index = D_AX;
p1->from.scale = 0;
gins(ASHLL, ncon(v), &ax);
break;
}
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
p1 = P;
if(is64(r->type)) {
gins(ACMPL, &hi2, ncon(0));
p1 = gbranch(AJNE, T, +1);
gins(AMOVL, &lo2, &cx);
} else {
cx.type = types[TUINT32];
gmove(r, &cx);
}
gins(ACMPL, &cx, ncon(64));
p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p1 != P)
patch(p1, pc);
gins(AXORL, &dx, &dx);
gins(AXORL, &ax, &ax);
patch(p2, pc);
gins(ACMPL, &cx, ncon(32));
p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
gins(AMOVL, &ax, &dx);
gins(ASHLL, &cx, &dx);
gins(AXORL, &ax, &ax);
p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
p1 = gins(ASHLL, &cx, &dx);
p1->from.index = D_AX;
p1->from.scale = 0;
gins(ASHLL, &cx, &ax);
patch(p2, pc);
break;
case ORSH:
if(r->op == OLITERAL) {
v = mpgetfix(r->val.u.xval);
if(v >= 64) {
if(is64(r->type))
splitclean();
splitclean();
split64(res, &lo2, &hi2);
if(hi1.type->etype == TINT32) {
gmove(&hi1, &lo2);
gins(ASARL, ncon(31), &lo2);
gmove(&hi1, &hi2);
gins(ASARL, ncon(31), &hi2);
} else {
gins(AMOVL, ncon(0), &lo2);
gins(AMOVL, ncon(0), &hi2);
}
splitclean();
goto out;
}
if(v >= 32) {
if(is64(r->type))
splitclean();
split64(res, &lo2, &hi2);
gmove(&hi1, &lo2);
if(v > 32)
gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
if(hi1.type->etype == TINT32) {
gmove(&hi1, &hi2);
gins(ASARL, ncon(31), &hi2);
} else
gins(AMOVL, ncon(0), &hi2);
splitclean();
splitclean();
goto out;
}
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
p1 = gins(ASHRL, ncon(v), &ax);
p1->from.index = D_DX;
p1->from.scale = 0;
gins(optoas(ORSH, hi1.type), ncon(v), &dx);
break;
}
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
p1 = P;
if(is64(r->type)) {
gins(ACMPL, &hi2, ncon(0));
p1 = gbranch(AJNE, T, +1);
gins(AMOVL, &lo2, &cx);
} else {
cx.type = types[TUINT32];
gmove(r, &cx);
}
gins(ACMPL, &cx, ncon(64));
p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p1 != P)
patch(p1, pc);
if(hi1.type->etype == TINT32) {
gins(ASARL, ncon(31), &dx);
gins(AMOVL, &dx, &ax);
} else {
gins(AXORL, &dx, &dx);
gins(AXORL, &ax, &ax);
}
patch(p2, pc);
gins(ACMPL, &cx, ncon(32));
p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
gins(AMOVL, &dx, &ax);
if(hi1.type->etype == TINT32) {
gins(ASARL, &cx, &ax);
gins(ASARL, ncon(31), &dx);
} else {
gins(ASHRL, &cx, &ax);
gins(AXORL, &dx, &dx);
}
p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
p1 = gins(ASHRL, &cx, &ax);
p1->from.index = D_DX;
p1->from.scale = 0;
gins(optoas(ORSH, hi1.type), &cx, &dx);
patch(p2, pc);
break;
case OXOR:
case OAND:
case OOR:
if(lo1.op == OLITERAL) {
nswap(&lo1, &lo2);
nswap(&hi1, &hi2);
}
if(lo2.op == OLITERAL) {
lv = mpgetfix(lo2.val.u.xval);
hv = mpgetfix(hi2.val.u.xval);
splitclean();
split64(res, &lo2, &hi2);
switch(n->op) {
case OXOR:
gmove(&lo1, &lo2);
gmove(&hi1, &hi2);
switch(lv) {
case 0:
break;
case 0xffffffffu:
gins(ANOTL, N, &lo2);
break;
default:
gins(AXORL, ncon(lv), &lo2);
break;
}
switch(hv) {
case 0:
break;
case 0xffffffffu:
gins(ANOTL, N, &hi2);
break;
default:
gins(AXORL, ncon(hv), &hi2);
break;
}
break;
case OAND:
switch(lv) {
case 0:
gins(AMOVL, ncon(0), &lo2);
break;
default:
gmove(&lo1, &lo2);
if(lv != 0xffffffffu)
gins(AANDL, ncon(lv), &lo2);
break;
}
switch(hv) {
case 0:
gins(AMOVL, ncon(0), &hi2);
break;
default:
gmove(&hi1, &hi2);
if(hv != 0xffffffffu)
gins(AANDL, ncon(hv), &hi2);
break;
}
break;
case OOR:
switch(lv) {
case 0:
gmove(&lo1, &lo2);
break;
case 0xffffffffu:
gins(AMOVL, ncon(0xffffffffu), &lo2);
break;
default:
gmove(&lo1, &lo2);
gins(AORL, ncon(lv), &lo2);
break;
}
switch(hv) {
case 0:
gmove(&hi1, &hi2);
break;
case 0xffffffffu:
gins(AMOVL, ncon(0xffffffffu), &hi2);
break;
default:
gmove(&hi1, &hi2);
gins(AORL, ncon(hv), &hi2);
break;
}
break;
}
splitclean();
splitclean();
goto out;
}
gins(AMOVL, &lo1, &ax);
gins(AMOVL, &hi1, &dx);
gins(optoas(n->op, lo1.type), &lo2, &ax);
gins(optoas(n->op, lo1.type), &hi2, &dx);
break;
}
if(is64(r->type))
splitclean();
splitclean();
split64(res, &lo1, &hi1);
gins(AMOVL, &ax, &lo1);
gins(AMOVL, &dx, &hi1);
splitclean();
out:;
}
void
cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
{
Node lo1, hi1, lo2, hi2, rr;
Prog *br;
Type *t;
split64(nl, &lo1, &hi1);
split64(nr, &lo2, &hi2);
t = hi1.type;
if(nl->op == OLITERAL || nr->op == OLITERAL)
gins(ACMPL, &hi1, &hi2);
else {
regalloc(&rr, types[TINT32], N);
gins(AMOVL, &hi1, &rr);
gins(ACMPL, &rr, &hi2);
regfree(&rr);
}
br = P;
switch(op) {
default:
fatal("cmp64 %O %T", op, t);
case OEQ:
br = gbranch(AJNE, T, -likely);
break;
case ONE:
patch(gbranch(AJNE, T, likely), to);
break;
case OGE:
case OGT:
patch(gbranch(optoas(OGT, t), T, likely), to);
br = gbranch(optoas(OLT, t), T, -likely);
break;
case OLE:
case OLT:
patch(gbranch(optoas(OLT, t), T, likely), to);
br = gbranch(optoas(OGT, t), T, -likely);
break;
}
t = lo1.type;
if(nl->op == OLITERAL || nr->op == OLITERAL)
gins(ACMPL, &lo1, &lo2);
else {
regalloc(&rr, types[TINT32], N);
gins(AMOVL, &lo1, &rr);
gins(ACMPL, &rr, &lo2);
regfree(&rr);
}
patch(gbranch(optoas(op, t), T, likely), to);
if(br != P)
patch(br, pc);
splitclean();
splitclean();
}