From 9c6df3ca1398ef2d183418a75cd2e523f51b72bc Mon Sep 17 00:00:00 2001 From: Ken Thompson Date: Wed, 3 Nov 2010 17:31:07 -0700 Subject: [PATCH] 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 --- src/cmd/5g/Makefile | 1 + src/cmd/5g/gg.h | 5 +- src/cmd/5g/ggen.c | 5 +- src/cmd/5g/list.c | 14 +- src/cmd/5g/opt.h | 2 +- src/cmd/5g/reg.c | 1246 +++++++++++++++++++++++++++++++++++++++ src/cmd/5l/5.out.h | 1 + src/cmd/5l/asm.c | 184 ++++-- src/cmd/5l/l.h | 5 +- src/cmd/5l/list.c | 4 +- src/cmd/5l/obj.c | 6 +- src/cmd/5l/optab.c | 13 +- src/cmd/5l/softfloat.c | 5 +- src/cmd/5l/span.c | 10 +- src/cmd/5l/thumb.c | 2 +- src/pkg/runtime/print.c | 2 +- 16 files changed, 1416 insertions(+), 89 deletions(-) create mode 100644 src/cmd/5g/reg.c 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; zprog; + 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; isym == 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; zlink) { + 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; zuse1.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; zset.b[z] |= bit.b[z]; + break; + + /* + * funny + */ + case ABL: + for(z=0; zas == 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; zset.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; zrefahead.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; zset.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; zact.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; ivarno); + 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; zcalbehind.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; isym == 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; zetype != et || !typechlpfd[et]) /* funny punning */ +// for(z=0; zp1) { + for(z=0; zrefahead.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; zset.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; zrefbehind.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; zcalbehind.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= 10) { e++; -- 2.48.1