summaryrefslogtreecommitdiff
path: root/src/cmd/6c/txt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6c/txt.c')
-rw-r--r--src/cmd/6c/txt.c1564
1 files changed, 1564 insertions, 0 deletions
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
new file mode 100644
index 000000000..12fc5b498
--- /dev/null
+++ b/src/cmd/6c/txt.c
@@ -0,0 +1,1564 @@
+// Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+ginit(void)
+{
+ int i;
+ Type *t;
+
+ thechar = '6';
+ thestring = "amd64";
+ dodefine("_64BIT");
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TINT];
+
+ typeword = typechlvp;
+ typecmplx = typesu;
+
+ /* TO DO */
+ memmove(typechlpv, typechlp, sizeof(typechlpv));
+ typechlpv[TVLONG] = 1;
+ typechlpv[TUVLONG] = 1;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.from.type = D_NONE;
+ zprog.from.index = D_NONE;
+ zprog.from.scale = 0;
+ zprog.to = zprog.from;
+
+ lregnode.op = OREGISTER;
+ lregnode.class = CEXREG;
+ lregnode.reg = REGTMP;
+ lregnode.complex = 0;
+ lregnode.addable = 11;
+ lregnode.type = types[TLONG];
+
+ qregnode = lregnode;
+ qregnode.type = types[TVLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ vconstnode = constnode;
+ vconstnode.type = types[TVLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ 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);
+
+ if(0)
+ com64init();
+
+ for(i=0; i<nelem(reg); i++) {
+ reg[i] = 1;
+ if(i >= D_AX && i <= D_R15 && i != D_SP)
+ reg[i] = 0;
+ if(i >= D_X0 && i <= D_X7)
+ reg[i] = 0;
+ }
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ reg[D_SP]--;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i])
+ diag(Z, "reg %R left allocated", i);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ int32 regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+int
+nareg(void)
+{
+ int i, n;
+
+ n = 0;
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ n++;
+ return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG >= 0 && curarg == 0 && typechlpv[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gmove(n, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gmove(tn1, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodgconst(vlong v, Type *t)
+{
+ if(!typev[t->etype])
+ return nodconst((int32)v);
+ vconstnode.vconst = v;
+ return &vconstnode;
+}
+
+Node*
+nodconst(int32 v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+ if(n->op == OREGISTER)
+ if(n->reg == r)
+ return 1;
+ return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+ int et;
+
+ *n = qregnode;
+ n->reg = r;
+ if(nn != Z){
+ et = nn->type->etype;
+ if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+ n->type = typeu[et]? types[TUINT]: types[TINT];
+ else
+ n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+ n->lineno = nn->lineno;
+ }
+ if(reg[r] == 0)
+ return 0;
+ if(nn != Z) {
+ if(nn->op == OREGISTER)
+ if(nn->reg == r)
+ return 0;
+ }
+ return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_AX && i <= D_R15)
+ goto out;
+ }
+ for(i=D_AX; i<=D_R15; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= D_X0 && i <= D_X7)
+ goto out;
+ }
+ for(i=D_X0; i<=D_X7; i++)
+ if(reg[i] == 0)
+ goto out;
+ diag(tn, "out of float registers");
+ goto out;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ i = 0;
+out:
+ if(i)
+ reg[i]++;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ if(REGARG < 0) {
+ fatal(n, "regaalloc1 and REGARG<0");
+ return;
+ }
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2, nil);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ int32 v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O %D", n->op, a);
+ break;
+
+ case OREGISTER:
+ a->type = n->reg;
+ a->sym = S;
+ break;
+
+ case OEXREG:
+ a->type = D_INDIR + D_GS;
+ a->offset = n->reg - 1;
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ break;
+
+ case OINDEX:
+ a->type = idx.ptr;
+ if(n->left->op == OADDR || n->left->op == OCONST)
+ naddr(n->left, a);
+ if(a->type >= D_AX && a->type <= D_R15)
+ a->type += D_INDIR;
+ else
+ if(a->type == D_CONST)
+ a->type = D_NONE+D_INDIR;
+ else
+ if(a->type == D_ADDR) {
+ a->type = a->index;
+ a->index = D_NONE;
+ } else
+ goto bad;
+ a->index = idx.reg;
+ a->scale = n->scale;
+ a->offset += n->xoffset;
+ break;
+
+ case OINDREG:
+ a->type = n->reg+D_INDIR;
+ a->sym = S;
+ a->offset = n->xoffset;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->type = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->type = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->type = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ break;
+ }
+ a->sym = S;
+ a->type = D_CONST;
+ if(typev[n->type->etype] || n->type->etype == TIND)
+ a->offset = n->vconst;
+ else
+ a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type >= D_INDIR) {
+ a->type -= D_INDIR;
+ break;
+ }
+ if(a->type == D_EXTERN || a->type == D_STATIC ||
+ a->type == D_AUTO || a->type == D_PARAM)
+ if(a->index == D_NONE) {
+ a->index = a->type;
+ a->type = D_ADDR;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->right->op == OCONST) {
+ v = n->right->vconst;
+ naddr(n->left, a);
+ } else
+ if(n->left->op == OCONST) {
+ v = n->left->vconst;
+ naddr(n->right, a);
+ } else
+ goto bad;
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+ Node *cn, nod;
+
+ cn = nodgconst(val, n->type);
+ if(!immconst(cn)){
+ regalloc(&nod, n, Z);
+ gmove(cn, &nod);
+ gopcode(op, n->type, n, &nod);
+ regfree(&nod);
+ }else
+ gopcode(op, n->type, n, cn);
+}
+
+#define CASE(a,b) ((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, t64, a;
+ Node nod, nod1, nod2, nod3;
+ Prog *p1, *p2;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+ t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
+ if(debug['M'])
+ print("gop: %O %O[%s],%O[%s]\n", OAS,
+ f->op, tnames[ft], t->op, tnames[tt]);
+ if(typefd[ft] && f->op == OCONST) {
+ /* TO DO: pick up special constants, possibly preloaded */
+ if(f->fconst == 0.0){
+ regalloc(&nod, t, t);
+ gins(AXORPD, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ }
+/*
+ * load
+ */
+ if(ft == TVLONG || ft == TUVLONG)
+ if(f->op == OCONST)
+ if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
+ if(t->op != OREGISTER) {
+ regalloc(&nod, f, Z);
+ gmove(f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ if(f->op == ONAME || f->op == OINDREG ||
+ f->op == OIND || f->op == OINDEX)
+ switch(ft) {
+ case TCHAR:
+ a = AMOVBLSX;
+ if(t64)
+ a = AMOVBQSX;
+ goto ld;
+ case TUCHAR:
+ a = AMOVBLZX;
+ if(t64)
+ a = AMOVBQZX;
+ goto ld;
+ case TSHORT:
+ a = AMOVWLSX;
+ if(t64)
+ a = AMOVWQSX;
+ goto ld;
+ case TUSHORT:
+ a = AMOVWLZX;
+ if(t64)
+ a = AMOVWQZX;
+ goto ld;
+ case TINT:
+ case TLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSL2SD;
+ else
+ a = ACVTSL2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQSX;
+ goto ld;
+ case TUINT:
+ case TULONG:
+ a = AMOVL;
+ if(t64)
+ a = AMOVLQZX; /* could probably use plain MOVL */
+ goto ld;
+ case TVLONG:
+ if(typefd[tt]) {
+ regalloc(&nod, t, t);
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ else
+ a = ACVTSQ2SS;
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ case TUVLONG:
+ a = AMOVQ;
+ goto ld;
+ case TIND:
+ a = AMOVQ;
+
+ ld:
+ regalloc(&nod, f, t);
+ nod.type = t64? types[TVLONG]: types[TINT];
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fld;
+ case TDOUBLE:
+ a = AMOVSD;
+ fld:
+ regalloc(&nod, f, t);
+ if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
+ prtree(f, "odd tree");
+ nod.type = t64? types[TVLONG]: types[TINT];
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+/*
+ * store
+ */
+ if(t->op == ONAME || t->op == OINDREG ||
+ t->op == OIND || t->op == OINDEX)
+ switch(tt) {
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVB; goto st;
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVW; goto st;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ a = AMOVL; goto st;
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVQ; goto st;
+
+ st:
+ if(f->op == OCONST) {
+ gins(a, f, t);
+ return;
+ }
+ fst:
+ regalloc(&nod, t, f);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+
+ case TFLOAT:
+ a = AMOVSS;
+ goto fst;
+ case TDOUBLE:
+ a = AMOVSD;
+ goto fst;
+ }
+
+/*
+ * convert
+ */
+ switch(CASE(ft,tt)) {
+ default:
+/*
+ * integer to integer
+ ********
+ a = AGOK; break;
+
+ case CASE( TCHAR, TCHAR):
+ case CASE( TUCHAR, TCHAR):
+ case CASE( TSHORT, TCHAR):
+ case CASE( TUSHORT,TCHAR):
+ case CASE( TINT, TCHAR):
+ case CASE( TUINT, TCHAR):
+ case CASE( TLONG, TCHAR):
+ case CASE( TULONG, TCHAR):
+ case CASE( TIND, TCHAR):
+
+ case CASE( TCHAR, TUCHAR):
+ case CASE( TUCHAR, TUCHAR):
+ case CASE( TSHORT, TUCHAR):
+ case CASE( TUSHORT,TUCHAR):
+ case CASE( TINT, TUCHAR):
+ case CASE( TUINT, TUCHAR):
+ case CASE( TLONG, TUCHAR):
+ case CASE( TULONG, TUCHAR):
+ case CASE( TIND, TUCHAR):
+
+ case CASE( TSHORT, TSHORT):
+ case CASE( TUSHORT,TSHORT):
+ case CASE( TINT, TSHORT):
+ case CASE( TUINT, TSHORT):
+ case CASE( TLONG, TSHORT):
+ case CASE( TULONG, TSHORT):
+ case CASE( TIND, TSHORT):
+
+ case CASE( TSHORT, TUSHORT):
+ case CASE( TUSHORT,TUSHORT):
+ case CASE( TINT, TUSHORT):
+ case CASE( TUINT, TUSHORT):
+ case CASE( TLONG, TUSHORT):
+ case CASE( TULONG, TUSHORT):
+ case CASE( TIND, TUSHORT):
+
+ case CASE( TINT, TINT):
+ case CASE( TUINT, TINT):
+ case CASE( TLONG, TINT):
+ case CASE( TULONG, TINT):
+ case CASE( TIND, TINT):
+
+ case CASE( TINT, TUINT):
+ case CASE( TUINT, TUINT):
+ case CASE( TLONG, TUINT):
+ case CASE( TULONG, TUINT):
+ case CASE( TIND, TUINT):
+
+ case CASE( TUINT, TIND):
+ case CASE( TVLONG, TUINT):
+ case CASE( TVLONG, TULONG):
+ case CASE( TUVLONG, TUINT):
+ case CASE( TUVLONG, TULONG):
+ *****/
+ a = AMOVL;
+ break;
+
+ case CASE( TVLONG, TCHAR):
+ case CASE( TVLONG, TSHORT):
+ case CASE( TVLONG, TINT):
+ case CASE( TVLONG, TLONG):
+ case CASE( TUVLONG, TCHAR):
+ case CASE( TUVLONG, TSHORT):
+ case CASE( TUVLONG, TINT):
+ case CASE( TUVLONG, TLONG):
+ case CASE( TINT, TVLONG):
+ case CASE( TINT, TUVLONG):
+ case CASE( TLONG, TVLONG):
+ case CASE( TINT, TIND):
+ case CASE( TLONG, TIND):
+ a = AMOVLQSX;
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ if(f->vconst & 0x80000000)
+ f->vconst |= (vlong)0xffffffff << 32;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUINT, TIND):
+ case CASE( TUINT, TVLONG):
+ case CASE( TUINT, TUVLONG):
+ case CASE( TULONG, TVLONG):
+ case CASE( TULONG, TUVLONG):
+ case CASE( TULONG, TIND):
+ a = AMOVL; /* same effect as AMOVLQZX */
+ if(f->op == OCONST) {
+ f->vconst &= (uvlong)0xffffffffU;
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TIND, TVLONG):
+ case CASE( TVLONG, TVLONG):
+ case CASE( TUVLONG, TVLONG):
+ case CASE( TVLONG, TUVLONG):
+ case CASE( TUVLONG, TUVLONG):
+ case CASE( TIND, TUVLONG):
+ case CASE( TVLONG, TIND):
+ case CASE( TUVLONG, TIND):
+ case CASE( TIND, TIND):
+ a = AMOVQ;
+ break;
+
+ case CASE( TSHORT, TINT):
+ case CASE( TSHORT, TUINT):
+ case CASE( TSHORT, TLONG):
+ case CASE( TSHORT, TULONG):
+ a = AMOVWLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000)
+ f->vconst |= 0xffff0000;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TSHORT, TVLONG):
+ case CASE( TSHORT, TUVLONG):
+ case CASE( TSHORT, TIND):
+ a = AMOVWQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ if(f->vconst & 0x8000){
+ f->vconst |= 0xffff0000;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TINT):
+ case CASE( TUSHORT,TUINT):
+ case CASE( TUSHORT,TLONG):
+ case CASE( TUSHORT,TULONG):
+ a = AMOVWLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUSHORT,TVLONG):
+ case CASE( TUSHORT,TUVLONG):
+ case CASE( TUSHORT,TIND):
+ a = AMOVWQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xffff;
+ a = AMOVL; /* MOVL also zero-extends to 64 bits */
+ }
+ break;
+
+ case CASE( TCHAR, TSHORT):
+ case CASE( TCHAR, TUSHORT):
+ case CASE( TCHAR, TINT):
+ case CASE( TCHAR, TUINT):
+ case CASE( TCHAR, TLONG):
+ case CASE( TCHAR, TULONG):
+ a = AMOVBLSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80)
+ f->vconst |= 0xffffff00;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TCHAR, TVLONG):
+ case CASE( TCHAR, TUVLONG):
+ case CASE( TCHAR, TIND):
+ a = AMOVBQSX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ if(f->vconst & 0x80){
+ f->vconst |= 0xffffff00;
+ f->vconst |= (vlong)~0 << 32;
+ }
+ a = AMOVQ;
+ }
+ break;
+
+ case CASE( TUCHAR, TSHORT):
+ case CASE( TUCHAR, TUSHORT):
+ case CASE( TUCHAR, TINT):
+ case CASE( TUCHAR, TUINT):
+ case CASE( TUCHAR, TLONG):
+ case CASE( TUCHAR, TULONG):
+ a = AMOVBLZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL;
+ }
+ break;
+
+ case CASE( TUCHAR, TVLONG):
+ case CASE( TUCHAR, TUVLONG):
+ case CASE( TUCHAR, TIND):
+ a = AMOVBQZX;
+ if(f->op == OCONST) {
+ f->vconst &= 0xff;
+ a = AMOVL; /* zero-extends to 64-bits */
+ }
+ break;
+
+/*
+ * float to fix
+ */
+ case CASE( TFLOAT, TCHAR):
+ case CASE( TFLOAT, TUCHAR):
+ case CASE( TFLOAT, TSHORT):
+ case CASE( TFLOAT, TUSHORT):
+ case CASE( TFLOAT, TINT):
+ case CASE( TFLOAT, TUINT):
+ case CASE( TFLOAT, TLONG):
+ case CASE( TFLOAT, TULONG):
+ case CASE( TFLOAT, TVLONG):
+ case CASE( TFLOAT, TUVLONG):
+ case CASE( TFLOAT, TIND):
+
+ case CASE( TDOUBLE,TCHAR):
+ case CASE( TDOUBLE,TUCHAR):
+ case CASE( TDOUBLE,TSHORT):
+ case CASE( TDOUBLE,TUSHORT):
+ case CASE( TDOUBLE,TINT):
+ case CASE( TDOUBLE,TUINT):
+ case CASE( TDOUBLE,TLONG):
+ case CASE( TDOUBLE,TULONG):
+ case CASE( TDOUBLE,TVLONG):
+ case CASE( TDOUBLE,TUVLONG):
+ case CASE( TDOUBLE,TIND):
+ regalloc(&nod, t, Z);
+ if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+ if(ft == TFLOAT)
+ a = ACVTTSS2SQ;
+ else
+ a = ACVTTSD2SQ;
+ }else{
+ if(ft == TFLOAT)
+ a = ACVTTSS2SL;
+ else
+ a = ACVTTSD2SL;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * uvlong to float
+ */
+ case CASE( TUVLONG, TDOUBLE):
+ case CASE( TUVLONG, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gmove(f, &nod);
+ regalloc(&nod1, t, t);
+ gins(ACMPQ, &nod, nodconst(0));
+ gins(AJLT, Z, Z);
+ p1 = p;
+ gins(a, &nod, &nod1);
+ gins(AJMP, Z, Z);
+ p2 = p;
+ patch(p1, pc);
+ regalloc(&nod2, f, Z);
+ regalloc(&nod3, f, Z);
+ gmove(&nod, &nod2);
+ gins(ASHRQ, nodconst(1), &nod2);
+ gmove(&nod, &nod3);
+ gins(AANDL, nodconst(1), &nod3);
+ gins(AORQ, &nod3, &nod2);
+ gins(a, &nod2, &nod1);
+ gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+ regfree(&nod2);
+ regfree(&nod3);
+ patch(p2, pc);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+ case CASE( TULONG, TDOUBLE):
+ case CASE( TUINT, TDOUBLE):
+ case CASE( TULONG, TFLOAT):
+ case CASE( TUINT, TFLOAT):
+ a = ACVTSQ2SS;
+ if(tt == TDOUBLE)
+ a = ACVTSQ2SD;
+ regalloc(&nod, f, f);
+ gins(AMOVLQZX, f, &nod);
+ regalloc(&nod1, t, t);
+ gins(a, &nod, &nod1);
+ gmove(&nod1, t);
+ regfree(&nod);
+ regfree(&nod1);
+ return;
+
+/*
+ * fix to float
+ */
+ case CASE( TCHAR, TFLOAT):
+ case CASE( TUCHAR, TFLOAT):
+ case CASE( TSHORT, TFLOAT):
+ case CASE( TUSHORT,TFLOAT):
+ case CASE( TINT, TFLOAT):
+ case CASE( TLONG, TFLOAT):
+ case CASE( TVLONG, TFLOAT):
+ case CASE( TIND, TFLOAT):
+
+ case CASE( TCHAR, TDOUBLE):
+ case CASE( TUCHAR, TDOUBLE):
+ case CASE( TSHORT, TDOUBLE):
+ case CASE( TUSHORT,TDOUBLE):
+ case CASE( TINT, TDOUBLE):
+ case CASE( TLONG, TDOUBLE):
+ case CASE( TVLONG, TDOUBLE):
+ case CASE( TIND, TDOUBLE):
+ regalloc(&nod, t, t);
+ if(ewidth[ft] == SZ_VLONG){
+ if(tt == TFLOAT)
+ a = ACVTSQ2SS;
+ else
+ a = ACVTSQ2SD;
+ }else{
+ if(tt == TFLOAT)
+ a = ACVTSL2SS;
+ else
+ a = ACVTSL2SD;
+ }
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+
+/*
+ * float to float
+ */
+ case CASE( TFLOAT, TFLOAT):
+ a = AMOVSS;
+ break;
+ case CASE( TDOUBLE,TFLOAT):
+ a = ACVTSD2SS;
+ break;
+ case CASE( TFLOAT, TDOUBLE):
+ a = ACVTSS2SD;
+ break;
+ case CASE( TDOUBLE,TDOUBLE):
+ a = AMOVSD;
+ break;
+ }
+ if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+ Node nod, nod1;
+ int32 v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+ regalloc(&nod, &qregnode, Z);
+ v = constnode.vconst;
+ cgen(n->right, &nod);
+ idx.ptr = D_NONE;
+ if(n->left->op == OCONST)
+ idx.ptr = D_CONST;
+ else if(n->left->op == OREGISTER)
+ idx.ptr = n->left->reg;
+ else if(n->left->op != OADDR) {
+ reg[D_BP]++; // cant be used as a base
+ regalloc(&nod1, &qregnode, Z);
+ cgen(n->left, &nod1);
+ idx.ptr = nod1.reg;
+ regfree(&nod1);
+ reg[D_BP]--;
+ }
+ idx.reg = nod.reg;
+ regfree(&nod);
+ constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ if(f != Z && f->op == OINDEX)
+ doindex(f);
+ if(t != Z && t->op == OINDEX)
+ doindex(t);
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+ int a, et;
+
+ et = TLONG;
+ if(ty != T)
+ et = ty->etype;
+ if(debug['M']) {
+ if(f != Z && f->type != T)
+ print("gop: %O %O[%s],", o, f->op, tnames[et]);
+ else
+ print("gop: %O Z,", o);
+ if(t != Z && t->type != T)
+ print("%O[%s]\n", t->op, tnames[t->type->etype]);
+ else
+ print("Z\n");
+ }
+ a = AGOK;
+ switch(o) {
+ case OCOM:
+ a = ANOTL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANOTB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANOTW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANOTQ;
+ break;
+
+ case ONEG:
+ a = ANEGL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ANEGB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ANEGW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ANEGQ;
+ break;
+
+ case OADDR:
+ a = ALEAQ;
+ break;
+
+ case OASADD:
+ case OADD:
+ a = AADDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AADDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AADDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AADDQ;
+ if(et == TFLOAT)
+ a = AADDSS;
+ if(et == TDOUBLE)
+ a = AADDSD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASUBB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASUBW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASUBQ;
+ if(et == TFLOAT)
+ a = ASUBSS;
+ if(et == TDOUBLE)
+ a = ASUBSD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AORQ;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AANDL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AANDB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AANDW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AANDQ;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXORL;
+ if(et == TCHAR || et == TUCHAR)
+ a = AXORB;
+ if(et == TSHORT || et == TUSHORT)
+ a = AXORW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AXORQ;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASHRL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASHRB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASHRW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASHRQ;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASARL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASARB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASARW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASARQ;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASALL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ASALB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ASALW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASALQ;
+ break;
+
+ case OFUNC:
+ a = ACALL;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+ t = Z;
+ a = AIMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIMULQ;
+ if(et == TFLOAT)
+ a = AMULSS;
+ if(et == TDOUBLE)
+ a = AMULSD;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ case OASDIV:
+ case ODIV:
+ a = AIDIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AIDIVQ;
+ if(et == TFLOAT)
+ a = ADIVSS;
+ if(et == TDOUBLE)
+ a = ADIVSD;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULQ;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVQ;
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ a = ACMPL;
+ if(et == TCHAR || et == TUCHAR)
+ a = ACMPB;
+ if(et == TSHORT || et == TUSHORT)
+ a = ACMPW;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ACMPQ;
+ if(et == TFLOAT)
+ a = AUCOMISS;
+ if(et == TDOUBLE)
+ a = AUCOMISD;
+ gins(a, f, t);
+ switch(o) {
+ case OEQ: a = AJEQ; break;
+ case ONE: a = AJNE; break;
+ case OLT: a = AJLT; break;
+ case OLE: a = AJLE; break;
+ case OGE: a = AJGE; break;
+ case OGT: a = AJGT; break;
+ case OLO: a = AJCS; break;
+ case OLS: a = AJLS; break;
+ case OHS: a = AJCC; break;
+ case OHI: a = AJHI; break;
+ }
+ gins(a, Z, Z);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+ return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->from.scale = textflag;
+ textflag = 0;
+
+ if(s->class == CSTATIC)
+ p->from.type = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ int32 v;
+
+ if(n->op == OCONST && !typefd[n->type->etype]) {
+ v = n->vconst;
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ }
+ return 0;
+}
+
+int32
+exreg(Type *t)
+{
+ int32 o;
+
+ if(typechlpv[t->etype]) {
+ if(exregoffset >= 64)
+ return 0;
+ o = exregoffset;
+ exregoffset += 8;
+ return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /*[TXXX]*/
+ SZ_CHAR, /*[TCHAR]*/
+ SZ_CHAR, /*[TUCHAR]*/
+ SZ_SHORT, /*[TSHORT]*/
+ SZ_SHORT, /*[TUSHORT]*/
+ SZ_INT, /*[TINT]*/
+ SZ_INT, /*[TUINT]*/
+ SZ_LONG, /*[TLONG]*/
+ SZ_LONG, /*[TULONG]*/
+ SZ_VLONG, /*[TVLONG]*/
+ SZ_VLONG, /*[TUVLONG]*/
+ SZ_FLOAT, /*[TFLOAT]*/
+ SZ_DOUBLE, /*[TDOUBLE]*/
+ SZ_IND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ -1, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ -1, /*[TSTRUCT]*/
+ -1, /*[TUNION]*/
+ SZ_INT, /*[TENUM]*/
+};
+int32 ncast[NTYPE] =
+{
+ 0, /*[TXXX]*/
+ BCHAR|BUCHAR, /*[TCHAR]*/
+ BCHAR|BUCHAR, /*[TUCHAR]*/
+ BSHORT|BUSHORT, /*[TSHORT]*/
+ BSHORT|BUSHORT, /*[TUSHORT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TUINT]*/
+ BINT|BUINT|BLONG|BULONG, /*[TLONG]*/
+ BINT|BUINT|BLONG|BULONG, /*[TULONG]*/
+ BVLONG|BUVLONG|BIND, /*[TVLONG]*/
+ BVLONG|BUVLONG|BIND, /*[TUVLONG]*/
+ BFLOAT, /*[TFLOAT]*/
+ BDOUBLE, /*[TDOUBLE]*/
+ BVLONG|BUVLONG|BIND, /*[TIND]*/
+ 0, /*[TFUNC]*/
+ 0, /*[TARRAY]*/
+ 0, /*[TVOID]*/
+ BSTRUCT, /*[TSTRUCT]*/
+ BUNION, /*[TUNION]*/
+ 0, /*[TENUM]*/
+};