void
cgen(Node *n, Node *nn)
+{
+ cgenrel(n, nn, 0);
+}
+
+void
+cgenrel(Node *n, Node *nn, int inrel)
{
Node *l, *r;
Prog *p1;
Node nod, nod1, nod2, nod3, nod4;
- int o;
+ int o, t;
long v, curs;
if(debug['g']) {
if(r != Z && r->complex >= FNX)
switch(o) {
default:
+ if(cond(o) && typesu[l->type->etype])
+ break;
+
regret(&nod, r);
cgen(r, &nod);
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;
if(l->addable >= INDEXED && l->complex < FNX) {
- if(nn != Z || r->addable < INDEXED) {
- regalloc(&nod, r, nn);
+ if(nn != Z || r->addable < INDEXED) { /* || hardconst(r) */
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
cgen(r, &nod);
gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
regfree(&nod);
} else
gmove(r, l);
break;
}
if(l->complex >= r->complex) {
+ /* TO DO: see 6c for OINDEX && immconst(r) */
reglcgen(&nod1, l, Z);
- if(r->addable >= INDEXED) {
+ if(r->addable >= INDEXED) { /* && !hardconst(r) */
gmove(r, &nod1);
if(nn != Z)
gmove(r, nn);
reglcgen(&nod1, l, Z);
}
gmove(&nod, &nod1);
+ if(nn != Z)
+ gmove(&nod, nn);
regfree(&nod);
regfree(&nod1);
break;
regfree(&nod);
break;
- case OADD:
+ case ODIV:
+ case OMOD:
+ if(nn != Z)
+ if((t = vlog(r)) >= 0) {
+ /* signed div/mod by constant power of 2 */
+ cgen(l, nn);
+ gopcode(OGE, nodconst(0), nn, Z);
+ p1 = p;
+ if(o == ODIV) {
+ gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ gopcode(OASHR, nodconst(t), Z, nn);
+ } else {
+ gopcode(ONEG, nn, Z, nn);
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ gopcode(ONEG, nn, Z, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+ patch(p1, pc);
+ }
+ break;
+ }
+ goto muldiv;
+
+ case OXOR:
+#ifdef NOTYET
+ if(nn != Z)
+ if(r->op == OCONST && r->vconst == -1){
+ cgen(l, nn);
+ gopcode(OCOM, nn, Z, nn);
+ break;
+ }
+#endif
+
case OSUB:
+ case OADD:
case OAND:
case OOR:
- case OXOR:
case OLSHR:
case OASHL:
case OASHR:
- case OLDIV:
- case OLMOD:
- case ODIV:
- case OMOD:
- case OMUL:
- case OLMUL:
/*
* immediate operands
*/
break;
}
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ muldiv:
if(nn == Z) {
nullwarn(l, r);
break;
}
-/* if(o == OMUL || o == OLMUL) {
+ if(o == OMUL || o == OLMUL) {
if(mulcon(n, nn))
break;
- } */
+ }
if(l->complex >= r->complex) {
regalloc(&nod, l, nn);
cgen(l, &nod);
case OASSUB:
case OASXOR:
case OASOR:
- case OASLDIV:
- case OASLMOD:
- case OASDIV:
- case OASMOD:
- case OASLMUL:
- case OASMUL:
if(l->op == OBIT)
goto asbitop;
if(r->op == OCONST)
gopcode(OAS, &nod2, Z, &nod);
gopcode(o, r, Z, &nod);
gopcode(OAS, &nod, Z, &nod2);
-
+ if(nn != Z)
+ gmove(&nod, nn);
regfree(&nod);
if(l->addable < INDEXED)
regfree(&nod2);
break;
}
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
if(l->complex >= r->complex) {
if(l->addable < INDEXED)
reglcgen(&nod2, l, Z);
else
nod2 = *l;
}
-
- regalloc(&nod, n, nn);
- gmove(&nod2, &nod);
+ if(nod1.type->etype == nod2.type->etype || !typefd[nod1.type->etype])
+ regalloc(&nod, &nod2, nn);
+ else
+ regalloc(&nod, &nod1, Z);
+ gopcode(OAS, &nod2, Z, &nod);
if(nod1.type->etype != nod.type->etype){
regalloc(&nod3, &nod, Z);
gmove(&nod1, &nod3);
regfree(&nod1);
nod1 = nod3;
}
- gopcode(o, &nod1, Z, &nod);
+ gopcode(o, &nod1, &nod, &nod);
gmove(&nod, &nod2);
if(nn != Z)
- gopcode(OAS, &nod, Z, nn);
+ gmove(&nod, nn);
regfree(&nod);
regfree(&nod1);
if(l->addable < INDEXED)
asbitop:
regalloc(&nod4, n, nn);
+ regalloc(&nod3, r, Z);
if(l->complex >= r->complex) {
bitload(l, &nod, &nod1, &nod2, &nod4);
- regalloc(&nod3, r, Z);
cgen(r, &nod3);
} else {
- regalloc(&nod3, r, Z);
cgen(r, &nod3);
bitload(l, &nod, &nod1, &nod2, &nod4);
}
break;
case OFUNC:
+ l = uncomma(l);
if(l->complex >= FNX) {
if(l->op != OIND)
diag(n, "bad function call");
return;
}
- if(REGARG != NREG)
+ if(REGARG >= 0)
o = reg[REGARG];
gargs(r, &nod, &nod1);
if(l->addable < INDEXED) {
regfree(&nod);
} else
gopcode(OFUNC, Z, Z, l);
- if(REGARG != NREG)
+ if(REGARG >= 0)
if(o != reg[REGARG])
reg[REGARG]--;
if(nn != Z) {
r = l;
while(r->op == OADD)
r = r->right;
- if(sconst(r)) {
+ if(usableoffset(n, nod.xoffset, r)){
v = r->vconst;
r->vconst = 0;
cgen(l, &nod);
case OCAST:
if(nn == Z) {
- nullwarn(l, Z);
+ cgen(l, Z);
break;
}
/*
* convert from types l->n->nn
*/
- if(nocast(l->type, n->type)) {
- if(nocast(n->type, nn->type)) {
- cgen(l, nn);
+ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+ /* both null, gen l->nn */
+ cgen(l, nn);
+ break;
+ }
+ if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+ if(l->type->etype == TIND && typechlp[n->type->etype])
+ warn(n, "conversion of pointer to shorter integer");
+ }else if(0){
+ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+ if(typefd[l->type->etype] != typefd[nn->type->etype])
+ regalloc(&nod, l, nn);
+ else
+ regalloc(&nod, nn, nn);
+ cgen(l, &nod);
+ gmove(&nod, nn);
+ regfree(&nod);
break;
}
}
regalloc(&nod, l, nn);
cgen(l, &nod);
regalloc(&nod1, n, &nod);
- gopcode(OAS, &nod, Z, &nod1);
+ if(inrel)
+ gmover(&nod, &nod1);
+ else
+ gopcode(OAS, &nod, Z, &nod1);
gopcode(OAS, &nod1, Z, nn);
regfree(&nod1);
regfree(&nod);
regalloc(&nod, l, nn);
gopcode(OAS, &nod2, Z, &nod);
+ if(nn != Z)
+ gmove(&nod, nn);
regalloc(&nod1, l, Z);
if(typefd[l->type->etype]) {
regalloc(&nod3, l, Z);
} 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);
-
+ if(nn != Z){
+ gmove(&nod, nn);
+ if(l->op == ONAME) /* in x=++i, emit USED(i) */
+ gins(ANOP, l, Z);
+ }
regfree(&nod);
if(l->addable < INDEXED)
regfree(&nod2);
r = n->left;
while(r->op == OADD)
r = r->right;
- if(sconst(r)) {
+ if(usableoffset(n, t->xoffset, r)) {
v = r->vconst;
r->vconst = 0;
lcgen(n, t);
regind(t, n);
return;
}
+ } else if(n->op == OINDREG) {
+ if(usableoffset(n, t->xoffset+n->xoffset, nil)) {
+ Type *tt = n->type;
+ n->type = types[TIND];
+ n->op = OREGISTER;
+ v = n->xoffset;
+ n->xoffset = 0;
+ cgen(n, t);
+ t->xoffset += v;
+ n->xoffset = v;
+ n->op = OINDREG;
+ n->type = tt;
+ regind(t, n);
+ return;
+ }
}
lcgen(n, t);
regind(t, n);
cgen(n, &nod);
o = ONE;
if(true)
- o = comrel[relindex(o)];
+ o = OEQ;
if(typefd[n->type->etype]) {
- nodreg(&nod1, n, NREG+FREGZERO);
- gopcode(o, &nod, Z, &nod1);
+ gopcode(true ? o | BTRUE : o, nodfconst(0), &nod, Z);
} else
- gopcode(o, &nod, Z, nodconst(0));
+ gopcode(o, nodconst(0), &nod, Z);
regfree(&nod);
goto com;
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
regret(&nod, r);
- cgen(r, &nod);
+ cgenrel(r, &nod, 1);
regsalloc(&nod1, r);
gopcode(OAS, &nod, Z, &nod1);
regfree(&nod);
boolgen(&nod, true, nn);
break;
}
- if(bconst(r)) {
+ if(sconst(l)) {
+ regalloc(&nod, r, nn);
+ cgenrel(r, &nod, 1);
+ o = invrel[relindex(o)];
+ gopcode(true ? o | BTRUE : o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(sconst(r)) {
regalloc(&nod, l, nn);
- cgen(l, &nod);
- gopcode(o, &nod, Z, r);
+ cgenrel(l, &nod, 1);
+ gopcode(true ? o | BTRUE : o, r, &nod, Z);
regfree(&nod);
goto com;
}
if(l->complex >= r->complex) {
regalloc(&nod1, l, nn);
- cgen(l, &nod1);
+ cgenrel(l, &nod1, 1);
regalloc(&nod, r, Z);
- cgen(r, &nod);
+ cgenrel(r, &nod, 1);
} else {
regalloc(&nod, r, nn);
- cgen(r, &nod);
+ cgenrel(r, &nod, 1);
regalloc(&nod1, l, Z);
- cgen(l, &nod1);
+ cgenrel(l, &nod1, 1);
}
- gopcode(o, &nod1, Z, &nod);
+ gopcode(true ? o | BTRUE : o, &nod, &nod1, Z);
regfree(&nod);
regfree(&nod1);
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);
case OSTRUCT:
/*
- * rewrite so lhs has no fn call
+ * rewrite so lhs has no side effects
*/
- if(nn != Z && nn->complex >= FNX) {
+ if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
regret(&nod2, &nod1);
xcom(&nod0);
nod0.addable = 0;
- /* prtree(&nod0, "hand craft"); /* */
cgen(&nod0, Z);
}
break;
nn->type = types[TLONG];
regialloc(&nod1, nn, Z);
lcgen(nn, &nod1);
- regsalloc(&nod2, nn);
+ regsalloc(&nod2, &nod1);
nn->type = t;
gopcode(OAS, &nod1, Z, &nod2);
return;
}
+ /* TO DO: use AMOV/VLONG when possible */
if(n->complex > nn->complex) {
t = n->type;
n->type = types[TLONG];
pc1 = pc;
layout(&nod1, &nod2, c, 0, Z);
- gopcode(OSUB, nodconst(1), Z, &nod3);
+ gopcode(OSUB, nodconst(1L), Z, &nod3);
nod1.op = OREGISTER;
+ t = nod1.type;
+ nod1.type = types[TIND];
gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+ nod1.type = t;
nod2.op = OREGISTER;
+ t = nod2.type;
+ nod2.type = types[TIND];
gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+ nod2.type = t;
- gopcode(OGT, &nod3, Z, nodconst(0));
+ gopcode(OGT, nodconst(0), &nod3, Z);
patch(p, pc1);
regfree(&nod3);
regfree(&t1);
regfree(&t2);
}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+ return n->op == OCONST && !sconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+ int ft;
+
+ if(!nilcast(t1, t2))
+ return 0;
+ /* known to be small to large */
+ ft = t1->etype;
+ switch(t2->etype){
+ case TINT:
+ case TLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+ case TUINT:
+ case TULONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+ case TVLONG:
+ return ft == TLONG || ft == TINT || ft == TSHORT;
+ case TUVLONG:
+ return ft == TULONG || ft == TUINT || ft == TUSHORT;
+ }
+ return 0;
+}
+
+int
+cond(int op)
+{
+ switch(op) {
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+ }
+ return 0;
+}