diff options
author | Russ Cox <rsc@golang.org> | 2009-01-06 09:41:38 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-01-06 09:41:38 -0800 |
commit | 012bfad187d3a9a21ebcdbc0844b28a901b4b638 (patch) | |
tree | 2c683e103fc1c4ae0cdbf05c6631184624b5f6df /src/cmd/8c | |
parent | 4587de918b143ba48a8fd5853950626ac2ee7fd2 (diff) | |
download | golang-012bfad187d3a9a21ebcdbc0844b28a901b4b638.tar.gz |
8a, 8c, and 8l from inferno distribution
R=r
DELTA=19539 (19539 added, 0 deleted, 0 changed)
OCL=22109
CL=22109
Diffstat (limited to 'src/cmd/8c')
-rw-r--r-- | src/cmd/8c/8.out.h | 475 | ||||
-rw-r--r-- | src/cmd/8c/cgen.c | 1851 | ||||
-rw-r--r-- | src/cmd/8c/cgen64.c | 2741 | ||||
-rw-r--r-- | src/cmd/8c/div.c | 236 | ||||
-rw-r--r-- | src/cmd/8c/gc.h | 404 | ||||
-rw-r--r-- | src/cmd/8c/list.c | 312 | ||||
-rw-r--r-- | src/cmd/8c/machcap.c | 116 | ||||
-rw-r--r-- | src/cmd/8c/mkenam | 45 | ||||
-rw-r--r-- | src/cmd/8c/mul.c | 458 | ||||
-rw-r--r-- | src/cmd/8c/peep.c | 787 | ||||
-rw-r--r-- | src/cmd/8c/reg.c | 1285 | ||||
-rw-r--r-- | src/cmd/8c/sgen.c | 872 | ||||
-rw-r--r-- | src/cmd/8c/swt.c | 677 | ||||
-rw-r--r-- | src/cmd/8c/txt.c | 1440 |
14 files changed, 11699 insertions, 0 deletions
diff --git a/src/cmd/8c/8.out.h b/src/cmd/8c/8.out.h new file mode 100644 index 000000000..e7d3f76d4 --- /dev/null +++ b/src/cmd/8c/8.out.h @@ -0,0 +1,475 @@ +// Inferno utils/8c/8.out.h +// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.h +// +// 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. + +#define NSYM 50 +#define NSNAME 8 +#define NOPROF (1<<0) +#define DUPOK (1<<1) + +enum as +{ + AXXX, + AAAA, + AAAD, + AAAM, + AAAS, + AADCB, + AADCL, + AADCW, + AADDB, + AADDL, + AADDW, + AADJSP, + AANDB, + AANDL, + AANDW, + AARPL, + ABOUNDL, + ABOUNDW, + ABSFL, + ABSFW, + ABSRL, + ABSRW, + ABTL, + ABTW, + ABTCL, + ABTCW, + ABTRL, + ABTRW, + ABTSL, + ABTSW, + ABYTE, + ACALL, + ACLC, + ACLD, + ACLI, + ACLTS, + ACMC, + ACMPB, + ACMPL, + ACMPW, + ACMPSB, + ACMPSL, + ACMPSW, + ADAA, + ADAS, + ADATA, + ADECB, + ADECL, + ADECW, + ADIVB, + ADIVL, + ADIVW, + AENTER, + AGLOBL, + AGOK, + AHISTORY, + AHLT, + AIDIVB, + AIDIVL, + AIDIVW, + AIMULB, + AIMULL, + AIMULW, + AINB, + AINL, + AINW, + AINCB, + AINCL, + AINCW, + AINSB, + AINSL, + AINSW, + AINT, + AINTO, + AIRETL, + AIRETW, + AJCC, + AJCS, + AJCXZ, + AJEQ, + AJGE, + AJGT, + AJHI, + AJLE, + AJLS, + AJLT, + AJMI, + AJMP, + AJNE, + AJOC, + AJOS, + AJPC, + AJPL, + AJPS, + ALAHF, + ALARL, + ALARW, + ALEAL, + ALEAW, + ALEAVEL, + ALEAVEW, + ALOCK, + ALODSB, + ALODSL, + ALODSW, + ALONG, + ALOOP, + ALOOPEQ, + ALOOPNE, + ALSLL, + ALSLW, + AMOVB, + AMOVL, + AMOVW, + AMOVBLSX, + AMOVBLZX, + AMOVBWSX, + AMOVBWZX, + AMOVWLSX, + AMOVWLZX, + AMOVSB, + AMOVSL, + AMOVSW, + AMULB, + AMULL, + AMULW, + ANAME, + ANEGB, + ANEGL, + ANEGW, + ANOP, + ANOTB, + ANOTL, + ANOTW, + AORB, + AORL, + AORW, + AOUTB, + AOUTL, + AOUTW, + AOUTSB, + AOUTSL, + AOUTSW, + APOPAL, + APOPAW, + APOPFL, + APOPFW, + APOPL, + APOPW, + APUSHAL, + APUSHAW, + APUSHFL, + APUSHFW, + APUSHL, + APUSHW, + ARCLB, + ARCLL, + ARCLW, + ARCRB, + ARCRL, + ARCRW, + AREP, + AREPN, + ARET, + AROLB, + AROLL, + AROLW, + ARORB, + ARORL, + ARORW, + ASAHF, + ASALB, + ASALL, + ASALW, + ASARB, + ASARL, + ASARW, + ASBBB, + ASBBL, + ASBBW, + ASCASB, + ASCASL, + ASCASW, + ASETCC, + ASETCS, + ASETEQ, + ASETGE, + ASETGT, + ASETHI, + ASETLE, + ASETLS, + ASETLT, + ASETMI, + ASETNE, + ASETOC, + ASETOS, + ASETPC, + ASETPL, + ASETPS, + ACDQ, + ACWD, + ASHLB, + ASHLL, + ASHLW, + ASHRB, + ASHRL, + ASHRW, + ASTC, + ASTD, + ASTI, + ASTOSB, + ASTOSL, + ASTOSW, + ASUBB, + ASUBL, + ASUBW, + ASYSCALL, + ATESTB, + ATESTL, + ATESTW, + ATEXT, + AVERR, + AVERW, + AWAIT, + AWORD, + AXCHGB, + AXCHGL, + AXCHGW, + AXLAT, + AXORB, + AXORL, + AXORW, + + AFMOVB, + AFMOVBP, + AFMOVD, + AFMOVDP, + AFMOVF, + AFMOVFP, + AFMOVL, + AFMOVLP, + AFMOVV, + AFMOVVP, + AFMOVW, + AFMOVWP, + AFMOVX, + AFMOVXP, + + AFCOMB, + AFCOMBP, + AFCOMD, + AFCOMDP, + AFCOMDPP, + AFCOMF, + AFCOMFP, + AFCOML, + AFCOMLP, + AFCOMW, + AFCOMWP, + AFUCOM, + AFUCOMP, + AFUCOMPP, + + AFADDDP, + AFADDW, + AFADDL, + AFADDF, + AFADDD, + + AFMULDP, + AFMULW, + AFMULL, + AFMULF, + AFMULD, + + AFSUBDP, + AFSUBW, + AFSUBL, + AFSUBF, + AFSUBD, + + AFSUBRDP, + AFSUBRW, + AFSUBRL, + AFSUBRF, + AFSUBRD, + + AFDIVDP, + AFDIVW, + AFDIVL, + AFDIVF, + AFDIVD, + + AFDIVRDP, + AFDIVRW, + AFDIVRL, + AFDIVRF, + AFDIVRD, + + AFXCHD, + AFFREE, + + AFLDCW, + AFLDENV, + AFRSTOR, + AFSAVE, + AFSTCW, + AFSTENV, + AFSTSW, + + AF2XM1, + AFABS, + AFCHS, + AFCLEX, + AFCOS, + AFDECSTP, + AFINCSTP, + AFINIT, + AFLD1, + AFLDL2E, + AFLDL2T, + AFLDLG2, + AFLDLN2, + AFLDPI, + AFLDZ, + AFNOP, + AFPATAN, + AFPREM, + AFPREM1, + AFPTAN, + AFRNDINT, + AFSCALE, + AFSIN, + AFSINCOS, + AFSQRT, + AFTST, + AFXAM, + AFXTRACT, + AFYL2X, + AFYL2XP1, + + AEND, + + ADYNT, + AINIT, + + ASIGNAME, + + ALAST +}; + +enum +{ + D_AL = 0, + D_CL, + D_DL, + D_BL, + + D_AH = 4, + D_CH, + D_DH, + D_BH, + + D_AX = 8, + D_CX, + D_DX, + D_BX, + D_SP, + D_BP, + D_SI, + D_DI, + + D_F0 = 16, + + D_CS = 24, + D_SS, + D_DS, + D_ES, + D_FS, + D_GS, + + D_GDTR, /* global descriptor table register */ + D_IDTR, /* interrupt descriptor table register */ + D_LDTR, /* local descriptor table register */ + D_MSW, /* machine status word */ + D_TASK, /* task register */ + + D_CR = 35, + D_DR = 43, + D_TR = 51, + + D_NONE = 59, + + D_BRANCH = 60, + D_EXTERN = 61, + D_STATIC = 62, + D_AUTO = 63, + D_PARAM = 64, + D_CONST = 65, + D_FCONST = 66, + D_SCONST = 67, + D_ADDR = 68, + + D_FILE, + D_FILE1, + + D_INDIR, /* additive */ + + T_TYPE = 1<<0, + T_INDEX = 1<<1, + T_OFFSET = 1<<2, + T_FCONST = 1<<3, + T_SYM = 1<<4, + T_SCONST = 1<<5, + + REGARG = 0, + REGRET = D_AX, + FREGRET = D_F0, + REGSP = D_SP, + REGTMP = D_DI, +}; + +/* + * this is the ranlib header + */ +#define SYMDEF "__.SYMDEF" + +/* + * this is the simulated IEEE floating point + */ +typedef struct ieee Ieee; +struct ieee +{ + long l; /* contains ls-man 0xffffffff */ + long h; /* contains sign 0x80000000 + exp 0x7ff00000 + ms-man 0x000fffff */ +}; diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c new file mode 100644 index 000000000..cd2cc8136 --- /dev/null +++ b/src/cmd/8c/cgen.c @@ -0,0 +1,1851 @@ +// Inferno utils/8c/cgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.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" + +/* ,x/^(print|prtree)\(/i/\/\/ */ + +void +cgen(Node *n, Node *nn) +{ + Node *l, *r, *t; + Prog *p1; + Node nod, nod1, nod2, nod3, nod4; + int o, hardleft; + long v, curs; + vlong c; + + if(debug['g']) { + prtree(nn, "cgen lhs"); + prtree(n, "cgen"); + } + if(n == Z || n->type == T) + return; + if(typesuv[n->type->etype]) { + sugen(n, nn, n->type->width); + return; + } + l = n->left; + r = n->right; + o = n->op; + if(n->addable >= INDEXED) { + if(nn == Z) { + switch(o) { + default: + nullwarn(Z, Z); + break; + case OINDEX: + nullwarn(l, r); + break; + } + return; + } + gmove(n, nn); + return; + } + curs = cursafe; + + if(l->complex >= FNX) + if(r != Z && r->complex >= FNX) + switch(o) { + default: + if(cond(o) && typesuv[l->type->etype]) + break; + + regret(&nod, r); + cgen(r, &nod); + + regsalloc(&nod1, r); + gmove(&nod, &nod1); + + regfree(&nod); + nod = *n; + nod.right = &nod1; + + cgen(&nod, nn); + return; + + case OFUNC: + case OCOMMA: + case OANDAND: + case OOROR: + case OCOND: + case ODOT: + break; + } + + hardleft = l->addable < INDEXED || l->complex >= FNX; + switch(o) { + default: + 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, n->type, Z, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + + case OAS: + if(typefd[n->type->etype]) { + cgen(r, &fregnode0); + if(nn != Z) + gins(AFMOVD, &fregnode0, &fregnode0); + if(l->addable < INDEXED) { + reglcgen(&nod, l, Z); + gmove(&fregnode0, &nod); + regfree(&nod); + } else + gmove(&fregnode0, l); + if(nn != Z) + gmove(&fregnode0, nn); + return; + } + if(l->op == OBIT) + goto bitas; + if(!hardleft) { + if(nn != Z || r->addable < INDEXED) { + 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) { + if(l->op == OINDEX && r->op == OCONST) { + gmove(r, l); + break; + } + reglcgen(&nod1, l, Z); + if(r->addable >= INDEXED) { + gmove(r, &nod1); + if(nn != Z) + gmove(r, nn); + regfree(&nod1); + break; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + } else { + regalloc(&nod, r, nn); + cgen(r, &nod); + reglcgen(&nod1, l, Z); + } + gmove(&nod, &nod1); + regfree(&nod); + regfree(&nod1); + break; + + bitas: + n = l->left; + regalloc(&nod, r, nn); + if(l->complex >= r->complex) { + reglcgen(&nod1, n, Z); + cgen(r, &nod); + } else { + cgen(r, &nod); + reglcgen(&nod1, n, Z); + } + regalloc(&nod2, n, Z); + gmove(&nod1, &nod2); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OBIT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + bitload(n, &nod, Z, Z, nn); + gmove(&nod, nn); + regfree(&nod); + break; + + case OLSHR: + case OASHL: + case OASHR: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(r->op == OCONST) { + if(r->vconst == 0) { + cgen(l, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + if(o == OASHL && r->vconst == 1) + gopcode(OADD, n->type, &nod, &nod); + else + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); /* probably a bug */ + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + if(nn->op == OREGISTER && nn->reg == D_CX) + regalloc(&nod1, l, Z); + else + regalloc(&nod1, l, nn); + if(r->complex >= l->complex) { + cgen(r, &nod); + cgen(l, &nod1); + } else { + cgen(l, &nod1); + cgen(r, &nod); + } + gopcode(o, n->type, &nod, &nod1); + gmove(&nod1, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OADD: + case OSUB: + case OOR: + case OXOR: + case OAND: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST) { + if(r->vconst == 0 && o != OAND) { + cgen(l, nn); + break; + } + } + if(n->op == OADD && l->op == OASHL && l->right->op == OCONST + && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { + c = l->right->vconst; + if(c > 0 && c <= 3) { + if(l->left->complex >= r->complex) { + regalloc(&nod, l->left, nn); + cgen(l->left, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + genmuladd(&nod, &nod, 1 << c, &nod1); + regfree(&nod1); + } + else + genmuladd(&nod, &nod, 1 << c, r); + } + else { + regalloc(&nod, r, nn); + cgen(r, &nod); + regalloc(&nod1, l->left, Z); + cgen(l->left, &nod1); + genmuladd(&nod, &nod1, 1 << c, &nod); + regfree(&nod1); + } + gmove(&nod, nn); + regfree(&nod); + break; + } + } + if(r->addable >= INDEXED) { + regalloc(&nod, l, nn); + cgen(l, &nod); + gopcode(o, n->type, r, &nod); + gmove(&nod, nn); + regfree(&nod); + break; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, n->type, &nod1, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + regalloc(&nod, l, Z); + cgen(l, &nod); + gopcode(o, n->type, &nod1, &nod); + } + gmove(&nod, nn); + regfree(&nod); + regfree(&nod1); + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + if(nn == Z) { + nullwarn(l, r); + break; + } + if(typefd[n->type->etype]) + goto fop; + if(r->op == OCONST) { + SET(v); + switch(o) { + case ODIV: + case OMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OMUL: + case OLMUL: + regalloc(&nod, l, nn); + cgen(l, &nod); + switch(o) { + case OMUL: + case OLMUL: + mulgen(n->type, r, &nod); + break; + case ODIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OMOD: + smod2(r->vconst, v, l, &nod); + break; + } + gmove(&nod, nn); + regfree(&nod); + goto done; + case OLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + regalloc(&nod1, l, Z); + cgen(l, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + gmove(&nod, nn); + regfree(&nod); + goto done; + } + } + + if(o == OMUL) { + if(l->addable >= INDEXED) { + t = l; + l = r; + r = t; + } + /* should favour AX */ + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(OMUL, n->type, &nod1, &nod); + regfree(&nod1); + }else + gopcode(OMUL, n->type, r, &nod); /* addressible */ + gmove(&nod, nn); + regfree(&nod); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + + if(r->op == OCONST && (o == ODIV || o == OLDIV)) { + reg[D_DX]++; + if(l->addable < INDEXED) { + regalloc(&nod2, l, Z); + cgen(l, &nod2); + l = &nod2; + } + if(o == ODIV) + sdivgen(l, r, &nod, &nod1); + else + udivgen(l, r, &nod, &nod1); + gmove(&nod1, nn); + if(l == &nod2) + regfree(l); + goto freeaxdx; + } + + if(l->complex >= r->complex) { + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(ACDQ, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST) { + regsalloc(&nod3, r); + cgen(r, &nod3); + gopcode(o, n->type, &nod3, Z); + } else + gopcode(o, n->type, r, Z); + } else { + regsalloc(&nod3, r); + cgen(r, &nod3); + cgen(l, &nod); + reg[D_DX]++; + if(o == ODIV || o == OMOD) + gins(ACDQ, Z, Z); + if(o == OLDIV || o == OLMOD) + zeroregm(&nod1); + gopcode(o, n->type, &nod3, Z); + } + if(o == OMOD || o == OLMOD) + gmove(&nod1, nn); + else + gmove(&nod, nn); + freeaxdx: + regfree(&nod); + regfree(&nod1); + break; + + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->op == OCONST) + goto asand; + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]) + goto asfop; + + /* + * get nod to be D_CX + */ + if(nodreg(&nod, nn, D_CX)) { + regsalloc(&nod1, n); + gmove(&nod, &nod1); + cgen(n, &nod); + if(nn != Z) + gmove(&nod, nn); + gmove(&nod1, &nod); + break; + } + reg[D_CX]++; + + if(r->complex >= l->complex) { + cgen(r, &nod); + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + } else { + if(hardleft) + reglcgen(&nod1, l, Z); + else + nod1 = *l; + cgen(r, &nod); + } + + gopcode(o, l->type, &nod, &nod1); + regfree(&nod); + if(nn != Z) + gmove(&nod1, nn); + if(hardleft) + regfree(&nod1); + break; + + case OASAND: + case OASADD: + case OASSUB: + case OASXOR: + case OASOR: + asand: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]||typefd[r->type->etype]) + goto asfop; + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(r->op != OCONST) { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, r, &nod); + } else { + regalloc(&nod1, r, nn); + cgen(r, &nod1); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(l->op == OBIT) + goto asbitop; + if(typefd[n->type->etype]||typefd[r->type->etype]) + goto asfop; + if(r->op == OCONST) { + SET(v); + switch(o) { + case OASDIV: + case OASMOD: + c = r->vconst; + if(c < 0) + c = -c; + v = log2(c); + if(v < 0) + break; + /* fall thru */ + case OASMUL: + case OASLMUL: + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod, l, nn); + cgen(&nod2, &nod); + switch(o) { + case OASMUL: + case OASLMUL: + mulgen(n->type, r, &nod); + break; + case OASDIV: + sdiv2(r->vconst, v, l, &nod); + break; + case OASMOD: + smod2(r->vconst, v, l, &nod); + break; + } + havev: + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod2); + regfree(&nod); + goto done; + case OASLDIV: + c = r->vconst; + if((c & 0x80000000) == 0) + break; + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + regalloc(&nod1, l, nn); + cgen(&nod2, &nod1); + regalloc(&nod, l, nn); + zeroregm(&nod); + gins(ACMPL, &nod1, nodconst(c)); + gins(ASBBL, nodconst(-1), &nod); + regfree(&nod1); + goto havev; + } + } + + if(o == OASMUL) { + /* should favour AX */ + regalloc(&nod, l, nn); + if(r->complex >= FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + r = &nod1; + } + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->addable < INDEXED) { + if(r->complex < FNX) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + } + gopcode(OASMUL, n->type, &nod1, &nod); + regfree(&nod1); + } + else + gopcode(OASMUL, n->type, r, &nod); + if(r == &nod1) + regfree(r); + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + regfree(&nod); + if(hardleft) + regfree(&nod2); + break; + } + + /* + * get nod to be D_AX + * get nod1 to be D_DX + */ + if(nodreg(&nod, nn, D_AX)) { + regsalloc(&nod2, n); + gmove(&nod, &nod2); + v = reg[D_AX]; + reg[D_AX] = 0; + + if(isreg(l, D_AX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_AX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod); + reg[D_AX] = v; + break; + } + if(nodreg(&nod1, nn, D_DX)) { + regsalloc(&nod2, n); + gmove(&nod1, &nod2); + v = reg[D_DX]; + reg[D_DX] = 0; + + if(isreg(l, D_DX)) { + nod3 = *n; + nod3.left = &nod2; + cgen(&nod3, nn); + } else + if(isreg(r, D_DX)) { + nod3 = *n; + nod3.right = &nod2; + cgen(&nod3, nn); + } else + cgen(n, nn); + + gmove(&nod2, &nod1); + reg[D_DX] = v; + break; + } + reg[D_AX]++; + reg[D_DX]++; + + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(r->op == OCONST) { + switch(o) { + case OASDIV: + sdivgen(&nod2, r, &nod, &nod1); + goto divdone; + case OASLDIV: + udivgen(&nod2, r, &nod, &nod1); + divdone: + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + goto freelxaxdx; + } + } + if(o == OASDIV || o == OASMOD) + gins(ACDQ, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + if(r->addable < INDEXED || r->op == OCONST || + !typeil[r->type->etype]) { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } else + gopcode(o, n->type, r, Z); + } else { + regalloc(&nod3, r, Z); + cgen(r, &nod3); + if(hardleft) + reglcgen(&nod2, l, Z); + else + nod2 = *l; + cgen(&nod2, &nod); + if(o == OASDIV || o == OASMOD) + gins(ACDQ, Z, Z); + if(o == OASLDIV || o == OASLMOD) + zeroregm(&nod1); + gopcode(o, l->type, &nod3, Z); + regfree(&nod3); + } + if(o == OASMOD || o == OASLMOD) { + gmove(&nod1, &nod2); + if(nn != Z) + gmove(&nod1, nn); + } else { + gmove(&nod, &nod2); + if(nn != Z) + gmove(&nod, nn); + } + freelxaxdx: + if(hardleft) + regfree(&nod2); + regfree(&nod); + regfree(&nod1); + break; + + fop: + if(l->complex >= r->complex) { + cgen(l, &fregnode0); + if(r->addable < INDEXED) { + cgen(r, &fregnode0); + fgopcode(o, &fregnode0, &fregnode1, 1, 0); + } else + fgopcode(o, r, &fregnode0, 0, 0); + } else { + cgen(r, &fregnode0); + if(l->addable < INDEXED) { + cgen(l, &fregnode0); + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + } else + fgopcode(o, l, &fregnode0, 0, 1); + } + gmove(&fregnode0, nn); + break; + + asfop: + if(l->complex >= r->complex) { + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + cgen(r, &fregnode0); + } else { + cgen(r, &fregnode0); + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + } + if(!typefd[l->type->etype]) { + gmove(&nod, &fregnode0); + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + } else + fgopcode(o, &nod, &fregnode0, 0, 1); + if(nn != Z) + gins(AFMOVD, &fregnode0, &fregnode0); + gmove(&fregnode0, &nod); + if(nn != Z) + gmove(&fregnode0, nn); + if(hardleft) + regfree(&nod); + break; + + asbitop: + regalloc(&nod4, n, nn); + 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); + } + gmove(&nod, &nod4); + + if(typefd[nod3.type->etype]) + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + else { + Node onod; + + /* incredible grot ... */ + onod = nod3; + onod.op = o; + onod.complex = 2; + onod.addable = 0; + onod.type = tfield; + onod.left = &nod4; + onod.right = &nod3; + cgen(&onod, Z); + } + regfree(&nod3); + gmove(&nod4, &nod); + regfree(&nod4); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + + case OADDR: + if(nn == Z) { + nullwarn(l, Z); + break; + } + lcgen(l, nn); + break; + + case OFUNC: + if(l->complex >= FNX) { + if(l->op != OIND) + diag(n, "bad function call"); + + regret(&nod, l->left); + cgen(l->left, &nod); + regsalloc(&nod1, l->left); + gmove(&nod, &nod1); + regfree(&nod); + + nod = *n; + nod.left = &nod2; + nod2 = *l; + nod2.left = &nod1; + nod2.complex = 1; + cgen(&nod, nn); + + return; + } + gargs(r, &nod, &nod1); + if(l->addable < INDEXED) { + reglcgen(&nod, l, nn); + nod.op = OREGISTER; + gopcode(OFUNC, n->type, Z, &nod); + regfree(&nod); + } else + gopcode(OFUNC, n->type, Z, l); + if(REGARG && reg[REGARG]) + reg[REGARG]--; + if(nn != Z) { + regret(&nod, n); + gmove(&nod, nn); + regfree(&nod); + } else + if(typefd[n->type->etype]) + gins(AFMOVDP, &fregnode0, &fregnode0); + break; + + case OIND: + if(nn == Z) { + nullwarn(l, Z); + break; + } + regialloc(&nod, n, nn); + r = l; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + cgen(l, &nod); + nod.xoffset += v; + r->vconst = v; + } else + cgen(l, &nod); + regind(&nod, n); + gmove(&nod, nn); + regfree(&nod); + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OLO: + case OLS: + case OHI: + case OHS: + if(nn == Z) { + nullwarn(l, r); + break; + } + boolgen(n, 1, nn); + break; + + case OANDAND: + case OOROR: + boolgen(n, 1, nn); + if(nn == Z) + patch(p, pc); + break; + + case ONOT: + if(nn == Z) { + nullwarn(l, Z); + break; + } + boolgen(n, 1, nn); + break; + + case OCOMMA: + cgen(l, Z); + cgen(r, nn); + break; + + case OCAST: + if(nn == Z) { + nullwarn(l, Z); + break; + } + /* + * convert from types l->n->nn + */ + if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { + /* both null, gen l->nn */ + cgen(l, nn); + break; + } + if(typev[l->type->etype]) { + cgen64(n, nn); + break; + } + regalloc(&nod, l, nn); + cgen(l, &nod); + regalloc(&nod1, n, &nod); + gmove(&nod, &nod1); + gmove(&nod1, nn); + regfree(&nod1); + regfree(&nod); + break; + + case ODOT: + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod = *nodrat; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod.xoffset += (long)r->vconst; + nod.type = n->type; + cgen(&nod, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + cgen(r->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + cgen(r->right, nn); + patch(p1, pc); + break; + + case OPOSTINC: + case OPOSTDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPOSTDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + if(nn == Z) + goto pre; + + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + + if(typefd[n->type->etype]) + goto fltinc; + gmove(&nod, nn); + gopcode(OADD, n->type, nodconst(v), &nod); + if(hardleft) + regfree(&nod); + break; + + case OPREINC: + case OPREDEC: + v = 1; + if(l->type->etype == TIND) + v = l->type->link->width; + if(o == OPREDEC) + v = -v; + if(l->op == OBIT) + goto bitinc; + + pre: + if(hardleft) + reglcgen(&nod, l, Z); + else + nod = *l; + if(typefd[n->type->etype]) + goto fltinc; + gopcode(OADD, n->type, nodconst(v), &nod); + if(nn != Z) + gmove(&nod, nn); + if(hardleft) + regfree(&nod); + break; + + fltinc: + gmove(&nod, &fregnode0); + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) + gins(AFMOVD, &fregnode0, &fregnode0); + gins(AFLD1, Z, Z); + if(v < 0) + fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0); + else + fgopcode(OADD, &fregnode0, &fregnode1, 1, 0); + if(nn != Z && (o == OPREINC || o == OPREDEC)) + gins(AFMOVD, &fregnode0, &fregnode0); + gmove(&fregnode0, &nod); + if(hardleft) + regfree(&nod); + break; + + bitinc: + if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { + bitload(l, &nod, &nod1, &nod2, Z); + gmove(&nod, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, Z); + break; + } + bitload(l, &nod, &nod1, &nod2, nn); + gopcode(OADD, tfield, nodconst(v), &nod); + bitstore(l, &nod, &nod1, &nod2, nn); + break; + } +done: + cursafe = curs; +} + +void +reglcgen(Node *t, Node *n, Node *nn) +{ + Node *r; + long v; + + regialloc(t, n, nn); + if(n->op == OIND) { + r = n->left; + while(r->op == OADD) + r = r->right; + if(sconst(r)) { + v = r->vconst; + r->vconst = 0; + lcgen(n, t); + t->xoffset += v; + r->vconst = v; + regind(t, n); + return; + } + } + lcgen(n, t); + regind(t, n); +} + +void +lcgen(Node *n, Node *nn) +{ + Prog *p1; + Node nod; + + if(debug['g']) { + prtree(nn, "lcgen lhs"); + prtree(n, "lcgen"); + } + if(n == Z || n->type == T) + return; + if(nn == Z) { + nn = &nod; + regalloc(&nod, n, Z); + } + switch(n->op) { + default: + if(n->addable < INDEXED) { + diag(n, "unknown op in lcgen: %O", n->op); + break; + } + gopcode(OADDR, n->type, n, nn); + break; + + case OCOMMA: + cgen(n->left, n->left); + lcgen(n->right, nn); + break; + + case OIND: + cgen(n->left, nn); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + lcgen(n->right->left, nn); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + lcgen(n->right->right, nn); + patch(p1, pc); + break; + } +} + +void +bcgen(Node *n, int true) +{ + + if(n->type == T) + gbranch(OGOTO); + else + boolgen(n, true, Z); +} + +void +boolgen(Node *n, int true, Node *nn) +{ + int o; + Prog *p1, *p2; + Node *l, *r, nod, nod1; + long curs; + + if(debug['g']) { + prtree(nn, "boolgen lhs"); + prtree(n, "boolgen"); + } + curs = cursafe; + l = n->left; + r = n->right; + switch(n->op) { + + default: + if(typev[n->type->etype]) { + testv(n, true); + goto com; + } + o = ONE; + if(true) + o = OEQ; + if(typefd[n->type->etype]) { + if(n->addable < INDEXED) { + cgen(n, &fregnode0); + gins(AFLDZ, Z, Z); + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + } else { + gins(AFLDZ, Z, Z); + fgopcode(o, n, &fregnode0, 0, 1); + } + goto com; + } + /* bad, 13 is address of external that becomes constant */ + if(n->addable >= INDEXED && n->addable != 13) { + gopcode(o, n->type, n, nodconst(0)); + goto com; + } + regalloc(&nod, n, nn); + cgen(n, &nod); + gopcode(o, n->type, &nod, nodconst(0)); + regfree(&nod); + goto com; + + case OCONST: + o = vconst(n); + if(!true) + o = !o; + gbranch(OGOTO); + if(o) { + p1 = p; + gbranch(OGOTO); + patch(p1, pc); + } + goto com; + + case OCOMMA: + cgen(l, Z); + boolgen(r, true, nn); + break; + + case ONOT: + boolgen(l, !true, nn); + break; + + case OCOND: + bcgen(l, 1); + p1 = p; + bcgen(r->left, true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + bcgen(r->right, !true); + patch(p2, pc); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OANDAND: + if(!true) + goto caseor; + + caseand: + bcgen(l, true); + p1 = p; + bcgen(r, !true); + p2 = p; + patch(p1, pc); + gbranch(OGOTO); + patch(p2, pc); + goto com; + + case OOROR: + if(!true) + goto caseand; + + caseor: + bcgen(l, !true); + p1 = p; + bcgen(r, !true); + p2 = p; + gbranch(OGOTO); + patch(p1, pc); + patch(p2, pc); + goto com; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + o = n->op; + if(typev[l->type->etype]) { + if(!true) + n->op = comrel[relindex(o)]; + cgen64(n, Z); + goto com; + } + if(true) + o = comrel[relindex(o)]; + if(l->complex >= FNX && r->complex >= FNX) { + regret(&nod, r); + cgen(r, &nod); + regsalloc(&nod1, r); + gmove(&nod, &nod1); + regfree(&nod); + nod = *n; + nod.right = &nod1; + boolgen(&nod, true, nn); + break; + } + if(typefd[l->type->etype]) { + if(l->complex >= r->complex) { + cgen(l, &fregnode0); + if(r->addable < INDEXED) { + cgen(r, &fregnode0); + o = invrel[relindex(o)]; + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + } else + fgopcode(o, r, &fregnode0, 0, 1); + } else { + o = invrel[relindex(o)]; + cgen(r, &fregnode0); + if(l->addable < INDEXED) { + cgen(l, &fregnode0); + o = invrel[relindex(o)]; + fgopcode(o, &fregnode0, &fregnode1, 1, 1); + } else + fgopcode(o, l, &fregnode0, 0, 1); + } + goto com; + } + if(l->op == OCONST) { + o = invrel[relindex(o)]; + /* bad, 13 is address of external that becomes constant */ + if(r->addable < INDEXED || r->addable == 13) { + regalloc(&nod, r, nn); + cgen(r, &nod); + gopcode(o, l->type, &nod, l); + regfree(&nod); + } else + gopcode(o, l->type, r, l); + goto com; + } + if(l->complex >= r->complex) { + regalloc(&nod, l, nn); + cgen(l, &nod); + if(r->addable < INDEXED) { + regalloc(&nod1, r, Z); + cgen(r, &nod1); + gopcode(o, l->type, &nod, &nod1); + regfree(&nod1); + } else + gopcode(o, l->type, &nod, r); + regfree(&nod); + goto com; + } + regalloc(&nod, r, nn); + cgen(r, &nod); + if(l->addable < INDEXED || l->addable == 13) { + regalloc(&nod1, l, Z); + cgen(l, &nod1); + if(typechlp[l->type->etype]) + gopcode(o, types[TINT], &nod1, &nod); + else + gopcode(o, l->type, &nod1, &nod); + regfree(&nod1); + } else + gopcode(o, l->type, l, &nod); + regfree(&nod); + + com: + if(nn != Z) { + p1 = p; + gmove(nodconst(1L), nn); + gbranch(OGOTO); + p2 = p; + patch(p1, pc); + gmove(nodconst(0L), nn); + patch(p2, pc); + } + break; + } + cursafe = curs; +} + +void +sugen(Node *n, Node *nn, long w) +{ + Prog *p1; + Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r; + Type *t; + int c, v, x; + + if(n == Z || n->type == T) + return; + if(debug['g']) { + prtree(nn, "sugen lhs"); + prtree(n, "sugen"); + } + if(nn == nodrat) + if(w > nrathole) + nrathole = w; + switch(n->op) { + case OIND: + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + default: + goto copy; + + case OCONST: + if(n->type && typev[n->type->etype]) { + if(nn == Z) { + nullwarn(n->left, Z); + break; + } + + if(nn->op == OREGPAIR) { + loadpair(n, nn); + break; + } + else if(!vaddr(nn, 0)) { + t = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod1, nn, Z); + nn->type = t; + + gmove(lo64(n), &nod1); + nod1.xoffset += SZ_LONG; + gmove(hi64(n), &nod1); + regfree(&nod1); + } + else { + gins(AMOVL, lo64(n), nn); + nn->xoffset += SZ_LONG; + gins(AMOVL, hi64(n), nn); + nn->xoffset -= SZ_LONG; + break; + } + break; + } + goto copy; + + case ODOT: + l = n->left; + sugen(l, nodrat, l->type->width); + if(nn == Z) + break; + warn(n, "non-interruptable temporary"); + nod1 = *nodrat; + r = n->right; + if(!r || r->op != OCONST) { + diag(n, "DOT and no offset"); + break; + } + nod1.xoffset += (long)r->vconst; + nod1.type = n->type; + sugen(&nod1, nn, w); + break; + + case OSTRUCT: + /* + * rewrite so lhs has no fn call + */ + if(nn != Z && side(nn)) { + nod1 = *n; + nod1.type = typ(TIND, n->type); + regret(&nod2, &nod1); + lcgen(nn, &nod2); + regsalloc(&nod0, &nod1); + cgen(&nod2, &nod0); + regfree(&nod2); + + nod1 = *n; + nod1.op = OIND; + nod1.left = &nod0; + nod1.right = Z; + nod1.complex = 1; + + sugen(n, &nod1, w); + return; + } + + r = n->left; + for(t = n->type->link; t != T; t = t->down) { + l = r; + if(r->op == OLIST) { + l = r->left; + r = r->right; + } + if(nn == Z) { + cgen(l, nn); + continue; + } + /* + * hand craft *(&nn + o) = l + */ + nod0 = znode; + nod0.op = OAS; + nod0.type = t; + nod0.left = &nod1; + nod0.right = nil; + + nod1 = znode; + nod1.op = OIND; + nod1.type = t; + nod1.left = &nod2; + + nod2 = znode; + nod2.op = OADD; + nod2.type = typ(TIND, t); + nod2.left = &nod3; + nod2.right = &nod4; + + nod3 = znode; + nod3.op = OADDR; + nod3.type = nod2.type; + nod3.left = nn; + + nod4 = znode; + nod4.op = OCONST; + nod4.type = nod2.type; + nod4.vconst = t->offset; + + ccom(&nod0); + acom(&nod0); + xcom(&nod0); + nod0.addable = 0; + nod0.right = l; + + /* prtree(&nod0, "hand craft"); /* */ + cgen(&nod0, Z); + } + break; + + case OAS: + if(nn == Z) { + if(n->addable < INDEXED) + sugen(n->right, n->left, w); + break; + } + + sugen(n->right, nodrat, w); + warn(n, "non-interruptable temporary"); + sugen(nodrat, n->left, w); + sugen(nodrat, nn, w); + break; + + case OFUNC: + if(nn == Z) { + sugen(n, nodrat, w); + break; + } + h = nn; + if(nn->op == OREGPAIR) { + regsalloc(&nod1, nn); + nn = &nod1; + } + if(nn->op != OIND) { + nn = new1(OADDR, nn, Z); + nn->type = types[TIND]; + nn->addable = 0; + } else + nn = nn->left; + n = new(OFUNC, n->left, new(OLIST, nn, n->right)); + n->type = types[TVOID]; + n->left->type = types[TVOID]; + cgen(n, Z); + if(h->op == OREGPAIR) + loadpair(nn->left, h); + break; + + case OCOND: + bcgen(n->left, 1); + p1 = p; + sugen(n->right->left, nn, w); + gbranch(OGOTO); + patch(p1, pc); + p1 = p; + sugen(n->right->right, nn, w); + patch(p1, pc); + break; + + case OCOMMA: + cgen(n->left, Z); + sugen(n->right, nn, w); + break; + } + return; + +copy: + if(nn == Z) { + switch(n->op) { + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + + case OASMUL: + case OASLMUL: + + + case OASASHL: + case OASASHR: + case OASLSHR: + break; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + break; + + default: + return; + } + } + + if(n->complex >= FNX && nn != nil && nn->complex >= FNX) { + t = nn->type; + nn->type = types[TLONG]; + regialloc(&nod1, nn, Z); + lcgen(nn, &nod1); + regsalloc(&nod2, nn); + nn->type = t; + + gins(AMOVL, &nod1, &nod2); + regfree(&nod1); + + nod2.type = typ(TIND, t); + + nod1 = nod2; + nod1.op = OIND; + nod1.left = &nod2; + nod1.right = Z; + nod1.complex = 1; + nod1.type = t; + + sugen(n, &nod1, w); + return; + } + + x = 0; + v = w == 8; + if(v) { + c = cursafe; + if(n->left != Z && n->left->complex >= FNX + && n->right != Z && n->right->complex >= FNX) { +// warn(n, "toughie"); + regsalloc(&nod1, n->right); + cgen(n->right, &nod1); + nod2 = *n; + nod2.right = &nod1; + cgen(&nod2, nn); + cursafe = c; + return; + } + if(cgen64(n, nn)) { + cursafe = c; + return; + } + if(n->op == OCOM) { + n = n->left; + x = 1; + } + } + + /* botch, need to save in .safe */ + c = 0; + if(n->complex > nn->complex) { + t = n->type; + n->type = types[TLONG]; + if(v) { + regalloc(&nod0, n, Z); + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + } + else { + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHL, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + } + + t = nn->type; + nn->type = types[TLONG]; + if(v) { + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + } + else { + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { + gins(APUSHL, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + } + } else { + t = nn->type; + nn->type = types[TLONG]; + if(v) { + regalloc(&nod0, nn, Z); + if(!vaddr(nn, 0)) { + reglcgen(&nod2, nn, Z); + nn->type = t; + nn = &nod2; + } + else + nn->type = t; + } + else { + nodreg(&nod2, nn, D_DI); + if(reg[D_DI]) { + gins(APUSHL, &nod2, Z); + c |= 2; + reg[D_DI]++; + } + lcgen(nn, &nod2); + nn->type = t; + } + + t = n->type; + n->type = types[TLONG]; + if(v) { + if(!vaddr(n, 0)) { + reglcgen(&nod1, n, Z); + n->type = t; + n = &nod1; + } + else + n->type = t; + } + else { + nodreg(&nod1, n, D_SI); + if(reg[D_SI]) { + gins(APUSHL, &nod1, Z); + c |= 1; + reg[D_SI]++; + } + lcgen(n, &nod1); + n->type = t; + } + } + if(v) { + gins(AMOVL, n, &nod0); + if(x) + gins(ANOTL, Z, &nod0); + gins(AMOVL, &nod0, nn); + n->xoffset += SZ_LONG; + nn->xoffset += SZ_LONG; + gins(AMOVL, n, &nod0); + if(x) + gins(ANOTL, Z, &nod0); + gins(AMOVL, &nod0, nn); + n->xoffset -= SZ_LONG; + nn->xoffset -= SZ_LONG; + if(nn == &nod2) + regfree(&nod2); + if(n == &nod1) + regfree(&nod1); + regfree(&nod0); + return; + } + nodreg(&nod3, n, D_CX); + if(reg[D_CX]) { + gins(APUSHL, &nod3, Z); + c |= 4; + reg[D_CX]++; + } + gins(AMOVL, nodconst(w/SZ_LONG), &nod3); + gins(ACLD, Z, Z); + gins(AREP, Z, Z); + gins(AMOVSL, Z, Z); + if(c & 4) { + gins(APOPL, Z, &nod3); + reg[D_CX]--; + } + if(c & 2) { + gins(APOPL, Z, &nod2); + reg[nod2.reg]--; + } + if(c & 1) { + gins(APOPL, Z, &nod1); + reg[nod1.reg]--; + } +} diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c new file mode 100644 index 000000000..75f87f91e --- /dev/null +++ b/src/cmd/8c/cgen64.c @@ -0,0 +1,2741 @@ +// Inferno utils/8c/cgen64.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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 +zeroregm(Node *n) +{ + gins(AMOVL, nodconst(0), n); +} + +/* do we need to load the address of a vlong? */ +int +vaddr(Node *n, int a) +{ + switch(n->op) { + case ONAME: + if(a) + return 1; + return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC); + + case OCONST: + case OREGISTER: + case OINDREG: + return 1; + } + return 0; +} + +long +hi64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)(n->vconst) & ~0L; + else + return (long)((uvlong)n->vconst>>32) & ~0L; +} + +long +lo64v(Node *n) +{ + if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ + return (long)((uvlong)n->vconst>>32) & ~0L; + else + return (long)(n->vconst) & ~0L; +} + +Node * +hi64(Node *n) +{ + return nodconst(hi64v(n)); +} + +Node * +lo64(Node *n) +{ + return nodconst(lo64v(n)); +} + +static Node * +anonreg(void) +{ + Node *n; + + n = new(OREGISTER, Z, Z); + n->reg = D_NONE; + n->type = types[TLONG]; + return n; +} + +static Node * +regpair(Node *n, Node *t) +{ + Node *r; + + if(n != Z && n->op == OREGPAIR) + return n; + r = new(OREGPAIR, anonreg(), anonreg()); + if(n != Z) + r->type = n->type; + else + r->type = t->type; + return r; +} + +static void +evacaxdx(Node *r) +{ + Node nod1, nod2; + + if(r->reg == D_AX || r->reg == D_DX) { + reg[D_AX]++; + reg[D_DX]++; + /* + * this is just an optim that should + * check for spill + */ + r->type = types[TULONG]; + regalloc(&nod1, r, Z); + nodreg(&nod2, Z, r->reg); + gins(AMOVL, &nod2, &nod1); + regfree(r); + r->reg = nod1.reg; + reg[D_AX]--; + reg[D_DX]--; + } +} + +/* lazy instantiation of register pair */ +static int +instpair(Node *n, Node *l) +{ + int r; + + r = 0; + if(n->left->reg == D_NONE) { + if(l != Z) { + n->left->reg = l->reg; + r = 1; + } + else + regalloc(n->left, n->left, Z); + } + if(n->right->reg == D_NONE) + regalloc(n->right, n->right, Z); + return r; +} + +static void +zapreg(Node *n) +{ + if(n->reg != D_NONE) { + regfree(n); + n->reg = D_NONE; + } +} + +static void +freepair(Node *n) +{ + regfree(n->left); + regfree(n->right); +} + +/* n is not OREGPAIR, nn is */ +void +loadpair(Node *n, Node *nn) +{ + Node nod; + + instpair(nn, Z); + if(n->op == OCONST) { + gins(AMOVL, lo64(n), nn->left); + n->xoffset += SZ_LONG; + gins(AMOVL, hi64(n), nn->right); + n->xoffset -= SZ_LONG; + return; + } + if(!vaddr(n, 0)) { + /* steal the right register for the laddr */ + nod = regnode; + nod.reg = nn->right->reg; + lcgen(n, &nod); + n = &nod; + regind(n, n); + n->xoffset = 0; + } + gins(AMOVL, n, nn->left); + n->xoffset += SZ_LONG; + gins(AMOVL, n, nn->right); + n->xoffset -= SZ_LONG; +} + +/* n is OREGPAIR, nn is not */ +static void +storepair(Node *n, Node *nn, int f) +{ + Node nod; + + if(!vaddr(nn, 0)) { + reglcgen(&nod, nn, Z); + nn = &nod; + } + gins(AMOVL, n->left, nn); + nn->xoffset += SZ_LONG; + gins(AMOVL, n->right, nn); + nn->xoffset -= SZ_LONG; + if(nn == &nod) + regfree(&nod); + if(f) + freepair(n); +} + +/* generate a cast t from n to tt */ +static void +cast(Node *n, Type *t, Node *nn) +{ + Node *r; + + r = new(OCAST, n, Z); + r->type = t; + sugen(r, nn, 8); +} + +static void +swapregs(Node *a, Node *b) +{ + int t; + + t = a->reg; + a->reg = b->reg; + b->reg = t; +} + +static void +swappairs(Node *a, Node *b) +{ + swapregs(a->left, b->left); + swapregs(a->right, b->right); +} + +static int +saveme(Node *n) +{ + int r; + + r = n->reg; + return r >= D_AX && r <= D_DI; +} + +static void +saveit(Node *n, Node *t, Node *r) +{ + Node nod; + + if(saveme(n)) { + t->reg = n->reg; + gins(AMOVL, t, r); + r->xoffset += SZ_LONG; + if(n->reg == D_AX) { + regalloc(&nod, n, Z); + regfree(n); + n->reg = nod.reg; + } + } +} + +static void +restoreit(Node *n, Node *t, Node *r) +{ + if(saveme(n)) { + t->reg = n->reg; + gins(AMOVL, r, t); + r->xoffset += SZ_LONG; + } +} + +enum +{ +/* 4 only, see WW */ + WNONE = 0, + WCONST, + WADDR, + WHARD, +}; + +static int +whatof(Node *n, int a) +{ + if(n->op == OCONST) + return WCONST; + return !vaddr(n, a) ? WHARD : WADDR; +} + +/* can upgrade an extern to addr for AND */ +static int +reduxv(Node *n) +{ + return lo64v(n) == 0 || hi64v(n) == 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; +} + +/* + * for a func operand call it and then return + * the safe node + */ +static Node * +vfunc(Node *n, Node *nn) +{ + Node *t; + + if(n->op != OFUNC) + return n; + t = new(0, Z, Z); + if(nn == Z || nn == nodret) + nn = n; + regsalloc(t, nn); + sugen(n, t, 8); + return t; +} + +static int +forcereg(Node *d, int r, int o, Node *t) +{ + int a; + + if(d->reg != D_NONE) + diag(Z, "force alloc"); + d->reg = r; + a = 0; + if(reg[r]) { + reg[o]++; + regalloc(t, d, Z); + a = 1; + gins(AMOVL, d, t); + reg[o]--; + } + reg[r]++; + return a; +} + +/* try to steal a reg */ +static int +getreg(Node **np, Node *t, int r) +{ + Node *n, *p; + + n = *np; + if(n->reg == r) { + p = new(0, Z, Z); + regalloc(p, n, Z); + gins(AMOVL, n, p); + *t = *n; + *np = p; + return 1; + } + return 0; +} + +static Node * +snarfreg(Node *n, Node *t, int r, Node *d, Node *c) +{ + if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) { + if(nodreg(t, Z, r)) { + regalloc(c, d, Z); + gins(AMOVL, t, c); + reg[r]++; + return c; + } + reg[r]++; + } + return Z; +} + +enum +{ + Vstart = OEND, + + Vgo, + Vamv, + Vmv, + Vzero, + Vop, + Vopx, + Vins, + Vins0, + Vinsl, + Vinsr, + Vinsla, + Vinsra, + Vinsx, + Vmul, + Vshll, + VT, + VF, + V_l_lo_f, + V_l_hi_f, + V_l_lo_t, + V_l_hi_t, + V_l_lo_u, + V_l_hi_u, + V_r_lo_f, + V_r_hi_f, + V_r_lo_t, + V_r_hi_t, + V_r_lo_u, + V_r_hi_u, + Vspazz, + Vend, + + V_T0, + V_T1, + V_F0, + V_F1, + + V_a0, + V_a1, + V_f0, + V_f1, + + V_p0, + V_p1, + V_p2, + V_p3, + V_p4, + + V_s0, + V_s1, + V_s2, + V_s3, + V_s4, + + C00, + C01, + C31, + C32, + + O_l_lo, + O_l_hi, + O_r_lo, + O_r_hi, + O_t_lo, + O_t_hi, + O_l, + O_r, + O_l_rp, + O_r_rp, + O_t_rp, + O_r0, + O_r1, + O_Zop, + + O_a0, + O_a1, + + V_C0, + V_C1, + + V_S0, + V_S1, + + VOPS = 5, + VLEN = 5, + VARGS = 2, + + S00 = 0, + Sc0, + Sc1, + Sc2, + Sac3, + Sac4, + S10, + + SAgen = 0, + SAclo, + SAc32, + SAchi, + SAdgen, + SAdclo, + SAdc32, + SAdchi, + + B0c = 0, + Bca, + Bac, + + T0i = 0, + Tii, + + Bop0 = 0, + Bop1, +}; + +/* + * _testv: + * CMPL lo,$0 + * JNE true + * CMPL hi,$0 + * JNE true + * GOTO false + * false: + * GOTO code + * true: + * GOTO patchme + * code: + */ + +static uchar testi[][VLEN] = +{ + {Vop, ONE, O_l_lo, C00}, + {V_s0, Vop, ONE, O_l_hi, C00}, + {V_s1, Vgo, V_s2, Vgo, V_s3}, + {VF, V_p0, V_p1, VT, V_p2}, + {Vgo, V_p3}, + {VT, V_p0, V_p1, VF, V_p2}, + {Vend}, +}; + +/* shift left general case */ +static uchar shll00[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vinsl, ASHLL, O_r, O_l_rp}, + {Vins, ASHLL, O_r, O_l_lo, Vgo}, + {V_p0, V_s0}, + {Vins, ASHLL, O_r, O_l_lo}, + {Vins, AMOVL, O_l_lo, O_l_hi}, + {Vzero, O_l_lo, V_p0, Vend}, +}; + +/* shift left rp, const < 32 */ +static uchar shllc0[][VLEN] = +{ + {Vinsl, ASHLL, O_r, O_l_rp}, + {Vshll, O_r, O_l_lo, Vend}, +}; + +/* shift left rp, const == 32 */ +static uchar shllc1[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_l_hi}, + {Vzero, O_l_lo, Vend}, +}; + +/* shift left rp, const > 32 */ +static uchar shllc2[][VLEN] = +{ + {Vshll, O_r, O_l_lo}, + {Vins, AMOVL, O_l_lo, O_l_hi}, + {Vzero, O_l_lo, Vend}, +}; + +/* shift left addr, const == 32 */ +static uchar shllac3[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_hi}, + {Vzero, O_t_lo, Vend}, +}; + +/* shift left addr, const > 32 */ +static uchar shllac4[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_hi}, + {Vshll, O_r, O_t_hi}, + {Vzero, O_t_lo, Vend}, +}; + +/* shift left of constant */ +static uchar shll10[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsl, ASHLL, O_r, O_t_rp}, + {Vins, ASHLL, O_r, O_t_lo, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_lo, O_t_hi}, + {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi}, + {Vzero, O_t_lo, V_p0, Vend}, +}; + +static uchar (*shlltab[])[VLEN] = +{ + shll00, + shllc0, + shllc1, + shllc2, + shllac3, + shllac4, + shll10, +}; + +/* shift right general case */ +static uchar shrl00[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vinsr, ASHRL, O_r, O_l_rp}, + {Vins, O_a0, O_r, O_l_hi, Vgo}, + {V_p0, V_s0}, + {Vins, O_a0, O_r, O_l_hi}, + {Vins, AMOVL, O_l_hi, O_l_lo}, + {V_T1, Vzero, O_l_hi}, + {V_F1, Vins, ASARL, C31, O_l_hi}, + {V_p0, Vend}, +}; + +/* shift right rp, const < 32 */ +static uchar shrlc0[][VLEN] = +{ + {Vinsr, ASHRL, O_r, O_l_rp}, + {Vins, O_a0, O_r, O_l_hi, Vend}, +}; + +/* shift right rp, const == 32 */ +static uchar shrlc1[][VLEN] = +{ + {Vins, AMOVL, O_l_hi, O_l_lo}, + {V_T1, Vzero, O_l_hi}, + {V_F1, Vins, ASARL, C31, O_l_hi}, + {Vend}, +}; + +/* shift right rp, const > 32 */ +static uchar shrlc2[][VLEN] = +{ + {Vins, O_a0, O_r, O_l_hi}, + {Vins, AMOVL, O_l_hi, O_l_lo}, + {V_T1, Vzero, O_l_hi}, + {V_F1, Vins, ASARL, C31, O_l_hi}, + {Vend}, +}; + +/* shift right addr, const == 32 */ +static uchar shrlac3[][VLEN] = +{ + {Vins, AMOVL, O_l_hi, O_t_lo}, + {V_T1, Vzero, O_t_hi}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {Vend}, +}; + +/* shift right addr, const > 32 */ +static uchar shrlac4[][VLEN] = +{ + {Vins, AMOVL, O_l_hi, O_t_lo}, + {Vins, O_a0, O_r, O_t_lo}, + {V_T1, Vzero, O_t_hi}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {Vend}, +}; + +/* shift right of constant */ +static uchar shrl10[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsr, ASHRL, O_r, O_t_rp}, + {Vins, O_a0, O_r, O_t_hi, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_hi, O_t_lo}, + {V_l_hi_t, Vins, O_a0, O_r, O_t_lo}, + {V_l_hi_u, V_S1}, + {V_T1, Vzero, O_t_hi, V_p0}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {Vend}, +}; + +static uchar (*shrltab[])[VLEN] = +{ + shrl00, + shrlc0, + shrlc1, + shrlc2, + shrlac3, + shrlac4, + shrl10, +}; + +/* shift asop left general case */ +static uchar asshllgen[][VLEN] = +{ + {V_a0, V_a1}, + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_r0}, + {Vins, AMOVL, O_l_hi, O_r1}, + {Vinsla, ASHLL, O_r, O_r0}, + {Vins, ASHLL, O_r, O_r0}, + {Vins, AMOVL, O_r1, O_l_hi}, + {Vins, AMOVL, O_r0, O_l_lo, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vzero, O_l_lo}, + {Vins, ASHLL, O_r, O_r0}, + {Vins, AMOVL, O_r0, O_l_hi, V_p0}, + {V_f0, V_f1, Vend}, +}; + +/* shift asop left, const < 32 */ +static uchar asshllclo[][VLEN] = +{ + {V_a0, V_a1}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vins, AMOVL, O_l_hi, O_r1}, + {Vinsla, ASHLL, O_r, O_r0}, + {Vshll, O_r, O_r0}, + {Vins, AMOVL, O_r1, O_l_hi}, + {Vins, AMOVL, O_r0, O_l_lo}, + {V_f0, V_f1, Vend}, +}; + +/* shift asop left, const == 32 */ +static uchar asshllc32[][VLEN] = +{ + {V_a0}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vzero, O_l_lo}, + {Vins, AMOVL, O_r0, O_l_hi}, + {V_f0, Vend}, +}; + +/* shift asop left, const > 32 */ +static uchar asshllchi[][VLEN] = +{ + {V_a0}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vzero, O_l_lo}, + {Vshll, O_r, O_r0}, + {Vins, AMOVL, O_r0, O_l_hi}, + {V_f0, Vend}, +}; + +/* shift asop dest left general case */ +static uchar asdshllgen[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsl, ASHLL, O_r, O_t_rp}, + {Vins, ASHLL, O_r, O_t_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_lo, O_t_hi}, + {Vzero, O_l_lo}, + {Vins, ASHLL, O_r, O_t_hi}, + {Vzero, O_t_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi, V_p0}, + {Vend}, +}; + +/* shift asop dest left, const < 32 */ +static uchar asdshllclo[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsl, ASHLL, O_r, O_t_rp}, + {Vshll, O_r, O_t_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vend}, +}; + +/* shift asop dest left, const == 32 */ +static uchar asdshllc32[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_hi}, + {Vzero, O_t_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vend}, +}; + +/* shift asop dest, const > 32 */ +static uchar asdshllchi[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_hi}, + {Vzero, O_t_lo}, + {Vshll, O_r, O_t_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vend}, +}; + +static uchar (*asshlltab[])[VLEN] = +{ + asshllgen, + asshllclo, + asshllc32, + asshllchi, + asdshllgen, + asdshllclo, + asdshllc32, + asdshllchi, +}; + +/* shift asop right general case */ +static uchar asshrlgen[][VLEN] = +{ + {V_a0, V_a1}, + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_r0}, + {Vins, AMOVL, O_l_hi, O_r1}, + {Vinsra, ASHRL, O_r, O_r0}, + {Vinsx, Bop0, O_r, O_r1}, + {Vins, AMOVL, O_r0, O_l_lo}, + {Vins, AMOVL, O_r1, O_l_hi, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_hi, O_r0}, + {Vinsx, Bop0, O_r, O_r0}, + {V_T1, Vzero, O_l_hi}, + {Vins, AMOVL, O_r0, O_l_lo}, + {V_F1, Vins, ASARL, C31, O_r0}, + {V_F1, Vins, AMOVL, O_r0, O_l_hi}, + {V_p0, V_f0, V_f1, Vend}, +}; + +/* shift asop right, const < 32 */ +static uchar asshrlclo[][VLEN] = +{ + {V_a0, V_a1}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vins, AMOVL, O_l_hi, O_r1}, + {Vinsra, ASHRL, O_r, O_r0}, + {Vinsx, Bop0, O_r, O_r1}, + {Vins, AMOVL, O_r0, O_l_lo}, + {Vins, AMOVL, O_r1, O_l_hi}, + {V_f0, V_f1, Vend}, +}; + +/* shift asop right, const == 32 */ +static uchar asshrlc32[][VLEN] = +{ + {V_a0}, + {Vins, AMOVL, O_l_hi, O_r0}, + {V_T1, Vzero, O_l_hi}, + {Vins, AMOVL, O_r0, O_l_lo}, + {V_F1, Vins, ASARL, C31, O_r0}, + {V_F1, Vins, AMOVL, O_r0, O_l_hi}, + {V_f0, Vend}, +}; + +/* shift asop right, const > 32 */ +static uchar asshrlchi[][VLEN] = +{ + {V_a0}, + {Vins, AMOVL, O_l_hi, O_r0}, + {V_T1, Vzero, O_l_hi}, + {Vinsx, Bop0, O_r, O_r0}, + {Vins, AMOVL, O_r0, O_l_lo}, + {V_F1, Vins, ASARL, C31, O_r0}, + {V_F1, Vins, AMOVL, O_r0, O_l_hi}, + {V_f0, Vend}, +}; + +/* shift asop dest right general case */ +static uchar asdshrlgen[][VLEN] = +{ + {Vop, OGE, O_r, C32}, + {V_s0, Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsr, ASHRL, O_r, O_t_rp}, + {Vinsx, Bop0, O_r, O_t_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi, Vgo}, + {V_p0, V_s0}, + {Vins, AMOVL, O_l_hi, O_t_lo}, + {V_T1, Vzero, O_t_hi}, + {Vinsx, Bop0, O_r, O_t_lo}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {Vins, AMOVL, O_t_hi, O_l_hi, V_p0}, + {Vend}, +}; + +/* shift asop dest right, const < 32 */ +static uchar asdshrlclo[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsr, ASHRL, O_r, O_t_rp}, + {Vinsx, Bop0, O_r, O_t_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vend}, +}; + +/* shift asop dest right, const == 32 */ +static uchar asdshrlc32[][VLEN] = +{ + {Vins, AMOVL, O_l_hi, O_t_lo}, + {V_T1, Vzero, O_t_hi}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi}, + {Vend}, +}; + +/* shift asop dest, const > 32 */ +static uchar asdshrlchi[][VLEN] = +{ + {Vins, AMOVL, O_l_hi, O_t_lo}, + {V_T1, Vzero, O_t_hi}, + {Vinsx, Bop0, O_r, O_t_lo}, + {V_T1, Vins, AMOVL, O_t_hi, O_l_hi}, + {V_T1, Vins, AMOVL, O_t_lo, O_l_lo}, + {V_F1, Vins, AMOVL, O_t_lo, O_t_hi}, + {V_F1, Vins, ASARL, C31, O_t_hi}, + {V_F1, Vins, AMOVL, O_t_lo, O_l_lo}, + {V_F1, Vins, AMOVL, O_t_hi, O_l_hi}, + {Vend}, +}; + +static uchar (*asshrltab[])[VLEN] = +{ + asshrlgen, + asshrlclo, + asshrlc32, + asshrlchi, + asdshrlgen, + asdshrlclo, + asdshrlc32, + asdshrlchi, +}; + +static uchar shrlargs[] = { ASHRL, 1 }; +static uchar sarlargs[] = { ASARL, 0 }; + +/* ++ -- */ +static uchar incdec[][VLEN] = +{ + {Vinsx, Bop0, C01, O_l_lo}, + {Vinsx, Bop1, C00, O_l_hi, Vend}, +}; + +/* ++ -- *p */ +static uchar incdecpre[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsx, Bop0, C01, O_t_lo}, + {Vinsx, Bop1, C00, O_t_hi}, + {Vins, AMOVL, O_t_lo, O_l_lo}, + {Vins, AMOVL, O_t_hi, O_l_hi, Vend}, +}; + +/* *p ++ -- */ +static uchar incdecpost[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsx, Bop0, C01, O_l_lo}, + {Vinsx, Bop1, C00, O_l_hi, Vend}, +}; + +/* binop rp, rp */ +static uchar binop00[][VLEN] = +{ + {Vinsx, Bop0, O_r_lo, O_l_lo}, + {Vinsx, Bop1, O_r_hi, O_l_hi, Vend}, + {Vend}, +}; + +/* binop rp, addr */ +static uchar binoptmp[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_r_lo, O_r0}, + {Vinsx, Bop0, O_r0, O_l_lo}, + {Vins, AMOVL, O_r_hi, O_r0}, + {Vinsx, Bop1, O_r0, O_l_hi}, + {V_f0, Vend}, +}; + +/* binop t = *a op *b */ +static uchar binop11[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vinsx, Bop0, O_r_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsx, Bop1, O_r_hi, O_t_hi, Vend}, +}; + +/* binop t = rp +- c */ +static uchar add0c[][VLEN] = +{ + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, + {V_r_lo_f, Vamv, Bop0, Bop1}, + {Vinsx, Bop1, O_r_hi, O_l_hi}, + {Vend}, +}; + +/* binop t = rp & c */ +static uchar and0c[][VLEN] = +{ + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, + {V_r_lo_f, Vins, AMOVL, C00, O_l_lo}, + {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi}, + {V_r_hi_f, Vins, AMOVL, C00, O_l_hi}, + {Vend}, +}; + +/* binop t = rp | c */ +static uchar or0c[][VLEN] = +{ + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo}, + {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi}, + {Vend}, +}; + +/* binop t = c - rp */ +static uchar sub10[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_l_lo, O_r0}, + {Vinsx, Bop0, O_r_lo, O_r0}, + {Vins, AMOVL, O_l_hi, O_r_lo}, + {Vinsx, Bop1, O_r_hi, O_r_lo}, + {Vspazz, V_f0, Vend}, +}; + +/* binop t = c + *b */ +static uchar addca[][VLEN] = +{ + {Vins, AMOVL, O_r_lo, O_t_lo}, + {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, + {V_l_lo_f, Vamv, Bop0, Bop1}, + {Vins, AMOVL, O_r_hi, O_t_hi}, + {Vinsx, Bop1, O_l_hi, O_t_hi}, + {Vend}, +}; + +/* binop t = c & *b */ +static uchar andca[][VLEN] = +{ + {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo}, + {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, + {V_l_lo_f, Vzero, O_t_lo}, + {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi}, + {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi}, + {V_l_hi_f, Vzero, O_t_hi}, + {Vend}, +}; + +/* binop t = c | *b */ +static uchar orca[][VLEN] = +{ + {Vins, AMOVL, O_r_lo, O_t_lo}, + {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_r_hi, O_t_hi}, + {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi}, + {Vend}, +}; + +/* binop t = c - *b */ +static uchar subca[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsx, Bop0, O_r_lo, O_t_lo}, + {Vinsx, Bop1, O_r_hi, O_t_hi}, + {Vend}, +}; + +/* binop t = *a +- c */ +static uchar addac[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, + {V_r_lo_f, Vamv, Bop0, Bop1}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {Vinsx, Bop1, O_r_hi, O_t_hi}, + {Vend}, +}; + +/* binop t = *a | c */ +static uchar orac[][VLEN] = +{ + {Vins, AMOVL, O_l_lo, O_t_lo}, + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, + {Vins, AMOVL, O_l_hi, O_t_hi}, + {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi}, + {Vend}, +}; + +/* binop t = *a & c */ +static uchar andac[][VLEN] = +{ + {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo}, + {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo}, + {V_r_lo_f, Vzero, O_t_lo}, + {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi}, + {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi}, + {V_r_hi_f, Vzero, O_t_hi}, + {Vend}, +}; + +static uchar ADDargs[] = { AADDL, AADCL }; +static uchar ANDargs[] = { AANDL, AANDL }; +static uchar ORargs[] = { AORL, AORL }; +static uchar SUBargs[] = { ASUBL, ASBBL }; +static uchar XORargs[] = { AXORL, AXORL }; + +static uchar (*ADDtab[])[VLEN] = +{ + add0c, addca, addac, +}; + +static uchar (*ANDtab[])[VLEN] = +{ + and0c, andca, andac, +}; + +static uchar (*ORtab[])[VLEN] = +{ + or0c, orca, orac, +}; + +static uchar (*SUBtab[])[VLEN] = +{ + add0c, subca, addac, +}; + +/* mul of const32 */ +static uchar mulc32[][VLEN] = +{ + {V_a0, Vop, ONE, O_l_hi, C00}, + {V_s0, Vins, AMOVL, O_r_lo, O_r0}, + {Vins, AMULL, O_r0, O_Zop}, + {Vgo, V_p0, V_s0}, + {Vins, AMOVL, O_l_hi, O_r0}, + {Vmul, O_r_lo, O_r0}, + {Vins, AMOVL, O_r_lo, O_l_hi}, + {Vins, AMULL, O_l_hi, O_Zop}, + {Vins, AADDL, O_r0, O_l_hi}, + {V_f0, V_p0, Vend}, +}; + +/* mul of const64 */ +static uchar mulc64[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_r_hi, O_r0}, + {Vop, OOR, O_l_hi, O_r0}, + {Vop, ONE, O_r0, C00}, + {V_s0, Vins, AMOVL, O_r_lo, O_r0}, + {Vins, AMULL, O_r0, O_Zop}, + {Vgo, V_p0, V_s0}, + {Vmul, O_r_lo, O_l_hi}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vmul, O_r_hi, O_r0}, + {Vins, AADDL, O_l_hi, O_r0}, + {Vins, AMOVL, O_r_lo, O_l_hi}, + {Vins, AMULL, O_l_hi, O_Zop}, + {Vins, AADDL, O_r0, O_l_hi}, + {V_f0, V_p0, Vend}, +}; + +/* mul general */ +static uchar mull[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_r_hi, O_r0}, + {Vop, OOR, O_l_hi, O_r0}, + {Vop, ONE, O_r0, C00}, + {V_s0, Vins, AMOVL, O_r_lo, O_r0}, + {Vins, AMULL, O_r0, O_Zop}, + {Vgo, V_p0, V_s0}, + {Vins, AIMULL, O_r_lo, O_l_hi}, + {Vins, AMOVL, O_l_lo, O_r0}, + {Vins, AIMULL, O_r_hi, O_r0}, + {Vins, AADDL, O_l_hi, O_r0}, + {Vins, AMOVL, O_r_lo, O_l_hi}, + {Vins, AMULL, O_l_hi, O_Zop}, + {Vins, AADDL, O_r0, O_l_hi}, + {V_f0, V_p0, Vend}, +}; + +/* cast rp l to rp t */ +static uchar castrp[][VLEN] = +{ + {Vmv, O_l, O_t_lo}, + {VT, Vins, AMOVL, O_t_lo, O_t_hi}, + {VT, Vins, ASARL, C31, O_t_hi}, + {VF, Vzero, O_t_hi}, + {Vend}, +}; + +/* cast rp l to addr t */ +static uchar castrpa[][VLEN] = +{ + {VT, V_a0, Vmv, O_l, O_r0}, + {VT, Vins, AMOVL, O_r0, O_t_lo}, + {VT, Vins, ASARL, C31, O_r0}, + {VT, Vins, AMOVL, O_r0, O_t_hi}, + {VT, V_f0}, + {VF, Vmv, O_l, O_t_lo}, + {VF, Vzero, O_t_hi}, + {Vend}, +}; + +static uchar netab0i[][VLEN] = +{ + {Vop, ONE, O_l_lo, O_r_lo}, + {V_s0, Vop, ONE, O_l_hi, O_r_hi}, + {V_s1, Vgo, V_s2, Vgo, V_s3}, + {VF, V_p0, V_p1, VT, V_p2}, + {Vgo, V_p3}, + {VT, V_p0, V_p1, VF, V_p2}, + {Vend}, +}; + +static uchar netabii[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_l_lo, O_r0}, + {Vop, ONE, O_r0, O_r_lo}, + {V_s0, Vins, AMOVL, O_l_hi, O_r0}, + {Vop, ONE, O_r0, O_r_hi}, + {V_s1, Vgo, V_s2, Vgo, V_s3}, + {VF, V_p0, V_p1, VT, V_p2}, + {Vgo, V_p3}, + {VT, V_p0, V_p1, VF, V_p2}, + {V_f0, Vend}, +}; + +static uchar cmptab0i[][VLEN] = +{ + {Vopx, Bop0, O_l_hi, O_r_hi}, + {V_s0, Vins0, AJNE}, + {V_s1, Vopx, Bop1, O_l_lo, O_r_lo}, + {V_s2, Vgo, V_s3, Vgo, V_s4}, + {VT, V_p1, V_p3}, + {VF, V_p0, V_p2}, + {Vgo, V_p4}, + {VT, V_p0, V_p2}, + {VF, V_p1, V_p3}, + {Vend}, +}; + +static uchar cmptabii[][VLEN] = +{ + {V_a0, Vins, AMOVL, O_l_hi, O_r0}, + {Vopx, Bop0, O_r0, O_r_hi}, + {V_s0, Vins0, AJNE}, + {V_s1, Vins, AMOVL, O_l_lo, O_r0}, + {Vopx, Bop1, O_r0, O_r_lo}, + {V_s2, Vgo, V_s3, Vgo, V_s4}, + {VT, V_p1, V_p3}, + {VF, V_p0, V_p2}, + {Vgo, V_p4}, + {VT, V_p0, V_p2}, + {VF, V_p1, V_p3}, + {V_f0, Vend}, +}; + +static uchar (*NEtab[])[VLEN] = +{ + netab0i, netabii, +}; + +static uchar (*cmptab[])[VLEN] = +{ + cmptab0i, cmptabii, +}; + +static uchar GEargs[] = { OGT, OHS }; +static uchar GTargs[] = { OGT, OHI }; +static uchar HIargs[] = { OHI, OHI }; +static uchar HSargs[] = { OHI, OHS }; + +/* Big Generator */ +static void +biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a) +{ + int i, j, g, oc, op, lo, ro, to, xo, *xp; + Type *lt; + Prog *pr[VOPS]; + Node *ot, *tl, *tr, tmps[2]; + uchar *c, (*cp)[VLEN], args[VARGS]; + + if(a != nil) + memmove(args, a, VARGS); +//print("biggen %d %d %d\n", args[0], args[1], args[2]); +//if(l) prtree(l, "l"); +//if(r) prtree(r, "r"); +//if(t) prtree(t, "t"); + lo = ro = to = 0; + cp = code; + + for (;;) { + c = *cp++; + g = 1; + i = 0; +//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]); + for(;;) { + switch(op = c[i]) { + case Vgo: + if(g) + gbranch(OGOTO); + i++; + break; + + case Vamv: + i += 3; + if(i > VLEN) { + diag(l, "bad Vop"); + return; + } + if(g) + args[c[i - 1]] = args[c[i - 2]]; + break; + + case Vzero: + i += 2; + if(i > VLEN) { + diag(l, "bad Vop"); + return; + } + j = i - 1; + goto op; + + case Vspazz: // nasty hack to save a reg in SUB +//print("spazz\n"); + if(g) { +//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg); + ot = r->right; + r->right = r->left; + tl = new(0, Z, Z); + *tl = tmps[0]; + r->left = tl; + tmps[0] = *ot; +//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg); + } + i++; + break; + + case Vmv: + case Vmul: + case Vshll: + i += 3; + if(i > VLEN) { + diag(l, "bad Vop"); + return; + } + j = i - 2; + goto op; + + case Vins0: + i += 2; + if(i > VLEN) { + diag(l, "bad Vop"); + return; + } + gins(c[i - 1], Z, Z); + break; + + case Vop: + case Vopx: + case Vins: + case Vinsl: + case Vinsr: + case Vinsla: + case Vinsra: + case Vinsx: + i += 4; + if(i > VLEN) { + diag(l, "bad Vop"); + return; + } + j = i - 2; + goto op; + + op: + if(!g) + break; + tl = Z; + tr = Z; + for(; j < i; j++) { + switch(c[j]) { + case C00: + ot = nodconst(0); + break; + case C01: + ot = nodconst(1); + break; + case C31: + ot = nodconst(31); + break; + case C32: + ot = nodconst(32); + break; + + case O_l: + case O_l_lo: + ot = l; xp = &lo; xo = 0; + goto op0; + case O_l_hi: + ot = l; xp = &lo; xo = SZ_LONG; + goto op0; + case O_r: + case O_r_lo: + ot = r; xp = &ro; xo = 0; + goto op0; + case O_r_hi: + ot = r; xp = &ro; xo = SZ_LONG; + goto op0; + case O_t_lo: + ot = t; xp = &to; xo = 0; + goto op0; + case O_t_hi: + ot = t; xp = &to; xo = SZ_LONG; + goto op0; + case O_l_rp: + ot = l; + break; + case O_r_rp: + ot = r; + break; + case O_t_rp: + ot = t; + break; + case O_r0: + case O_r1: + ot = &tmps[c[j] - O_r0]; + break; + case O_Zop: + ot = Z; + break; + + op0: + switch(ot->op) { + case OCONST: + if(xo) + ot = hi64(ot); + else + ot = lo64(ot); + break; + case OREGPAIR: + if(xo) + ot = ot->right; + else + ot = ot->left; + break; + case OREGISTER: + break; + default: + if(xo != *xp) { + ot->xoffset += xo - *xp; + *xp = xo; + } + } + break; + + default: + diag(l, "bad V_lop"); + return; + } + if(tl == nil) + tl = ot; + else + tr = ot; + } + if(op == Vzero) { + zeroregm(tl); + break; + } + oc = c[i - 3]; + if(op == Vinsx || op == Vopx) { +//print("%d -> %d\n", oc, args[oc]); + oc = args[oc]; + } + else { + switch(oc) { + case O_a0: + case O_a1: + oc = args[oc - O_a0]; + break; + } + } + switch(op) { + case Vmul: + mulgen(tr->type, tl, tr); + break; + case Vmv: + gmove(tl, tr); + break; + case Vshll: + shiftit(tr->type, tl, tr); + break; + case Vop: + case Vopx: + gopcode(oc, types[TULONG], tl, tr); + break; + case Vins: + case Vinsx: + gins(oc, tl, tr); + break; + case Vinsl: + gins(oc, tl, tr->right); + p->from.index = tr->left->reg; + break; + case Vinsr: + gins(oc, tl, tr->left); + p->from.index = tr->right->reg; + break; + case Vinsla: + gins(oc, tl, tr + 1); + p->from.index = tr->reg; + break; + case Vinsra: + gins(oc, tl, tr); + p->from.index = (tr + 1)->reg; + break; + } + break; + + case VT: + g = true; + i++; + break; + case VF: + g = !true; + i++; + break; + + case V_T0: case V_T1: + g = args[op - V_T0]; + i++; + break; + + case V_F0: case V_F1: + g = !args[op - V_F0]; + i++; + break; + + case V_C0: case V_C1: + if(g) + args[op - V_C0] = 0; + i++; + break; + + case V_S0: case V_S1: + if(g) + args[op - V_S0] = 1; + i++; + break; + + case V_l_lo_f: + g = lo64v(l) == 0; + i++; + break; + case V_l_hi_f: + g = hi64v(l) == 0; + i++; + break; + case V_l_lo_t: + g = lo64v(l) != 0; + i++; + break; + case V_l_hi_t: + g = hi64v(l) != 0; + i++; + break; + case V_l_lo_u: + g = lo64v(l) >= 0; + i++; + break; + case V_l_hi_u: + g = hi64v(l) >= 0; + i++; + break; + case V_r_lo_f: + g = lo64v(r) == 0; + i++; + break; + case V_r_hi_f: + g = hi64v(r) == 0; + i++; + break; + case V_r_lo_t: + g = lo64v(r) != 0; + i++; + break; + case V_r_hi_t: + g = hi64v(r) != 0; + i++; + break; + case V_r_lo_u: + g = lo64v(r) >= 0; + i++; + break; + case V_r_hi_u: + g = hi64v(r) >= 0; + i++; + break; + + case Vend: + goto out; + + case V_a0: case V_a1: + if(g) { + lt = l->type; + l->type = types[TULONG]; + regalloc(&tmps[op - V_a0], l, Z); + l->type = lt; + } + i++; + break; + + case V_f0: case V_f1: + if(g) + regfree(&tmps[op - V_f0]); + i++; + break; + + case V_p0: case V_p1: case V_p2: case V_p3: case V_p4: + if(g) + patch(pr[op - V_p0], pc); + i++; + break; + + case V_s0: case V_s1: case V_s2: case V_s3: case V_s4: + if(g) + pr[op - V_s0] = p; + i++; + break; + + default: + diag(l, "bad biggen: %d", op); + return; + } + if(i == VLEN || c[i] == 0) + break; + } + } +out: + if(lo) + l->xoffset -= lo; + if(ro) + r->xoffset -= ro; + if(to) + t->xoffset -= to; +} + +int +cgen64(Node *n, Node *nn) +{ + Type *dt; + uchar *args, (*cp)[VLEN], (**optab)[VLEN]; + int li, ri, lri, dr, si, m, op, sh, cmp, true; + Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5; + + if(debug['g']) { + prtree(nn, "cgen64 lhs"); + prtree(n, "cgen64"); + print("AX = %d\n", reg[D_AX]); + } + cmp = 0; + sh = 0; + + switch(n->op) { + case ONEG: + d = regpair(nn, n); + sugen(n->left, d, 8); + gins(ANOTL, Z, d->right); + gins(ANEGL, Z, d->left); + gins(ASBBL, nodconst(-1), d->right); + break; + + case OCOM: + if(!vaddr(n->left, 0) || !vaddr(nn, 0)) + d = regpair(nn, n); + else + return 0; + sugen(n->left, d, 8); + gins(ANOTL, Z, d->left); + gins(ANOTL, Z, d->right); + break; + + case OADD: + optab = ADDtab; + args = ADDargs; + goto twoop; + case OAND: + optab = ANDtab; + args = ANDargs; + goto twoop; + case OOR: + optab = ORtab; + args = ORargs; + goto twoop; + case OSUB: + optab = SUBtab; + args = SUBargs; + goto twoop; + case OXOR: + optab = ORtab; + args = XORargs; + goto twoop; + case OASHL: + sh = 1; + args = nil; + optab = shlltab; + goto twoop; + case OLSHR: + sh = 1; + args = shrlargs; + optab = shrltab; + goto twoop; + case OASHR: + sh = 1; + args = sarlargs; + optab = shrltab; + goto twoop; + case OEQ: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case ONE: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OLE: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OLT: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OGE: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OGT: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OHI: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OHS: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OLO: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + case OLS: + cmp = 1; + args = nil; + optab = nil; + goto twoop; + +twoop: + dr = nn != Z && nn->op == OREGPAIR; + l = vfunc(n->left, nn); + if(sh) + r = n->right; + else + r = vfunc(n->right, nn); + + li = l->op == ONAME || l->op == OINDREG || l->op == OCONST; + ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST; + +#define IMM(l, r) ((l) | ((r) << 1)) + + lri = IMM(li, ri); + + /* find out what is so easy about some operands */ + if(li) + li = whatof(l, sh | cmp); + if(ri) + ri = whatof(r, cmp); + + if(sh) + goto shift; + + if(cmp) + goto cmp; + + /* evaluate hard subexps, stealing nn if possible. */ + switch(lri) { + case IMM(0, 0): + bin00: + if(l->complex > r->complex) { + if(dr) + t = nn; + else + t = regpair(Z, n); + sugen(l, t, 8); + l = t; + t = regpair(Z, n); + sugen(r, t, 8); + r = t; + } + else { + t = regpair(Z, n); + sugen(r, t, 8); + r = t; + if(dr) + t = nn; + else + t = regpair(Z, n); + sugen(l, t, 8); + l = t; + } + break; + case IMM(0, 1): + if(dr) + t = nn; + else + t = regpair(Z, n); + sugen(l, t, 8); + l = t; + break; + case IMM(1, 0): + if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) { + lri = IMM(0, 0); + goto bin00; + } + if(dr) + t = nn; + else + t = regpair(Z, n); + sugen(r, t, 8); + r = t; + break; + case IMM(1, 1): + break; + } + +#define WW(l, r) ((l) | ((r) << 2)) + d = Z; + dt = nn->type; + nn->type = types[TLONG]; + + switch(lri) { + case IMM(0, 0): + biggen(l, r, Z, 0, binop00, args); + break; + case IMM(0, 1): + switch(ri) { + case WNONE: + diag(r, "bad whatof\n"); + break; + case WCONST: + biggen(l, r, Z, 0, optab[B0c], args); + break; + case WHARD: + reglcgen(&nod2, r, Z); + r = &nod2; + /* fall thru */ + case WADDR: + biggen(l, r, Z, 0, binoptmp, args); + if(ri == WHARD) + regfree(r); + break; + } + break; + case IMM(1, 0): + if(n->op == OSUB) { + switch(li) { + case WNONE: + diag(l, "bad whatof\n"); + break; + case WHARD: + reglcgen(&nod2, l, Z); + l = &nod2; + /* fall thru */ + case WADDR: + case WCONST: + biggen(l, r, Z, 0, sub10, args); + break; + } + if(li == WHARD) + regfree(l); + } + else { + switch(li) { + case WNONE: + diag(l, "bad whatof\n"); + break; + case WCONST: + biggen(r, l, Z, 0, optab[B0c], args); + break; + case WHARD: + reglcgen(&nod2, l, Z); + l = &nod2; + /* fall thru */ + case WADDR: + biggen(r, l, Z, 0, binoptmp, args); + if(li == WHARD) + regfree(l); + break; + } + } + break; + case IMM(1, 1): + switch(WW(li, ri)) { + case WW(WCONST, WHARD): + if(r->op == ONAME && n->op == OAND && reduxv(l)) + ri = WADDR; + break; + case WW(WHARD, WCONST): + if(l->op == ONAME && n->op == OAND && reduxv(r)) + li = WADDR; + break; + } + if(li == WHARD) { + reglcgen(&nod3, l, Z); + l = &nod3; + } + if(ri == WHARD) { + reglcgen(&nod2, r, Z); + r = &nod2; + } + d = regpair(nn, n); + instpair(d, Z); + switch(WW(li, ri)) { + case WW(WCONST, WADDR): + case WW(WCONST, WHARD): + biggen(l, r, d, 0, optab[Bca], args); + break; + + case WW(WADDR, WCONST): + case WW(WHARD, WCONST): + biggen(l, r, d, 0, optab[Bac], args); + break; + + case WW(WADDR, WADDR): + case WW(WADDR, WHARD): + case WW(WHARD, WADDR): + case WW(WHARD, WHARD): + biggen(l, r, d, 0, binop11, args); + break; + + default: + diag(r, "bad whatof pair %d %d\n", li, ri); + break; + } + if(li == WHARD) + regfree(l); + if(ri == WHARD) + regfree(r); + break; + } + + nn->type = dt; + + if(d != Z) + goto finished; + + switch(lri) { + case IMM(0, 0): + freepair(r); + /* fall thru */; + case IMM(0, 1): + if(!dr) + storepair(l, nn, 1); + break; + case IMM(1, 0): + if(!dr) + storepair(r, nn, 1); + break; + case IMM(1, 1): + break; + } + return 1; + + shift: + c = Z; + + /* evaluate hard subexps, stealing nn if possible. */ + /* must also secure CX. not as many optims as binop. */ + switch(lri) { + case IMM(0, 0): + imm00: + if(l->complex + 1 > r->complex) { + if(dr) + t = nn; + else + t = regpair(Z, l); + sugen(l, t, 8); + l = t; + t = &nod1; + c = snarfreg(l, t, D_CX, r, &nod2); + cgen(r, t); + r = t; + } + else { + t = &nod1; + c = snarfreg(nn, t, D_CX, r, &nod2); + cgen(r, t); + r = t; + if(dr) + t = nn; + else + t = regpair(Z, l); + sugen(l, t, 8); + l = t; + } + break; + case IMM(0, 1): + imm01: + if(ri != WCONST) { + lri = IMM(0, 0); + goto imm00; + } + if(dr) + t = nn; + else + t = regpair(Z, n); + sugen(l, t, 8); + l = t; + break; + case IMM(1, 0): + imm10: + if(li != WCONST) { + lri = IMM(0, 0); + goto imm00; + } + t = &nod1; + c = snarfreg(nn, t, D_CX, r, &nod2); + cgen(r, t); + r = t; + break; + case IMM(1, 1): + if(ri != WCONST) { + lri = IMM(1, 0); + goto imm10; + } + if(li == WHARD) { + lri = IMM(0, 1); + goto imm01; + } + break; + } + + d = Z; + + switch(lri) { + case IMM(0, 0): + biggen(l, r, Z, 0, optab[S00], args); + break; + case IMM(0, 1): + switch(ri) { + case WNONE: + case WADDR: + case WHARD: + diag(r, "bad whatof\n"); + break; + case WCONST: + m = r->vconst & 63; + s = nodconst(m); + if(m < 32) + cp = optab[Sc0]; + else if(m == 32) + cp = optab[Sc1]; + else + cp = optab[Sc2]; + biggen(l, s, Z, 0, cp, args); + break; + } + break; + case IMM(1, 0): + /* left is const */ + d = regpair(nn, n); + instpair(d, Z); + biggen(l, r, d, 0, optab[S10], args); + regfree(r); + break; + case IMM(1, 1): + d = regpair(nn, n); + instpair(d, Z); + switch(WW(li, ri)) { + case WW(WADDR, WCONST): + m = r->vconst & 63; + s = nodconst(m); + if(m < 32) { + loadpair(l, d); + l = d; + cp = optab[Sc0]; + } + else if(m == 32) + cp = optab[Sac3]; + else + cp = optab[Sac4]; + biggen(l, s, d, 0, cp, args); + break; + + default: + diag(r, "bad whatof pair %d %d\n", li, ri); + break; + } + break; + } + + if(c != Z) { + gins(AMOVL, c, r); + regfree(c); + } + + if(d != Z) + goto finished; + + switch(lri) { + case IMM(0, 0): + regfree(r); + /* fall thru */ + case IMM(0, 1): + if(!dr) + storepair(l, nn, 1); + break; + case IMM(1, 0): + regfree(r); + break; + case IMM(1, 1): + break; + } + return 1; + + cmp: + op = n->op; + /* evaluate hard subexps */ + switch(lri) { + case IMM(0, 0): + if(l->complex > r->complex) { + t = regpair(Z, l); + sugen(l, t, 8); + l = t; + t = regpair(Z, r); + sugen(r, t, 8); + r = t; + } + else { + t = regpair(Z, r); + sugen(r, t, 8); + r = t; + t = regpair(Z, l); + sugen(l, t, 8); + l = t; + } + break; + case IMM(1, 0): + t = r; + r = l; + l = t; + ri = li; + op = invrel[relindex(op)]; + /* fall thru */ + case IMM(0, 1): + t = regpair(Z, l); + sugen(l, t, 8); + l = t; + break; + case IMM(1, 1): + break; + } + + true = 1; + optab = cmptab; + switch(op) { + case OEQ: + optab = NEtab; + true = 0; + break; + case ONE: + optab = NEtab; + break; + case OLE: + args = GTargs; + true = 0; + break; + case OGT: + args = GTargs; + break; + case OLS: + args = HIargs; + true = 0; + break; + case OHI: + args = HIargs; + break; + case OLT: + args = GEargs; + true = 0; + break; + case OGE: + args = GEargs; + break; + case OLO: + args = HSargs; + true = 0; + break; + case OHS: + args = HSargs; + break; + default: + diag(n, "bad cmp\n"); + SET(optab); + } + + switch(lri) { + case IMM(0, 0): + biggen(l, r, Z, true, optab[T0i], args); + break; + case IMM(0, 1): + case IMM(1, 0): + switch(ri) { + case WNONE: + diag(l, "bad whatof\n"); + break; + case WCONST: + biggen(l, r, Z, true, optab[T0i], args); + break; + case WHARD: + reglcgen(&nod2, r, Z); + r = &nod2; + /* fall thru */ + case WADDR: + biggen(l, r, Z, true, optab[T0i], args); + if(ri == WHARD) + regfree(r); + break; + } + break; + case IMM(1, 1): + if(li == WHARD) { + reglcgen(&nod3, l, Z); + l = &nod3; + } + if(ri == WHARD) { + reglcgen(&nod2, r, Z); + r = &nod2; + } + biggen(l, r, Z, true, optab[Tii], args); + if(li == WHARD) + regfree(l); + if(ri == WHARD) + regfree(r); + break; + } + + switch(lri) { + case IMM(0, 0): + freepair(r); + /* fall thru */; + case IMM(0, 1): + case IMM(1, 0): + freepair(l); + break; + case IMM(1, 1): + break; + } + return 1; + + case OASMUL: + case OASLMUL: + m = 0; + goto mulop; + + case OMUL: + case OLMUL: + m = 1; + goto mulop; + + mulop: + dr = nn != Z && nn->op == OREGPAIR; + l = vfunc(n->left, nn); + r = vfunc(n->right, nn); + if(r->op != OCONST) { + if(l->complex > r->complex) { + if(m) { + t = l; + l = r; + r = t; + } + else if(!vaddr(l, 1)) { + reglcgen(&nod5, l, Z); + l = &nod5; + evacaxdx(l); + } + } + t = regpair(Z, n); + sugen(r, t, 8); + r = t; + evacaxdx(r->left); + evacaxdx(r->right); + if(l->complex <= r->complex && !m && !vaddr(l, 1)) { + reglcgen(&nod5, l, Z); + l = &nod5; + evacaxdx(l); + } + } + if(dr) + t = nn; + else + t = regpair(Z, n); + c = Z; + d = Z; + if(!nodreg(&nod1, t->left, D_AX)) { + if(t->left->reg != D_AX){ + t->left->reg = D_AX; + reg[D_AX]++; + }else if(reg[D_AX] == 0) + fatal(Z, "vlong mul AX botch"); + } + if(!nodreg(&nod2, t->right, D_DX)) { + if(t->right->reg != D_DX){ + t->right->reg = D_DX; + reg[D_DX]++; + }else if(reg[D_DX] == 0) + fatal(Z, "vlong mul DX botch"); + } + if(m) + sugen(l, t, 8); + else + loadpair(l, t); + if(t->left->reg != D_AX) { + c = &nod3; + regsalloc(c, t->left); + gmove(&nod1, c); + gmove(t->left, &nod1); + zapreg(t->left); + } + if(t->right->reg != D_DX) { + d = &nod4; + regsalloc(d, t->right); + gmove(&nod2, d); + gmove(t->right, &nod2); + zapreg(t->right); + } + if(c != Z || d != Z) { + s = regpair(Z, n); + s->left = &nod1; + s->right = &nod2; + } + else + s = t; + if(r->op == OCONST) { + if(hi64v(r) == 0) + biggen(s, r, Z, 0, mulc32, nil); + else + biggen(s, r, Z, 0, mulc64, nil); + } + else + biggen(s, r, Z, 0, mull, nil); + instpair(t, Z); + if(c != Z) { + gmove(&nod1, t->left); + gmove(&nod3, &nod1); + } + if(d != Z) { + gmove(&nod2, t->right); + gmove(&nod4, &nod2); + } + if(r->op == OREGPAIR) + freepair(r); + if(!m) + storepair(t, l, 0); + if(l == &nod5) + regfree(l); + if(!dr) { + if(nn != Z) + storepair(t, nn, 1); + else + freepair(t); + } + return 1; + + case OASADD: + args = ADDargs; + goto vasop; + case OASAND: + args = ANDargs; + goto vasop; + case OASOR: + args = ORargs; + goto vasop; + case OASSUB: + args = SUBargs; + goto vasop; + case OASXOR: + args = XORargs; + goto vasop; + + vasop: + l = n->left; + r = n->right; + dr = nn != Z && nn->op == OREGPAIR; + m = 0; + if(l->complex > r->complex) { + if(!vaddr(l, 1)) { + reglcgen(&nod1, l, Z); + l = &nod1; + } + if(!vaddr(r, 1) || nn != Z || r->op == OCONST) { + if(dr) + t = nn; + else + t = regpair(Z, r); + sugen(r, t, 8); + r = t; + m = 1; + } + } + else { + if(!vaddr(r, 1) || nn != Z || r->op == OCONST) { + if(dr) + t = nn; + else + t = regpair(Z, r); + sugen(r, t, 8); + r = t; + m = 1; + } + if(!vaddr(l, 1)) { + reglcgen(&nod1, l, Z); + l = &nod1; + } + } + if(nn != Z) { + if(n->op == OASSUB) + biggen(l, r, Z, 0, sub10, args); + else + biggen(r, l, Z, 0, binoptmp, args); + storepair(r, l, 0); + } + else { + if(m) + biggen(l, r, Z, 0, binop00, args); + else + biggen(l, r, Z, 0, binoptmp, args); + } + if(l == &nod1) + regfree(&nod1); + if(m) { + if(nn == Z) + freepair(r); + else if(!dr) + storepair(r, nn, 1); + } + return 1; + + case OASASHL: + args = nil; + optab = asshlltab; + goto assh; + case OASLSHR: + args = shrlargs; + optab = asshrltab; + goto assh; + case OASASHR: + args = sarlargs; + optab = asshrltab; + goto assh; + + assh: + c = Z; + l = n->left; + r = n->right; + if(r->op == OCONST) { + m = r->vconst & 63; + if(m < 32) + m = SAclo; + else if(m == 32) + m = SAc32; + else + m = SAchi; + } + else + m = SAgen; + if(l->complex > r->complex) { + if(!vaddr(l, 0)) { + reglcgen(&nod1, l, Z); + l = &nod1; + } + if(m == SAgen) { + t = &nod2; + if(l->reg == D_CX) { + regalloc(t, r, Z); + gmove(l, t); + l->reg = t->reg; + t->reg = D_CX; + } + else + c = snarfreg(nn, t, D_CX, r, &nod3); + cgen(r, t); + r = t; + } + } + else { + if(m == SAgen) { + t = &nod2; + c = snarfreg(nn, t, D_CX, r, &nod3); + cgen(r, t); + r = t; + } + if(!vaddr(l, 0)) { + reglcgen(&nod1, l, Z); + l = &nod1; + } + } + + if(nn != Z) { + m += SAdgen - SAgen; + d = regpair(nn, n); + instpair(d, Z); + biggen(l, r, d, 0, optab[m], args); + if(l == &nod1) { + regfree(&nod1); + l = Z; + } + if(r == &nod2 && c == Z) { + regfree(&nod2); + r = Z; + } + if(d != nn) + storepair(d, nn, 1); + } + else + biggen(l, r, Z, 0, optab[m], args); + + if(c != Z) { + gins(AMOVL, c, r); + regfree(c); + } + if(l == &nod1) + regfree(&nod1); + if(r == &nod2) + regfree(&nod2); + return 1; + + case OPOSTINC: + args = ADDargs; + cp = incdecpost; + goto vinc; + case OPOSTDEC: + args = SUBargs; + cp = incdecpost; + goto vinc; + case OPREINC: + args = ADDargs; + cp = incdecpre; + goto vinc; + case OPREDEC: + args = SUBargs; + cp = incdecpre; + goto vinc; + + vinc: + l = n->left; + if(!vaddr(l, 1)) { + reglcgen(&nod1, l, Z); + l = &nod1; + } + + if(nn != Z) { + d = regpair(nn, n); + instpair(d, Z); + biggen(l, Z, d, 0, cp, args); + if(l == &nod1) { + regfree(&nod1); + l = Z; + } + if(d != nn) + storepair(d, nn, 1); + } + else + biggen(l, Z, Z, 0, incdec, args); + + if(l == &nod1) + regfree(&nod1); + return 1; + + case OCAST: + l = n->left; + if(typev[l->type->etype]) { + if(!vaddr(l, 1)) { + if(l->complex + 1 > nn->complex) { + d = regpair(Z, l); + sugen(l, d, 8); + if(!vaddr(nn, 1)) { + reglcgen(&nod1, nn, Z); + r = &nod1; + } + else + r = nn; + } + else { + if(!vaddr(nn, 1)) { + reglcgen(&nod1, nn, Z); + r = &nod1; + } + else + r = nn; + d = regpair(Z, l); + sugen(l, d, 8); + } +// d->left->type = r->type; + d->left->type = types[TLONG]; + gmove(d->left, r); + freepair(d); + } + else { + if(nn->op != OREGISTER && !vaddr(nn, 1)) { + reglcgen(&nod1, nn, Z); + r = &nod1; + } + else + r = nn; +// l->type = r->type; + l->type = types[TLONG]; + gmove(l, r); + } + if(r != nn) + regfree(r); + } + else { + if(typeu[l->type->etype] || cond(l->op)) + si = TUNSIGNED; + else + si = TSIGNED; + regalloc(&nod1, l, Z); + cgen(l, &nod1); + if(nn->op == OREGPAIR) { + m = instpair(nn, &nod1); + biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil); + } + else { + m = 0; + if(!vaddr(nn, si != TSIGNED)) { + dt = nn->type; + nn->type = types[TLONG]; + reglcgen(&nod2, nn, Z); + nn->type = dt; + nn = &nod2; + } + dt = nn->type; + nn->type = types[TLONG]; + biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil); + nn->type = dt; + if(nn == &nod2) + regfree(&nod2); + } + if(!m) + regfree(&nod1); + } + return 1; + + default: + if(n->op == OREGPAIR) { + storepair(n, nn, 1); + return 1; + } + if(nn->op == OREGPAIR) { + loadpair(n, nn); + return 1; + } + return 0; + } +finished: + if(d != nn) + storepair(d, nn, 1); + return 1; +} + +void +testv(Node *n, int true) +{ + Type *t; + Node *nn, nod; + + switch(n->op) { + case OINDREG: + case ONAME: + biggen(n, Z, Z, true, testi, nil); + break; + + default: + n = vfunc(n, n); + if(n->addable >= INDEXED) { + t = n->type; + n->type = types[TLONG]; + reglcgen(&nod, n, Z); + n->type = t; + n = &nod; + biggen(n, Z, Z, true, testi, nil); + if(n == &nod) + regfree(n); + } + else { + nn = regpair(Z, n); + sugen(n, nn, 8); + biggen(nn, Z, Z, true, testi, nil); + freepair(nn); + } + } +} diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c new file mode 100644 index 000000000..3be47730f --- /dev/null +++ b/src/cmd/8c/div.c @@ -0,0 +1,236 @@ +// Inferno utils/8c/div.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.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" + +/* + * Based on: Granlund, T.; Montgomery, P.L. + * "Division by Invariant Integers using Multiplication". + * SIGPLAN Notices, Vol. 29, June 1994, page 61. + */ + +#define TN(n) ((uvlong)1 << (n)) +#define T31 TN(31) +#define T32 TN(32) + +int +multiplier(ulong d, int p, uvlong *mp) +{ + int l; + uvlong mlo, mhi, tlo, thi; + + l = topbit(d - 1) + 1; + mlo = (((TN(l) - d) << 32) / d) + T32; + if(l + p == 64) + mhi = (((TN(l) + 1 - d) << 32) / d) + T32; + else + mhi = (TN(32 + l) + TN(32 + l - p)) / d; + /*assert(mlo < mhi);*/ + while(l > 0) { + tlo = mlo >> 1; + thi = mhi >> 1; + if(tlo == thi) + break; + mlo = tlo; + mhi = thi; + l--; + } + *mp = mhi; + return l; +} + +int +sdiv(ulong d, ulong *mp, int *sp) +{ + int s; + uvlong m; + + s = multiplier(d, 32 - 1, &m); + *mp = m; + *sp = s; + if(m >= T31) + return 1; + else + return 0; +} + +int +udiv(ulong d, ulong *mp, int *sp, int *pp) +{ + int p, s; + uvlong m; + + s = multiplier(d, 32, &m); + p = 0; + if(m >= T32) { + while((d & 1) == 0) { + d >>= 1; + p++; + } + s = multiplier(d, 32 - p, &m); + } + *mp = m; + *pp = p; + if(m >= T32) { + /*assert(p == 0);*/ + *sp = s - 1; + return 1; + } + else { + *sp = s; + return 0; + } +} + +void +sdivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s; + ulong m; + vlong c; + + c = r->vconst; + if(c < 0) + c = -c; + a = sdiv(c, &m, &s); +//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); + gins(AMOVL, nodconst(m), ax); + gins(AIMULL, l, Z); + gins(AMOVL, l, ax); + if(a) + gins(AADDL, ax, dx); + gins(ASHRL, nodconst(31), ax); + gins(ASARL, nodconst(s), dx); + gins(AADDL, ax, dx); + if(r->vconst < 0) + gins(ANEGL, Z, dx); +} + +void +udivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s, t; + ulong m; + Node nod; + + a = udiv(r->vconst, &m, &s, &t); +//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); + if(t != 0) { + gins(AMOVL, l, ax); + gins(ASHRL, nodconst(t), ax); + gins(AMOVL, nodconst(m), dx); + gins(AMULL, dx, Z); + } + else if(a) { + if(l->op != OREGISTER) { + regalloc(&nod, l, Z); + gins(AMOVL, l, &nod); + l = &nod; + } + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + gins(AADDL, l, dx); + gins(ARCRL, nodconst(1), dx); + if(l == &nod) + regfree(l); + } + else { + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + } + if(s != 0) + gins(ASHRL, nodconst(s), dx); +} + +void +sext(Node *d, Node *s, Node *l) +{ + if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { + reg[D_DX]++; + gins(ACDQ, Z, Z); + } + else { + regalloc(d, l, Z); + gins(AMOVL, s, d); + gins(ASARL, nodconst(31), d); + } +} + +void +sdiv2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(v > 0) { + if(v > 1) { + sext(&nod, n, l); + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + regfree(&nod); + } + else { + gins(ACMPL, n, nodconst(0x80000000)); + gins(ASBBL, nodconst(-1), n); + } + gins(ASARL, nodconst(v), n); + } + if(c < 0) + gins(ANEGL, Z, n); +} + +void +smod2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(c == 1) { + zeroregm(n); + return; + } + + sext(&nod, n, l); + if(v == 0) { + zeroregm(n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + else if(v > 1) { + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + gins(AANDL, nodconst((1 << v) - 1), n); + gins(ASUBL, &nod, n); + } + else { + gins(AANDL, nodconst(1), n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + regfree(&nod); +} diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h new file mode 100644 index 000000000..866c1f94b --- /dev/null +++ b/src/cmd/8c/gc.h @@ -0,0 +1,404 @@ +// Inferno utils/8c/gc.h +// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h +// +// 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 "../cc/cc.h" +#include "../8c/8.out.h" + +/* + * 8c/386 + * Intel 386 + */ +#define SZ_CHAR 1 +#define SZ_SHORT 2 +#define SZ_INT 4 +#define SZ_LONG 4 +#define SZ_IND 4 +#define SZ_FLOAT 4 +#define SZ_VLONG 8 +#define SZ_DOUBLE 8 +#define FNX 100 + +typedef struct Adr Adr; +typedef struct Prog Prog; +typedef struct Case Case; +typedef struct C1 C1; +typedef struct Var Var; +typedef struct Reg Reg; +typedef struct Rgn Rgn; +typedef struct Renv Renv; + +EXTERN struct +{ + Node* regtree; + Node* basetree; + short scale; + short reg; + short ptr; +} idx; + +struct Adr +{ + long offset; + double dval; + char sval[NSNAME]; + + Sym* sym; + uchar type; + uchar index; + uchar etype; + uchar scale; /* doubles as width in DATA op */ +}; +#define A ((Adr*)0) + +#define INDEXED 9 +struct Prog +{ + Adr from; + Adr to; + Prog* link; + long lineno; + short as; +}; +#define P ((Prog*)0) + +struct Case +{ + Case* link; + long val; + long label; + char def; +}; +#define C ((Case*)0) + +struct C1 +{ + long val; + long label; +}; + +struct Var +{ + long offset; + Sym* sym; + char name; + char etype; +}; + +struct Reg +{ + long pc; + long rpo; /* reverse post ordering */ + + Bits set; + Bits use1; + Bits use2; + + Bits refbehind; + Bits refahead; + Bits calbehind; + Bits calahead; + Bits regdiff; + Bits act; + + long regu; + long loop; /* could be shorter */ + + Reg* log5; + long active; + + Reg* p1; + Reg* p2; + Reg* p2link; + Reg* s1; + Reg* s2; + Reg* link; + Prog* prog; +}; +#define R ((Reg*)0) + +struct Renv +{ + int safe; + Node base; + Node* saved; + Node* scope; +}; + +#define NRGN 600 +struct Rgn +{ + Reg* enter; + short cost; + short varno; + short regno; +}; + +EXTERN long breakpc; +EXTERN Case* cases; +EXTERN Node constnode; +EXTERN Node fconstnode; +EXTERN long continpc; +EXTERN long curarg; +EXTERN long cursafe; +EXTERN Prog* firstp; +EXTERN Prog* lastp; +EXTERN long maxargsafe; +EXTERN int mnstring; +EXTERN int retok; +EXTERN Node* nodrat; +EXTERN Node* nodret; +EXTERN Node* nodsafe; +EXTERN long nrathole; +EXTERN long nstring; +EXTERN Prog* p; +EXTERN long pc; +EXTERN Node regnode; +EXTERN Node fregnode0; +EXTERN Node fregnode1; +EXTERN char string[NSNAME]; +EXTERN Sym* symrathole; +EXTERN Node znode; +EXTERN Prog zprog; +EXTERN int reg[D_NONE]; +EXTERN long exregoffset; +EXTERN long exfregoffset; + +#define BLOAD(r) band(bnot(r->refbehind), r->refahead) +#define BSTORE(r) band(bnot(r->calbehind), r->calahead) +#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) +#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) + +#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) + +#define CLOAD 5 +#define CREF 5 +#define CINF 1000 +#define LOOP 3 + +EXTERN Rgn region[NRGN]; +EXTERN Rgn* rgp; +EXTERN int nregion; +EXTERN int nvar; + +EXTERN Bits externs; +EXTERN Bits params; +EXTERN Bits consts; +EXTERN Bits addrs; + +EXTERN long regbits; +EXTERN long exregbits; + +EXTERN int change; +EXTERN int suppress; + +EXTERN Reg* firstr; +EXTERN Reg* lastr; +EXTERN Reg zreg; +EXTERN Reg* freer; +EXTERN Var var[NVAR]; +EXTERN long* idom; +EXTERN Reg** rpo2r; +EXTERN long maxnr; + +extern char* anames[]; + +/* + * sgen.c + */ +void codgen(Node*, Node*); +void gen(Node*); +void noretval(int); +void usedset(Node*, int); +void xcom(Node*); +void indx(Node*); +int bcomplex(Node*, Node*); + +/* + * cgen.c + */ +void zeroregm(Node*); +void cgen(Node*, Node*); +void reglcgen(Node*, Node*, Node*); +void lcgen(Node*, Node*); +void bcgen(Node*, int); +void boolgen(Node*, int, Node*); +void sugen(Node*, Node*, long); +int needreg(Node*, int); + +/* + * cgen64.c + */ +int vaddr(Node*, int); +void loadpair(Node*, Node*); +int cgen64(Node*, Node*); +void testv(Node*, int); + +/* + * txt.c + */ +void ginit(void); +void gclean(void); +void nextpc(void); +void gargs(Node*, Node*, Node*); +void garg1(Node*, Node*, Node*, int, Node**); +Node* nodconst(long); +Node* nodfconst(double); +int nodreg(Node*, Node*, int); +int isreg(Node*, int); +void regret(Node*, Node*); +void regalloc(Node*, Node*, Node*); +void regfree(Node*); +void regialloc(Node*, Node*, Node*); +void regsalloc(Node*, Node*); +void regaalloc1(Node*, Node*); +void regaalloc(Node*, Node*); +void regind(Node*, Node*); +void gprep(Node*, Node*); +void naddr(Node*, Adr*); +void gmove(Node*, Node*); +void gins(int a, Node*, Node*); +void fgopcode(int, Node*, Node*, int, int); +void gopcode(int, Type*, Node*, Node*); +int samaddr(Node*, Node*); +void gbranch(int); +void patch(Prog*, long); +int sconst(Node*); +void gpseudo(int, Sym*, Node*); + +/* + * swt.c + */ +int swcmp(const void*, const void*); +void doswit(Node*); +void swit1(C1*, int, long, Node*); +void cas(void); +void bitload(Node*, Node*, Node*, Node*, Node*); +void bitstore(Node*, Node*, Node*, Node*, Node*); +long outstring(char*, long); +void nullwarn(Node*, Node*); +void sextern(Sym*, Node*, long, long); +void gextern(Sym*, Node*, long, long); +void outcode(void); +void ieeedtod(Ieee*, double); + +/* + * list + */ +void listinit(void); +int Pconv(Fmt*); +int Aconv(Fmt*); +int Dconv(Fmt*); +int Sconv(Fmt*); +int Rconv(Fmt*); +int Xconv(Fmt*); +int Bconv(Fmt*); + +/* + * reg.c + */ +Reg* rega(void); +int rcmp(const void*, const void*); +void regopt(Prog*); +void addmove(Reg*, int, int, int); +Bits mkvar(Reg*, Adr*); +void prop(Reg*, Bits, Bits); +void loopit(Reg*, long); +void synch(Reg*, Bits); +ulong allreg(ulong, Rgn*); +void paint1(Reg*, int); +ulong paint2(Reg*, int); +void paint3(Reg*, int, long, int); +void addreg(Adr*, int); + +/* + * peep.c + */ +void peep(void); +void excise(Reg*); +Reg* uniqp(Reg*); +Reg* uniqs(Reg*); +int regtyp(Adr*); +int anyvar(Adr*); +int subprop(Reg*); +int copyprop(Reg*); +int copy1(Adr*, Adr*, Reg*, int); +int copyu(Prog*, Adr*, Adr*); + +int copyas(Adr*, Adr*); +int copyau(Adr*, Adr*); +int copysub(Adr*, Adr*, Adr*, int); +int copysub1(Prog*, Adr*, Adr*, int); + +long RtoB(int); +long FtoB(int); +int BtoR(long); +int BtoF(long); + +#define D_HI D_NONE +#define D_LO D_NONE + +/* + * bound + */ +void comtarg(void); + +/* + * com64 + */ +int cond(int); +int com64(Node*); +void com64init(void); +void bool64(Node*); +long lo64v(Node*); +long hi64v(Node*); +Node* lo64(Node*); +Node* hi64(Node*); + +/* + * div/mul + */ +void sdivgen(Node*, Node*, Node*, Node*); +void udivgen(Node*, Node*, Node*, Node*); +void sdiv2(long, int, Node*, Node*); +void smod2(long, int, Node*, Node*); +void mulgen(Type*, Node*, Node*); +void genmuladd(Node*, Node*, int, Node*); +void shiftit(Type*, Node*, Node*); + +#pragma varargck type "A" int +#pragma varargck type "B" Bits +#pragma varargck type "D" Adr* +#pragma varargck type "P" Prog* +#pragma varargck type "R" int +#pragma varargck type "S" char* + +/* wrecklessly steal a field */ + +#define rplink label diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c new file mode 100644 index 000000000..d700b63af --- /dev/null +++ b/src/cmd/8c/list.c @@ -0,0 +1,312 @@ +// Inferno utils/8c/list.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.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. + +#define EXTERN +#include "gc.h" + +void +listinit(void) +{ + + fmtinstall('A', Aconv); + fmtinstall('B', Bconv); + fmtinstall('P', Pconv); + fmtinstall('S', Sconv); + fmtinstall('D', Dconv); + fmtinstall('R', Rconv); +} + +int +Bconv(Fmt *fp) +{ + char str[STRINGSZ], ss[STRINGSZ], *s; + Bits bits; + int i; + + str[0] = 0; + bits = va_arg(fp->args, Bits); + while(bany(&bits)) { + i = bnum(bits); + if(str[0]) + strcat(str, " "); + if(var[i].sym == S) { + sprint(ss, "$%ld", var[i].offset); + s = ss; + } else + s = var[i].sym->name; + if(strlen(str) + strlen(s) + 1 >= STRINGSZ) + break; + strcat(str, s); + bits.b[i/32] &= ~(1L << (i%32)); + } + return fmtstrcpy(fp, str); +} + +int +Pconv(Fmt *fp) +{ + char str[STRINGSZ]; + Prog *p; + + p = va_arg(fp->args, Prog*); + if(p->as == ADATA) + sprint(str, " %A %D/%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else if(p->as == ATEXT) + sprint(str, " %A %D,%d,%D", + p->as, &p->from, p->from.scale, &p->to); + else + sprint(str, " %A %D,%D", + p->as, &p->from, &p->to); + return fmtstrcpy(fp, str); +} + +int +Aconv(Fmt *fp) +{ + int i; + + i = va_arg(fp->args, int); + return fmtstrcpy(fp, anames[i]); +} + +int +Dconv(Fmt *fp) +{ + char str[40], s[20]; + Adr *a; + int i; + + a = va_arg(fp->args, Adr*); + i = a->type; + if(i >= D_INDIR) { + if(a->offset) + sprint(str, "%ld(%R)", a->offset, i-D_INDIR); + else + sprint(str, "(%R)", i-D_INDIR); + goto brk; + } + switch(i) { + + default: + if(a->offset) + sprint(str, "$%ld,%R", a->offset, i); + else + sprint(str, "%R", i); + break; + + case D_NONE: + str[0] = 0; + break; + + case D_BRANCH: + sprint(str, "%ld(PC)", a->offset-pc); + break; + + case D_EXTERN: + sprint(str, "%s+%ld(SB)", a->sym->name, a->offset); + break; + + case D_STATIC: + sprint(str, "%s<>+%ld(SB)", a->sym->name, + a->offset); + break; + + case D_AUTO: + sprint(str, "%s+%ld(SP)", a->sym->name, a->offset); + break; + + case D_PARAM: + if(a->sym) + sprint(str, "%s+%ld(FP)", a->sym->name, a->offset); + else + sprint(str, "%ld(FP)", a->offset); + break; + + case D_CONST: + sprint(str, "$%ld", a->offset); + break; + + case D_FCONST: + sprint(str, "$(%.17e)", a->dval); + break; + + case D_SCONST: + sprint(str, "$\"%S\"", a->sval); + break; + + case D_ADDR: + a->type = a->index; + a->index = D_NONE; + sprint(str, "$%D", a); + a->index = a->type; + a->type = D_ADDR; + goto conv; + } +brk: + if(a->index != D_NONE) { + sprint(s, "(%R*%d)", (int)a->index, (int)a->scale); + strcat(str, s); + } +conv: + return fmtstrcpy(fp, str); +} + +char* regstr[] = +{ + "AL", /*[D_AL]*/ + "CL", + "DL", + "BL", + "AH", + "CH", + "DH", + "BH", + + "AX", /*[D_AX]*/ + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + + "F0", /*[D_F0]*/ + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + + "CS", /*[D_CS]*/ + "SS", + "DS", + "ES", + "FS", + "GS", + + "GDTR", /*[D_GDTR]*/ + "IDTR", /*[D_IDTR]*/ + "LDTR", /*[D_LDTR]*/ + "MSW", /*[D_MSW] */ + "TASK", /*[D_TASK]*/ + + "CR0", /*[D_CR]*/ + "CR1", + "CR2", + "CR3", + "CR4", + "CR5", + "CR6", + "CR7", + + "DR0", /*[D_DR]*/ + "DR1", + "DR2", + "DR3", + "DR4", + "DR5", + "DR6", + "DR7", + + "TR0", /*[D_TR]*/ + "TR1", + "TR2", + "TR3", + "TR4", + "TR5", + "TR6", + "TR7", + + "NONE", /*[D_NONE]*/ +}; + +int +Rconv(Fmt *fp) +{ + char str[20]; + int r; + + r = va_arg(fp->args, int); + if(r >= D_AL && r <= D_NONE) + sprint(str, "%s", regstr[r-D_AL]); + else + sprint(str, "gok(%d)", r); + + return fmtstrcpy(fp, str); +} + +int +Sconv(Fmt *fp) +{ + int i, c; + char str[30], *p, *a; + + a = va_arg(fp->args, char*); + p = str; + for(i=0; i<sizeof(double); i++) { + c = a[i] & 0xff; + if(c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9') { + *p++ = c; + continue; + } + *p++ = '\\'; + switch(c) { + default: + if(c < 040 || c >= 0177) + break; /* not portable */ + p[-1] = c; + continue; + case 0: + *p++ = 'z'; + continue; + case '\\': + case '"': + *p++ = c; + continue; + case '\n': + *p++ = 'n'; + continue; + case '\t': + *p++ = 't'; + continue; + } + *p++ = (c>>6) + '0'; + *p++ = ((c>>3) & 7) + '0'; + *p++ = (c & 7) + '0'; + } + *p = 0; + return fmtstrcpy(fp, str); +} diff --git a/src/cmd/8c/machcap.c b/src/cmd/8c/machcap.c new file mode 100644 index 000000000..61e5aad16 --- /dev/null +++ b/src/cmd/8c/machcap.c @@ -0,0 +1,116 @@ +// Inferno utils/8c/machcap.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.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" + +int +machcap(Node *n) +{ + + if(n == Z) + return 1; /* test */ + + switch(n->op) { + case OMUL: + case OLMUL: + case OASMUL: + case OASLMUL: + if(typechl[n->type->etype]) + return 1; + if(typev[n->type->etype]) { + return 1; + } + break; + + case OCOM: + case ONEG: + case OADD: + case OAND: + case OOR: + case OSUB: + case OXOR: + case OASHL: + case OLSHR: + case OASHR: + if(typechlv[n->left->type->etype]) + return 1; + break; + + case OCAST: + if(typev[n->type->etype]) { + if(typechlp[n->left->type->etype]) + return 1; + } + else if(!typefd[n->type->etype]) { + if(typev[n->left->type->etype]) + return 1; + } + break; + + case OCOND: + case OCOMMA: + case OLIST: + case OANDAND: + case OOROR: + case ONOT: + return 1; + + case OASADD: + case OASSUB: + case OASAND: + case OASOR: + case OASXOR: + return 1; + + case OASASHL: + case OASASHR: + case OASLSHR: + return 1; + + case OPOSTINC: + case OPOSTDEC: + case OPREINC: + case OPREDEC: + return 1; + + case OEQ: + case ONE: + case OLE: + case OGT: + case OLT: + case OGE: + case OHI: + case OHS: + case OLO: + case OLS: + return 1; + } + return 0; +} diff --git a/src/cmd/8c/mkenam b/src/cmd/8c/mkenam new file mode 100644 index 000000000..a40140c92 --- /dev/null +++ b/src/cmd/8c/mkenam @@ -0,0 +1,45 @@ +# Inferno utils/8c/mkenam +# http://code.google.com/p/inferno-os/source/browse/utils/8c/mkenam +# +# 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. + +ed - ../8c/8.out.h <<'!' +v/^ A/d +,s/^ A/ "/ +g/ .*$/s/// +,s/,*$/",/ +1i +char* anames[] = +{ +. +$a +}; +. +w enam.c +Q +! diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c new file mode 100644 index 000000000..06394cdd5 --- /dev/null +++ b/src/cmd/8c/mul.c @@ -0,0 +1,458 @@ +// Inferno utils/8c/mul.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.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" + +typedef struct Malg Malg; +typedef struct Mparam Mparam; + +struct Malg +{ + char vals[10]; +}; + +struct Mparam +{ + ulong value; + char alg; + char neg; + char shift; + char arg; + char off; +}; + +static Mparam multab[32]; +static int mulptr; + +static Malg malgs[] = +{ + {0, 100}, + {-1, 1, 100}, + {-9, -5, -3, 3, 5, 9, 100}, + {6, 10, 12, 18, 20, 24, 36, 40, 72, 100}, + {-8, -4, -2, 2, 4, 8, 100}, +}; + +/* + * return position of lowest 1 + */ +int +lowbit(ulong v) +{ + int s, i; + ulong m; + + s = 0; + m = 0xFFFFFFFFUL; + for(i = 16; i > 0; i >>= 1) { + m >>= i; + if((v & m) == 0) { + v >>= i; + s += i; + } + } + return s; +} + +void +genmuladd(Node *d, Node *s, int m, Node *a) +{ + Node nod; + + nod.op = OINDEX; + nod.left = a; + nod.right = s; + nod.scale = m; + nod.type = types[TIND]; + nod.xoffset = 0; + xcom(&nod); + gopcode(OADDR, d->type, &nod, d); +} + +void +mulparam(ulong m, Mparam *mp) +{ + int c, i, j, n, o, q, s; + int bc, bi, bn, bo, bq, bs, bt; + char *p; + long u; + ulong t; + + bc = bq = 10; + bi = bn = bo = bs = bt = 0; + for(i = 0; i < nelem(malgs); i++) { + for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++) + for(s = 0; s < 2; s++) { + c = 10; + q = 10; + u = m - o; + if(u == 0) + continue; + if(s) { + o = -o; + if(o > 0) + continue; + u = -u; + } + n = lowbit(u); + t = (ulong)u >> n; + switch(i) { + case 0: + if(t == 1) { + c = s + 1; + q = 0; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = s + 1; + if(n) + c++; + q = 0; + break; + } + if(s) + break; + switch(t) { + case 15: + case 25: + case 27: + case 45: + case 81: + c = 2; + if(n) + c++; + q = 1; + break; + } + break; + case 1: + if(t == 1) { + c = 3; + q = 3; + break; + } + switch(t) { + case 3: + case 5: + case 9: + c = 3; + q = 2; + break; + } + break; + case 2: + if(t == 1) { + c = 3; + q = 2; + break; + } + break; + case 3: + if(s) + break; + if(t == 1) { + c = 3; + q = 1; + break; + } + break; + case 4: + if(t == 1) { + c = 3; + q = 0; + break; + } + break; + } + if(c < bc || (c == bc && q > bq)) { + bc = c; + bi = i; + bn = n; + bo = o; + bq = q; + bs = s; + bt = t; + } + } + } + mp->value = m; + if(bc <= 3) { + mp->alg = bi; + mp->shift = bn; + mp->off = bo; + mp->neg = bs; + mp->arg = bt; + } + else + mp->alg = -1; +} + +int +m0(int a) +{ + switch(a) { + case -2: + case 2: + return 2; + case -3: + case 3: + return 2; + case -4: + case 4: + return 4; + case -5: + case 5: + return 4; + case 6: + return 2; + case -8: + case 8: + return 8; + case -9: + case 9: + return 8; + case 10: + return 4; + case 12: + return 2; + case 15: + return 2; + case 18: + return 8; + case 20: + return 4; + case 24: + return 2; + case 25: + return 4; + case 27: + return 2; + case 36: + return 8; + case 40: + return 4; + case 45: + return 4; + case 72: + return 8; + case 81: + return 8; + } + diag(Z, "bad m0"); + return 0; +} + +int +m1(int a) +{ + switch(a) { + case 15: + return 4; + case 25: + return 4; + case 27: + return 8; + case 45: + return 8; + case 81: + return 8; + } + diag(Z, "bad m1"); + return 0; +} + +int +m2(int a) +{ + switch(a) { + case 6: + return 2; + case 10: + return 2; + case 12: + return 4; + case 18: + return 2; + case 20: + return 4; + case 24: + return 8; + case 36: + return 4; + case 40: + return 8; + case 72: + return 8; + } + diag(Z, "bad m2"); + return 0; +} + +void +shiftit(Type *t, Node *s, Node *d) +{ + long c; + + c = (long)s->vconst & 31; + switch(c) { + case 0: + break; + case 1: + gopcode(OADD, t, d, d); + break; + default: + gopcode(OASHL, t, s, d); + } +} + +static int +mulgen1(ulong v, Node *n) +{ + int i, o; + Mparam *p; + Node nod, nods; + + for(i = 0; i < nelem(multab); i++) { + p = &multab[i]; + if(p->value == v) + goto found; + } + + p = &multab[mulptr]; + if(++mulptr == nelem(multab)) + mulptr = 0; + + mulparam(v, p); + +found: +// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off); + if(p->alg < 0) + return 0; + + nods = *nodconst(p->shift); + + o = OADD; + if(p->alg > 0) { + regalloc(&nod, n, Z); + if(p->off < 0) + o = OSUB; + } + + switch(p->alg) { + case 0: + switch(p->arg) { + case 1: + shiftit(n->type, &nods, n); + break; + case 15: + case 25: + case 27: + case 45: + case 81: + genmuladd(n, n, m1(p->arg), n); + /* fall thru */ + case 3: + case 5: + case 9: + genmuladd(n, n, m0(p->arg), n); + shiftit(n->type, &nods, n); + break; + default: + goto bad; + } + if(p->neg == 1) + gins(ANEGL, Z, n); + break; + case 1: + switch(p->arg) { + case 1: + gmove(n, &nod); + shiftit(n->type, &nods, &nod); + break; + case 3: + case 5: + case 9: + genmuladd(&nod, n, m0(p->arg), n); + shiftit(n->type, &nods, &nod); + break; + default: + goto bad; + } + if(p->neg) + gopcode(o, n->type, &nod, n); + else { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + break; + case 2: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + goto comop; + case 3: + genmuladd(&nod, n, m0(p->off), n); + shiftit(n->type, &nods, n); + genmuladd(n, &nod, m2(p->off), n); + break; + case 4: + genmuladd(&nod, n, m0(p->off), nodconst(0)); + shiftit(n->type, &nods, n); + goto comop; + default: + diag(Z, "bad mul alg"); + break; + comop: + if(p->neg) { + gopcode(o, n->type, n, &nod); + gmove(&nod, n); + } + else + gopcode(o, n->type, &nod, n); + } + + if(p->alg > 0) + regfree(&nod); + + return 1; + +bad: + diag(Z, "mulgen botch"); + return 1; +} + +void +mulgen(Type *t, Node *r, Node *n) +{ + if(!mulgen1(r->vconst, n)) + gopcode(OMUL, t, r, n); +} diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c new file mode 100644 index 000000000..b30a57b0a --- /dev/null +++ b/src/cmd/8c/peep.c @@ -0,0 +1,787 @@ +// Inferno utils/8c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.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" + +static int +needc(Prog *p) +{ + while(p != P) { + switch(p->as) { + case AADCL: + case ASBBL: + case ARCRL: + return 1; + case AADDL: + case ASUBL: + case AJMP: + case ARET: + case ACALL: + return 0; + default: + if(p->to.type == D_BRANCH) + return 0; + } + p = p->link; + } + return 0; +} + +void +peep(void) +{ + Reg *r, *r1, *r2; + Prog *p, *p1; + int t; + + /* + * complete R structure + */ + t = 0; + for(r=firstr; r!=R; r=r1) { + r1 = r->link; + if(r1 == R) + break; + p = r->prog->link; + while(p != r1->prog) + switch(p->as) { + default: + r2 = rega(); + r->link = r2; + r2->link = r1; + + r2->prog = p; + r2->p1 = r; + r->s1 = r2; + r2->s1 = r1; + r1->p1 = r2; + + r = r2; + t++; + + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + p = p->link; + } + } + + pc = 0; /* speculating it won't kill */ + +loop1: + + t = 0; + for(r=firstr; r!=R; r=r->link) { + p = r->prog; + switch(p->as) { + case AMOVL: + if(regtyp(&p->to)) + if(regtyp(&p->from)) { + if(copyprop(r)) { + excise(r); + t++; + } + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + break; + + case AMOVBLSX: + case AMOVBLZX: + case AMOVWLSX: + case AMOVWLZX: + if(regtyp(&p->to)) { + r1 = uniqs(r); + if(r1 != R) { + p1 = r1->prog; + if(p->as == p1->as && p->to.type == p1->from.type) + p1->as = AMOVL; + } + } + break; + case AADDL: + case AADDW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1){ + if(p->as == AADDL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == AADDL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + break; + case ASUBL: + case ASUBW: + if(p->from.type != D_CONST || needc(p->link)) + break; + if(p->from.offset == -1) { + if(p->as == ASUBL) + p->as = AINCL; + else + p->as = AINCW; + p->from = zprog.from; + } + else if(p->from.offset == 1){ + if(p->as == ASUBL) + p->as = ADECL; + else + p->as = ADECW; + p->from = zprog.from; + } + break; + } + } + if(t) + goto loop1; +} + +void +excise(Reg *r) +{ + Prog *p; + + p = r->prog; + p->as = ANOP; + p->from = zprog.from; + p->to = zprog.to; +} + +Reg* +uniqp(Reg *r) +{ + Reg *r1; + + r1 = r->p1; + if(r1 == R) { + r1 = r->p2; + if(r1 == R || r1->p2link != R) + return R; + } else + if(r->p2 != R) + return R; + return r1; +} + +Reg* +uniqs(Reg *r) +{ + Reg *r1; + + r1 = r->s1; + if(r1 == R) { + r1 = r->s2; + if(r1 == R) + return R; + } else + if(r->s2 != R) + return R; + return r1; +} + +int +regtyp(Adr *a) +{ + int t; + + t = a->type; + if(t >= D_AX && t <= D_DI) + return 1; + return 0; +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +int +subprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + int t; + + p = r0->prog; + v1 = &p->from; + if(!regtyp(v1)) + return 0; + v2 = &p->to; + if(!regtyp(v2)) + return 0; + for(r=uniqp(r0); r!=R; r=uniqp(r)) { + if(uniqs(r) == R) + break; + p = r->prog; + switch(p->as) { + case ACALL: + return 0; + + case AIMULL: + case AIMULW: + if(p->to.type != D_NONE) + break; + + case ADIVB: + case ADIVL: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULW: + + case AROLB: + case AROLL: + case AROLW: + case ARORB: + case ARORL: + case ARORW: + case ASALB: + case ASALL: + case ASALW: + case ASARB: + case ASARL: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRW: + + case AREP: + case AREPN: + + case ACWD: + case ACDQ: + + case AMOVSL: + case AFSTSW: + return 0; + + case AMOVL: + if(p->to.type == v1->type) + goto gotit; + break; + } + if(copyau(&p->from, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->type; + v1->type = v2->type; + v2->type = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +int +copyprop(Reg *r0) +{ + Prog *p; + Adr *v1, *v2; + Reg *r; + + p = r0->prog; + v1 = &p->from; + v2 = &p->to; + if(copyas(v1, v2)) + return 1; + for(r=firstr; r!=R; r=r->link) + r->active = 0; + return copy1(v1, v2, r0->s1, 0); +} + +int +copy1(Adr *v1, Adr *v2, Reg *r, int f) +{ + int t; + Prog *p; + + if(r->active) { + if(debug['P']) + print("act set; return 1\n"); + return 1; + } + r->active = 1; + if(debug['P']) + print("copy %D->%D f=%d\n", v1, v2, f); + for(; r != R; r = r->s1) { + p = r->prog; + if(debug['P']) + print("%P", p); + if(!f && uniqp(r) == R) { + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(p, v2, A); + switch(t) { + case 2: /* rar, cant split */ + if(debug['P']) + print("; %D rar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %D set; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %D used+set and f=%d; return 0\n", v2, f); + else + print("; %D used and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub %D/%D", v2, v1); + if(t == 4) { + if(debug['P']) + print("; %D used+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, A); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %D set and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +int +copyu(Prog *p, Adr *v, Adr *s) +{ + + switch(p->as) { + + default: + if(debug['P']) + print("unknown op %A\n", p->as); + return 2; + + case ANEGB: + case ANEGW: + case ANEGL: + case ANOTB: + case ANOTW: + case ANOTL: + if(copyas(&p->to, v)) + return 2; + break; + + case ALEAL: /* lhs addr, rhs store */ + if(copyas(&p->from, v)) + return 2; + + + case ANOP: /* rhs store */ + case AMOVL: + case AMOVBLSX: + case AMOVBLZX: + case AMOVWLSX: + case AMOVWLZX: + if(copyas(&p->to, v)) { + if(s != A) + return copysub(&p->from, v, s, 1); + if(copyau(&p->from, v)) + return 4; + return 3; + } + goto caseread; + + case AROLB: + case AROLL: + case AROLW: + case ARORB: + case ARORL: + case ARORW: + case ASALB: + case ASALL: + case ASALW: + case ASARB: + case ASARL: + case ASARW: + case ASHLB: + case ASHLL: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRW: + if(copyas(&p->to, v)) + return 2; + if(copyas(&p->from, v)) + if(p->from.type == D_CX) + return 2; + goto caseread; + + case AADDB: /* rhs rar */ + case AADDL: + case AADDW: + case AANDB: + case AANDL: + case AANDW: + case ADECL: + case ADECW: + case AINCL: + case AINCW: + case ASUBB: + case ASUBL: + case ASUBW: + case AORB: + case AORL: + case AORW: + case AXORB: + case AXORL: + case AXORW: + case AMOVB: + case AMOVW: + + case AFMOVB: + case AFMOVBP: + case AFMOVD: + case AFMOVDP: + case AFMOVF: + case AFMOVFP: + case AFMOVL: + case AFMOVLP: + case AFMOVV: + case AFMOVVP: + case AFMOVW: + case AFMOVWP: + case AFMOVX: + case AFMOVXP: + case AFADDDP: + case AFADDW: + case AFADDL: + case AFADDF: + case AFADDD: + case AFMULDP: + case AFMULW: + case AFMULL: + case AFMULF: + case AFMULD: + case AFSUBDP: + case AFSUBW: + case AFSUBL: + case AFSUBF: + case AFSUBD: + case AFSUBRDP: + case AFSUBRW: + case AFSUBRL: + case AFSUBRF: + case AFSUBRD: + case AFDIVDP: + case AFDIVW: + case AFDIVL: + case AFDIVF: + case AFDIVD: + case AFDIVRDP: + case AFDIVRW: + case AFDIVRL: + case AFDIVRF: + case AFDIVRD: + if(copyas(&p->to, v)) + return 2; + goto caseread; + + case ACMPL: /* read only */ + case ACMPW: + case ACMPB: + + case AFCOMB: + case AFCOMBP: + case AFCOMD: + case AFCOMDP: + case AFCOMDPP: + case AFCOMF: + case AFCOMFP: + case AFCOML: + case AFCOMLP: + case AFCOMW: + case AFCOMWP: + case AFUCOM: + case AFUCOMP: + case AFUCOMPP: + caseread: + if(s != A) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub(&p->to, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + break; + + case AJGE: /* no reference */ + case AJNE: + case AJLE: + case AJEQ: + case AJHI: + case AJLS: + case AJMI: + case AJPL: + case AJGT: + case AJLT: + case AJCC: + case AJCS: + + case AADJSP: + case AFLDZ: + case AWAIT: + break; + + case AIMULL: + case AIMULW: + if(p->to.type != D_NONE) { + if(copyas(&p->to, v)) + return 2; + goto caseread; + } + + case ADIVB: + case ADIVL: + case ADIVW: + case AIDIVB: + case AIDIVL: + case AIDIVW: + case AIMULB: + case AMULB: + case AMULL: + case AMULW: + + case ACWD: + case ACDQ: + if(v->type == D_AX || v->type == D_DX) + return 2; + goto caseread; + + case AMOVSL: + case AREP: + case AREPN: + if(v->type == D_CX || v->type == D_DI || v->type == D_SI) + return 2; + goto caseread; + + case AFSTSW: + if(v->type == D_AX) + return 2; + goto caseread; + + case AJMP: /* funny */ + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 1; + return 0; + + case ARET: /* funny */ + if(v->type == REGRET) + return 2; + if(s != A) + return 1; + return 3; + + case ACALL: /* funny */ + if(REGARG && v->type == REGARG) + return 2; + + if(s != A) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 4; + return 3; + } + return 0; +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +int +copyas(Adr *a, Adr *v) +{ + if(a->type != v->type) + return 0; + if(regtyp(v)) + return 1; + if(v->type == D_AUTO || v->type == D_PARAM) + if(v->offset == a->offset) + return 1; + return 0; +} + +/* + * either direct or indirect + */ +int +copyau(Adr *a, Adr *v) +{ + + if(copyas(a, v)) + return 1; + if(regtyp(v)) { + if(a->type-D_INDIR == v->type) + return 1; + if(a->index == v->type) + return 1; + } + return 0; +} + +/* + * substitute s for v in a + * return failure to substitute + */ +int +copysub(Adr *a, Adr *v, Adr *s, int f) +{ + int t; + + if(copyas(a, v)) { + t = s->type; + if(t >= D_AX && t <= D_DI) { + if(f) + a->type = t; + } + return 0; + } + if(regtyp(v)) { + t = v->type; + if(a->type == t+D_INDIR) { + if(s->type == D_BP && a->index != D_NONE) + return 1; /* can't use BP-base with index */ + if(f) + a->type = s->type+D_INDIR; +// return 0; + } + if(a->index == t) { + if(f) + a->index = s->type; + return 0; + } + return 0; + } + return 0; +} diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c new file mode 100644 index 000000000..94b41534e --- /dev/null +++ b/src/cmd/8c/reg.c @@ -0,0 +1,1285 @@ +// Inferno utils/8c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.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" + +Reg* +rega(void) +{ + Reg *r; + + r = freer; + if(r == R) { + r = alloc(sizeof(*r)); + } else + freer = r->link; + + *r = zreg; + return r; +} + +int +rcmp(const void *a1, const void *a2) +{ + Rgn *p1, *p2; + int c1, c2; + + p1 = (Rgn*)a1; + p2 = (Rgn*)a2; + c1 = p2->cost; + c2 = p1->cost; + if(c1 -= c2) + return c1; + return p2->varno - p1->varno; +} + +void +regopt(Prog *p) +{ + Reg *r, *r1, *r2; + Prog *p1; + int i, z; + long initpc, val, npc; + ulong vreg; + Bits bit; + struct + { + long m; + long c; + Reg* p; + } log5[6], *lp; + + firstr = R; + lastr = R; + nvar = 0; + regbits = RtoB(D_SP) | RtoB(D_AX); + for(z=0; z<BITS; z++) { + externs.b[z] = 0; + params.b[z] = 0; + consts.b[z] = 0; + addrs.b[z] = 0; + } + + /* + * pass 1 + * build aux data structure + * allocate pcs + * find use and set of variables + */ + val = 5L * 5L * 5L * 5L * 5L; + lp = log5; + for(i=0; i<5; i++) { + lp->m = val; + lp->c = 0; + lp->p = R; + val /= 5L; + lp++; + } + val = 0; + for(; p != P; p = p->link) { + switch(p->as) { + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + continue; + } + r = rega(); + if(firstr == R) { + firstr = r; + lastr = r; + } else { + lastr->link = r; + r->p1 = lastr; + lastr->s1 = r; + lastr = r; + } + r->prog = p; + r->pc = val; + val++; + + lp = log5; + for(i=0; i<5; i++) { + lp->c--; + if(lp->c <= 0) { + lp->c = lp->m; + if(lp->p != R) + lp->p->log5 = r; + lp->p = r; + (lp+1)->c = 0; + break; + } + lp++; + } + + r1 = r->p1; + if(r1 != R) + switch(r1->prog->as) { + case ARET: + case AJMP: + case AIRETL: + r->p1 = R; + r1->s1 = R; + } + + bit = mkvar(r, &p->from); + if(bany(&bit)) + switch(p->as) { + /* + * funny + */ + case ALEAL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + break; + + /* + * left side read + */ + default: + for(z=0; z<BITS; z++) + r->use1.b[z] |= bit.b[z]; + break; + } + + bit = mkvar(r, &p->to); + if(bany(&bit)) + switch(p->as) { + default: + diag(Z, "reg: unknown op: %A", p->as); + break; + + /* + * right side read + */ + case ACMPB: + case ACMPL: + case ACMPW: + for(z=0; z<BITS; z++) + r->use2.b[z] |= bit.b[z]; + break; + + /* + * right side write + */ + case ANOP: + case AMOVL: + case AMOVB: + case AMOVW: + case AMOVBLSX: + case AMOVBLZX: + case AMOVWLSX: + case AMOVWLZX: + for(z=0; z<BITS; z++) + r->set.b[z] |= bit.b[z]; + break; + + /* + * right side read+write + */ + case AADDB: + case AADDL: + case AADDW: + case AANDB: + case AANDL: + case AANDW: + case ASUBB: + case ASUBL: + case ASUBW: + case AORB: + case AORL: + case AORW: + case AXORB: + case AXORL: + case AXORW: + case ASALB: + case ASALL: + case ASALW: + case ASARB: + case ASARL: + case ASARW: + case AROLB: + case AROLL: + case AROLW: + case ARORB: + case ARORL: + case ARORW: + case ASHLB: + case ASHLL: + case ASHLW: + case ASHRB: + case ASHRL: + case ASHRW: + case AIMULL: + case AIMULW: + case ANEGL: + case ANOTL: + case AADCL: + case ASBBL: + for(z=0; z<BITS; z++) { + r->set.b[z] |= bit.b[z]; + r->use2.b[z] |= bit.b[z]; + } + break; + + /* + * funny + */ + case AFMOVDP: + case AFMOVFP: + case AFMOVVP: + case ACALL: + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + break; + } + + switch(p->as) { + case AIMULL: + case AIMULW: + if(p->to.type != D_NONE) + break; + + case AIDIVB: + case AIDIVL: + case AIDIVW: + case AIMULB: + case ADIVB: + case ADIVL: + case ADIVW: + case AMULB: + case AMULL: + case AMULW: + + case ACWD: + case ACDQ: + r->regu |= RtoB(D_AX) | RtoB(D_DX); + break; + + case AREP: + case AREPN: + case ALOOP: + case ALOOPEQ: + case ALOOPNE: + r->regu |= RtoB(D_CX); + break; + + case AMOVSB: + case AMOVSL: + case AMOVSW: + case ACMPSB: + case ACMPSL: + case ACMPSW: + r->regu |= RtoB(D_SI) | RtoB(D_DI); + break; + + case ASTOSB: + case ASTOSL: + case ASTOSW: + case ASCASB: + case ASCASL: + case ASCASW: + r->regu |= RtoB(D_AX) | RtoB(D_DI); + break; + + case AINSB: + case AINSL: + case AINSW: + case AOUTSB: + case AOUTSL: + case AOUTSW: + r->regu |= RtoB(D_DI) | RtoB(D_DX); + break; + + case AFSTSW: + case ASAHF: + r->regu |= RtoB(D_AX); + break; + } + } + if(firstr == R) + return; + initpc = pc - val; + npc = val; + + /* + * pass 2 + * turn branch references to pointers + * build back pointers + */ + for(r = firstr; r != R; r = r->link) { + p = r->prog; + if(p->to.type == D_BRANCH) { + val = p->to.offset - initpc; + r1 = firstr; + while(r1 != R) { + r2 = r1->log5; + if(r2 != R && val >= r2->pc) { + r1 = r2; + continue; + } + if(r1->pc == val) + break; + r1 = r1->link; + } + if(r1 == R) { + nearln = p->lineno; + diag(Z, "ref not found\n%P", p); + continue; + } + if(r1 == r) { + nearln = p->lineno; + diag(Z, "ref to self\n%P", p); + continue; + } + r->s2 = r1; + r->p2link = r1->p2; + r1->p2 = r; + } + } + if(debug['R']) { + p = firstr->prog; + print("\n%L %D\n", p->lineno, &p->from); + } + + /* + * pass 2.5 + * find looping structure + */ + for(r = firstr; r != R; r = r->link) + r->active = 0; + change = 0; + loopit(firstr, npc); + if(debug['R'] && debug['v']) { + print("\nlooping structure:\n"); + for(r = firstr; r != R; r = r->link) { + print("%ld:%P", r->loop, r->prog); + for(z=0; z<BITS; z++) + bit.b[z] = r->use1.b[z] | + r->use2.b[z] | + r->set.b[z]; + if(bany(&bit)) { + print("\t"); + if(bany(&r->use1)) + print(" u1=%B", r->use1); + if(bany(&r->use2)) + print(" u2=%B", r->use2); + if(bany(&r->set)) + print(" st=%B", r->set); + } + print("\n"); + } + } + + /* + * pass 3 + * iterate propagating usage + * back until flow graph is complete + */ +loop1: + change = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + for(r = firstr; r != R; r = r->link) + if(r->prog->as == ARET) + prop(r, zbits, zbits); +loop11: + /* pick up unreachable code */ + i = 0; + for(r = firstr; r != R; r = r1) { + r1 = r->link; + if(r1 && r1->active && !r->active) { + prop(r, zbits, zbits); + i = 1; + } + } + if(i) + goto loop11; + if(change) + goto loop1; + + + /* + * pass 4 + * iterate propagating register/variable synchrony + * forward until graph is complete + */ +loop2: + change = 0; + for(r = firstr; r != R; r = r->link) + r->active = 0; + synch(firstr, zbits); + if(change) + goto loop2; + + + /* + * pass 5 + * isolate regions + * calculate costs (paint1) + */ + r = firstr; + if(r) { + for(z=0; z<BITS; z++) + bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & + ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); + if(bany(&bit)) { + nearln = r->prog->lineno; + warn(Z, "used and not set: %B", bit); + if(debug['R'] && !debug['w']) + print("used and not set: %B\n", bit); + } + } + if(debug['R'] && debug['v']) + print("\nprop structure:\n"); + for(r = firstr; r != R; r = r->link) + r->act = zbits; + rgp = region; + nregion = 0; + for(r = firstr; r != R; r = r->link) { + if(debug['R'] && debug['v']) { + print("%P\t", r->prog); + if(bany(&r->set)) + print("s:%B ", r->set); + if(bany(&r->refahead)) + print("ra:%B ", r->refahead); + if(bany(&r->calahead)) + print("ca:%B ", r->calahead); + print("\n"); + } + for(z=0; z<BITS; z++) + bit.b[z] = r->set.b[z] & + ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); + if(bany(&bit)) { + nearln = r->prog->lineno; + warn(Z, "set and not used: %B", bit); + if(debug['R']) + print("set and not used: %B\n", bit); + excise(r); + } + for(z=0; z<BITS; z++) + bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); + while(bany(&bit)) { + i = bnum(bit); + rgp->enter = r; + rgp->varno = i; + change = 0; + if(debug['R'] && debug['v']) + print("\n"); + paint1(r, i); + bit.b[i/32] &= ~(1L<<(i%32)); + if(change <= 0) { + if(debug['R']) + print("%L$%d: %B\n", + r->prog->lineno, change, blsh(i)); + continue; + } + rgp->cost = change; + nregion++; + if(nregion >= NRGN) { + warn(Z, "too many regions"); + goto brk; + } + rgp++; + } + } +brk: + qsort(region, nregion, sizeof(region[0]), rcmp); + + /* + * pass 6 + * determine used registers (paint2) + * replace code (paint3) + */ + rgp = region; + for(i=0; i<nregion; i++) { + bit = blsh(rgp->varno); + vreg = paint2(rgp->enter, rgp->varno); + vreg = allreg(vreg, rgp); + if(debug['R']) { + print("%L$%d %R: %B\n", + rgp->enter->prog->lineno, + rgp->cost, + rgp->regno, + bit); + } + if(rgp->regno != 0) + paint3(rgp->enter, rgp->varno, vreg, rgp->regno); + rgp++; + } + /* + * pass 7 + * peep-hole on basic block + */ + if(!debug['R'] || debug['P']) + peep(); + + /* + * pass 8 + * recalculate pc + */ + val = initpc; + for(r = firstr; r != R; r = r1) { + r->pc = val; + p = r->prog; + p1 = P; + r1 = r->link; + if(r1 != R) + p1 = r1->prog; + for(; p != p1; p = p->link) { + switch(p->as) { + default: + val++; + break; + + case ANOP: + case ADATA: + case AGLOBL: + case ANAME: + case ASIGNAME: + break; + } + } + } + pc = val; + + /* + * fix up branches + */ + if(debug['R']) + if(bany(&addrs)) + print("addrs: %B\n", addrs); + + r1 = 0; /* set */ + for(r = firstr; r != R; r = r->link) { + p = r->prog; + if(p->to.type == D_BRANCH) + p->to.offset = r->s2->pc; + r1 = r; + } + + /* + * last pass + * eliminate nops + * free aux structures + */ + for(p = firstr->prog; p != P; p = p->link){ + while(p->link && p->link->as == ANOP) + p->link = p->link->link; + } + if(r1 != R) { + r1->link = freer; + freer = firstr; + } +} + +/* + * add mov b,rn + * just after r + */ +void +addmove(Reg *r, int bn, int rn, int f) +{ + Prog *p, *p1; + Adr *a; + Var *v; + + p1 = alloc(sizeof(*p1)); + *p1 = zprog; + p = r->prog; + + p1->link = p->link; + p->link = p1; + p1->lineno = p->lineno; + + v = var + bn; + + a = &p1->to; + a->sym = v->sym; + a->offset = v->offset; + a->etype = v->etype; + a->type = v->name; + + p1->as = AMOVL; + if(v->etype == TCHAR || v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TSHORT || v->etype == TUSHORT) + p1->as = AMOVW; + + p1->from.type = rn; + if(!f) { + p1->from = *a; + *a = zprog.from; + a->type = rn; + if(v->etype == TUCHAR) + p1->as = AMOVB; + if(v->etype == TUSHORT) + p1->as = AMOVW; + } + if(debug['R']) + print("%P\t.a%P\n", p, p1); +} + +ulong +doregbits(int r) +{ + ulong b; + + b = 0; + if(r >= D_INDIR) + r -= D_INDIR; + if(r >= D_AX && r <= D_DI) + b |= RtoB(r); + else + if(r >= D_AL && r <= D_BL) + b |= RtoB(r-D_AL+D_AX); + else + if(r >= D_AH && r <= D_BH) + b |= RtoB(r-D_AH+D_AX); + return b; +} + +Bits +mkvar(Reg *r, Adr *a) +{ + Var *v; + int i, t, n, et, z; + long o; + Bits bit; + Sym *s; + + /* + * mark registers used + */ + t = a->type; + r->regu |= doregbits(t); + r->regu |= doregbits(a->index); + + switch(t) { + default: + goto none; + case D_ADDR: + a->type = a->index; + bit = mkvar(r, a); + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + a->type = t; + goto none; + case D_EXTERN: + case D_STATIC: + case D_PARAM: + case D_AUTO: + n = t; + break; + } + s = a->sym; + if(s == S) + goto none; + if(s->name[0] == '.') + goto none; + et = a->etype; + o = a->offset; + v = var; + for(i=0; i<nvar; i++) { + if(s == v->sym) + if(n == v->name) + if(o == v->offset) + goto out; + v++; + } + if(nvar >= NVAR) { + if(debug['w'] > 1 && s) + warn(Z, "variable not optimized: %s", s->name); + goto none; + } + i = nvar; + nvar++; + v = &var[i]; + v->sym = s; + v->offset = o; + v->name = n; + v->etype = et; + if(debug['R']) + print("bit=%2d et=%2d %D\n", i, et, a); + +out: + bit = blsh(i); + if(n == D_EXTERN || n == D_STATIC) + for(z=0; z<BITS; z++) + externs.b[z] |= bit.b[z]; + if(n == D_PARAM) + for(z=0; z<BITS; z++) + params.b[z] |= bit.b[z]; + if(v->etype != et || !typechlpfd[et]) /* funny punning */ + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + return bit; + +none: + return zbits; +} + +void +prop(Reg *r, Bits ref, Bits cal) +{ + Reg *r1, *r2; + int z; + + for(r1 = r; r1 != R; r1 = r1->p1) { + for(z=0; z<BITS; z++) { + ref.b[z] |= r1->refahead.b[z]; + if(ref.b[z] != r1->refahead.b[z]) { + r1->refahead.b[z] = ref.b[z]; + change++; + } + cal.b[z] |= r1->calahead.b[z]; + if(cal.b[z] != r1->calahead.b[z]) { + r1->calahead.b[z] = cal.b[z]; + change++; + } + } + switch(r1->prog->as) { + case ACALL: + for(z=0; z<BITS; z++) { + cal.b[z] |= ref.b[z] | externs.b[z]; + ref.b[z] = 0; + } + break; + + case ATEXT: + for(z=0; z<BITS; z++) { + cal.b[z] = 0; + ref.b[z] = 0; + } + break; + + case ARET: + for(z=0; z<BITS; z++) { + cal.b[z] = externs.b[z]; + ref.b[z] = 0; + } + } + for(z=0; z<BITS; z++) { + ref.b[z] = (ref.b[z] & ~r1->set.b[z]) | + r1->use1.b[z] | r1->use2.b[z]; + cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]); + r1->refbehind.b[z] = ref.b[z]; + r1->calbehind.b[z] = cal.b[z]; + } + if(r1->active) + break; + r1->active = 1; + } + for(; r != r1; r = r->p1) + for(r2 = r->p2; r2 != R; r2 = r2->p2link) + prop(r2, r->refbehind, r->calbehind); +} + +/* + * find looping structure + * + * 1) find reverse postordering + * 2) find approximate dominators, + * the actual dominators if the flow graph is reducible + * otherwise, dominators plus some other non-dominators. + * See Matthew S. Hecht and Jeffrey D. Ullman, + * "Analysis of a Simple Algorithm for Global Data Flow Problems", + * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, + * Oct. 1-3, 1973, pp. 207-217. + * 3) find all nodes with a predecessor dominated by the current node. + * such a node is a loop head. + * recursively, all preds with a greater rpo number are in the loop + */ +long +postorder(Reg *r, Reg **rpo2r, long n) +{ + Reg *r1; + + r->rpo = 1; + r1 = r->s1; + if(r1 && !r1->rpo) + n = postorder(r1, rpo2r, n); + r1 = r->s2; + if(r1 && !r1->rpo) + n = postorder(r1, rpo2r, n); + rpo2r[n] = r; + n++; + return n; +} + +long +rpolca(long *idom, long rpo1, long rpo2) +{ + long t; + + if(rpo1 == -1) + return rpo2; + while(rpo1 != rpo2){ + if(rpo1 > rpo2){ + t = rpo2; + rpo2 = rpo1; + rpo1 = t; + } + while(rpo1 < rpo2){ + t = idom[rpo2]; + if(t >= rpo2) + fatal(Z, "bad idom"); + rpo2 = t; + } + } + return rpo1; +} + +int +doms(long *idom, long r, long s) +{ + while(s > r) + s = idom[s]; + return s == r; +} + +int +loophead(long *idom, Reg *r) +{ + long src; + + src = r->rpo; + if(r->p1 != R && doms(idom, src, r->p1->rpo)) + return 1; + for(r = r->p2; r != R; r = r->p2link) + if(doms(idom, src, r->rpo)) + return 1; + return 0; +} + +void +loopmark(Reg **rpo2r, long head, Reg *r) +{ + if(r->rpo < head || r->active == head) + return; + r->active = head; + r->loop += LOOP; + if(r->p1 != R) + loopmark(rpo2r, head, r->p1); + for(r = r->p2; r != R; r = r->p2link) + loopmark(rpo2r, head, r); +} + +void +loopit(Reg *r, long nr) +{ + Reg *r1; + long i, d, me; + + if(nr > maxnr) { + rpo2r = alloc(nr * sizeof(Reg*)); + idom = alloc(nr * sizeof(long)); + maxnr = nr; + } + + d = postorder(r, rpo2r, 0); + if(d > nr) + fatal(Z, "too many reg nodes"); + nr = d; + for(i = 0; i < nr / 2; i++){ + r1 = rpo2r[i]; + rpo2r[i] = rpo2r[nr - 1 - i]; + rpo2r[nr - 1 - i] = r1; + } + for(i = 0; i < nr; i++) + rpo2r[i]->rpo = i; + + idom[0] = 0; + for(i = 0; i < nr; i++){ + r1 = rpo2r[i]; + me = r1->rpo; + d = -1; + if(r1->p1 != R && r1->p1->rpo < me) + d = r1->p1->rpo; + for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) + if(r1->rpo < me) + d = rpolca(idom, d, r1->rpo); + idom[i] = d; + } + + for(i = 0; i < nr; i++){ + r1 = rpo2r[i]; + r1->loop++; + if(r1->p2 != R && loophead(idom, r1)) + loopmark(rpo2r, i, r1); + } +} + +void +synch(Reg *r, Bits dif) +{ + Reg *r1; + int z; + + for(r1 = r; r1 != R; r1 = r1->s1) { + for(z=0; z<BITS; z++) { + dif.b[z] = (dif.b[z] & + ~(~r1->refbehind.b[z] & r1->refahead.b[z])) | + r1->set.b[z] | r1->regdiff.b[z]; + if(dif.b[z] != r1->regdiff.b[z]) { + r1->regdiff.b[z] = dif.b[z]; + change++; + } + } + if(r1->active) + break; + r1->active = 1; + for(z=0; z<BITS; z++) + dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]); + if(r1->s2 != R) + synch(r1->s2, dif); + } +} + +ulong +allreg(ulong b, Rgn *r) +{ + Var *v; + int i; + + v = var + r->varno; + r->regno = 0; + switch(v->etype) { + + default: + diag(Z, "unknown etype %d/%d", bitno(b), v->etype); + break; + + case TCHAR: + case TUCHAR: + case TSHORT: + case TUSHORT: + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + case TARRAY: + i = BtoR(~b); + if(i && r->cost > 0) { + r->regno = i; + return RtoB(i); + } + break; + + case TDOUBLE: + case TFLOAT: + break; + } + return 0; +} + +void +paint1(Reg *r, int bn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L<<(bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { + change -= CLOAD * r->loop; + if(debug['R'] && debug['v']) + print("%ld%P\tld %B $%d\n", r->loop, + r->prog, blsh(bn), change); + } + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + change += CREF * r->loop; + if(p->as == AFMOVL) + if(BtoR(bb) != D_F0) + change = -CINF; + if(debug['R'] && debug['v']) + print("%ld%P\tu1 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if((r->use2.b[z]|r->set.b[z]) & bb) { + change += CREF * r->loop; + if(p->as == AFMOVL) + if(BtoR(bb) != D_F0) + change = -CINF; + if(debug['R'] && debug['v']) + print("%ld%P\tu2 %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(STORE(r) & r->regdiff.b[z] & bb) { + change -= CLOAD * r->loop; + if(p->as == AFMOVL) + if(BtoR(bb) != D_F0) + change = -CINF; + if(debug['R'] && debug['v']) + print("%ld%P\tst %B $%d\n", r->loop, + p, blsh(bn), change); + } + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint1(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint1(r1, bn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +ulong +regset(Reg *r, ulong bb) +{ + ulong b, set; + Adr v; + int c; + + set = 0; + v = zprog.from; + while(b = bb & ~(bb-1)) { + v.type = BtoR(b); + c = copyu(r->prog, &v, A); + if(c == 3) + set |= b; + bb &= ~b; + } + return set; +} + +ulong +reguse(Reg *r, ulong bb) +{ + ulong b, set; + Adr v; + int c; + + set = 0; + v = zprog.from; + while(b = bb & ~(bb-1)) { + v.type = BtoR(b); + c = copyu(r->prog, &v, A); + if(c == 1 || c == 2 || c == 4) + set |= b; + bb &= ~b; + } + return set; +} + +ulong +paint2(Reg *r, int bn) +{ + Reg *r1; + int z; + ulong bb, vreg, x; + + z = bn/32; + bb = 1L << (bn%32); + vreg = regbits; + if(!(r->act.b[z] & bb)) + return vreg; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(!(r1->act.b[z] & bb)) + break; + r = r1; + } + for(;;) { + r->act.b[z] &= ~bb; + + vreg |= r->regu; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + vreg |= paint2(r1, bn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + vreg |= paint2(r1, bn); + r = r->s1; + if(r == R) + break; + if(!(r->act.b[z] & bb)) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } + + bb = vreg; + for(; r; r=r->s1) { + x = r->regu & ~bb; + if(x) { + vreg |= reguse(r, x); + bb |= regset(r, x); + } + } + return vreg; +} + +void +paint3(Reg *r, int bn, long rb, int rn) +{ + Reg *r1; + Prog *p; + int z; + ulong bb; + + z = bn/32; + bb = 1L << (bn%32); + if(r->act.b[z] & bb) + return; + for(;;) { + if(!(r->refbehind.b[z] & bb)) + break; + r1 = r->p1; + if(r1 == R) + break; + if(!(r1->refahead.b[z] & bb)) + break; + if(r1->act.b[z] & bb) + break; + r = r1; + } + + if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) + addmove(r, bn, rn, 0); + for(;;) { + r->act.b[z] |= bb; + p = r->prog; + + if(r->use1.b[z] & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->from, rn); + if(debug['R']) + print("\t.c%P\n", p); + } + if((r->use2.b[z]|r->set.b[z]) & bb) { + if(debug['R']) + print("%P", p); + addreg(&p->to, rn); + if(debug['R']) + print("\t.c%P\n", p); + } + + if(STORE(r) & r->regdiff.b[z] & bb) + addmove(r, bn, rn, 1); + r->regu |= rb; + + if(r->refbehind.b[z] & bb) + for(r1 = r->p2; r1 != R; r1 = r1->p2link) + if(r1->refahead.b[z] & bb) + paint3(r1, bn, rb, rn); + + if(!(r->refahead.b[z] & bb)) + break; + r1 = r->s2; + if(r1 != R) + if(r1->refbehind.b[z] & bb) + paint3(r1, bn, rb, rn); + r = r->s1; + if(r == R) + break; + if(r->act.b[z] & bb) + break; + if(!(r->refbehind.b[z] & bb)) + break; + } +} + +void +addreg(Adr *a, int rn) +{ + + a->sym = 0; + a->offset = 0; + a->type = rn; +} + +long +RtoB(int r) +{ + + if(r < D_AX || r > D_DI) + return 0; + return 1L << (r-D_AX); +} + +int +BtoR(long b) +{ + + b &= 0xffL; + if(b == 0) + return 0; + return bitno(b) + D_AX; +} diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c new file mode 100644 index 000000000..d7f56d51c --- /dev/null +++ b/src/cmd/8c/sgen.c @@ -0,0 +1,872 @@ +// Inferno utils/8c/sgen.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.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 +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)); + + /* + * isolate first argument + */ + if(REGARG) { + if(typesuv[thisfn->link->etype]) { + nod1 = *nodret->left; + nodreg(&nod, &nod1, REGARG); + gmove(&nod, &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); + gmove(&nod, &nod1); + } + } + + sp = p; + 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); + if(thisfn && thisfn->link && typefd[thisfn->link->etype]) + gins(AFLDZ, Z, Z); + 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 f, o; + +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); + if(typefd[n->type->etype]) + gins(AFLDZ, Z, Z); + 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) +{ + + if(n & 1) { + gins(ANOP, Z, Z); + p->to.type = REGRET; + } + if(n & 2) { + gins(ANOP, Z, Z); + p->to.type = FREGRET; + } +} + +/* welcome to commute */ +static void +commute(Node *n) +{ + Node *l, *r; + + l = n->left; + r = n->right; + if(r->complex > l->complex) { + n->left = r; + n->right = l; + } +} + +void +indexshift(Node *n) +{ + int g; + + if(!typechlp[n->type->etype]) + return; + simplifyshift(n); + if(n->op == OASHL && n->right->op == OCONST){ + g = vconst(n->right); + if(g >= 0 && g < 4) + n->addable = 7; + } +} + +/* + * calculate addressability as follows + * NAME ==> 10/11 name+value(SB/SP) + * REGISTER ==> 12 register + * CONST ==> 20 $value + * *(20) ==> 21 value + * &(10) ==> 13 $name+value(SB) + * &(11) ==> 1 $name+value(SP) + * (13) + (20) ==> 13 fold constants + * (1) + (20) ==> 1 fold constants + * *(13) ==> 10 back to name + * *(1) ==> 11 back to name + * + * (20) * (X) ==> 7 multiplier in indexing + * (X,7) + (13,1) ==> 8 adder in indexing (addresses) + * (8) ==> &9(OINDEX) index, almost addressable + * + * calculate complexity (number of registers) + */ +void +xcom(Node *n) +{ + Node *l, *r; + int g; + + if(n == Z) + return; + l = n->left; + r = n->right; + n->complex = 0; + n->addable = 0; + switch(n->op) { + case OCONST: + n->addable = 20; + break; + + case ONAME: + n->addable = 10; + if(n->class == CPARAM || n->class == CAUTO) + n->addable = 11; + break; + + case OREGISTER: + n->addable = 12; + break; + + case OINDREG: + n->addable = 12; + break; + + case OADDR: + xcom(l); + if(l->addable == 10) + n->addable = 13; + else + if(l->addable == 11) + n->addable = 1; + break; + + case OADD: + xcom(l); + xcom(r); + if(n->type->etype != TIND) + break; + + switch(r->addable) { + case 20: + switch(l->addable) { + case 1: + case 13: + commadd: + l->type = n->type; + *n = *l; + l = new(0, Z, Z); + *l = *(n->left); + l->xoffset += r->vconst; + n->left = l; + r = n->right; + goto brk; + } + break; + + case 1: + case 13: + case 10: + case 11: + /* l is the base, r is the index */ + if(l->addable != 20) + n->addable = 8; + break; + } + switch(l->addable) { + case 20: + switch(r->addable) { + case 13: + case 1: + r = n->left; + l = n->right; + n->left = l; + n->right = r; + goto commadd; + } + break; + + case 13: + case 1: + case 10: + case 11: + /* r is the base, l is the index */ + if(r->addable != 20) + n->addable = 8; + break; + } + if(n->addable == 8 && !side(n)) { + indx(n); + l = new1(OINDEX, idx.basetree, idx.regtree); + l->scale = idx.scale; + l->addable = 9; + l->complex = l->right->complex; + l->type = l->left->type; + n->op = OADDR; + n->left = l; + n->right = Z; + n->addable = 8; + break; + } + break; + + case OINDEX: + xcom(l); + xcom(r); + n->addable = 9; + break; + + case OIND: + xcom(l); + if(l->op == OADDR) { + l = l->left; + l->type = n->type; + *n = *l; + return; + } + switch(l->addable) { + case 20: + n->addable = 21; + break; + case 1: + n->addable = 11; + break; + case 13: + n->addable = 10; + break; + } + break; + + case OASHL: + xcom(l); + xcom(r); + indexshift(n); + break; + + case OMUL: + case OLMUL: + xcom(l); + xcom(r); + g = vlog(l); + if(g >= 0) { + n->left = r; + n->right = l; + l = r; + r = n->right; + } + g = vlog(r); + if(g >= 0) { + n->op = OASHL; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } +commute(n); + break; + + case OASLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASLSHR; + r->vconst = g; + r->type = types[TINT]; + } + break; + + case OLDIV: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OLSHR; + r->vconst = g; + r->type = types[TINT]; + indexshift(n); + break; + } + break; + + case OASLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASAND; + r->vconst--; + } + break; + + case OLMOD: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OAND; + r->vconst--; + } + break; + + case OASMUL: + case OASLMUL: + xcom(l); + xcom(r); + g = vlog(r); + if(g >= 0) { + n->op = OASASHL; + r->vconst = g; + } + break; + + case OLSHR: + case OASHR: + xcom(l); + xcom(r); + indexshift(n); + break; + + default: + if(l != Z) + xcom(l); + if(r != Z) + xcom(r); + break; + } +brk: + if(n->addable >= 10) + return; + if(l != Z) + n->complex = l->complex; + if(r != Z) { + if(r->complex == n->complex) + n->complex = r->complex+1; + else + if(r->complex > n->complex) + n->complex = r->complex; + } + if(n->complex == 0) + n->complex++; + + if(com64(n)) + return; + + switch(n->op) { + + case OFUNC: + n->complex = FNX; + break; + + case OLMOD: + case OMOD: + case OLMUL: + case OLDIV: + case OMUL: + case ODIV: + case OASLMUL: + case OASLDIV: + case OASLMOD: + case OASMUL: + case OASDIV: + case OASMOD: + if(r->complex >= l->complex) { + n->complex = l->complex + 3; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 3; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OLSHR: + case OASHL: + case OASHR: + case OASLSHR: + case OASASHL: + case OASASHR: + if(r->complex >= l->complex) { + n->complex = l->complex + 2; + if(r->complex > n->complex) + n->complex = r->complex; + } else { + n->complex = r->complex + 2; + if(l->complex > n->complex) + n->complex = l->complex; + } + break; + + case OADD: + case OXOR: + case OAND: + case OOR: + /* + * immediate operators, make const on right + */ + if(l->op == OCONST) { + n->left = r; + n->right = l; + } + break; + + case OEQ: + case ONE: + case OLE: + case OLT: + case OGE: + case OGT: + case OHI: + case OHS: + case OLO: + case OLS: + /* + * compare operators, make const on left + */ + if(r->op == OCONST) { + n->left = r; + n->right = l; + n->op = invrel[relindex(n->op)]; + } + break; + } +} + +void +indx(Node *n) +{ + Node *l, *r; + + if(debug['x']) + prtree(n, "indx"); + + l = n->left; + r = n->right; + if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) { + n->right = l; + n->left = r; + l = r; + r = n->right; + } + if(l->addable != 7) { + idx.regtree = l; + idx.scale = 1; + } else + if(l->right->addable == 20) { + idx.regtree = l->left; + idx.scale = 1 << l->right->vconst; + } else + if(l->left->addable == 20) { + idx.regtree = l->right; + idx.scale = 1 << l->left->vconst; + } else + diag(n, "bad index"); + + idx.basetree = r; + if(debug['x']) { + print("scale = %d\n", idx.scale); + prtree(idx.regtree, "index"); + prtree(idx.basetree, "base"); + } +} + +int +bcomplex(Node *n, Node *c) +{ + Node *b, nod; + + 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; + if(typev[n->type->etype] && machcap(Z)) { + b = &nod; + b->op = ONE; + b->left = n; + b->right = new(0, Z, Z); + *b->right = *nodconst(0); + b->right->type = n->type; + b->type = types[TLONG]; + cgen64(b, Z); + return 0; + } + bool64(n); + boolgen(n, 1, Z); + } else + gbranch(OGOTO); + return 0; +} diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c new file mode 100644 index 000000000..63866d56e --- /dev/null +++ b/src/cmd/8c/swt.c @@ -0,0 +1,677 @@ +// Inferno utils/8c/swt.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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" + +int +swcmp(const void *a1, const void *a2) +{ + C1 *p1, *p2; + + p1 = (C1*)a1; + p2 = (C1*)a2; + if(p1->val < p2->val) + return -1; + return p1->val > p2->val; +} + +void +doswit(Node *n) +{ + Case *c; + C1 *q, *iq; + long def, nc, i; + + 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(debug['W']) + for(i=0; i<nc; i++) + print("case %2ld: = %.8lux\n", i, iq[i].val); + 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); + swit1(iq, nc, def, n); +} + +void +swit1(C1 *q, int nc, long def, Node *n) +{ + C1 *r; + int i; + Prog *sp; + + if(nc < 5) { + for(i=0; i<nc; i++) { + if(debug['W']) + print("case = %.8lux\n", q->val); + gopcode(OEQ, n->type, n, nodconst(q->val)); + patch(p, q->label); + q++; + } + gbranch(OGOTO); + patch(p, def); + return; + } + i = nc / 2; + r = q+i; + if(debug['W']) + print("case > %.8lux\n", r->val); + gopcode(OGT, n->type, n, nodconst(r->val)); + sp = p; + gbranch(OGOTO); + p->as = AJEQ; + patch(p, r->label); + swit1(q, i, def, n); + + if(debug['W']) + print("case < %.8lux\n", r->val); + patch(sp, pc); + swit1(r+1, nc-i-1, def, n); +} + +void +cas(void) +{ + Case *c; + + c = alloc(sizeof(*c)); + c->link = cases; + cases = c; +} + +void +bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + int sh; + long v; + Node *l; + + /* + * n1 gets adjusted/masked value + * n2 gets address of cell + * n3 gets contents of cell + */ + l = b->left; + if(n2 != Z) { + regalloc(n1, l, nn); + reglcgen(n2, l, Z); + regalloc(n3, l, Z); + gmove(n2, n3); + gmove(n3, n1); + } else { + regalloc(n1, l, nn); + cgen(l, n1); + } + if(b->type->shift == 0 && typeu[b->type->etype]) { + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, types[TLONG], nodconst(v), n1); + } else { + sh = 32 - b->type->shift - b->type->nbits; + if(sh > 0) + gopcode(OASHL, types[TLONG], nodconst(sh), n1); + sh += b->type->shift; + if(sh > 0) + if(typeu[b->type->etype]) + gopcode(OLSHR, types[TLONG], nodconst(sh), n1); + else + gopcode(OASHR, types[TLONG], nodconst(sh), n1); + } +} + +void +bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) +{ + long v; + Node nod; + int sh; + + regalloc(&nod, b->left, Z); + v = ~0 + (1L << b->type->nbits); + gopcode(OAND, types[TLONG], nodconst(v), n1); + gmove(n1, &nod); + if(nn != Z) + gmove(n1, nn); + sh = b->type->shift; + if(sh > 0) + gopcode(OASHL, types[TLONG], nodconst(sh), &nod); + v <<= sh; + gopcode(OAND, types[TLONG], nodconst(~v), n3); + gopcode(OOR, types[TLONG], n3, &nod); + gmove(&nod, n2); + + regfree(&nod); + regfree(n1); + regfree(n2); + regfree(n3); +} + +long +outstring(char *s, long n) +{ + long r; + + if(suppress) + return nstring; + r = nstring; + while(n) { + string[mnstring] = *s++; + mnstring++; + nstring++; + if(mnstring >= NSNAME) { + gpseudo(ADATA, symstring, nodconst(0L)); + p->from.offset += nstring - NSNAME; + p->from.scale = NSNAME; + p->to.type = D_SCONST; + memmove(p->to.sval, string, NSNAME); + mnstring = 0; + } + 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; +} + +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; + + for(e=0; e<w; e+=NSNAME) { + lw = NSNAME; + if(w-e < lw) + lw = w-e; + gpseudo(ADATA, s, nodconst(0L)); + p->from.offset += o+e; + p->from.scale = lw; + p->to.type = D_SCONST; + memmove(p->to.sval, a->cstring+e, lw); + } +} + +void +gextern(Sym *s, Node *a, long o, long w) +{ + if(a->op == OCONST && typev[a->type->etype]) { + gpseudo(ADATA, s, lo64(a)); + p->from.offset += o; + p->from.scale = 4; + gpseudo(ADATA, s, hi64(a)); + p->from.offset += o + 4; + p->from.scale = 4; + return; + } + gpseudo(ADATA, s, a); + p->from.offset += o; + p->from.scale = w; + switch(p->to.type) { + default: + p->to.index = p->to.type; + p->to.type = D_ADDR; + case D_CONST: + case D_FCONST: + case D_ADDR: + break; + } +} + +void zname(Biobuf*, Sym*, int); +void zaddr(Biobuf*, Adr*, int); +void outhist(Biobuf*); + +void +outcode(void) +{ + struct { Sym *sym; short type; } h[NSYM]; + Prog *p; + Sym *s; + int f, sf, st, t, sym; + Biobuf b; + + if(debug['S']) { + for(p = firstp; p != P; p = p->link) + if(p->as != ADATA && p->as != AGLOBL) + pc--; + for(p = firstp; p != P; p = p->link) { + print("%P\n", p); + if(p->as != ADATA && p->as != AGLOBL) + pc++; + } + } + f = open(outfile, OWRITE); + if(f < 0) { + diag(Z, "cannot open %s", outfile); + return; + } + Binit(&b, f, OWRITE); + Bseek(&b, 0L, 2); + outhist(&b); + for(sym=0; sym<NSYM; sym++) { + h[sym].sym = S; + h[sym].type = 0; + } + sym = 1; + for(p = firstp; p != P; p = p->link) { + jackpot: + sf = 0; + s = p->from.sym; + while(s != S) { + sf = s->sym; + if(sf < 0 || sf >= NSYM) + sf = 0; + t = p->from.type; + if(t == D_ADDR) + t = p->from.index; + if(h[sf].type == t) + if(h[sf].sym == s) + break; + s->sym = sym; + zname(&b, s, t); + h[sym].sym = s; + h[sym].type = t; + sf = sym; + sym++; + if(sym >= NSYM) + sym = 1; + break; + } + st = 0; + s = p->to.sym; + while(s != S) { + st = s->sym; + if(st < 0 || st >= NSYM) + st = 0; + t = p->to.type; + if(t == D_ADDR) + t = p->to.index; + if(h[st].type == t) + if(h[st].sym == s) + break; + s->sym = sym; + zname(&b, s, t); + h[sym].sym = s; + h[sym].type = t; + st = sym; + sym++; + if(sym >= NSYM) + sym = 1; + if(st == sf) + goto jackpot; + break; + } + Bputc(&b, p->as); + Bputc(&b, p->as>>8); + Bputc(&b, p->lineno); + Bputc(&b, p->lineno>>8); + Bputc(&b, p->lineno>>16); + Bputc(&b, p->lineno>>24); + zaddr(&b, &p->from, sf); + zaddr(&b, &p->to, st); + } + Bflush(&b); + close(f); + firstp = P; + lastp = P; +} + +void +outhist(Biobuf *b) +{ + Hist *h; + char *p, *q, *op, c; + Prog pg; + int n; + + pg = zprog; + pg.as = AHISTORY; + c = pathchar(); + for(h = hist; h != H; h = h->link) { + p = h->name; + op = 0; + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && p && p[1] == ':'){ + p += 2; + c = *p; + } + if(p && p[0] != c && h->offset == 0 && pathname){ + /* on windows skip drive specifier in pathname */ + if(systemtype(Windows) && pathname[1] == ':') { + op = p; + p = pathname+2; + c = *p; + } else if(pathname[0] == c){ + op = p; + p = pathname; + } + } + while(p) { + q = utfrune(p, c); + if(q) { + n = q-p; + if(n == 0){ + n = 1; /* leading "/" */ + *p = '/'; /* don't emit "\" on windows */ + } + q++; + } else { + n = strlen(p); + q = 0; + } + if(n) { + Bputc(b, ANAME); + Bputc(b, ANAME>>8); + Bputc(b, D_FILE); + Bputc(b, 1); + Bputc(b, '<'); + Bwrite(b, p, n); + Bputc(b, 0); + } + p = q; + if(p == 0 && op) { + p = op; + op = 0; + } + } + pg.lineno = h->line; + pg.to.type = zprog.to.type; + pg.to.offset = h->offset; + if(h->offset) + pg.to.type = D_CONST; + + Bputc(b, pg.as); + Bputc(b, pg.as>>8); + Bputc(b, pg.lineno); + Bputc(b, pg.lineno>>8); + Bputc(b, pg.lineno>>16); + Bputc(b, pg.lineno>>24); + zaddr(b, &pg.from, 0); + zaddr(b, &pg.to, 0); + } +} + +void +zname(Biobuf *b, Sym *s, int t) +{ + char *n; + ulong sig; + + if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){ + sig = sign(s); + Bputc(b, ASIGNAME); + Bputc(b, ASIGNAME>>8); + Bputc(b, sig); + Bputc(b, sig>>8); + Bputc(b, sig>>16); + Bputc(b, sig>>24); + s->sig = SIGDONE; + } + else{ + Bputc(b, ANAME); /* as */ + Bputc(b, ANAME>>8); /* as */ + } + Bputc(b, t); /* type */ + Bputc(b, s->sym); /* sym */ + n = s->name; + while(*n) { + Bputc(b, *n); + n++; + } + Bputc(b, 0); +} + +void +zaddr(Biobuf *b, Adr *a, int s) +{ + long l; + int i, t; + char *n; + Ieee e; + + t = 0; + if(a->index != D_NONE || a->scale != 0) + t |= T_INDEX; + if(s != 0) + t |= T_SYM; + + switch(a->type) { + default: + t |= T_TYPE; + case D_NONE: + if(a->offset != 0) + t |= T_OFFSET; + break; + case D_FCONST: + t |= T_FCONST; + break; + case D_SCONST: + t |= T_SCONST; + break; + } + Bputc(b, t); + + if(t & T_INDEX) { /* implies index, scale */ + Bputc(b, a->index); + Bputc(b, a->scale); + } + if(t & T_OFFSET) { /* implies offset */ + l = a->offset; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + } + if(t & T_SYM) /* implies sym */ + Bputc(b, s); + if(t & T_FCONST) { + ieeedtod(&e, a->dval); + l = e.l; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + l = e.h; + Bputc(b, l); + Bputc(b, l>>8); + Bputc(b, l>>16); + Bputc(b, l>>24); + return; + } + if(t & T_SCONST) { + n = a->sval; + for(i=0; i<NSNAME; i++) { + Bputc(b, *n); + n++; + } + return; + } + if(t & T_TYPE) + Bputc(b, a->type); +} + +void +ieeedtod(Ieee *ieee, double native) +{ + double fr, ho, f; + int exp; + + if(native < 0) { + ieeedtod(ieee, -native); + ieee->h |= 0x80000000L; + return; + } + if(native == 0) { + ieee->l = 0; + ieee->h = 0; + return; + } + 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); +} + +long +align(long i, Type *t, int op) +{ + long o; + Type *v; + int w; + + o = i; + w = 1; + switch(op) { + default: + diag(Z, "unknown align opcode %d", op); + break; + + case Asu2: /* padding at end of a struct */ + w = SZ_LONG; + if(packflg) + w = packflg; + break; + + case Ael1: /* initial allign of struct element */ + for(v=t; v->etype==TARRAY; v=v->link) + ; + w = ewidth[v->etype]; + if(w <= 0 || w >= SZ_LONG) + w = SZ_LONG; + if(packflg) + w = packflg; + break; + + case Ael2: /* width of a struct element */ + o += t->width; + break; + + case Aarg0: /* initial passbyptr argument in arg list */ + if(typesuv[t->etype]) { + o = align(o, types[TIND], Aarg1); + o = align(o, types[TIND], Aarg2); + } + break; + + case Aarg1: /* initial allign of parameter */ + w = ewidth[t->etype]; + if(w <= 0 || w >= SZ_LONG) { + w = SZ_LONG; + break; + } + w = 1; /* little endian no adjustment */ + break; + + case Aarg2: /* width of a parameter */ + o += t->width; + w = SZ_LONG; + break; + + case Aaut3: /* total allign of automatic */ + o = align(o, t, Ael1); + o = align(o, t, Ael2); + break; + } + o = round(o, w); + if(debug['A']) + print("align %s %ld %T = %ld\n", bnames[op], i, t, o); + return o; +} + +long +maxround(long max, long v) +{ + v += SZ_LONG-1; + if(v > max) + max = round(v, SZ_LONG); + return max; +} diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c new file mode 100644 index 000000000..88c4b1715 --- /dev/null +++ b/src/cmd/8c/txt.c @@ -0,0 +1,1440 @@ +// Inferno utils/8c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 = '8'; + thestring = "386"; + exregoffset = 0; + exfregoffset = 0; + listinit(); + nstring = 0; + mnstring = 0; + nrathole = 0; + pc = 0; + breakpc = -1; + continpc = -1; + cases = C; + firstp = P; + lastp = P; + tfield = types[TLONG]; + + zprog.link = P; + zprog.as = AGOK; + zprog.from.type = D_NONE; + zprog.from.index = D_NONE; + zprog.from.scale = 0; + zprog.to = zprog.from; + + regnode.op = OREGISTER; + regnode.class = CEXREG; + regnode.reg = REGTMP; + regnode.complex = 0; + regnode.addable = 11; + regnode.type = types[TLONG]; + + fregnode0 = regnode; + fregnode0.reg = D_F0; + fregnode0.type = types[TDOUBLE]; + + fregnode1 = fregnode0; + fregnode1.reg = D_F0+1; + + constnode.op = OCONST; + constnode.class = CXXX; + constnode.complex = 0; + constnode.addable = 20; + constnode.type = types[TLONG]; + + 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); + + com64init(); + + for(i=0; i<nelem(reg); i++) { + reg[i] = 1; + if(i >= D_AX && i <= D_DI && i != D_SP) + reg[i] = 0; + } +} + +void +gclean(void) +{ + int i; + Sym *s; + + reg[D_SP]--; + for(i=D_AX; i<=D_DI; 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) +{ + long 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_DI; 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] || typev[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 && curarg == 0 && typeilp[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* +nodconst(long 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) +{ + + *n = regnode; + n->reg = r; + if(reg[r] == 0) + return 0; + if(nn != Z) { + n->type = nn->type; + n->lineno = nn->lineno; + 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 TIND: + if(o != Z && o->op == OREGISTER) { + i = o->reg; + if(i >= D_AX && i <= D_DI) + goto out; + } + for(i=D_AX; i<=D_DI; i++) + if(reg[i] == 0) + goto out; + diag(tn, "out of fixed registers"); + goto err; + + case TFLOAT: + case TDOUBLE: + case TVLONG: + i = D_F0; + 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); + 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) +{ + nodreg(n, nn, REGARG); + reg[REGARG]++; + curarg = align(curarg, nn->type, Aarg1); + curarg = align(curarg, nn->type, Aarg2); + maxargsafe = maxround(maxargsafe, cursafe+curarg); +} + +void +regaalloc(Node *n, Node *nn) +{ + curarg = align(curarg, nn->type, Aarg1); + *n = *nn; + n->op = OINDREG; + n->reg = REGSP; + n->xoffset = curarg; + n->complex = 0; + n->addable = 20; + curarg = align(curarg, nn->type, Aarg2); + 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) +{ + long 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 OIND: + naddr(n->left, a); + if(a->type >= D_AX && a->type <= D_DI) + 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_DI) + 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; + a->offset = n->vconst; + 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; + + } +} + +#define CASE(a,b) ((a<<8)|(b<<0)) + +void +gmove(Node *f, Node *t) +{ + int ft, tt, a; + Node nod, nod1; + Prog *p1; + + ft = f->type->etype; + tt = t->type->etype; + 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) { + if(f->fconst == 0) + gins(AFLDZ, Z, Z); + else + if(f->fconst == 1) + gins(AFLD1, Z, Z); + else + gins(AFMOVD, f, &fregnode0); + gmove(&fregnode0, t); + return; + } +/* + * load + */ + if(f->op == ONAME || f->op == OINDREG || + f->op == OIND || f->op == OINDEX) + switch(ft) { + case TCHAR: + a = AMOVBLSX; + goto ld; + case TUCHAR: + a = AMOVBLZX; + goto ld; + case TSHORT: + if(typefd[tt]) { + gins(AFMOVW, f, &fregnode0); + gmove(&fregnode0, t); + return; + } + a = AMOVWLSX; + goto ld; + case TUSHORT: + a = AMOVWLZX; + goto ld; + case TINT: + case TUINT: + case TLONG: + case TULONG: + case TIND: + if(typefd[tt]) { + gins(AFMOVL, f, &fregnode0); + gmove(&fregnode0, t); + return; + } + a = AMOVL; + + ld: + regalloc(&nod, f, t); + nod.type = types[TLONG]; + gins(a, f, &nod); + gmove(&nod, t); + regfree(&nod); + return; + + case TFLOAT: + gins(AFMOVF, f, t); + return; + case TDOUBLE: + gins(AFMOVD, f, t); + return; + case TVLONG: + gins(AFMOVV, f, t); + 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: + case TIND: + a = AMOVL; goto st; + + st: + if(f->op == OCONST) { + gins(a, f, t); + return; + } + regalloc(&nod, t, f); + gmove(f, &nod); + gins(a, &nod, t); + regfree(&nod); + return; + + case TFLOAT: + gins(AFMOVFP, f, t); + return; + case TDOUBLE: + gins(AFMOVDP, f, t); + return; + case TVLONG: + gins(AFMOVVP, f, t); + return; + } + +/* + * 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( TINT, TLONG): + case CASE( TUINT, TLONG): + case CASE( TLONG, TLONG): + case CASE( TULONG, TLONG): + case CASE( TIND, TLONG): + + case CASE( TINT, TULONG): + case CASE( TUINT, TULONG): + case CASE( TLONG, TULONG): + case CASE( TULONG, TULONG): + case CASE( TIND, TULONG): + + case CASE( TINT, TIND): + case CASE( TUINT, TIND): + case CASE( TLONG, TIND): + case CASE( TULONG, TIND): + case CASE( TIND, TIND): + *****/ + a = AMOVL; + break; + + case CASE( TSHORT, TINT): + case CASE( TSHORT, TUINT): + case CASE( TSHORT, TLONG): + case CASE( TSHORT, TULONG): + case CASE( TSHORT, TIND): + a = AMOVWLSX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + if(f->vconst & 0x8000) + f->vconst |= 0xffff0000; + a = AMOVL; + } + break; + + case CASE( TUSHORT,TINT): + case CASE( TUSHORT,TUINT): + case CASE( TUSHORT,TLONG): + case CASE( TUSHORT,TULONG): + case CASE( TUSHORT,TIND): + a = AMOVWLZX; + if(f->op == OCONST) { + f->vconst &= 0xffff; + a = AMOVL; + } + 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): + case CASE( TCHAR, TIND): + a = AMOVBLSX; + if(f->op == OCONST) { + f->vconst &= 0xff; + if(f->vconst & 0x80) + f->vconst |= 0xffffff00; + a = AMOVL; + } + 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): + case CASE( TUCHAR, TIND): + a = AMOVBLZX; + if(f->op == OCONST) { + f->vconst &= 0xff; + a = AMOVL; + } + 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, 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,TIND): + + case CASE( TVLONG, TCHAR): + case CASE( TVLONG, TUCHAR): + case CASE( TVLONG, TSHORT): + case CASE( TVLONG, TUSHORT): + case CASE( TVLONG, TINT): + case CASE( TVLONG, TUINT): + case CASE( TVLONG, TLONG): + case CASE( TVLONG, TULONG): + case CASE( TVLONG, TIND): + if(fproundflg) { + regsalloc(&nod, ®node); + gins(AFMOVLP, f, &nod); + gmove(&nod, t); + return; + } + regsalloc(&nod, ®node); + regsalloc(&nod1, ®node); + gins(AFSTCW, Z, &nod1); + nod1.xoffset += 2; + gins(AMOVW, nodconst(0xf7f), &nod1); + gins(AFLDCW, &nod1, Z); + gins(AFMOVLP, f, &nod); + nod1.xoffset -= 2; + gins(AFLDCW, &nod1, Z); + gmove(&nod, t); + return; + +/* + * ulong to float + */ + case CASE( TULONG, TDOUBLE): + case CASE( TULONG, TVLONG): + case CASE( TULONG, TFLOAT): + case CASE( TUINT, TDOUBLE): + case CASE( TUINT, TVLONG): + case CASE( TUINT, TFLOAT): + regalloc(&nod, f, f); + gmove(f, &nod); + regsalloc(&nod1, ®node); + gmove(&nod, &nod1); + gins(AFMOVL, &nod1, &fregnode0); + gins(ACMPL, &nod, nodconst(0)); + gins(AJGE, Z, Z); + p1 = p; + gins(AFADDD, nodfconst(4294967296.), &fregnode0); + patch(p1, pc); + regfree(&nod); + 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( 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( TIND, TDOUBLE): + + case CASE( TCHAR, TVLONG): + case CASE( TUCHAR, TVLONG): + case CASE( TSHORT, TVLONG): + case CASE( TUSHORT,TVLONG): + case CASE( TINT, TVLONG): + case CASE( TLONG, TVLONG): + case CASE( TIND, TVLONG): + regsalloc(&nod, ®node); + gmove(f, &nod); + gins(AFMOVL, &nod, &fregnode0); + return; + +/* + * float to float + */ + case CASE( TFLOAT, TFLOAT): + case CASE( TDOUBLE,TFLOAT): + case CASE( TVLONG, TFLOAT): + + case CASE( TFLOAT, TDOUBLE): + case CASE( TDOUBLE,TDOUBLE): + case CASE( TVLONG, TDOUBLE): + + case CASE( TFLOAT, TVLONG): + case CASE( TDOUBLE,TVLONG): + case CASE( TVLONG, TVLONG): + a = AFMOVD; break; + } + if(a == AMOVL || a == AFMOVD) + if(samaddr(f, t)) + return; + gins(a, f, t); +} + +void +doindex(Node *n) +{ + Node nod, nod1; + long v; + +if(debug['Y']) +prtree(n, "index"); + +if(n->left->complex >= FNX) +print("botch in doindex\n"); + + regalloc(&nod, ®node, 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, ®node, 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 +fgopcode(int o, Node *f, Node *t, int pop, int rev) +{ + int a, et; + Node nod; + + et = TLONG; + if(f != Z && f->type != T) + et = f->type->etype; + if(!typefd[et]) { + diag(f, "fop: integer %O", o); + return; + } + if(debug['M']) { + if(t != Z && t->type != T) + print("gop: %O %O-%s Z\n", o, f->op, tnames[et]); + else + print("gop: %O %O-%s %O-%s\n", o, + f->op, tnames[et], t->op, tnames[t->type->etype]); + } + a = AGOK; + switch(o) { + + case OASADD: + case OADD: + if(et == TFLOAT) + a = AFADDF; + else + if(et == TDOUBLE || et == TVLONG) { + a = AFADDD; + if(pop) + a = AFADDDP; + } + break; + + case OASSUB: + case OSUB: + if(et == TFLOAT) { + a = AFSUBF; + if(rev) + a = AFSUBRF; + } else + if(et == TDOUBLE || et == TVLONG) { + a = AFSUBD; + if(pop) + a = AFSUBDP; + if(rev) { + a = AFSUBRD; + if(pop) + a = AFSUBRDP; + } + } + break; + + case OASMUL: + case OMUL: + if(et == TFLOAT) + a = AFMULF; + else + if(et == TDOUBLE || et == TVLONG) { + a = AFMULD; + if(pop) + a = AFMULDP; + } + break; + + case OASMOD: + case OMOD: + case OASDIV: + case ODIV: + if(et == TFLOAT) { + a = AFDIVF; + if(rev) + a = AFDIVRF; + } else + if(et == TDOUBLE || et == TVLONG) { + a = AFDIVD; + if(pop) + a = AFDIVDP; + if(rev) { + a = AFDIVRD; + if(pop) + a = AFDIVRDP; + } + } + break; + + case OEQ: + case ONE: + case OLT: + case OLE: + case OGE: + case OGT: + pop += rev; + if(et == TFLOAT) { + a = AFCOMF; + if(pop) { + a = AFCOMFP; + if(pop > 1) + a = AGOK; + } + } else + if(et == TDOUBLE || et == TVLONG) { + a = AFCOMF; + if(pop) { + a = AFCOMDP; + if(pop > 1) + a = AFCOMDPP; + } + } + gins(a, f, t); + regalloc(&nod, ®node, Z); + if(nod.reg != D_AX) { + regfree(&nod); + nod.reg = D_AX; + gins(APUSHL, &nod, Z); + gins(AWAIT, Z, Z); + gins(AFSTSW, Z, &nod); + gins(ASAHF, Z, Z); + gins(APOPL, Z, &nod); + } else { + gins(AWAIT, Z, Z); + gins(AFSTSW, Z, &nod); + gins(ASAHF, Z, Z); + regfree(&nod); + } + switch(o) { + case OEQ: a = AJEQ; break; + case ONE: a = AJNE; break; + case OLT: a = AJCS; break; + case OLE: a = AJLS; break; + case OGE: a = AJCC; break; + case OGT: a = AJHI; break; + } + gins(a, Z, Z); + return; + } + if(a == AGOK) + diag(Z, "bad in gopcode %O", o); + gins(a, f, t); +} + +void +gopcode(int o, Type *ty, Node *f, Node *t) +{ + int a, et; + + et = TLONG; + if(ty != T) + et = ty->etype; + if(typefd[et] && o != OADDR && o != OFUNC) { + diag(f, "gop: float %O", o); + return; + } + 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; + break; + + case ONEG: + a = ANEGL; + if(et == TCHAR || et == TUCHAR) + a = ANEGB; + if(et == TSHORT || et == TUSHORT) + a = ANEGW; + break; + + case OADDR: + a = ALEAL; + break; + + case OASADD: + case OADD: + a = AADDL; + if(et == TCHAR || et == TUCHAR) + a = AADDB; + if(et == TSHORT || et == TUSHORT) + a = AADDW; + break; + + case OASSUB: + case OSUB: + a = ASUBL; + if(et == TCHAR || et == TUCHAR) + a = ASUBB; + if(et == TSHORT || et == TUSHORT) + a = ASUBW; + break; + + case OASOR: + case OOR: + a = AORL; + if(et == TCHAR || et == TUCHAR) + a = AORB; + if(et == TSHORT || et == TUSHORT) + a = AORW; + break; + + case OASAND: + case OAND: + a = AANDL; + if(et == TCHAR || et == TUCHAR) + a = AANDB; + if(et == TSHORT || et == TUSHORT) + a = AANDW; + break; + + case OASXOR: + case OXOR: + a = AXORL; + if(et == TCHAR || et == TUCHAR) + a = AXORB; + if(et == TSHORT || et == TUSHORT) + a = AXORW; + break; + + case OASLSHR: + case OLSHR: + a = ASHRL; + if(et == TCHAR || et == TUCHAR) + a = ASHRB; + if(et == TSHORT || et == TUSHORT) + a = ASHRW; + break; + + case OASASHR: + case OASHR: + a = ASARL; + if(et == TCHAR || et == TUCHAR) + a = ASARB; + if(et == TSHORT || et == TUSHORT) + a = ASARW; + break; + + case OASASHL: + case OASHL: + a = ASALL; + if(et == TCHAR || et == TUCHAR) + a = ASALB; + if(et == TSHORT || et == TUSHORT) + a = ASALW; + 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; + break; + + case OASMOD: + case OMOD: + case OASDIV: + case ODIV: + a = AIDIVL; + break; + + case OASLMUL: + case OLMUL: + a = AMULL; + break; + + case OASLMOD: + case OLMOD: + case OASLDIV: + case OLDIV: + a = ADIVL; + 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; + 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) +{ + + if(f->op != t->op) + return 0; + switch(f->op) { + + case OREGISTER: + if(f->reg != t->reg) + break; + return 1; + } + return 0; +} + +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, long 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 = (profileflg ? 0 : NOPROF); + if(s->class == CSTATIC) + p->from.type = D_STATIC; + naddr(n, &p->to); + if(a == ADATA || a == AGLOBL) + pc--; +} + +int +sconst(Node *n) +{ + long v; + + if(n->op == OCONST && !typefd[n->type->etype]) { + v = n->vconst; + if(v >= -32766L && v < 32766L) + return 1; + } + return 0; +} + +long +exreg(Type *t) +{ + + USED(t); + 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]*/ +}; +long ncast[NTYPE] = +{ + 0, /*[TXXX]*/ + BCHAR|BUCHAR, /*[TCHAR]*/ + BCHAR|BUCHAR, /*[TUCHAR]*/ + BSHORT|BUSHORT, /*[TSHORT]*/ + BSHORT|BUSHORT, /*[TUSHORT]*/ + BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/ + BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/ + BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/ + BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/ + BVLONG|BUVLONG, /*[TVLONG]*/ + BVLONG|BUVLONG, /*[TUVLONG]*/ + BFLOAT, /*[TFLOAT]*/ + BDOUBLE, /*[TDOUBLE]*/ + BLONG|BULONG|BIND, /*[TIND]*/ + 0, /*[TFUNC]*/ + 0, /*[TARRAY]*/ + 0, /*[TVOID]*/ + BSTRUCT, /*[TSTRUCT]*/ + BUNION, /*[TUNION]*/ + 0, /*[TENUM]*/ +}; |