aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Thompson <ken@golang.org>2010-11-03 17:31:07 -0700
committerKen Thompson <ken@golang.org>2010-11-03 17:31:07 -0700
commit9c6df3ca1398ef2d183418a75cd2e523f51b72bc (patch)
tree071e59727d62f9137b0fb8f06a595556341386ba
parent0aa9d84b56e716fcba784d5007b02af839fd34df (diff)
downloadgo-9c6df3ca1398ef2d183418a75cd2e523f51b72bc.tar.gz
go-9c6df3ca1398ef2d183418a75cd2e523f51b72bc.zip
add hardware floating point.
currently, softfloat does not work and there are some unsigned-to-float conversion errors. R=rsc CC=golang-dev https://golang.org/cl/2886041
-rw-r--r--src/cmd/5g/Makefile1
-rw-r--r--src/cmd/5g/gg.h5
-rw-r--r--src/cmd/5g/ggen.c5
-rw-r--r--src/cmd/5g/list.c14
-rw-r--r--src/cmd/5g/opt.h2
-rw-r--r--src/cmd/5g/reg.c1246
-rw-r--r--src/cmd/5l/5.out.h1
-rw-r--r--src/cmd/5l/asm.c184
-rw-r--r--src/cmd/5l/l.h5
-rw-r--r--src/cmd/5l/list.c4
-rw-r--r--src/cmd/5l/obj.c6
-rw-r--r--src/cmd/5l/optab.c13
-rw-r--r--src/cmd/5l/softfloat.c5
-rw-r--r--src/cmd/5l/span.c10
-rw-r--r--src/cmd/5l/thumb.c2
-rw-r--r--src/pkg/runtime/print.c2
16 files changed, 1416 insertions, 89 deletions
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
index f1fabe6a49..1da0ef6290 100644
--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -23,6 +23,7 @@ OFILES=\
cgen.$O\
cgen64.$O\
cplx.$O\
+ reg.$O\
LIB=\
../gc/gc.a\
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 4801e47217..603c09fc8a 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -33,12 +33,13 @@ struct Addr
struct Prog
{
- short as; // opcode
+ short as; // opcode
uint32 loc; // pc offset in this func
uint32 lineno; // source line that generated this
Addr from; // src address
- Addr to; // dst address
+ Addr to; // dst address
Prog* link; // next instruction in this func
+ void* regp; // points to enclosing Reg struct
char reg; // doubles as width in DATA op
uchar scond;
};
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index d665f6158b..db1837b110 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -104,10 +104,9 @@ compile(Node *fn)
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
- /* TODO(kaib): Add back register optimizations
- if(!debug['N'] || debug['R'] || debug['P'])
+ if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
- */
+ }
// fill in argument size
ptxt->to.type = D_CONST2;
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index 6f0eeabfa8..8547bb2f8c 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -49,20 +49,22 @@ listinit(void)
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
+ char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
sconsize = 8;
switch(p->as) {
default:
+ snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
if(p->reg == NREG)
- snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, &p->to);
- else if (p->from.type != D_FREG)
- snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,R%d,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
+ p->loc, p->lineno, str1, &p->from, &p->to);
else
+ if (p->from.type != D_FREG) {
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D",
+ p->loc, p->lineno, str1, &p->from, p->reg, &p->to);
+ } else
snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D",
p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
break;
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 1b03662902..9a4e17571c 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -128,7 +128,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
+Bits mkvar(Reg *r, Adr *a, int);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
new file mode 100644
index 0000000000..4c5b3e31a9
--- /dev/null
+++ b/src/cmd/5g/reg.c
@@ -0,0 +1,1246 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5g/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 "gg.h"
+#include "opt.h"
+
+#define P2R(p) (Reg*)(p->reg)
+
+void addsplits(void);
+int onlyone;
+static int first = 1;
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = mal(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;
+}
+
+static void
+setoutvar(void)
+{
+ Type *t;
+ Node *n;
+ Addr a;
+ Iter save;
+ Bits bit;
+ int z;
+
+ t = structfirst(&save, getoutarg(curfn->type));
+ while(t != T) {
+ n = nodarg(t, 1);
+ a = zprog.from;
+ naddr(n, &a, 0);
+ bit = mkvar(R, &a, 0);
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+ t = structnext(&save);
+ }
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->scond = zprog.scond;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+static void
+setaddrs(Bits bit)
+{
+ int i, n;
+ Var *v;
+ Sym *s;
+
+ while(bany(&bit)) {
+ // convert each bit to a variable
+ i = bnum(bit);
+ s = var[i].sym;
+ n = var[i].name;
+ bit.b[i/32] &= ~(1L<<(i%32));
+
+ // disable all pieces of that variable
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->sym == s && v->name == n)
+ v->addr = 2;
+ }
+ }
+}
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+return;
+
+ if(first) {
+ fmtinstall('Q', Qconv);
+// exregoffset = D_R13; // R14,R15 are external
+ first = 0;
+ }
+
+ // count instructions
+ nr = 0;
+ for(p=firstp; p!=P; p=p->link)
+ nr++;
+
+ // if too big dont bother
+ if(nr >= 10000) {
+ print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
+ return;
+ }
+
+ r1 = R;
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ ovar.b[z] = 0;
+ }
+
+ // build list of return variables
+ setoutvar();
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+print("pass 1\n");
+ nr = 0;
+ for(p=firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ nr++;
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ p->regp = r;
+
+ r1 = r->p1;
+ if(r1 != R) {
+ switch(r1->prog->as) {
+ case ARET:
+ case AB:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(r, &p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(r, &p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ if(p->as == AMOVM) {
+ z = p->to.offset;
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R) {
+ return;
+ }
+
+onlyone++;
+if(onlyone != 1)
+ return;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+print("pass 2\n");
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ if(p->to.branch == P)
+ fatal("pnil %P", p);
+ r1 = p->to.branch->regp;
+ if(r1 == R)
+ fatal("rnil %P", p);
+ if(r1 == r) {
+ //fatal("ref to self %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
+ */
+print("pass 2.5\n");
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, nr);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+print("loop 1\n");
+ 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:
+print("loop 11\n");
+ /* 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:
+print("loop 2\n");
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++) {
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ }
+
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%Q", r->use2);
+ if(bany(&r->set))
+ print(" st=%Q", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%Q", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%Q", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%Q", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%Q", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+print("pass 5\n");
+ 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) & !r->refset) {
+ // should never happen - all variables are preset
+ if(debug['w'])
+ print("%L: used and not set: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ 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) && !r->refset) {
+ if(debug['w'])
+ print("%L: set and not used: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ 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: %Q\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] && debug['v'])
+ print("too many regions\n");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+print("pass 6 -- %d regions\n", nregion);
+ 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']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %Q\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %Q\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
+ */
+print("pass 7\n");
+ if(!debug['R'] || debug['P']) {
+// peep();
+ }
+
+ /*
+ * 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;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == ABL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * 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 = mal(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->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TINT8 || v->etype == TUINT8)
+ p1->as = AMOVB;
+ if(v->etype == TINT16 || v->etype == TUINT16)
+ p1->as = AMOVH;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TFLOAT64)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUINT8)
+ p1->as = AMOVBU;
+ if(v->etype == TUINT16)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+static int
+overlap(int32 o1, int w1, int32 o2, int w2)
+{
+ int32 t1, t2;
+
+ t1 = o1+w1;
+ t2 = o2+w2;
+
+ if(!(t1 > o2 && t2 > o1))
+ return 0;
+
+ return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z, w, flag;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ r->regu |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ r->regu |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TINT32;
+ }
+ if(t == D_CONST) {
+// if(s == S && sval(o))
+// goto none;
+ }
+
+ flag = 0;
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->sym == s && v->name == n) {
+ if(v->offset == o)
+ if(v->etype == et)
+ if(v->width == w)
+ return blsh(i);
+
+ // if they overlaps, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+
+// if(a->pun)
+// flag = 1;
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ goto none;
+ }
+
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ fatal("variable not optimized: %D", a);
+ goto none;
+ }
+
+ i = nvar;
+ nvar++;
+ v = var+i;
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+// v->gotype = a->gotype;
+ v->etype = et;
+ v->width = w;
+ v->addr = flag; // funny punning
+
+ 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];
+// if(t == D_CONST) {
+// if(s == S) {
+// for(z=0; z<BITS; z++)
+// consts.b[z] |= bit.b[z];
+// return bit;
+// }
+// if(et != TARRAY)
+// for(z=0; z<BITS; z++)
+// addrs.b[z] |= bit.b[z];
+// for(z=0; z<BITS; z++)
+// params.b[z] |= bit.b[z];
+// return bit;
+// }
+// if(t != D_OREG)
+// goto none;
+
+ 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 ABL:
+ 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
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 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;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+ int32 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("bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+ int32 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, int32 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, int32 nr)
+{
+ Reg *r1;
+ int32 i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = mal(nr * sizeof(Reg*));
+ idom = mal(nr * sizeof(int32));
+ maxnr = nr;
+ }
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal("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);
+ }
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ fatal("unknown etype %d/%E", bitno(b), v->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 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("%d%P\td %Q $%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(debug['R'] && debug['v'])
+ print("%d%P\tu1 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%d%P\tu2 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%d%P\tst %Q $%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;
+ }
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg;
+
+ 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;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 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->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 10 R10
+ */
+int32
+RtoB(int r)
+{
+
+ if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
+ return 0;
+ return 1L << r;
+}
+
+int
+BtoR(int32 b)
+{
+ b &= 0x01fcL; // excluded R9 and R10 for m and g
+ if(b == 0)
+ return 0;
+ return bitno(b);
+}
+
+/*
+ * bit reg
+ * 18 F2
+ * 19 F3
+ * ... ...
+ * 23 F7
+ */
+int32
+FtoB(int f)
+{
+
+ if(f < 2 || f > NFREG-1)
+ return 0;
+ return 1L << (f + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+ b &= 0xfc0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16;
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 3c7223d288..865bc6945b 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -58,6 +58,7 @@
#define NFREG 8
#define FREGRET 0
#define FREGEXT 7
+#define FREGTMP 15
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 790228c25f..fcee2447e4 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -1246,38 +1246,41 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
case 54: /* floating point arith */
o1 = oprrr(p->as, p->scond);
- if(p->from.type == D_FCONST) {
- rf = chipfloat(&p->from.ieee);
- if(rf < 0){
- diag("invalid floating-point immediate\n%P", p);
- rf = 0;
- }
- rf |= (1<<3);
- } else
- rf = p->from.reg;
+ rf = p->from.reg;
rt = p->to.reg;
r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0; /* CMP[FD] */
- else if(o1 & (1<<15))
- r = 0; /* monadic */
- else if(r == NREG)
+ if(r == NREG) {
r = rt;
+ if(p->as == AMOVF || p->as == AMOVD)
+ r = 0;
+ }
o1 |= rf | (r<<16) | (rt<<12);
break;
case 55: /* floating point fix and float */
- o1 = oprrr(p->as, p->scond);
rf = p->from.reg;
rt = p->to.reg;
- if(p->to.type == D_NONE){
- rt = 0;
- diag("to.type==D_NONE (asm/fp)");
+ if(p->from.type == D_REG) {
+ // MOV R,FTMP
+ o1 = oprrr(AMOVWF+AEND, p->scond);
+ o1 |= (FREGTMP<<16);
+ o1 |= (rf<<12);
+
+ // CVT FTMP,F
+ o2 = oprrr(p->as, p->scond);
+ o2 |= (FREGTMP<<0);
+ o2 |= (rt<<12);
+ } else {
+ // CVT F,FTMP
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (rf<<0);
+ o1 |= (FREGTMP<<12);
+
+ // MOV FTMP,R
+ o2 = oprrr(AMOVFW+AEND, p->scond);
+ o2 |= (FREGTMP<<16);
+ o2 |= (rt<<12);
}
- if(p->from.type == D_REG)
- o1 |= (rf<<12) | (rt<<16);
- else
- o1 |= rf | (rt<<12);
break;
case 56: /* move to FP[CS]R */
@@ -1485,7 +1488,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= immrot(instoffset);
o1 |= p->to.reg << 16;
o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
break;
case 76: /* bx O(R) when returning from fn*/
@@ -1517,6 +1520,38 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= p->to.reg << 12;
o1 |= (p->scond & C_SCOND) << 28;
break;
+
+ case 80: /* fmov zfcon,reg */
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ diag("floating point cannot be conditional"); // cant happen
+ o1 = 0xf3000110; // EOR 64
+
+ // always clears the double float register
+ r = p->to.reg;
+ o1 |= r << 0;
+ o1 |= r << 12;
+ o1 |= r << 16;
+ break;
+ case 81: /* fmov sfcon,reg */
+ o1 = 0x0eb00a00; // VMOV imm 32
+ if(p->as == AMOVD)
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= p->to.reg << 12;
+ v = chipfloat(&p->from.ieee);
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+ break;
+ case 82: /* fcmp reg,reg, */
+ o1 = oprrr(p->as, p->scond);
+ r = p->reg;
+ if(r == NREG) {
+ o1 |= (p->from.reg<<12) | (1<<16);
+ } else
+ o1 |= (r<<12) | (p->from.reg<<0);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
}
out[0] = o1;
@@ -1623,26 +1658,38 @@ oprrr(int a, int sc)
case ASRA: return o | (0xd<<21) | (2<<5);
case ASWI: return o | (0xf<<24);
- case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
- case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8);
- case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
- case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8);
- case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
- case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8);
- case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
- case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8);
- case ACMPD:
- case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */
-
- case AMOVF:
- case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
- case AMOVD:
- case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
-
- case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
- case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
- case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
- case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
+ case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
+ case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
+ case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
+ case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
+ case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
+ case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
+ case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
+ case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
+ case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
+
+ case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
+ case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
+
+ case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (1<<8); // dtof
+ case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (0<<8); // dtof
+
+ case AMOVWF: return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<16) | (0<<8) | (1<<7); // toint, signed, double, round
+ case AMOVWD: return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<16) | (1<<8) | (1<<7); // toint, signed, double, round
+ case AMOVFW: return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<16) | (0<<8) | (1<<7); // toint, signed, double, round
+ case AMOVDW: return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<16) | (1<<8) | (1<<7); // toint, signed, double, round
+
+ case AMOVWF+AEND: // copy WtoF
+ return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
+ case AMOVFW+AEND: // copy FtoW
+ return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
}
diag("bad rrr %d", a);
prasm(curp);
@@ -1796,7 +1843,7 @@ ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
o |= 1 << 24;
if(sc & C_WBIT)
o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23);
+ o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
if(v < 0) {
v = -v;
o ^= 1 << 23;
@@ -1809,13 +1856,12 @@ ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
o |= (v>>2) & 0xFF;
o |= b << 16;
o |= r << 12;
- o |= 1 << 8;
switch(a) {
default:
diag("bad fst %A", a);
case AMOVD:
- o |= 1<<15;
+ o |= 1 << 8;
case AMOVF:
break;
}
@@ -1844,28 +1890,42 @@ omvl(Prog *p, Adr *a, int dr)
return o1;
}
-static Ieee chipfloats[] = {
- {0x00000000, 0x00000000}, /* 0 */
- {0x00000000, 0x3ff00000}, /* 1 */
- {0x00000000, 0x40000000}, /* 2 */
- {0x00000000, 0x40080000}, /* 3 */
- {0x00000000, 0x40100000}, /* 4 */
- {0x00000000, 0x40140000}, /* 5 */
- {0x00000000, 0x3fe00000}, /* .5 */
- {0x00000000, 0x40240000}, /* 10 */
-};
+int
+chipzero(Ieee *e)
+{
+ if(e->l != 0 || e->h != 0)
+ return -1;
+ return 0;
+}
int
chipfloat(Ieee *e)
{
- Ieee *p;
int n;
+ ulong h;
- for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
- p = &chipfloats[n];
- if(p->l == e->l && p->h == e->h)
- return n;
- }
+ if(e->l != 0 || (e->h&0xffff) != 0)
+ goto no;
+ h = e->h & 0x7fc00000;
+ if(h != 0x40000000 && h != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(e->h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (e->h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
+ return n;
+
+no:
return -1;
}
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index 3a54e20f8f..1d4613df4a 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -225,7 +225,9 @@ enum
C_SCON, /* 0xffff */
C_BCON, /* thumb */
C_LCON,
- C_FCON,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
C_GCON, /* thumb */
C_RACON,
@@ -382,6 +384,7 @@ void buildop(void);
void thumbbuildop(void);
void buildrep(int, int);
void cflush(void);
+int chipzero(Ieee*);
int chipfloat(Ieee*);
int cmp(int, int);
int compound(Prog*);
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index c7cb95b98a..b4df895878 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -410,7 +410,9 @@ cnames[] =
[C_ADDR] = "C_ADDR",
[C_BCON] = "C_BCON",
[C_FAUTO] = "C_FAUTO",
- [C_FCON] = "C_FCON",
+ [C_ZFCON] = "C_SFCON",
+ [C_SFCON] = "C_SFCON",
+ [C_LFCON] = "C_LFCON",
[C_FCR] = "C_FCR",
[C_FOREG] = "C_FOREG",
[C_FREG] = "C_FREG",
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 763ddd758b..cb9ad9805e 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -664,7 +664,8 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 9 max */
sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
@@ -686,7 +687,8 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 18 max */
sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index cfbb5d5a9d..277b5ef406 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -193,16 +193,15 @@ Optab optab[] =
{ AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 },
- { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 },
+ { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 4, 0 },
+ { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
+ { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
+// { ACMPF, C_FREG, C_NONE, C_NONE, 82, 8, 0 },
- { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 },
- { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 },
+ { AMOVFW, C_FREG, C_NONE, C_REG, 55, 8, 0 },
+ { AMOVFW, C_REG, C_NONE, C_FREG, 55, 8, 0 },
{ AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
{ AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 308a5fbeda..8df8e5b3cb 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -13,7 +13,10 @@ softfloat(void)
Prog *p, *next, *psfloat;
Sym *symsfloat;
int wasfloat;
-
+
+ if(!debug['F'])
+ return;
+
symsfloat = lookup("_sfloat", 0);
psfloat = P;
if(symsfloat->type == STEXT)
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 6ee432c382..7c4470f3a7 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -712,7 +712,11 @@ aclass(Adr *a)
return C_GOK;
case D_FCONST:
- return C_FCON;
+ if(chipzero(&a->ieee) >= 0)
+ return C_ZFCON;
+ if(chipfloat(&a->ieee) >= 0)
+ return C_SFCON;
+ return C_LFCON;
case D_CONST:
case D_CONST2:
@@ -849,6 +853,10 @@ cmp(int a, int b)
if(b == C_RACON)
return 1;
break;
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
+ return 1;
+ break;
case C_HFAUTO:
return b == C_HAUTO || b == C_FAUTO;
diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c
index d2c84b2537..b2ba630c39 100644
--- a/src/cmd/5l/thumb.c
+++ b/src/cmd/5l/thumb.c
@@ -251,7 +251,7 @@ thumbaclass(Adr *a, Prog *p)
return C_GOK;
case D_FCONST:
diag("D_FCONST in thumaclass");
- return C_FCON;
+ return C_LFCON;
case D_CONST:
switch(a->name) {
case D_NONE:
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index cf37886183..68f84b40f5 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -209,7 +209,6 @@ void
return;
}
-
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
@@ -234,6 +233,7 @@ void
h = 5;
for(i=0; i<n; i++)
h /= 10;
+
v += h;
if(v >= 10) {
e++;