diff options
Diffstat (limited to 'utils/qc/txt.c')
| -rw-r--r-- | utils/qc/txt.c | 554 |
1 files changed, 511 insertions, 43 deletions
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, ®node, o->left); + regalloc(n->right, ®node, o->right); + } else { + regalloc(n->left, ®node, Z); + regalloc(n->right, ®node, 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, ®node, 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, ®node, Z); + gins3(ASUBC, f1, nodconst(32), &nod); + gins3(ASRW, f1, f2->right, t->right); + regalloc(&nod1, ®node, 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, ®node, Z); + gins3(ASUBC, f1, nodconst(32), &nod); + gins3(ASRW, f1, f2->right, t->right); + regalloc(&nod1, ®node, 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, ®node, Z); + gins3(ASUBC, f1, nodconst(32), &nod); + gins3(ASLW, f1, f2->left, t->left); + regalloc(&nod1, ®node, 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, ®node, Z); + gins3(AMULLW, f1->right, f2->right, &nod); /* lo(f2.low*f1.low) */ + a1 = AMULHW; + if(o == OLMUL || o == OASLMUL) + a1 = AMULHWU; + regalloc(&nod1, ®node, Z); + gins3(a1, f1->right, f2->right, &nod1); /* hi(f2.low*f1.low) */ + regalloc(&nod2, ®node, 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) { |
