]> Cypherpunks repositories - gostls13.git/commitdiff
add hardware floating point.
authorKen Thompson <ken@golang.org>
Thu, 4 Nov 2010 00:31:07 +0000 (17:31 -0700)
committerKen Thompson <ken@golang.org>
Thu, 4 Nov 2010 00:31:07 +0000 (17:31 -0700)
currently, softfloat does not work and
there are some unsigned-to-float conversion errors.

R=rsc
CC=golang-dev
https://golang.org/cl/2886041

16 files changed:
src/cmd/5g/Makefile
src/cmd/5g/gg.h
src/cmd/5g/ggen.c
src/cmd/5g/list.c
src/cmd/5g/opt.h
src/cmd/5g/reg.c [new file with mode: 0644]
src/cmd/5l/5.out.h
src/cmd/5l/asm.c
src/cmd/5l/l.h
src/cmd/5l/list.c
src/cmd/5l/obj.c
src/cmd/5l/optab.c
src/cmd/5l/softfloat.c
src/cmd/5l/span.c
src/cmd/5l/thumb.c
src/pkg/runtime/print.c

index f1fabe6a49c5faa58dfb8fbb599716ae84f54ddd..1da0ef6290c030a6bb05cdbf4af7b42d51b4f524 100644 (file)
@@ -23,6 +23,7 @@ OFILES=\
        cgen.$O\
        cgen64.$O\
        cplx.$O\
+       reg.$O\
 
 LIB=\
        ../gc/gc.a\
index 4801e472173d56ef39e0f5ae93d60c2e6dc8bc52..603c09fc8ac660a087b3610ff4077c482dd86ad6 100644 (file)
@@ -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;
 };
index d665f6158b7f04811dff6ee33c71a316aeda76a2..db1837b110e0a975cb9e8dd83bd115d58a70fccf 100644 (file)
@@ -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;
index 6f0eeabfa8fb1fa364df205a9fefee1c6051bc2b..8547bb2f8c2ca521d066fc20d95a546608f99730 100644 (file)
@@ -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;
index 1b03662902d59b1787df0ccbfeaa9a43344816e0..9a4e17571c0ab50738b49b8d45fbdc4dd99effe3 100644 (file)
@@ -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 (file)
index 0000000..4c5b3e3
--- /dev/null
@@ -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;
+}
index 3c7223d2889ca0b7583f8c4f97d5c2aee394cc26..865bc6945b9be8346e7f661119e5847858c102f2 100644 (file)
@@ -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 */
 
index 790228c25f8a0ccdc9da31f877b0c5dc2a63f62a..fcee2447e4aedd7257ce0f2e24f7928d8c936fe6 100644 (file)
@@ -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;
 }
 
index 3a54e20f8fe5c9772bf5c206719df1f34c6ae891..1d4613df4a357679645f182ce319bbafd05bba10 100644 (file)
@@ -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*);
index c7cb95b98a403b46c5a3ad5f301a53f14dff5f36..b4df8958785eb3248e79e784408b0cfeb99cc716 100644 (file)
@@ -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",
index 763ddd758b4b8b1010b234e9c02f329f28e9c5a9..cb9ad9805e7ff1824516671788c139ba77e4edba 100644 (file)
@@ -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);
index cfbb5d5a9d62ab9a8991051907ee1758809a6429..277b5ef4068ab19e109606903c12111fadd5a4ed 100644 (file)
@@ -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 },
index 308a5fbeda1d4dd057cebfc497b5853c37da40ea..8df8e5b3cb3f346a840bb8937bc17eb9b1999e32 100644 (file)
@@ -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)
index 6ee432c38288a682d10910e46b8782d24c777807..7c4470f3a7bd186a81fa732e523670448eb425ea 100644 (file)
@@ -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;
index d2c84b25371603f1d27bceac190b972ea2621d30..b2ba630c39308a34be9b8697f7501b11abbd7535 100644 (file)
@@ -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:
index cf3788618337a6be8976c39c717e844a685aad92..68f84b40f58950ffe37374b7c73c2613d5e16fc4 100644 (file)
@@ -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++;