summaryrefslogtreecommitdiff
path: root/utils/qc
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2010-04-27 12:51:13 +0100
committerforsyth <forsyth@vitanuova.com>2010-04-27 12:51:13 +0100
commitd67b7dad77bb8aa973dad1f7c3ab0c309b114278 (patch)
tree6794120fb327d6de19cf05eed53f80d877781a3e /utils/qc
parent09da2e137d5eb0c940df35d989e4c31ec0654fc4 (diff)
20100427-1251
Diffstat (limited to 'utils/qc')
-rw-r--r--utils/qc/cgen.c520
-rw-r--r--utils/qc/enam.c83
-rw-r--r--utils/qc/gc.h16
-rw-r--r--utils/qc/list.c2
-rw-r--r--utils/qc/machcap.c16
-rw-r--r--utils/qc/mkfile21
-rw-r--r--utils/qc/peep.c87
-rw-r--r--utils/qc/q.out.h89
-rw-r--r--utils/qc/reg.c1
-rw-r--r--utils/qc/sgen.c407
-rw-r--r--utils/qc/swt.c231
-rw-r--r--utils/qc/txt.c554
12 files changed, 1324 insertions, 703 deletions
diff --git a/utils/qc/cgen.c b/utils/qc/cgen.c
index 8323466c..d26704de 100644
--- a/utils/qc/cgen.c
+++ b/utils/qc/cgen.c
@@ -1,5 +1,10 @@
#include "gc.h"
+static void cmpv(Node*, int, Node*);
+static void testv(Node*, int);
+static void cgen64(Node*, Node*);
+static int isvconstable(int, vlong);
+
void
cgen(Node *n, Node *nn)
{
@@ -15,10 +20,18 @@ cgen(Node *n, Node *nn)
}
if(n == Z || n->type == T)
return;
- if(typesuv[n->type->etype]) {
+ if(typesu[n->type->etype]) {
sugen(n, nn, n->type->width);
return;
}
+ if(typev[n->type->etype]) {
+ switch(n->op) {
+ case OCONST:
+ case OFUNC:
+ cgen64(n, nn);
+ return;
+ }
+ }
l = n->left;
r = n->right;
o = n->op;
@@ -44,13 +57,17 @@ cgen(Node *n, Node *nn)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
- regret(&nod, r);
- cgen(r, &nod);
-
- regsalloc(&nod1, r);
- gopcode(OAS, &nod, Z, &nod1);
+ if(!typev[r->type->etype]) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ } else {
+ regsalloc(&nod1, r);
+ cgen(r, &nod1);
+ }
- regfree(&nod);
nod = *n;
nod.right = &nod1;
cgen(&nod, nn);
@@ -70,6 +87,19 @@ cgen(Node *n, Node *nn)
diag(n, "unknown op in cgen: %O", o);
break;
+ case ONEG:
+ case OCOM:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
+ break;
+
case OAS:
if(l->op == OBIT)
goto bitas;
@@ -132,8 +162,11 @@ cgen(Node *n, Node *nn)
case OXOR:
if(nn != Z)
if(r->op == OCONST && r->vconst == -1){
- cgen(l, nn);
- gopcode(OCOM, nn, Z, nn);
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(OCOM, &nod, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
break;
}
@@ -147,15 +180,14 @@ cgen(Node *n, Node *nn)
/*
* immediate operands
*/
- if(nn != Z)
- if(r->op == OCONST)
- if(!typefd[n->type->etype]) {
- cgen(l, nn);
- if(r->vconst == 0)
- if(o != OAND)
- break;
- if(nn != Z)
- gopcode(o, r, Z, nn);
+ if(nn != Z && r->op == OCONST && !typefd[n->type->etype] &&
+ (!typev[n->type->etype] || isvconstable(o, r->vconst))) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ if(o == OAND || r->vconst != 0)
+ gopcode(o, r, Z, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
break;
}
@@ -169,7 +201,7 @@ cgen(Node *n, Node *nn)
nullwarn(l, r);
break;
}
- if(o == OMUL || o == OLMUL) {
+ if((o == OMUL || o == OLMUL) && !typev[n->type->etype]) {
if(mulcon(n, nn))
break;
if(debug['M'])
@@ -178,19 +210,23 @@ cgen(Node *n, Node *nn)
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
- regalloc(&nod1, r, Z);
+ if(o != OMUL || typev[n->type->etype] || !sconst(r)) {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ regfree(&nod1);
+ } else
+ gopcode(o, r, Z, &nod);
+ } else {
+ regalloc(&nod1, r, nn);
cgen(r, &nod1);
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
gopcode(o, &nod1, Z, &nod);
- } else {
- regalloc(&nod, r, nn);
- cgen(r, &nod);
- regalloc(&nod1, l, Z);
- cgen(l, &nod1);
- gopcode(o, &nod, &nod1, &nod);
+ regfree(&nod1);
}
gopcode(OAS, &nod, Z, nn);
regfree(&nod);
- regfree(&nod1);
break;
case OASLSHR:
@@ -203,14 +239,13 @@ cgen(Node *n, Node *nn)
case OASOR:
if(l->op == OBIT)
goto asbitop;
- if(r->op == OCONST)
- if(!typefd[r->type->etype])
- if(!typefd[n->type->etype]) {
+ if(r->op == OCONST && !typefd[r->type->etype] && !typefd[n->type->etype] &&
+ (!typev[n->type->etype] || isvconstable(o, r->vconst))) {
if(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
- regalloc(&nod, r, nn);
+ regalloc(&nod, l, nn);
gopcode(OAS, &nod2, Z, &nod);
gopcode(o, r, Z, &nod);
gopcode(OAS, &nod, Z, &nod2);
@@ -234,20 +269,22 @@ cgen(Node *n, Node *nn)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
- regalloc(&nod, n, nn);
+ regalloc(&nod, r, Z);
cgen(r, &nod);
} else {
- regalloc(&nod, n, nn);
+ regalloc(&nod, r, Z);
cgen(r, &nod);
if(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
}
- regalloc(&nod1, n, Z);
+ regalloc(&nod1, n, nn);
gopcode(OAS, &nod2, Z, &nod1);
- gopcode(o, &nod, &nod1, &nod);
- gopcode(OAS, &nod, Z, &nod2);
+ gopcode(o, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+ if(nn != Z)
+ gopcode(OAS, &nod1, Z, nn);
regfree(&nod);
regfree(&nod1);
if(l->addable < INDEXED)
@@ -336,7 +373,7 @@ cgen(Node *n, Node *nn)
} else
cgen(l, &nod);
regind(&nod, n);
- gopcode(OAS, &nod, Z, nn);
+ gmove(&nod, nn);
regfree(&nod);
break;
@@ -390,11 +427,15 @@ cgen(Node *n, Node *nn)
cgen(l, nn);
break;
}
+ if(typev[l->type->etype] || typev[n->type->etype]) {
+ cgen64(n, nn);
+ break;
+ }
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, n, &nod);
- gopcode(OAS, &nod, Z, &nod1);
- gopcode(OAS, &nod1, Z, nn);
+ gmove(&nod, &nod1);
+ gmove(&nod1, nn);
regfree(&nod1);
regfree(&nod);
break;
@@ -496,6 +537,8 @@ cgen(Node *n, Node *nn)
} else
gopcode(OADD, nodconst(v), Z, &nod);
gopcode(OAS, &nod, Z, &nod2);
+ if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */
+ gins(ANOP, l, Z);
regfree(&nod);
if(l->addable < INDEXED)
@@ -608,7 +651,7 @@ bcgen(Node *n, int true)
void
boolgen(Node *n, int true, Node *nn)
{
- int o;
+ int o, uns;
Prog *p1, *p2;
Node *l, *r, nod, nod1;
long curs;
@@ -617,6 +660,7 @@ boolgen(Node *n, int true, Node *nn)
prtree(nn, "boolgen lhs");
prtree(n, "boolgen");
}
+ uns = 0;
curs = cursafe;
l = n->left;
r = n->right;
@@ -635,6 +679,10 @@ boolgen(Node *n, int true, Node *nn)
}
goto com;
}
+ if(typev[n->type->etype]) {
+ testv(n, true);
+ goto com;
+ }
regalloc(&nod, n, nn);
cgen(n, &nod);
o = ONE;
@@ -701,16 +749,22 @@ boolgen(Node *n, int true, Node *nn)
patch(p2, pc);
goto com;
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ uns = 1;
+ /* fall through */
case OEQ:
case ONE:
case OLE:
case OLT:
case OGE:
case OGT:
- case OHI:
- case OHS:
- case OLO:
- case OLS:
+ if(typev[l->type->etype]){
+ cmpv(n, true, Z);
+ goto com;
+ }
o = n->op;
if(true)
o = comrel[relindex(o)];
@@ -725,7 +779,7 @@ boolgen(Node *n, int true, Node *nn)
boolgen(&nod, true, nn);
break;
}
- if(sconst(r)) {
+ if(!uns && sconst(r) || (uns || o == OEQ || o == ONE) && uconst(r)) {
regalloc(&nod, l, nn);
cgen(l, &nod);
gopcode(o, &nod, Z, r);
@@ -773,13 +827,17 @@ sugen(Node *n, Node *nn, long w)
if(n == Z || n->type == T)
return;
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
if(debug['g']) {
prtree(nn, "sugen lhs");
prtree(n, "sugen");
}
- if(nn == nodrat)
- if(w > nrathole)
- nrathole = w;
+ if(typev[n->type->etype]) {
+ diag(n, "old vlong sugen: %O", n->op);
+ return;
+ }
switch(n->op) {
case OIND:
if(nn == Z) {
@@ -790,33 +848,6 @@ sugen(Node *n, Node *nn, long w)
default:
goto copy;
- case OCONST:
- if(n->type && typev[n->type->etype]) {
- if(nn == Z) {
- nullwarn(n->left, Z);
- break;
- }
-
- t = nn->type;
- nn->type = types[TLONG];
- reglcgen(&nod1, nn, Z);
- nn->type = t;
-
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- nod1.xoffset += SZ_LONG;
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
- gopcode(OAS, nod32const(n->vconst), Z, &nod1);
- else
- gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
-
- regfree(&nod1);
- break;
- }
- goto copy;
-
case ODOT:
l = n->left;
sugen(l, nodrat, l->type->width);
@@ -922,6 +953,7 @@ sugen(Node *n, Node *nn, long w)
break;
case OFUNC:
+ /* this transformation should probably be done earlier */
if(nn == Z) {
sugen(n, nodrat, w);
break;
@@ -933,6 +965,7 @@ sugen(Node *n, Node *nn, long w)
} else
nn = nn->left;
n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->complex = FNX;
n->type = types[TVOID];
n->left->type = types[TVOID];
cgen(n, Z);
@@ -967,7 +1000,7 @@ copy:
regsalloc(&nod2, nn);
nn->type = t;
- gopcode(OAS, &nod1, Z, &nod2);
+ gmove(&nod1, &nod2);
regfree(&nod1);
nod2.type = typ(TIND, t);
@@ -1089,3 +1122,338 @@ layout(Node *f, Node *t, int c, int cv, Node *cn)
regfree(&t1);
regfree(&t2);
}
+
+/*
+ * is the vlong's value directly addressible?
+ */
+int
+isvdirect(Node *n)
+{
+ return n->op == ONAME || n->op == OCONST || n->op == OINDREG;
+}
+
+/*
+ * can the constant be used with given vlong op?
+ */
+static int
+isvconstable(int o, vlong v)
+{
+ switch(o) {
+ case OADD:
+ case OASADD:
+ /* there isn't an immediate form for ADDE/SUBE, but there are special ADDME/ADDZE etc */
+ return v == 0 || v == -1;
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * most 64-bit operations: cgen into a register pair, then operate.
+ * 64-bit comparisons are handled a little differently because the two underlying
+ * comparisons can be compiled separately, since the calculations don't interact.
+ */
+
+static void
+vcgen(Node *n, Node *o, int *f)
+{
+ *f = 0;
+ if(!isvdirect(n)) {
+ if(n->complex >= FNX) {
+ regsalloc(o, n);
+ cgen(n, o);
+ return;
+ }
+ *f = 1;
+ if(n->addable < INDEXED && n->op != OIND && n->op != OINDEX) {
+ regalloc(o, n, Z);
+ cgen(n, o);
+ } else
+ reglcgen(o, n, Z);
+ } else
+ *o = *n;
+}
+
+static int
+isuns(int op)
+{
+ switch(op){
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void
+gcmpv(Node *l, Node *r, void (*mov)(Node*, Node*, int), int op)
+{
+ Node vl, vr;
+
+ regalloc(&vl, &regnode, Z);
+ mov(l, &vl, 0);
+ regalloc(&vr, &regnode, Z);
+ mov(r, &vr, 1+isuns(op));
+ gopcode(op, &vl, Z, &vr);
+ if(vl.op == OREGISTER)
+ regfree(&vl);
+ if(vr.op == OREGISTER)
+ regfree(&vr);
+}
+
+static void
+brcondv(Node *l, Node *r, int chi, int clo)
+{
+ Prog *p1, *p2, *p3, *p4;
+
+ gcmpv(l, r, gloadhi, chi);
+ p1 = p;
+ gins(ABNE, Z, Z);
+ p2 = p;
+ gcmpv(l, r, gloadlo, clo);
+ p3 = p;
+ gbranch(OGOTO);
+ p4 = p;
+ patch(p1, pc);
+ patch(p3, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ patch(p4, pc);
+}
+
+static void
+testv(Node *n, int true)
+{
+ Node nod;
+
+ nod = znode;
+ nod.op = ONE;
+ nod.left = n;
+ nod.right = new1(0, Z, Z);
+ *nod.right = *nodconst(0);
+ nod.right->type = n->type;
+ nod.type = types[TLONG];
+ cmpv(&nod, true, Z);
+}
+
+/*
+ * comparison for vlong does high and low order parts separately,
+ * which saves loading the latter if the high order comparison suffices
+ */
+static void
+cmpv(Node *n, int true, Node *nn)
+{
+ Node *l, *r, nod, nod1;
+ int o, f1, f2;
+ Prog *p1, *p2;
+ long curs;
+
+ if(debug['g']) {
+ if(nn != nil)
+ prtree(nn, "cmpv lhs");
+ prtree(n, "cmpv");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regsalloc(&nod1, r);
+ cgen(r, &nod1);
+ nod = *n;
+ nod.right = &nod1;
+ cmpv(&nod, true, nn);
+ cursafe = curs;
+ return;
+ }
+ if(l->complex >= r->complex) {
+ vcgen(l, &nod1, &f1);
+ vcgen(r, &nod, &f2);
+ } else {
+ vcgen(r, &nod, &f2);
+ vcgen(l, &nod1, &f1);
+ }
+ nod.type = types[TLONG];
+ nod1.type = types[TLONG];
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ switch(o){
+ case OEQ:
+ gcmpv(&nod1, &nod, gloadhi, ONE);
+ p1 = p;
+ gcmpv(&nod1, &nod, gloadlo, ONE);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ break;
+ case ONE:
+ gcmpv(&nod1, &nod, gloadhi, ONE);
+ p1 = p;
+ gcmpv(&nod1, &nod, gloadlo, OEQ);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ break;
+ case OLE:
+ brcondv(&nod1, &nod, OLT, OLS);
+ break;
+ case OGT:
+ brcondv(&nod1, &nod, OGT, OHI);
+ break;
+ case OLS:
+ brcondv(&nod1, &nod, OLO, OLS);
+ break;
+ case OHI:
+ brcondv(&nod1, &nod, OHI, OHI);
+ break;
+ case OLT:
+ brcondv(&nod1, &nod, OLT, OLO);
+ break;
+ case OGE:
+ brcondv(&nod1, &nod, OGT, OHS);
+ break;
+ case OLO:
+ brcondv(&nod1, &nod, OLO, OLO);
+ break;
+ case OHS:
+ brcondv(&nod1, &nod, OHI, OHS);
+ break;
+ default:
+ diag(n, "bad cmpv");
+ return;
+ }
+ if(f1)
+ regfree(&nod1);
+ if(f2)
+ regfree(&nod);
+ cursafe = curs;
+}
+
+static void
+cgen64(Node *n, Node *nn)
+{
+ Node *l, *r, *d;
+ Node nod, nod1;
+ long curs;
+ Type *t;
+ int o, m;
+
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ switch(o) {
+
+ case OCONST:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+ if(nn->op != OREGPAIR) {
+//prtree(n, "cgen64 const");
+ t = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod1, nn, Z);
+ nn->type = t;
+
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gmove(nod32const(n->vconst>>32), &nod1);
+ else
+ gmove(nod32const(n->vconst), &nod1);
+ nod1.xoffset += SZ_LONG;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gmove(nod32const(n->vconst), &nod1);
+ else
+ gmove(nod32const(n->vconst>>32), &nod1);
+
+ regfree(&nod1);
+ } else
+ gmove(n, nn);
+ break;
+
+ case OCAST:
+ /*
+ * convert from types l->n->nn
+ */
+ if(typev[l->type->etype]){
+ /* vlong to non-vlong */
+ if(!isvdirect(l)) {
+ if(l->addable < INDEXED && l->op != OIND && l->op != OINDEX) {
+ regalloc(&nod, l, l);
+ cgen(l, &nod);
+ regalloc(&nod1, n, nn);
+ gmove(nod.right, &nod1);
+ } else {
+ reglcgen(&nod, l, Z);
+ regalloc(&nod1, n, nn);
+ gloadlo(&nod, &nod1, 0); /* TO DO: not correct for typefd */
+ }
+ regfree(&nod);
+ } else {
+ regalloc(&nod1, n, nn);
+ gloadlo(l, &nod1, 0); /* TO DO: not correct for typefd */
+ }
+ }else{
+ /* non-vlong to vlong */
+ regalloc(&nod, l, Z);
+ cgen(l, &nod);
+ regalloc(&nod1, n, nn);
+ gmove(&nod, nod1.right);
+ if(typeu[l->type->etype])
+ gmove(nodconst(0), nod1.left);
+ else
+ gopcode(OASHR, nodconst(31), nod1.right, nod1.left);
+ regfree(&nod);
+ }
+ gmove(&nod1, nn);
+ regfree(&nod1);
+ break;
+
+ case OFUNC:
+ /* this transformation should probably be done earlier */
+ if(nn == Z) {
+ regsalloc(&nod1, n);
+ nn = &nod1;
+ }
+ m = 0;
+ if(nn->op != OIND) {
+ if(nn->op == OREGPAIR) {
+ m = 1;
+ regsalloc(&nod1, nn);
+ d = &nod1;
+ }else
+ d = nn;
+ d = new1(OADDR, d, Z);
+ d->type = types[TIND];
+ d->addable = 0;
+ } else
+ d = nn->left;
+ n = new(OFUNC, l, new(OLIST, d, r));
+ n->complex = FNX;
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ if(m)
+ gmove(&nod1, nn);
+ break;
+
+ default:
+ diag(n, "bad cgen64 %O", o);
+ break;
+ }
+ cursafe = curs;
+}
diff --git a/utils/qc/enam.c b/utils/qc/enam.c
index 70535f8a..98d0edcf 100644
--- a/utils/qc/enam.c
+++ b/utils/qc/enam.c
@@ -130,21 +130,11 @@ char *anames[] =
"MOVW",
"MOVWU",
"MOVFL",
- "MOVCRFXXX",
"MOVCRFS",
- "MOVCRXRXXX",
- "MOVFCRXXX",
- "MFFSXXX",
- "MFFSCCXXX",
- "MTCRFXXX",
"MTFSB0",
"MTFSB0CC",
"MTFSB1",
"MTFSB1CC",
- "MTFSFXXX",
- "MTFSFCCXXX",
- "MTFSFIXXX",
- "MTFSFIXXXCC",
"MULHW",
"MULHWCC",
"MULHWU",
@@ -184,9 +174,7 @@ char *anames[] =
"SRAW",
"SRAWCC",
"SRWCC",
- "ILLXXX1",
"STSW",
- "STWBRXXX",
"STWCCC",
"SUB",
"SUBCC",
@@ -323,5 +311,76 @@ char *anames[] =
"NMACLHWV",
"NMACLHWVCC",
"RFCI",
+ "FRES",
+ "FRESCC",
+ "FRSQRTE",
+ "FRSQRTECC",
+ "FSEL",
+ "FSELCC",
+ "FSQRT",
+ "FSQRTCC",
+ "FSQRTS",
+ "FSQRTSCC",
+ "FPSEL",
+ "FPMUL",
+ "FXMUL",
+ "FXPMUL",
+ "FXSMUL",
+ "FPADD",
+ "FPSUB",
+ "FPRE",
+ "FPRSQRTE",
+ "FPMADD",
+ "FXMADD",
+ "FXCPMADD",
+ "FXCSMADD",
+ "FPNMADD",
+ "FXNMADD",
+ "FXCPNMADD",
+ "FXCSNMADD",
+ "FPMSUB",
+ "FXMSUB",
+ "FXCPMSUB",
+ "FXCSMSUB",
+ "FPNMSUB",
+ "FXNMSUB",
+ "FXCPNMSUB",
+ "FXCSNMSUB",
+ "FPMOVD",
+ "FPABS",
+ "FPNEG",
+ "FPRSP",
+ "FPNABS",
+ "FSMOVD",
+ "FSCMP",
+ "FSABS",
+ "FSNEG",
+ "FSNABS",
+ "FXMOVD",
+ "FPCTIW",
+ "FPCTIWZ",
+ "FSMOVP",
+ "FPMOVS",
+ "FXCPNPMA",
+ "FXCSNPMA",
+ "FXCPNSMA",
+ "FXCSNSMA",
+ "FXCXNPMA",
+ "FXCXNSMA",
+ "FXCXMA",
+ "FXCXNMS",
+ "FMOVSS",
+ "FMOVSSU",
+ "FMOVSD",
+ "FMOVSDU",
+ "FMOVXS",
+ "FMOVSXU",
+ "FMOVXD",
+ "FMOVXDU",
+ "FMOVPS",
+ "FMOVPSU",
+ "FMOVPD",
+ "FMOVPDU",
+ "FMOVPIW",
"LAST",
};
diff --git a/utils/qc/gc.h b/utils/qc/gc.h
index bf4e9091..16aab0ba 100644
--- a/utils/qc/gc.h
+++ b/utils/qc/gc.h
@@ -58,6 +58,7 @@ struct Case
long val;
long label;
char def;
+ char isv;
};
#define C ((Case*)0)
@@ -129,6 +130,7 @@ struct Rgn
};
EXTERN long breakpc;
+EXTERN long nbreak;
EXTERN Case* cases;
EXTERN Node constnode;
EXTERN Node fconstnode;
@@ -141,10 +143,10 @@ EXTERN int hintabsize;
EXTERN long maxargsafe;
EXTERN Multab multab[20];
EXTERN int mnstring;
-EXTERN int retok;
EXTERN Node* nodrat;
EXTERN Node* nodret;
EXTERN Node* nodsafe;
+EXTERN Node* nodretv;
EXTERN long nrathole;
EXTERN long nstring;
EXTERN Prog* p;
@@ -244,8 +246,11 @@ void regind(Node*, Node*);
void gprep(Node*, Node*);
void raddr(Node*, Prog*);
void naddr(Node*, Adr*);
+void gloadhi(Node*, Node*, int);
+void gloadlo(Node*, Node*, int);
void gmove(Node*, Node*);
void gins(int a, Node*, Node*);
+void gins3(int a, Node*, Node*, Node*);
void gopcode(int, Node*, Node*, Node*);
int samaddr(Node*, Node*);
void gbranch(int);
@@ -253,6 +258,10 @@ void patch(Prog*, long);
int sconst(Node*);
int sval(long);
int uconst(Node*);
+long hi64v(Node*);
+long lo64v(Node*);
+Node* hi64(Node*);
+Node* lo64(Node*);
void gpseudo(int, Sym*, Node*);
/*
@@ -260,8 +269,9 @@ void gpseudo(int, Sym*, Node*);
*/
int swcmp(void*, void*);
void doswit(Node*);
-void swit1(C1*, int, long, Node*, Node*);
-void cas(void);
+void swit1(C1*, int, long, Node*);
+void swit2(C1*, int, long, Node*, Node*);
+void casf(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
long outstring(char*, long);
diff --git a/utils/qc/list.c b/utils/qc/list.c
index 3538c621..2f7eeb18 100644
--- a/utils/qc/list.c
+++ b/utils/qc/list.c
@@ -72,7 +72,7 @@ Aconv(Fmt *fp)
a = va_arg(fp->args, int);
s = "???";
- if(a >= AXXX && a <= AEND)
+ if(a >= AXXX && a <= ALAST)
s = anames[a];
return fmtstrcpy(fp, s);
}
diff --git a/utils/qc/machcap.c b/utils/qc/machcap.c
new file mode 100644
index 00000000..5fae5731
--- /dev/null
+++ b/utils/qc/machcap.c
@@ -0,0 +1,16 @@
+#include "gc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+ if(n == Z)
+ return 0; /* test */
+ switch(n->op){
+ case OCOMMA:
+ case OCOND:
+ case OLIST:
+ return 1;
+ }
+ return 0;
+}
diff --git a/utils/qc/mkfile b/utils/qc/mkfile
index 21933876..19258dba 100644
--- a/utils/qc/mkfile
+++ b/utils/qc/mkfile
@@ -3,14 +3,17 @@
TARG=qc
OFILES=\
cgen.$O\
- reg.$O\
- txt.$O\
- peep.$O\
- swt.$O\
- sgen.$O\
- list.$O\
enam.$O\
+ list.$O\
+ machcap.$O\
mul.$O\
+ peep.$O\
+ pgen.$O\
+ pswt.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
HFILES=\
gc.h\
@@ -27,3 +30,9 @@ $ROOT/$OBJDIR/lib/libcc.a:
cd ../cc
mk $MKFLAGS install
mk $MKFLAGS clean
+
+%.$O: ../cc/%.c
+ $CC $CFLAGS ../cc/$stem.c
+
+#enam.c: q.out.h
+# rc mkenam
diff --git a/utils/qc/peep.c b/utils/qc/peep.c
index 69d021be..cf1114f0 100644
--- a/utils/qc/peep.c
+++ b/utils/qc/peep.c
@@ -167,7 +167,16 @@ loop1:
case AORNCC:
case AXORCC:
case ASUBCC:
+ case ASUBECC:
+ case ASUBMECC:
+ case ASUBZECC:
case AADDCC:
+ case AADDCCC:
+ case AADDECC:
+ case AADDMECC:
+ case AADDZECC:
+ case ARLWMICC:
+ case ARLWNMCC:
t = p1->as;
break;
/* don't deal with floating point instructions for now */
@@ -269,6 +278,7 @@ excise(Reg *r)
p = r->prog;
p->as = ANOP;
p->from = zprog.from;
+ p->from3 = zprog.from3;
p->to = zprog.to;
p->reg = zprog.reg; /**/
}
@@ -309,7 +319,6 @@ uniqs(Reg *r)
* if the system forces R0 to be zero,
* convert references to $0 to references to R0.
*/
-int
regzer(Adr *a)
{
if(R0ISZERO) {
@@ -324,7 +333,6 @@ regzer(Adr *a)
return 0;
}
-int
regtyp(Adr *a)
{
@@ -376,10 +384,22 @@ subprop(Reg *r0)
return 0;
case AADD:
+ case AADDC:
+ case AADDCC:
+ case AADDE:
+ case AADDECC:
case ASUB:
+ case ASUBCC:
+ case ASUBC:
+ case ASUBCCC:
+ case ASUBE:
+ case ASUBECC:
case ASLW:
+ case ASLWCC:
case ASRW:
+ case ASRWCC:
case ASRAW:
+ case ASRAWCC:
case AOR:
case AORCC:
case AORN:
@@ -394,13 +414,17 @@ subprop(Reg *r0)
case ANORCC:
case AXOR:
case AXORCC:
+ case AMULHW:
+ case AMULHWU:
case AMULLW:
case ADIVW:
case ADIVWU:
case AREM:
case AREMU:
- case ANEG:
- case ANEGCC:
+ case ARLWNM:
+ case ARLWNMCC:
+ case ARLWMI:
+ case ARLWMICC:
case AFADD:
case AFADDS:
@@ -410,8 +434,6 @@ subprop(Reg *r0)
case AFMULS:
case AFDIV:
case AFDIVS:
- case AFNEG:
- case AFNEGCC:
if(p->to.type == v1->type)
if(p->to.reg == v1->reg) {
if(p->reg == NREG)
@@ -420,6 +442,18 @@ subprop(Reg *r0)
}
break;
+ case AADDME:
+ case AADDMECC:
+ case AADDZE:
+ case AADDZECC:
+ case ASUBME:
+ case ASUBMECC:
+ case ASUBZE:
+ case ASUBZECC:
+ case ANEG:
+ case ANEGCC:
+ case AFNEG:
+ case AFNEGCC:
case AFMOVS:
case AFMOVD:
case AMOVW:
@@ -492,7 +526,6 @@ copyprop(Reg *r0)
return copy1(v1, v2, r0->s1, 0);
}
-int
copy1(Adr *v1, Adr *v2, Reg *r, int f)
{
int t;
@@ -585,7 +618,7 @@ copyu(Prog *p, Adr *v, Adr *s)
default:
if(debug['P'])
- print(" (?)");
+ print(" (???)");
return 2;
@@ -598,6 +631,14 @@ copyu(Prog *p, Adr *v, Adr *s)
case ANEG:
case ANEGCC:
+ case AADDME:
+ case AADDMECC:
+ case AADDZE:
+ case AADDZECC:
+ case ASUBME:
+ case ASUBMECC:
+ case ASUBZE:
+ case ASUBZECC:
case AFCTIW:
case AFCTIWZ:
@@ -626,6 +667,8 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case AADD: /* read read write */
+ case AADDC:
+ case AADDE:
case ASUB:
case ASLW:
case ASRW:
@@ -643,11 +686,17 @@ copyu(Prog *p, Adr *v, Adr *s)
case ANOR:
case ANORCC:
case AXOR:
+ case AMULHW:
+ case AMULHWU:
case AMULLW:
case ADIVW:
case ADIVWU:
case AREM:
case AREMU:
+ case ARLWMI:
+ case ARLWMICC:
+ case ARLWNM:
+ case ARLWNMCC:
case AFADDS:
case AFADD:
@@ -763,9 +812,25 @@ a2type(Prog *p)
switch(p->as) {
case AADD:
+ case AADDC:
case AADDCC:
+ case AADDCCC:
+ case AADDE:
+ case AADDECC:
+ case AADDME:
+ case AADDMECC:
+ case AADDZE:
+ case AADDZECC:
case ASUB:
+ case ASUBC:
case ASUBCC:
+ case ASUBCCC:
+ case ASUBE:
+ case ASUBECC:
+ case ASUBME:
+ case ASUBMECC:
+ case ASUBZE:
+ case ASUBZECC:
case ASLW:
case ASLWCC:
case ASRW:
@@ -784,6 +849,8 @@ a2type(Prog *p)
case AXORCC:
case ANEG:
case ANEGCC:
+ case AMULHW:
+ case AMULHWU:
case AMULLW:
case AMULLWCC:
case ADIVW:
@@ -798,6 +865,10 @@ a2type(Prog *p)
case ANANDCC:
case ANOR:
case ANORCC:
+ case ARLWMI:
+ case ARLWMICC:
+ case ARLWNM:
+ case ARLWNMCC:
return D_REG;
case AFADDS:
diff --git a/utils/qc/q.out.h b/utils/qc/q.out.h
index 795da7f7..1c5a141e 100644
--- a/utils/qc/q.out.h
+++ b/utils/qc/q.out.h
@@ -169,21 +169,11 @@ enum as
AMOVW,
AMOVWU,
AMOVFL,
- AMOVCRFXXX,
AMOVCRFS,
- AMOVCRXRXXX,
- AMOVFCRXXX,
- AMFFSXXX,
- AMFFSCCXXX,
- AMTCRFXXX,
AMTFSB0,
AMTFSB0CC,
AMTFSB1,
AMTFSB1CC,
- AMTFSFXXX,
- AMTFSFCCXXX,
- AMTFSFIXXX,
- AMTFSFIXXXCC,
AMULHW,
AMULHWCC,
AMULHWU,
@@ -223,9 +213,7 @@ enum as
ASRAW,
ASRAWCC,
ASRWCC,
- AILLXXX1,
ASTSW,
- ASTWBRXXX,
ASTWCCC,
ASUB,
ASUBCC,
@@ -368,6 +356,83 @@ enum as
ARFCI,
+ /* optional on 32-bit */
+ AFRES,
+ AFRESCC,
+ AFRSQRTE,
+ AFRSQRTECC,
+ AFSEL,
+ AFSELCC,
+ AFSQRT,
+ AFSQRTCC,
+ AFSQRTS,
+ AFSQRTSCC,
+
+ /* parallel, cross, and secondary */
+ AFPSEL,
+ AFPMUL,
+ AFXMUL,
+ AFXPMUL,
+ AFXSMUL,
+ AFPADD,
+ AFPSUB,
+ AFPRE,
+ AFPRSQRTE,
+ AFPMADD,
+ AFXMADD,
+ AFXCPMADD,
+ AFXCSMADD,
+ AFPNMADD,
+ AFXNMADD,
+ AFXCPNMADD,
+ AFXCSNMADD,
+ AFPMSUB,
+ AFXMSUB,
+ AFXCPMSUB,
+ AFXCSMSUB,
+ AFPNMSUB,
+ AFXNMSUB,
+ AFXCPNMSUB,
+ AFXCSNMSUB,
+ AFPMOVD,
+ AFPABS,
+ AFPNEG,
+ AFPRSP,
+ AFPNABS,
+ AFSMOVD,
+ AFSCMP,
+ AFSABS,
+ AFSNEG,
+ AFSNABS,
+ AFXMOVD,
+ AFPCTIW,
+ AFPCTIWZ,
+ AFSMOVP,
+ AFPMOVS,
+ AFXCPNPMA,
+ AFXCSNPMA,
+ AFXCPNSMA,
+ AFXCSNSMA,
+ AFXCXNPMA,
+ AFXCXNSMA,
+ AFXCXMA,
+ AFXCXNMS,
+
+ /* parallel, cross, and secondary load and store */
+ AFMOVSS,
+ AFMOVSSU,
+ AFMOVSD,
+ AFMOVSDU,
+ AFMOVXS,
+ AFMOVSXU,
+ AFMOVXD,
+ AFMOVXDU,
+ AFMOVPS,
+ AFMOVPSU,
+ AFMOVPD,
+ AFMOVPDU,
+ AFMOVPIW,
+
ALAST
};
diff --git a/utils/qc/reg.c b/utils/qc/reg.c
index c1a900b0..33152f27 100644
--- a/utils/qc/reg.c
+++ b/utils/qc/reg.c
@@ -840,7 +840,6 @@ allreg(ulong b, Rgn *r)
}
break;
- case TVLONG:
case TDOUBLE:
case TFLOAT:
i = BtoF(~b);
diff --git a/utils/qc/sgen.c b/utils/qc/sgen.c
index d557d375..37542ebb 100644
--- a/utils/qc/sgen.c
+++ b/utils/qc/sgen.c
@@ -1,381 +1,6 @@
#include "gc.h"
void
-codgen(Node *n, Node *nn)
-{
- Prog *sp;
- Node *n1, nod, nod1;
-
- cursafe = 0;
- curarg = 0;
- maxargsafe = 0;
-
- /*
- * isolate name
- */
- for(n1 = nn;; n1 = n1->left) {
- if(n1 == Z) {
- diag(nn, "cant find function name");
- return;
- }
- if(n1->op == ONAME)
- break;
- }
- nearln = nn->lineno;
- gpseudo(ATEXT, n1->sym, nodconst(stkoff));
- sp = p;
-
- /*
- * isolate first argument
- */
- if(REGARG) {
- if(typesuv[thisfn->link->etype]) {
- nod1 = *nodret->left;
- nodreg(&nod, &nod1, REGARG);
- gopcode(OAS, &nod, Z, &nod1);
- } else
- if(firstarg && typechlp[firstargtype->etype]) {
- nod1 = *nodret->left;
- nod1.sym = firstarg;
- nod1.type = firstargtype;
- nod1.xoffset = align(0, firstargtype, Aarg1);
- nod1.etype = firstargtype->etype;
- nodreg(&nod, &nod1, REGARG);
- gopcode(OAS, &nod, Z, &nod1);
- }
- }
-
- retok = 0;
- gen(n);
- if(!retok)
- if(thisfn->link->etype != TVOID)
- warn(Z, "no return at end of function: %s", n1->sym->name);
- noretval(3);
- gbranch(ORETURN);
-
- if(!debug['N'] || debug['R'] || debug['P'])
- regopt(sp);
-
- sp->to.offset += maxargsafe;
-}
-
-void
-supgen(Node *n)
-{
- long spc;
- Prog *sp;
-
- if(n == Z)
- return;
- suppress++;
- spc = pc;
- sp = lastp;
- gen(n);
- lastp = sp;
- pc = spc;
- sp->link = nil;
- suppress--;
-}
-
-void
-gen(Node *n)
-{
- Node *l, nod;
- Prog *sp, *spc, *spb;
- Case *cn;
- long sbc, scc;
- int o, f;
-
-loop:
- if(n == Z)
- return;
- nearln = n->lineno;
- o = n->op;
- if(debug['G'])
- if(o != OLIST)
- print("%L %O\n", nearln, o);
- retok = 0;
- switch(o) {
-
- default:
- complex(n);
- cgen(n, Z);
- break;
-
- case OLIST:
- gen(n->left);
-
- rloop:
- n = n->right;
- goto loop;
-
- case ORETURN:
- retok = 1;
- complex(n);
- if(n->type == T)
- break;
- l = n->left;
- if(l == Z) {
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- if(typesuv[n->type->etype]) {
- sugen(l, nodret, n->type->width);
- noretval(3);
- gbranch(ORETURN);
- break;
- }
- regret(&nod, n);
- cgen(l, &nod);
- regfree(&nod);
- if(typefd[n->type->etype])
- noretval(1);
- else
- noretval(2);
- gbranch(ORETURN);
- break;
-
- case OLABEL:
- l = n->left;
- if(l) {
- l->xoffset = pc;
- if(l->label)
- patch(l->label, pc);
- }
- gbranch(OGOTO); /* prevent self reference in reg */
- patch(p, pc);
- goto rloop;
-
- case OGOTO:
- retok = 1;
- n = n->left;
- if(n == Z)
- return;
- if(n->complex == 0) {
- diag(Z, "label undefined: %s", n->sym->name);
- return;
- }
- if(suppress)
- return;
- gbranch(OGOTO);
- if(n->xoffset) {
- patch(p, n->xoffset);
- return;
- }
- if(n->label)
- patch(n->label, pc-1);
- n->label = p;
- return;
-
- case OCASE:
- l = n->left;
- if(cases == C)
- diag(n, "case/default outside a switch");
- if(l == Z) {
- cas();
- cases->val = 0;
- cases->def = 1;
- cases->label = pc;
- goto rloop;
- }
- complex(l);
- if(l->type == T)
- goto rloop;
- if(l->op == OCONST)
- if(typechl[l->type->etype]) {
- cas();
- cases->val = l->vconst;
- cases->def = 0;
- cases->label = pc;
- goto rloop;
- }
- diag(n, "case expression must be integer constant");
- goto rloop;
-
- case OSWITCH:
- l = n->left;
- complex(l);
- if(l->type == T)
- break;
- if(!typechl[l->type->etype]) {
- diag(n, "switch expression must be integer");
- break;
- }
-
- gbranch(OGOTO); /* entry */
- sp = p;
-
- cn = cases;
- cases = C;
- cas();
-
- sbc = breakpc;
- breakpc = pc;
- gbranch(OGOTO);
- spb = p;
-
- gen(n->right);
- gbranch(OGOTO);
- patch(p, breakpc);
-
- patch(sp, pc);
- regalloc(&nod, l, Z);
- nod.type = types[TLONG];
- cgen(l, &nod);
- doswit(&nod);
- regfree(&nod);
- patch(spb, pc);
-
- cases = cn;
- breakpc = sbc;
- break;
-
- case OWHILE:
- case ODWHILE:
- l = n->left;
- gbranch(OGOTO); /* entry */
- sp = p;
-
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
-
- sbc = breakpc;
- breakpc = pc;
- gbranch(OGOTO);
- spb = p;
-
- patch(spc, pc);
- if(n->op == OWHILE)
- patch(sp, pc);
- bcomplex(l, Z); /* test */
- patch(p, breakpc);
-
- if(n->op == ODWHILE)
- patch(sp, pc);
- gen(n->right); /* body */
- gbranch(OGOTO);
- patch(p, continpc);
-
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- break;
-
- case OFOR:
- l = n->left;
- gen(l->right->left); /* init */
- gbranch(OGOTO); /* entry */
- sp = p;
-
- scc = continpc;
- continpc = pc;
- gbranch(OGOTO);
- spc = p;
-
- sbc = breakpc;
- breakpc = pc;
- gbranch(OGOTO);
- spb = p;
-
- patch(spc, pc);
- gen(l->right->right); /* inc */
- patch(sp, pc);
- if(l->left != Z) { /* test */
- bcomplex(l->left, Z);
- patch(p, breakpc);
- }
- gen(n->right); /* body */
- gbranch(OGOTO);
- patch(p, continpc);
-
- patch(spb, pc);
- continpc = scc;
- breakpc = sbc;
- break;
-
- case OCONTINUE:
- if(continpc < 0) {
- diag(n, "continue not in a loop");
- break;
- }
- gbranch(OGOTO);
- patch(p, continpc);
- break;
-
- case OBREAK:
- if(breakpc < 0) {
- diag(n, "break not in a loop");
- break;
- }
- gbranch(OGOTO);
- patch(p, breakpc);
- break;
-
- case OIF:
- l = n->left;
- if(bcomplex(l, n->right)) {
- if(typefd[l->type->etype])
- f = !l->fconst;
- else
- f = !l->vconst;
- if(debug['c'])
- print("%L const if %s\n", nearln, f ? "false" : "true");
- if(f) {
- supgen(n->right->left);
- gen(n->right->right);
- }
- else {
- gen(n->right->left);
- supgen(n->right->right);
- }
- }
- else {
- sp = p;
- if(n->right->left != Z)
- gen(n->right->left);
- if(n->right->right != Z) {
- gbranch(OGOTO);
- patch(sp, pc);
- sp = p;
- gen(n->right->right);
- }
- patch(sp, pc);
- }
- break;
-
- case OSET:
- case OUSED:
- usedset(n->left, o);
- break;
- }
-}
-
-void
-usedset(Node *n, int o)
-{
- if(n->op == OLIST) {
- usedset(n->left, o);
- usedset(n->right, o);
- return;
- }
- complex(n);
- switch(n->op) {
- case OADDR: /* volatile */
- gins(ANOP, n, Z);
- break;
- case ONAME:
- if(o == OSET)
- gins(ANOP, Z, n);
- else
- gins(ANOP, n, Z);
- break;
- }
-}
-
-void
noretval(int n)
{
@@ -410,7 +35,7 @@ void
xcom(Node *n)
{
Node *l, *r;
- int v;
+ int v, nr;
if(n == Z)
return;
@@ -568,14 +193,23 @@ xcom(Node *n)
if(l != Z)
n->complex = l->complex;
if(r != Z) {
+ nr = 1;
+ if(r->type != T && typev[r->type->etype] || n->type != T && typev[n->type->etype]) {
+ nr = 2;
+ if(n->op == OMUL || n->op == OLMUL)
+ nr += 3;
+ }
if(r->complex == n->complex)
- n->complex = r->complex+1;
+ n->complex = r->complex+nr;
else
if(r->complex > n->complex)
n->complex = r->complex;
}
- if(n->complex == 0)
+ if(n->complex == 0){
n->complex++;
+ if(n->type != T && typev[n->type->etype])
+ n->complex++;
+ }
if(com64(n))
return;
@@ -621,20 +255,3 @@ xcom(Node *n)
}
}
-int
-bcomplex(Node *n, Node *c)
-{
-
- complex(n);
- if(n->type != T)
- if(tcompat(n, T, n->type, tnot))
- n->type = T;
- if(n->type != T) {
- if(c != Z && n->op == OCONST && deadheads(c))
- return 1;
- bool64(n);
- boolgen(n, 1, Z);
- } else
- gbranch(OGOTO);
- return 0;
-}
diff --git a/utils/qc/swt.c b/utils/qc/swt.c
index 9bf0e58e..0170bad1 100644
--- a/utils/qc/swt.c
+++ b/utils/qc/swt.c
@@ -1,59 +1,20 @@
#include "gc.h"
-int
-swcmp(void *a1, void *a2)
-{
- C1 *p1, *p2;
-
- p1 = a1;
- p2 = a2;
- if(p1->val < p2->val)
- return -1;
- return p1->val > p2->val;
-}
+int hasdoubled;
+static int doubleflag;
void
-doswit(Node *n)
+swit1(C1 *q, int nc, long def, Node *n)
{
- Case *c;
- C1 *q, *iq;
- long def, nc, i;
Node tn;
-
- def = 0;
- nc = 0;
- for(c = cases; c->link != C; c = c->link) {
- if(c->def) {
- if(def)
- diag(n, "more than one default in switch");
- def = c->label;
- continue;
- }
- nc++;
- }
-
- iq = alloc(nc*sizeof(C1));
- q = iq;
- for(c = cases; c->link != C; c = c->link) {
- if(c->def)
- continue;
- q->label = c->label;
- q->val = c->val;
- q++;
- }
- qsort(iq, nc, sizeof(C1), swcmp);
- if(def == 0)
- def = breakpc;
- for(i=0; i<nc-1; i++)
- if(iq[i].val == iq[i+1].val)
- diag(n, "duplicate cases in switch %ld", iq[i].val);
+
regalloc(&tn, &regnode, Z);
- swit1(iq, nc, def, n, &tn);
+ swit2(q, nc, def, n, &tn);
regfree(&tn);
}
void
-swit1(C1 *q, int nc, long def, Node *n, Node *tn)
+swit2(C1 *q, int nc, long def, Node *n, Node *tn)
{
C1 *r;
int i;
@@ -87,20 +48,10 @@ swit1(C1 *q, int nc, long def, Node *n, Node *tn)
gbranch(OGOTO);
p->as = ABEQ;
patch(p, r->label);
- swit1(q, i, def, n, tn);
+ swit2(q, i, def, n, tn);
patch(sp, pc);
- swit1(r+1, nc-i-1, def, n, tn);
-}
-
-void
-cas(void)
-{
- Case *c;
-
- c = alloc(sizeof(*c));
- c->link = cases;
- cases = c;
+ swit2(r+1, nc-i-1, def, n, tn);
}
void
@@ -200,33 +151,6 @@ outstring(char *s, long n)
return r;
}
-long
-outlstring(ushort *s, long n)
-{
- char buf[2];
- int c;
- long r;
-
- if(suppress)
- return nstring;
- while(nstring & 1)
- outstring("", 1);
- r = nstring;
- while(n > 0) {
- c = *s++;
- if(align(0, types[TCHAR], Aarg1)) {
- buf[0] = c>>8;
- buf[1] = c;
- } else {
- buf[0] = c;
- buf[1] = c>>8;
- }
- outstring(buf, 2);
- n -= sizeof(ushort);
- }
- return r;
-}
-
int
mulcon(Node *n, Node *nn)
{
@@ -317,16 +241,6 @@ loop:
}
void
-nullwarn(Node *l, Node *r)
-{
- warn(Z, "result of operation not used");
- if(l != Z)
- cgen(l, Z);
- if(r != Z)
- cgen(r, Z);
-}
-
-void
sextern(Sym *s, Node *a, long o, long w)
{
long e, lw;
@@ -454,13 +368,14 @@ zwrite(Biobuf *b, Prog *p, int sf, int st)
long l;
bf[0] = p->as;
- bf[1] = p->reg;
+ bf[1] = p->as>>8;
+ bf[2] = p->reg;
l = p->lineno;
- bf[2] = l;
- bf[3] = l>>8;
- bf[4] = l>>16;
- bf[5] = l>>24;
- bp = zaddr(bf+6, &p->from, sf);
+ bf[3] = l;
+ bf[4] = l>>8;
+ bf[5] = l>>16;
+ bf[6] = l>>24;
+ bp = zaddr(bf+7, &p->from, sf);
bp = zaddr(bp, &p->to, st);
Bwrite(b, bf, bp-bf);
}
@@ -510,6 +425,7 @@ outhist(Biobuf *b)
}
if(n) {
Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
Bputc(b, D_FILE);
Bputc(b, 1);
Bputc(b, '<');
@@ -535,27 +451,29 @@ outhist(Biobuf *b)
void
zname(Biobuf *b, Sym *s, int t)
{
- char *n, bf[7];
+ char *n, bf[8];
ulong sig;
n = s->name;
if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
sig = sign(s);
bf[0] = ASIGNAME;
- bf[1] = sig;
- bf[2] = sig>>8;
- bf[3] = sig>>16;
- bf[4] = sig>>24;
- bf[5] = t;
- bf[6] = s->sym;
- Bwrite(b, bf, 7);
+ bf[1] = ASIGNAME>>8;
+ bf[2] = sig;
+ bf[3] = sig>>8;
+ bf[4] = sig>>16;
+ bf[5] = sig>>24;
+ bf[6] = t;
+ bf[7] = s->sym;
+ Bwrite(b, bf, 8);
s->sig = SIGDONE;
}
else{
bf[0] = ANAME;
- bf[1] = t; /* type */
- bf[2] = s->sym; /* sym */
- Bwrite(b, bf, 3);
+ bf[1] = ANAME>>8;
+ bf[2] = t; /* type */
+ bf[3] = s->sym; /* sym */
+ Bwrite(b, bf, 4);
}
Bwrite(b, n, strlen(n)+1);
}
@@ -616,33 +534,32 @@ zaddr(char *bp, Adr *a, int s)
return bp;
}
-void
-ieeedtod(Ieee *ieee, double native)
+static int
+doubled(Type *t)
{
- double fr, ho, f;
- int exp;
+ Type *v;
- if(native < 0) {
- ieeedtod(ieee, -native);
- ieee->h |= 0x80000000L;
- return;
- }
- if(native == 0) {
- ieee->l = 0;
- ieee->h = 0;
- return;
+ if(debug['4'])
+ return 0;
+ if(t->nbits != 0)
+ return 0;
+ switch(t->etype){
+ case TDOUBLE:
+ return 1;
+
+ case TARRAY:
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ return v->etype == TDOUBLE;
+
+ case TSTRUCT:
+ case TUNION:
+ for(v = t->link; v != T; v = v->down)
+ if(doubled(v))
+ return 1;
+ break;
}
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldnt use fp constants here */
- fr = modf(fr*f, &ho);
- ieee->h = ho;
- ieee->h &= 0xfffffL;
- ieee->h |= (exp+1022L) << 20;
- f = 65536L;
- fr = modf(fr*f, &ho);
- ieee->l = ho;
- ieee->l <<= 16;
- ieee->l |= (long)(fr*f);
+ return 0;
}
long
@@ -650,27 +567,33 @@ align(long i, Type *t, int op)
{
long o;
Type *v;
- int w;
+ int w, pc;
o = i;
w = 1;
+ pc = 0;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
break;
case Asu2: /* padding at end of a struct */
- w = SZ_LONG;
+ w = doubled(t)? SZ_DOUBLE: SZ_LONG;
if(packflg)
w = packflg;
break;
- case Ael1: /* initial allign of struct element */
+ case Ael1: /* initial align of struct element (also automatic) */
for(v=t; v->etype==TARRAY; v=v->link)
;
w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_LONG)
- w = SZ_LONG;
+ if(w <= 0 || w >= SZ_LONG){
+ if(doubled(v)){
+ w = SZ_DOUBLE;
+ doubleflag = 1;
+ }else
+ w = SZ_LONG;
+ }
if(packflg)
w = packflg;
break;
@@ -686,10 +609,15 @@ align(long i, Type *t, int op)
}
break;
- case Aarg1: /* initial allign of parameter */
+ case Aarg1: /* initial align of parameter */
w = ewidth[t->etype];
if(w <= 0 || w >= SZ_LONG) {
- w = SZ_LONG;
+ if(doubled(t)){
+ w = SZ_DOUBLE;
+ pc = SZ_LONG; /* alignment must account for pc */
+ hasdoubled = 1;
+ }else
+ w = SZ_LONG;
break;
}
o += SZ_LONG - w; /* big endian adjustment */
@@ -699,14 +627,20 @@ align(long i, Type *t, int op)
case Aarg2: /* width of a parameter */
o += t->width;
w = SZ_LONG;
+ if(doubled(t)){
+ pc = SZ_LONG;
+ hasdoubled = 1;
+ }
break;
- case Aaut3: /* total allign of automatic */
+ case Aaut3: /* total align of automatic */
+ doubleflag = 0;
o = align(o, t, Ael1);
o = align(o, t, Ael2);
+ hasdoubled |= doubleflag;
break;
}
- o = round(o, w);
+ o = round(o+pc, w)-pc;
if(debug['A'])
print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
return o;
@@ -715,8 +649,13 @@ align(long i, Type *t, int op)
long
maxround(long max, long v)
{
- v += SZ_LONG-1;
+ int w;
+
+ w = SZ_LONG;
+ if((debug['8'] || hasdoubled) && !debug['4'])
+ w = SZ_DOUBLE;
+ v += w-1;
if(v > max)
- max = round(v, SZ_LONG);
+ max = round(v, w);
return max;
}
diff --git a/utils/qc/txt.c b/utils/qc/txt.c
index c14386ac..d8102433 100644
--- a/utils/qc/txt.c
+++ b/utils/qc/txt.c
@@ -2,6 +2,9 @@
static int resvreg[nelem(reg)];
+static void gopcode64(int, Node*, Node*, Node*);
+static void gori64(int, Node*, Node*, Node*);
+static void gandi64(int, Node*, Node*, Node*);
void
ginit(void)
@@ -30,6 +33,7 @@ ginit(void)
zprog.from.type = D_NONE;
zprog.from.name = D_NONE;
zprog.from.reg = NREG;
+ zprog.from3 = zprog.from;
zprog.to = zprog.from;
regnode.op = OREGISTER;
@@ -71,14 +75,6 @@ ginit(void)
complex(nodrat);
nodrat->type = t;
- nodret = new(ONAME, Z, Z);
- nodret->sym = slookup(".ret");
- nodret->type = types[TIND];
- nodret->etype = TIND;
- nodret->class = CPARAM;
- nodret = new(OIND, nodret, Z);
- complex(nodret);
-
com64init();
memset(reg, 0, sizeof(reg));
@@ -188,10 +184,10 @@ garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
if(typesuv[n->type->etype]) {
regaalloc(tn2, n);
if(n->complex >= FNX) {
- sugen(*fnxp, tn2, n->type->width);
+ cgen(*fnxp, tn2);
(*fnxp)++;
} else
- sugen(n, tn2, n->type->width);
+ cgen(n, tn2);
return;
}
if(REGARG && curarg == 0 && typechlp[n->type->etype]) {
@@ -314,6 +310,27 @@ regalloc(Node *n, Node *tn, Node *o)
}
diag(tn, "out of float registers");
goto err;
+
+ case TVLONG:
+ case TUVLONG:
+ n->op = OREGPAIR;
+ n->complex = 0; /* already in registers */
+ n->addable = 11;
+ n->type = tn->type;
+ n->lineno = nearln;
+ n->left = alloc(sizeof(Node));
+ n->right = alloc(sizeof(Node));
+ if(o != Z && o->op == OREGPAIR) {
+ regalloc(n->left, &regnode, o->left);
+ regalloc(n->right, &regnode, o->right);
+ } else {
+ regalloc(n->left, &regnode, Z);
+ regalloc(n->right, &regnode, Z);
+ }
+ n->right->type = types[TULONG];
+ if(tn->type->etype == TUVLONG)
+ n->left->type = types[TULONG]; /* TO DO: is this a bad idea? */
+ return;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
@@ -342,6 +359,11 @@ regfree(Node *n)
{
int i;
+ if(n->op == OREGPAIR) {
+ regfree(n->left);
+ regfree(n->right);
+ return;
+ }
i = 0;
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
@@ -353,14 +375,19 @@ regfree(Node *n)
reg[i]--;
return;
err:
- diag(n, "error in regfree: %d", i);
+ diag(n, "error in regfree: %d [%d]", i, reg[i]);
+ prtree(n, "regfree");
}
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe+stkoff, nn->type, Aaut3)-stkoff;
maxargsafe = maxround(maxargsafe, cursafe+curarg);
+// if(nn->type->etype == TDOUBLE || nn->type->etype == TVLONG){
+// extern int hasdoubled;
+// fprint(2, "stkoff=%ld cursafe=%ld curarg=%ld %d\n", stkoff, cursafe, curarg, hasdoubled);
+// }
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
n->type = nn->type;
@@ -450,6 +477,7 @@ naddr(Node *n, Adr *a)
case OIND:
naddr(n->left, a);
+ a->offset += n->xoffset; /* little hack for reglcgenv */
if(a->type == D_REG) {
a->type = D_OREG;
break;
@@ -526,6 +554,59 @@ naddr(Node *n, Adr *a)
}
void
+gloadhi(Node *f, Node *t, int c)
+{
+ Type *ot;
+
+ if(f->op == OCONST){
+ f = nodconst((long)(f->vconst>>32));
+ if(c==1 && sconst(f) || c==2 && uconst(f)){
+ if(t->op == OREGISTER)
+ regfree(t);
+ *t = *f;
+ return;
+ }
+ }
+ if(f->op == OREGPAIR) {
+ gmove(f->left, t);
+ return;
+ }
+ ot = f->type;
+ f->type = types[TLONG];
+ gmove(f, t);
+ f->type = ot;
+}
+
+void
+gloadlo(Node *f, Node *t, int c)
+{
+ Type *ot;
+
+ if(f->op == OCONST){
+ f = nodconst((long)f->vconst);
+ if(c && uconst(f)){
+ if(t->op == OREGISTER)
+ regfree(t);
+ *t = *f;
+ return;
+ }
+ }
+ if(f->op == OREGPAIR) {
+ gmove(f->right, t);
+ return;
+ }
+ ot = f->type;
+ f->type = types[TLONG];
+ f->xoffset += SZ_LONG;
+ if(0){
+ prtree(f, "gloadlo f"); prtree(t, "gloadlo t");
+ }
+ gmove(f, t);
+ f->xoffset -= SZ_LONG;
+ f->type = ot;
+}
+
+void
fop(int as, int f1, int f2, Node *t)
{
Node nod1, nod2, nod3;
@@ -602,6 +683,17 @@ gmove(Node *f, Node *t)
return;
}
}
+ if((ft == TVLONG || ft == TUVLONG) && f->op == OCONST && t->op == OREGPAIR) {
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gmove(nod32const(f->vconst>>32), t->left);
+ else
+ gmove(nod32const(f->vconst), t->left);
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gmove(nod32const(f->vconst), t->right);
+ else
+ gmove(nod32const(f->vconst>>32), t->right);
+ return;
+ }
/*
* a load --
* put it into a register then
@@ -631,8 +723,25 @@ gmove(Node *f, Node *t)
a = AMOVHZ;
break;
}
- regalloc(&nod, f, t);
- gins(a, f, &nod);
+ if(typev[ft]) {
+ if(typev[tt]) {
+ regalloc(&nod, f, t);
+ /* low order first, because its value will be used first */
+ f->xoffset += SZ_LONG;
+ gins(AMOVW, f, nod.right);
+ f->xoffset -= SZ_LONG;
+ gins(AMOVW, f, nod.left);
+ } else {
+ /* assumed not float or double */
+ regalloc(&nod, &regnode, t);
+ f->xoffset += SZ_LONG;
+ gins(AMOVW, f, &nod);
+ f->xoffset -= SZ_LONG;
+ }
+ } else {
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ }
gmove(&nod, t);
regfree(&nod);
return;
@@ -669,6 +778,11 @@ gmove(Node *f, Node *t)
}
if(R0ISZERO && !typefd[ft] && vconst(f) == 0) {
gins(a, f, t);
+ if(typev[tt]) {
+ t->xoffset += SZ_LONG;
+ gins(a, f, t);
+ t->xoffset -= SZ_LONG;
+ }
return;
}
if(ft == tt)
@@ -676,7 +790,13 @@ gmove(Node *f, Node *t)
else
regalloc(&nod, t, Z);
gmove(f, &nod);
- gins(a, &nod, t);
+ if(typev[tt]) {
+ t->xoffset += SZ_LONG;
+ gins(a, nod.right, t);
+ t->xoffset -= SZ_LONG;
+ gins(a, nod.left, t);
+ } else
+ gins(a, &nod, t);
regfree(&nod);
return;
}
@@ -710,7 +830,7 @@ gmove(Node *f, Node *t)
case TUCHAR:
/* BUG: not right for unsigned long */
regalloc(&nod, f, Z); /* should be type float */
- regsalloc(&fxrat, f);
+ regsalloc(&fxrat, &fconstnode);
gins(AFCTIWZ, f, &nod);
gins(AFMOVD, &nod, &fxrat);
regfree(&nod);
@@ -817,7 +937,7 @@ gmove(Node *f, Node *t)
*/
regalloc(&fxc0, f, Z);
regalloc(&fxc2, f, Z);
- regsalloc(&fxrat, t); /* should be type float */
+ regsalloc(&fxrat, &fconstnode); /* should be type float */
gins(AMOVW, nodconst(0x43300000L), &fxc0);
gins(AMOVW, f, &fxc2);
gins(AMOVW, &fxc0, &fxrat);
@@ -876,13 +996,28 @@ gmove(Node *f, Node *t)
break;
}
break;
+ case TVLONG:
+ case TUVLONG:
+ switch(tt) {
+ case TVLONG:
+ case TUVLONG:
+ a = AMOVW;
+ break;
+ }
+ break;
}
if(a == AGOK)
diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
if(a == AMOVW || a == AFMOVS || a == AFMOVD)
if(samaddr(f, t))
return;
- gins(a, f, t);
+ if(typev[ft]) {
+ if(f->op != OREGPAIR || t->op != OREGPAIR)
+ diag(Z, "bad vlong in gmove (%O->%O)", f->op, t->op);
+ gins(a, f->left, t->left);
+ gins(a, f->right, t->right);
+ } else
+ gins(a, f, t);
}
void
@@ -900,21 +1035,75 @@ gins(int a, Node *f, Node *t)
}
void
-gopcode(int o, Node *f1, Node *f2, Node *t)
+gins3(int a, Node *f1, Node *f2, Node *t)
{
- int a, et;
Adr ta;
- int uns;
- uns = 0;
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z && (f2->op != OREGISTER || !samaddr(f2, t))) {
+ ta = zprog.from; /* TO DO */
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0) {
+ if(R0ISZERO)
+ p->reg = REGZERO;
+ else
+ diag(Z, "REGZERO in gins3 %A", a);
+ }else if(ta.type == D_CONST)
+ p->from3 = ta;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gins4(int a, Node *f1, Node *f2, Node *f3, Node *t)
+{
+ Adr ta;
+
+ nextpc();
+ p->as = a;
+ naddr(f1, &p->from);
+ if(f2->op != OREGISTER && (f2->op != OCONST || vconst(f2) != 0))
+ diag(f2, "invalid gins4");
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0)
+ p->reg = REGZERO;
+ naddr(f3, &p->from3);
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et, uns;
+
+ if(o == OAS) {
+ gmove(f1, t);
+ return;
+ }
et = TLONG;
- if(f1 != Z && f1->type != T)
- et = f1->type->etype;
+ if(f1 != Z && f1->type != T) {
+ if(f1->op == OCONST && t != Z && t->type != T)
+ et = t->type->etype;
+ else
+ et = f1->type->etype;
+ }
+ if((typev[et] || t->type != T && typev[t->type->etype]) && o != OFUNC) {
+ gopcode64(o, f1, f2, t);
+ return;
+ }
+ uns = 0;
a = AGOK;
switch(o) {
- case OAS:
- gmove(f1, t);
- return;
case OASADD:
case OADD:
@@ -965,7 +1154,7 @@ gopcode(int o, Node *f1, Node *f2, Node *t)
case OASASHL:
case OASHL:
- a = ASLW; /* BUG? */
+ a = ASLW;
break;
case OFUNC:
@@ -1027,10 +1216,14 @@ gopcode(int o, Node *f1, Node *f2, Node *t)
case OEQ:
a = ABEQ;
+ if(t->op == OCONST && t->vconst >= (1<<15))
+ goto cmpu;
goto cmp;
case ONE:
a = ABNE;
+ if(t->op == OCONST && t->vconst >= (1<<15))
+ goto cmpu;
goto cmp;
case OLT:
@@ -1090,24 +1283,258 @@ gopcode(int o, Node *f1, Node *f2, Node *t)
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
- nextpc();
- p->as = a;
- if(f1 != Z)
- naddr(f1, &p->from);
- if(f2 != Z) {
- naddr(f2, &ta);
- p->reg = ta.reg;
- if(ta.type == D_CONST && ta.offset == 0) {
- if(R0ISZERO)
- p->reg = REGZERO;
+ gins3(a, f1, f2, t);
+}
+
+static void
+gopcode64(int o, Node *f1, Node *f2, Node *t)
+{
+ int a1, a2;
+ Node nod, nod1, nod2, sh;
+ ulong m;
+ Prog *p1;
+
+ if(t->op != OREGPAIR || f2 != Z && f2->op != OREGPAIR) {
+ diag(Z, "bad f2/dest in gopcode64 %O", o);
+ return;
+ }
+ if(f1->op != OCONST &&
+ (typev[f1->type->etype] && f1->op != OREGPAIR || !typev[f1->type->etype] && f1->op != OREGISTER)) {
+ diag(Z, "bad f1[%O] in gopcode64 %O", f1->op, o);
+ return;
+ }
+ /* a1 for low-order, a2 for high-order */
+ a1 = AGOK;
+ a2 = AGOK;
+ switch(o) {
+ case OASADD:
+ case OADD:
+ if(f1->op == OCONST && sconst(f1)) {
+ if(f2 == Z)
+ f2 = t;
+ gins3(AADDC, f1, f2->right, t->right);
+ if((f1->vconst>>32) == 0)
+ gins(AADDZE, f2->left, t->left);
+ else if((f1->vconst>>32) == -1)
+ gins(AADDME, f2->left, t->left);
else
- diag(Z, "REGZERO in gopcode %O", o);
+ diag(t, "odd vlong ADD: %lld", f1->vconst);
+ return;
+ }
+ a1 = AADDC;
+ a2 = AADDE;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a1 = ASUBC;
+ a2 = ASUBE;
+ break;
+
+ case OASOR:
+ case OOR:
+ if(f1->op == OCONST) {
+ gori64(AOR, f1, f2, t);
+ return;
+ }
+ a1 = a2 = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ if(f1->op == OCONST) {
+ gandi64(AANDCC, f1, f2, t);
+ return;
+ }
+ a1 = a2 = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ if(f1->op == OCONST) {
+ gori64(AXOR, f1, f2, t);
+ return;
+ }
+ a1 = a2 = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ if(f2 == Z)
+ f2 = t;
+ if(f1->op == OCONST) {
+ if(f1->vconst >= 32) {
+ if(f1->vconst == 32)
+ gmove(f2->left, t->right);
+ else if(f1->vconst < 64)
+ gins3(ASRW, nodconst(f1->vconst-32), f2->left, t->right);
+ else
+ gmove(nodconst(0), t->right);
+ gmove(nodconst(0), t->left);
+ return;
+ }
+ if(f1->vconst <= 0) {
+ if(f2 != t)
+ gmove(f2, t);
+ return;
+ }
+ sh = *nodconst(32 - f1->vconst);
+ m = 0xFFFFFFFFUL >> f1->vconst;
+ gins4(ARLWNM, &sh, f2->right, nodconst(m), t->right);
+ gins4(ARLWMI, &sh, f2->left, nodconst(~m), t->right);
+ gins4(ARLWNM, &sh, f2->left, nodconst(m), t->left);
+ return;
+ }
+ regalloc(&nod, &regnode, Z);
+ gins3(ASUBC, f1, nodconst(32), &nod);
+ gins3(ASRW, f1, f2->right, t->right);
+ regalloc(&nod1, &regnode, Z);
+ gins3(ASLW, &nod, f2->left, &nod1);
+ gins(AOR, &nod1, t->right);
+ gins3(AADD, nodconst(-32), f1, &nod);
+ gins3(ASRW, &nod, f2->left, &nod1);
+ gins(AOR, &nod1, t->right);
+ gins3(ASRW, f1, f2->left, t->left);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case OASASHR:
+ case OASHR:
+ if(f2 == Z)
+ f2 = t;
+ if(f1->op == OCONST) {
+ if(f1->vconst >= 32) {
+ if(f1->vconst == 32)
+ gmove(f2->left, t->right);
+ else if(f1->vconst < 64)
+ gins3(ASRAW, nodconst(f1->vconst-32), f2->left, t->right);
+ gins3(ASRAW, nodconst(31), f2->left, t->left);
+ if(f1->vconst >= 64) {
+ gmove(t->left, t->right);
+ return;
+ }
+ return;
+ }
+ if(f1->vconst <= 0) {
+ if(f2 != t)
+ gmove(f2, t);
+ return;
+ }
+ sh = *nodconst(32 - f1->vconst);
+ m = 0xFFFFFFFFUL >> f1->vconst;
+ gins4(ARLWNM, &sh, f2->right, nodconst(m), t->right);
+ gins4(ARLWMI, &sh, f2->left, nodconst(~m), t->right);
+ gins3(ASRAW, &sh, f2->left, t->left);
+ return;
+ }
+ regalloc(&nod, &regnode, Z);
+ gins3(ASUBC, f1, nodconst(32), &nod);
+ gins3(ASRW, f1, f2->right, t->right);
+ regalloc(&nod1, &regnode, Z);
+ gins3(ASLW, &nod, f2->left, &nod1);
+ gins(AOR, &nod1, t->right);
+ gins3(AADDCCC, nodconst(-32), f1, &nod);
+ gins3(ASRAW, &nod, f2->left, &nod1);
+ gins(ABLE, Z, Z);
+ p1 = p;
+ gins(AMOVW, &nod1, t->right);
+ patch(p1, pc);
+ gins3(ASRAW, f1, f2->left, t->left);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case OASASHL:
+ case OASHL:
+ if(f2 == Z)
+ f2 = t;
+ if(f1->op == OCONST) {
+ if(f1->vconst >= 32) {
+ if(f1->vconst == 32)
+ gmove(f2->right, t->left);
+ else if(f1->vconst >= 64)
+ gmove(nodconst(0), t->left);
+ else
+ gins3(ASLW, nodconst(f1->vconst-32), f2->right, t->left);
+ gmove(nodconst(0), t->right);
+ return;
+ }
+ if(f1->vconst <= 0) {
+ if(f2 != t)
+ gmove(f2, t);
+ return;
+ }
+ m = 0xFFFFFFFFUL << f1->vconst;
+ gins4(ARLWNM, f1, f2->left, nodconst(m), t->left);
+ gins4(ARLWMI, f1, f2->right, nodconst(~m), t->left);
+ gins4(ARLWNM, f1, f2->right, nodconst(m), t->right);
+ return;
+ }
+ regalloc(&nod, &regnode, Z);
+ gins3(ASUBC, f1, nodconst(32), &nod);
+ gins3(ASLW, f1, f2->left, t->left);
+ regalloc(&nod1, &regnode, Z);
+ gins3(ASRW, &nod, f2->right, &nod1);
+ gins(AOR, &nod1, t->left);
+ gins3(AADD, nodconst(-32), f1, &nod);
+ gins3(ASLW, &nod, f2->right, &nod1);
+ gins(AOR, &nod1, t->left);
+ gins3(ASLW, f1, f2->right, t->right);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case OASLMUL:
+ case OLMUL:
+ case OASMUL:
+ case OMUL:
+ if(f2 == Z)
+ f2 = t;
+ regalloc(&nod, &regnode, Z);
+ gins3(AMULLW, f1->right, f2->right, &nod); /* lo(f2.low*f1.low) */
+ a1 = AMULHW;
+ if(o == OLMUL || o == OASLMUL)
+ a1 = AMULHWU;
+ regalloc(&nod1, &regnode, Z);
+ gins3(a1, f1->right, f2->right, &nod1); /* hi(f2.low*f1.low) */
+ regalloc(&nod2, &regnode, Z);
+ gins3(AMULLW, f2->right, f1->left, &nod2); /* lo(f2.low*f1.high) */
+ gins(AADD, &nod2, &nod1);
+ gins3(AMULLW, f1->right, f2->left, &nod2); /* hi(f2.high*f1.low) */
+ gins(AADD, &nod2, &nod1);
+ regfree(&nod2);
+ gmove(&nod, t->right);
+ gmove(&nod1, t->left);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case OCOM:
+ a1 = a2 = ANOR;
+ break;
+
+ case ONEG:
+ gins3(ASUBC, t->right, nodconst(0), t->right);
+ gins(ASUBZE, t->left, t->left);
+ return;
+ }
+ if(a1 == AGOK || a2 == AGOK)
+ diag(Z, "bad in gopcode64 %O", o);
+ if(f1->op == OCONST) {
+ if(f2 != Z & f2 != t)
+ diag(Z, "bad const in gopcode64 %O", o);
+ gins(a1, nod32const(f1->vconst), t->right);
+ gins(a2, nod32const(f1->vconst>>32), t->left);
+ } else {
+ if(f2 != Z && f2 != t) {
+ gins3(a1, f1->right, f2->right, t->right);
+ gins3(a2, f1->left, f2->left, t->left);
+ } else {
+ gins(a1, f1->right, t->right);
+ gins(a2, f1->left, t->left);
}
}
- if(t != Z)
- naddr(t, &p->to);
- if(debug['g'])
- print("%P\n", p);
}
samaddr(Node *f, Node *t)
@@ -1121,10 +1548,51 @@ samaddr(Node *f, Node *t)
if(f->reg != t->reg)
break;
return 1;
+
+ case OREGPAIR:
+ return samaddr(f->left, t->left) && samaddr(f->right, t->right);
}
return 0;
}
+static void
+gori64(int a, Node *f1, Node *f2, Node *t)
+{
+ ulong lo, hi;
+
+ if(f2 == Z)
+ f2 = t;
+ lo = f1->vconst & MASK(32);
+ hi = (f1->vconst >> 32) & MASK(32);
+ if(lo & 0xFFFF)
+ gins3(a, nodconst(lo & 0xFFFF), f2->right, t->right);
+ if((lo >> 16) != 0)
+ gins3(a, nodconst(lo & 0xFFFF0000UL), f2->right, t->right);
+ if(hi & 0xFFFF)
+ gins3(a, nodconst(hi & 0xFFFF), f2->left, t->left);
+ if((hi >> 16) != 0)
+ gins3(a, nodconst(hi & 0xFFFF0000UL), f2->left, t->left);
+}
+
+static void
+gandi64(int a, Node *f1, Node *f2, Node *t)
+{
+ ulong lo, hi;
+
+ if(f2 == Z)
+ f2 = t;
+ lo = f1->vconst & MASK(32);
+ hi = (f1->vconst >> 32) & MASK(32);
+ if(lo == 0)
+ gins(AMOVW, nodconst(0), t->right);
+ else
+ gins3(a, nodconst(lo), f2->right, t->right);
+ if(hi == 0)
+ gins(AMOVW, nodconst(0), t->left);
+ else
+ gins3(a, nodconst(hi), f2->left, t->left);
+}
+
void
gbranch(int o)
{