Commit 9c6df3ca authored by Ken Thompson's avatar Ken Thompson

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
parent 0aa9d84b
......@@ -23,6 +23,7 @@ OFILES=\
cgen.$O\
cgen64.$O\
cplx.$O\
reg.$O\
LIB=\
../gc/gc.a\
......
......@@ -39,6 +39,7 @@ struct Prog
Addr from; // src 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;
};
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
// 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;
}
......@@ -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 */
......
......@@ -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;
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 */
......@@ -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;
if(e->l != 0 || (e->h&0xffff) != 0)
goto no;
h = e->h & 0x7fc00000;
if(h != 0x40000000 && h != 0x3fc00000)
goto no;
n = 0;
for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
p = &chipfloats[n];
if(p->l == e->l && p->h == e->h)
// 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;
}
......
......@@ -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*);
......
......@@ -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",
......
......@@ -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);
......
......@@ -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 },
......
......@@ -14,6 +14,9 @@ softfloat(void)
Sym *symsfloat;
int wasfloat;
if(!debug['F'])
return;
symsfloat = lookup("_sfloat", 0);
psfloat = P;
if(symsfloat->type == STEXT)
......
......@@ -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;
......
......@@ -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:
......
......@@ -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++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment