diff options
Diffstat (limited to 'limbo/optim.c')
| -rw-r--r-- | limbo/optim.c | 1803 |
1 files changed, 1803 insertions, 0 deletions
diff --git a/limbo/optim.c b/limbo/optim.c new file mode 100644 index 00000000..a3ccdec3 --- /dev/null +++ b/limbo/optim.c @@ -0,0 +1,1803 @@ +#include "limbo.h" + +#define bzero bbzero /* bsd name space pollution */ +/* + (r, s) := f(); => r, s have def on same pc + s = g(); => this def kills previous r def (and s def) + solution: r has def pc, s has def pc+1 and next instruction has pc pc+2 +*/ + +#define BLEN (8*sizeof(ulong)) +#define BSHIFT 5 /* assumes ulong 4 */ +#define BMASK (BLEN-1) + +#define SIGN(n) (1<<(n-1)) +#define MSK(n) (SIGN(n)|(SIGN(n)-1)) +#define MASK(a, b) (MSK((b)-(a)+1)<<(a)) + +#define isnilsrc(s) ((s)->start.line == 0 && (s)->stop.line == 0 && (s)->start.pos == 0 && (s)->stop.pos == 0) + +#define limbovar(d) ((d)->sym->name[0] != '.') +#define structure(t) ((t)->kind == Tadt || (t)->kind == Ttuple) + +enum +{ + Bclr, + Band, + Bandinv, + Bstore, + Bandrev, + Bnoop, + Bxor, + Bor, + Bnor, + Bequiv, + Binv, + Bimpby, + Brev, + Bimp, + Bnand, + Bset, +}; + +enum +{ + Suse = 1, + Muse = 2, + Duse = 4, + Sdef = 8, + Mdef = 16, + Ddef = 32, + Tuse1 = 64, /* fixed point temporary */ + Tuse2 = 128, /* fixed point temporary */ + Mduse = 256, /* D used if M nil */ + + None = 0, + Unop = Suse|Ddef, + Cunop = Muse|Ddef, + Threop = Suse|Muse|Ddef, + Binop = Suse|Muse|Ddef|Mduse, + Mbinop = Suse|Mdef|Duse, /* strange */ + Abinop=Suse|Duse|Ddef, + Mabinop = Suse|Muse|Duse|Ddef, + Use1 = Suse, + Use2 = Suse|Duse, + Use3 = Suse|Muse|Duse, +}; + +enum +{ + Sshift = 10, + Mshift = 5, + Dshift = 0, +}; + +#define S(x) ((x)<<Sshift) +#define M(x) ((x)<<Mshift) +#define D(x) ((x)<<Dshift) + +#define SS(x) (((x)>>Sshift)&0x1f) +#define SM(x) (((x)>>Mshift)&0x1f) +#define SD(x) (((x)>>Dshift)&0x1f) + +enum +{ + I = 0, /* ignore */ + B = 1, /* byte */ + W = 4, /* int */ + P = 4, /* pointer */ + A = 4, /* array */ + C = 4, /* string */ + X = 4, /* fixed */ + R = 4, /* float */ + L = 8, /* big */ + F = 8, /* real */ + Sh = 2, /* short */ + Pc = 4, /* pc */ + Mp = 16, /* memory */ + + Bop2 = S(B)|D(B), + Bop = S(B)|M(B)|D(B), + Bopb = S(B)|M(B)|D(Pc), + Wop2 = S(W)|D(W), + Wop = S(W)|M(W)|D(W), + Wopb = S(W)|M(W)|D(Pc), + Lop2 = S(L)|D(L), + Lop = S(L)|M(L)|D(L), + Lopb = S(L)|M(L)|D(Pc), + Cop2 = Wop2, + Cop = Wop, + Copb = Wopb, + Fop2 = Lop2, + Fop = Lop, + Fopb = Lopb, + Xop = Wop, +}; + +typedef struct Array Array; +typedef struct Bits Bits; +typedef struct Blist Blist; +typedef struct Block Block; +typedef struct Idlist Idlist; +typedef struct Optab Optab; + +struct Array +{ + int n; + int m; + Block **a; +}; + +struct Bits +{ + int n; + ulong *b; +}; + +struct Blist +{ + Block *block; + Blist *next; +}; + +struct Block +{ + int dfn; + int flags; + Inst *first; + Inst *last; + Block *prev; + Block *next; + Blist *pred; + Blist *succ; + Bits kill; + Bits gen; + Bits in; + Bits out; +}; + +struct Idlist +{ + int id; + Idlist *next; +}; + +struct Optab +{ + short flags; + short size; +}; + +Block zblock; +Decl *regdecls; +Idlist *frelist; +Idlist *deflist; +Idlist *uselist; + +static void +addlist(Idlist **hd, int id) +{ + Idlist *il; + + if(frelist == nil) + il = (Idlist*)malloc(sizeof(Idlist)); + else{ + il = frelist; + frelist = frelist->next; + } + il->id = id; + il->next = *hd; + *hd = il; +} + +static void +freelist(Idlist **hd) +{ + Idlist *il; + + for(il = *hd; il != nil && il->next != nil; il = il->next) + ; + if(il != nil){ + il->next = frelist; + frelist = *hd; + *hd = nil; + } +} + +Optab opflags[] = { + /* INOP */ None, 0, + /* IALT */ Unop, S(Mp)|D(W), + /* INBALT */ Unop, S(Mp)|D(W), + /* IGOTO */ Use2, S(W)|D(I), + /* ICALL */ Use2, S(P)|D(Pc), + /* IFRAME */ Unop, S(W)|D(P), + /* ISPAWN */ Use2, S(P)|D(Pc), + /* IRUNT */ None, 0, + /* ILOAD */ Threop, S(C)|M(P)|D(P), + /* IMCALL */ Use3, S(P)|M(W)|D(P), + /* IMSPAWN */ Use3, S(P)|M(W)|D(P), + /* IMFRAME */ Threop, S(P)|M(W)|D(P), + /* IRET */ None, 0, + /* IJMP */ Duse, D(Pc), + /* ICASE */ Use2, S(W)|D(I), + /* IEXIT */ None, 0, + /* INEW */ Unop, S(W)|D(P), + /* INEWA */ Threop, S(W)|M(W)|D(P), + /* INEWCB */ Cunop, M(W)|D(P), + /* INEWCW */ Cunop, M(W)|D(P), + /* INEWCF */ Cunop, M(W)|D(P), + /* INEWCP */ Cunop, M(W)|D(P), + /* INEWCM */ Threop, S(W)|M(W)|D(P), + /* INEWCMP */ Threop, S(W)|M(W)|D(P), + /* ISEND */ Use2, S(Mp)|D(P), + /* IRECV */ Unop, S(P)|D(Mp), + /* ICONSB */ Abinop, S(B)|D(P), + /* ICONSW */ Abinop, S(W)|D(P), + /* ICONSP */ Abinop, S(P)|D(P), + /* ICONSF */ Abinop, S(F)|D(P), + /* ICONSM */ Mabinop, S(Mp)|M(W)|D(P), + /* ICONSMP */ Mabinop, S(Mp)|M(W)|D(P), + /* IHEADB */ Unop, S(P)|D(B), + /* IHEADW */ Unop, S(P)|D(W), + /* IHEADP */ Unop, S(P)|D(P), + /* IHEADF */ Unop, S(P)|D(F), + /* IHEADM */ Threop, S(P)|M(W)|D(Mp), + /* IHEADMP */ Threop, S(P)|M(W)|D(Mp), + /* ITAIL */ Unop, S(P)|D(P), + /* ILEA */ Ddef, S(Mp)|D(P), /* S done specially cos of ALT */ + /* IINDX */ Mbinop, S(P)|M(P)|D(W), + /* IMOVP */ Unop, S(P)|D(P), + /* IMOVM */ Threop, S(Mp)|M(W)|D(Mp), + /* IMOVMP */ Threop, S(Mp)|M(W)|D(Mp), + /* IMOVB */ Unop, Bop2, + /* IMOVW */ Unop, Wop2, + /* IMOVF */ Unop, Fop2, + /* ICVTBW */ Unop, S(B)|D(W), + /* ICVTWB */ Unop, S(W)|D(B), + /* ICVTFW */ Unop, S(F)|D(W), + /* ICVTWF */ Unop, S(W)|D(F), + /* ICVTCA */ Unop, S(C)|D(A), + /* ICVTAC */ Unop, S(A)|D(C), + /* ICVTWC */ Unop, S(W)|D(C), + /* ICVTCW */ Unop, S(C)|D(W), + /* ICVTFC */ Unop, S(F)|D(C), + /* ICVTCF */ Unop, S(C)|D(F), + /* IADDB */ Binop, Bop, + /* IADDW */ Binop, Wop, + /* IADDF */ Binop, Fop, + /* ISUBB */ Binop, Bop, + /* ISUBW */ Binop, Wop, + /* ISUBF */ Binop, Fop, + /* IMULB */ Binop, Bop, + /* IMULW */ Binop, Wop, + /* IMULF */ Binop, Fop, + /* IDIVB */ Binop, Bop, + /* IDIVW */ Binop, Wop, + /* IDIVF */ Binop, Fop, + /* IMODW */ Binop, Wop, + /* IMODB */ Binop, Bop, + /* IANDB */ Binop, Bop, + /* IANDW */ Binop, Wop, + /* IORB */ Binop, Bop, + /* IORW */ Binop, Wop, + /* IXORB */ Binop, Bop, + /* IXORW */ Binop, Wop, + /* ISHLB */ Binop, S(W)|M(B)|D(B), + /* ISHLW */ Binop, Wop, + /* ISHRB */ Binop, S(W)|M(B)|D(B), + /* ISHRW */ Binop, Wop, + /* IINSC */ Mabinop, S(W)|M(W)|D(C), + /* IINDC */ Threop, S(C)|M(W)|D(W), + /* IADDC */ Binop, Cop, + /* ILENC */ Unop, S(C)|D(W), + /* ILENA */ Unop, S(A)|D(W), + /* ILENL */ Unop, S(P)|D(W), + /* IBEQB */ Use3, Bopb, + /* IBNEB */ Use3, Bopb, + /* IBLTB */ Use3, Bopb, + /* IBLEB */ Use3, Bopb, + /* IBGTB */ Use3, Bopb, + /* IBGEB */ Use3, Bopb, + /* IBEQW */ Use3, Wopb, + /* IBNEW */ Use3, Wopb, + /* IBLTW */ Use3, Wopb, + /* IBLEW */ Use3, Wopb, + /* IBGTW */ Use3, Wopb, + /* IBGEW */ Use3, Wopb, + /* IBEQF */ Use3, Fopb, + /* IBNEF */ Use3, Fopb, + /* IBLTF */ Use3, Fopb, + /* IBLEF */ Use3, Fopb, + /* IBGTF */ Use3, Fopb, + /* IBGEF */ Use3, Fopb, + /* IBEQC */ Use3, Copb, + /* IBNEC */ Use3, Copb, + /* IBLTC */ Use3, Copb, + /* IBLEC */ Use3, Copb, + /* IBGTC */ Use3, Copb, + /* IBGEC */ Use3, Copb, + /* ISLICEA */ Mabinop, S(W)|M(W)|D(P), + /* ISLICELA */ Use3, S(P)|M(W)|D(P), + /* ISLICEC */ Mabinop, S(W)|M(W)|D(C), + /* IINDW */ Mbinop, S(P)|M(P)|D(W), + /* IINDF */ Mbinop, S(P)|M(P)|D(W), + /* IINDB */ Mbinop, S(P)|M(P)|D(W), + /* INEGF */ Unop, Fop2, + /* IMOVL */ Unop, Lop2, + /* IADDL */ Binop, Lop, + /* ISUBL */ Binop, Lop, + /* IDIVL */ Binop, Lop, + /* IMODL */ Binop, Lop, + /* IMULL */ Binop, Lop, + /* IANDL */ Binop, Lop, + /* IORL */ Binop, Lop, + /* IXORL */ Binop, Lop, + /* ISHLL */ Binop, S(W)|M(L)|D(L), + /* ISHRL */ Binop, S(W)|M(L)|D(L), + /* IBNEL */ Use3, Lopb, + /* IBLTL */ Use3, Lopb, + /* IBLEL */ Use3, Lopb, + /* IBGTL */ Use3, Lopb, + /* IBGEL */ Use3, Lopb, + /* IBEQL */ Use3, Lopb, + /* ICVTLF */ Unop, S(L)|D(F), + /* ICVTFL */ Unop, S(F)|D(L), + /* ICVTLW */ Unop, S(L)|D(W), + /* ICVTWL */ Unop, S(W)|D(L), + /* ICVTLC */ Unop, S(L)|D(C), + /* ICVTCL */ Unop, S(C)|D(L), + /* IHEADL */ Unop, S(P)|D(L), + /* ICONSL */ Abinop, S(L)|D(P), + /* INEWCL */ Cunop, M(W)|D(P), + /* ICASEC */ Use2, S(C)|D(I), + /* IINDL */ Mbinop, S(P)|M(P)|D(W), + /* IMOVPC */ Unop, S(W)|D(P), + /* ITCMP */ Use2, S(P)|D(P), + /* IMNEWZ */ Threop, S(P)|M(W)|D(P), + /* ICVTRF */ Unop, S(R)|D(F), + /* ICVTFR */ Unop, S(F)|D(R), + /* ICVTWS */ Unop, S(W)|D(Sh), + /* ICVTSW */ Unop, S(Sh)|D(W), + /* ILSRW */ Binop, Wop, + /* ILSRL */ Binop, S(W)|M(L)|D(L), + /* IECLR */ None, 0, + /* INEWZ */ Unop, S(W)|D(P), + /* INEWAZ */ Threop, S(W)|M(W)|D(P), + /* IRAISE */ Use1, S(P), + /* ICASEL */ Use2, S(L)|D(I), + /* IMULX */ Binop|Tuse2, Xop, + /* IDIVX */ Binop|Tuse2, Xop, + /* ICVTXX */ Threop, Xop, + /* IMULX0 */ Binop|Tuse1|Tuse2, Xop, + /* IDIVX0 */ Binop|Tuse1|Tuse2, Xop, + /* ICVTXX0 */ Threop|Tuse1, Xop, + /* IMULX1 */ Binop|Tuse1|Tuse2, Xop, + /* IDIVX1 */ Binop|Tuse1|Tuse2, Xop, + /* ICVTXX1 */ Threop|Tuse1, Xop, + /* ICVTFX */ Threop, S(F)|M(F)|D(X), + /* ICVTXF */ Threop, S(X)|M(F)|D(F), + /* IEXPW */ Binop, S(W)|M(W)|D(W), + /* IEXPL */ Binop, S(W)|M(L)|D(L), + /* IEXPF */ Binop, S(W)|M(F)|D(F), + /* ISELF */ Ddef, D(P), + /* IEXC */ None, 0, + /* IEXC0 */ None, 0, + /* INOOP */ None, 0, +}; + +/* +static int +pop(int i) +{ + i = (i & 0x55555555) + ((i>>1) & 0x55555555); + i = (i & 0x33333333) + ((i>>2) & 0x33333333); + i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F); + i = (i & 0x00FF00FF) + ((i>>8) & 0x00FF00FF); + i = (i & 0x0000FFFF) + ((i>>16) & 0x0000FFFF); + return i; +} +*/ + +static int +bitc(uint x) +{ + uint n; + + n = (x>>1)&0x77777777; + x -= n; + n = (n>>1)&0x77777777; + x -= n; + n = (n>>1)&0x77777777; + x -= n; + x = (x+(x>>4))&0x0f0f0f0f; + x *= 0x01010101; + return x>>24; +} + +/* +static int +top(uint x) +{ + int i; + + for(i = -1; x; i++) + x >>= 1; + return i; +} +*/ + +static int +topb(uint x) +{ + int i; + + if(x == 0) + return -1; + i = 0; + if(x&0xffff0000){ + i |= 16; + x >>= 16; + } + if(x&0xff00){ + i |= 8; + x >>= 8; + } + if(x&0xf0){ + i |= 4; + x >>= 4; + } + if(x&0xc){ + i |= 2; + x >>= 2; + } + if(x&0x2) + i |= 1; + return i; +} + +/* +static int +lowb(uint x) +{ + int i; + + if(x == 0) + return -1; + for(i = BLEN; x; i--) + x <<= 1; + return i; +} +*/ + +static int +lowb(uint x) +{ + int i; + + if(x == 0) + return -1; + i = 0; + if((x&0xffff) == 0){ + i |= 16; + x >>= 16; + } + if((x&0xff) == 0){ + i |= 8; + x >>= 8; + } + if((x&0xf) == 0){ + i |= 4; + x >>= 4; + } + if((x&0x3) == 0){ + i |= 2; + x >>= 2; + } + return i+1-(x&1); +} + +static void +pbit(int x, int n) +{ + int i, m; + + m = 1; + for(i = 0; i < BLEN; i++){ + if(x&m) + print("%d ", i+n); + m <<= 1; + } +} + +static ulong +bop(int o, ulong s, ulong d) +{ + switch(o){ + case Bclr: return 0; + case Band: return s & d; + case Bandinv: return s & ~d; + case Bstore: return s; + case Bandrev: return ~s & d; + case Bnoop: return d; + case Bxor: return s ^ d; + case Bor: return s | d; + case Bnor: return ~(s | d); + case Bequiv: return ~(s ^ d); + case Binv: return ~d; + case Bimpby: return s | ~d; + case Brev: return ~s; + case Bimp: return ~s | d; + case Bnand: return ~(s & d); + case Bset: return 0xffffffff; + } + return 0; +} + +static Bits +bnew(int n, int bits) +{ + Bits b; + + if(bits) + b.n = (n+BLEN-1)>>BSHIFT; + else + b.n = n; + b.b = allocmem(b.n*sizeof(ulong)); + memset(b.b, 0, b.n*sizeof(ulong)); + return b; +} + +static void +bfree(Bits b) +{ + free(b.b); +} + +static void +bset(Bits b, int n) +{ + b.b[n>>BSHIFT] |= 1<<(n&BMASK); +} + +static void +bclr(Bits b, int n) +{ + b.b[n>>BSHIFT] &= ~(1<<(n&BMASK)); +} + +static int +bmem(Bits b, int n) +{ + return b.b[n>>BSHIFT] & (1<<(n&BMASK)); +} + +static void +bsets(Bits b, int m, int n) +{ + int i, c1, c2; + + c1 = m>>BSHIFT; + c2 = n>>BSHIFT; + m &= BMASK; + n &= BMASK; + if(c1 == c2){ + b.b[c1] |= MASK(m, n); + return; + } + for(i = c1+1; i < c2; i++) + b.b[i] = 0xffffffff; + b.b[c1] |= MASK(m, BLEN-1); + b.b[c2] |= MASK(0, n); +} + +static void +bclrs(Bits b, int m, int n) +{ + int i, c1, c2; + + if(n < 0) + n = (b.n<<BSHIFT)-1; + c1 = m>>BSHIFT; + c2 = n>>BSHIFT; + m &= BMASK; + n &= BMASK; + if(c1 == c2){ + b.b[c1] &= ~MASK(m, n); + return; + } + for(i = c1+1; i < c2; i++) + b.b[i] = 0; + b.b[c1] &= ~MASK(m, BLEN-1); + b.b[c2] &= ~MASK(0, n); +} + +/* b = a op b */ +static Bits +boper(int o, Bits a, Bits b) +{ + int i, n; + + n = a.n; + if(b.n != n) + fatal("boper %d %d %d", o, a.n, b.n); + for(i = 0; i < n; i++) + b.b[i] = bop(o, a.b[i], b.b[i]); + return b; +} + +static int +beq(Bits a, Bits b) +{ + int i, n; + + n = a.n; + for(i = 0; i < n; i++) + if(a.b[i] != b.b[i]) + return 0; + return 1; +} + +static int +bzero(Bits b) +{ + int i, n; + + n = b.n; + for(i = 0; i < n; i++) + if(b.b[i] != 0) + return 0; + return 1; +} + +static int +bitcnt(Bits b) +{ + int i, m, n; + + m = b.n; + n = 0; + for(i = 0; i < m; i++) + n += bitc(b.b[i]); + return n; +} + +static int +topbit(Bits b) +{ + int i, n; + + n = b.n; + for(i = n-1; i >= 0; i--) + if(b.b[i] != 0) + return (i<<BSHIFT)+topb(b.b[i]); + return -1; +} + +static int +lowbit(Bits b) +{ + int i, n; + + n = b.n; + for(i = 0; i < n; i++) + if(b.b[i] != 0) + return (i<<BSHIFT)+lowb(b.b[i]); + return -1; +} + +static void +pbits(Bits b) +{ + int i, n; + + n = b.n; + for(i = 0; i < n; i++) + pbit(b.b[i], i<<BSHIFT); +} + +static char* +decname(Decl *d) +{ + if(d->sym == nil) + return "<??>"; + return d->sym->name; +} + +static void +warning(Inst *i, char *s, Decl *d, Decl *sd) +{ + int n; + char *f; + Decl *ds; + + n = 0; + for(ds = sd; ds != nil; ds = ds->next) + if(ds->link == d) + n += strlen(ds->sym->name)+1; + if(n == 0){ + warn(i->src.start, "%s: %s", d->sym->name, s); + return; + } + n += strlen(d->sym->name); + f = malloc(n+1); + strcpy(f, d->sym->name); + for(ds = sd; ds != nil; ds = ds->next){ + if(ds->link == d){ + strcat(f, "/"); + strcat(f, ds->sym->name); + } + } + warn(i->src.start, "%s: %s", f, s); + free(f); +} + +static int +inspc(Inst *in) +{ + int n; + Inst *i; + + n = 0; + for(i = in; i != nil; i = i->next) + i->pc = n++; + return n; +} + +static Inst* +pc2i(Block *b, int pc) +{ + Inst *i; + + for( ; b != nil; b = b->next){ + if(pc > b->last->pc) + continue; + for(i = b->first; ; i = i->next){ + if(i->pc == pc) + return i; + if(i == b->last) + fatal("pc2i a"); + } + } + fatal("pc2i b"); + return nil; +} + +static void +padr(int am, Addr *a, Inst *br) +{ + long reg; + + if(br != nil){ + print("$%ld", br->pc); + return; + } + reg = a->reg; + if(a->decl != nil && am != Adesc) + reg += a->decl->offset; + switch(am){ + case Anone: + print("-"); + break; + case Aimm: + case Apc: + case Adesc: + print("$%ld", a->offset); + break; + case Aoff: + print("$%ld", a->decl->iface->offset); + break; + case Anoff: + print("-$%ld", a->decl->iface->offset); + break; + case Afp: + print("%ld(fp)", reg); + break; + case Afpind: + print("%ld(%ld(fp))", a->offset, reg); + break; + case Amp: + print("%ld(mp)", reg); + break; + case Ampind: + print("%ld(%ld(mp))", a->offset, reg); + break; + case Aldt: + print("$%ld", reg); + break; + case Aerr: + default: + print("%ld(%ld(?%d?))", a->offset, reg, am); + break; + } +} + +static void +pins(Inst *i) +{ + /* print("%L %ld ", i->src.start, i->pc); */ + print(" %ld ", i->pc); + if(i->op >= 0 && i->op < MAXDIS) + print("%s", instname[i->op]); + else + print("noop"); + print(" "); + padr(i->sm, &i->s, nil); + print(", "); + padr(i->mm, &i->m, nil); + print(", "); + padr(i->dm, &i->d, i->branch); + print("\n"); +} + +static void +blfree(Blist *bl) +{ + Blist *nbl; + + for( ; bl != nil; bl = nbl){ + nbl = bl->next; + free(bl); + } +} + +static void +freebits(Bits *bs, int nv) +{ + int i; + + for(i = 0; i < nv; i++) + bfree(bs[i]); + free(bs); +} + +static void +freeblks(Block *b) +{ + Block *nb; + + for( ; b != nil; b = nb){ + blfree(b->pred); + blfree(b->succ); + bfree(b->kill); + bfree(b->gen); + bfree(b->in); + bfree(b->out); + nb = b->next; + free(b); + } +} + +static int +len(Decl *d) +{ + int n; + + n = 0; + for( ; d != nil; d = d->next) + n++; + return n; +} + +static Bits* +allocbits(int nv, int npc) +{ + int i; + Bits *defs; + + defs = (Bits*)allocmem(nv*sizeof(Bits)); + for(i = 0; i < nv; i++) + defs[i] = bnew(npc, 1); + return defs; +} + +static int +bitcount(Bits *bs, int nv) +{ + int i, n; + + n = 0; + for(i = 0; i < nv; i++) + n += bitcnt(bs[i]); + return n; +} + +static Block* +mkblock(Inst *i) +{ + Block *b; + + b = allocmem(sizeof(Block)); + *b = zblock; + b->first = b->last = i; + return b; +} + +static Blist* +mkblist(Block *b, Blist *nbl) +{ + Blist *bl; + + bl = allocmem(sizeof(Blist)); + bl->block = b; + bl->next = nbl; + return bl; +} + +static void +leader(Inst *i, Array *ab) +{ + int m, n; + Block *b, **a; + + if(i != nil && i->pc == 0){ + if((n = ab->n) == (m = ab->m)){ + a = ab->a; + ab->a = allocmem(2*m*sizeof(Block*)); + memcpy(ab->a, a, m*sizeof(Block*)); + ab->m = 2*m; + free(a); + } + b = mkblock(i); + b->dfn = n; + ab->a[n] = b; + i->pc = ab->n = n+1; + } +} + +static Block* +findb(Inst *i, Array *ab) +{ + if(i == nil) + return nil; + if(i->pc <= 0) + fatal("pc <= 0 in findb"); + return ab->a[i->pc-1]; +} + +static int +memb(Block *b, Blist *bl) +{ + for( ; bl != nil; bl = bl->next) + if(bl->block == b) + return 1; + return 0; +} + +static int +canfallthrough(Inst *i) +{ + if(i == nil) + return 0; + switch(i->op){ + case IGOTO: + case ICASE: + case ICASEL: + case ICASEC: + case IRET: + case IEXIT: + case IRAISE: + case IJMP: + return 0; + case INOOP: + return i->branch != nil; + } + return 1; +} + +static void +predsucc(Block *b1, Block *b2) +{ + if(b1 == nil || b2 == nil) + return; + if(!memb(b1, b2->pred)) + b2->pred = mkblist(b1, b2->pred); + if(!memb(b2, b1->succ)) + b1->succ = mkblist(b2, b1->succ); +} + +static Block* +mkblocks(Inst *in, int *nb) +{ + Inst *i; + Block *b, *firstb, *lastb; + Label *lab; + Array *ab; + int j, n; + + ab = allocmem(sizeof(Array)); + ab->n = 0; + ab->m = 16; + ab->a = allocmem(ab->m*sizeof(Block*)); + leader(in, ab); + for(i = in; i != nil; i = i->next){ + switch(i->op){ + case IGOTO: + case ICASE: + case ICASEL: + case ICASEC: + case INOOP: + if(i->op == INOOP && i->branch != nil){ + leader(i->branch, ab); + leader(i->next, ab); + break; + } + leader(i->d.decl->ty->cse->iwild, ab); + lab = i->d.decl->ty->cse->labs; + n = i->d.decl->ty->cse->nlab; + for(j = 0; j < n; j++) + leader(lab[j].inst, ab); + leader(i->next, ab); + break; + case IRET: + case IEXIT: + case IRAISE: + leader(i->next, ab); + break; + case IJMP: + leader(i->branch, ab); + leader(i->next, ab); + break; + default: + if(i->branch != nil){ + leader(i->branch, ab); + leader(i->next, ab); + } + break; + } + } + firstb = lastb = mkblock(nil); + for(i = in; i != nil; i = i->next){ + if(i->pc != 0){ + b = findb(i, ab); + b->prev = lastb; + lastb->next = b; + if(canfallthrough(lastb->last)) + predsucc(lastb, b); + lastb = b; + } + else + lastb->last = i; + switch(i->op){ + case IGOTO: + case ICASE: + case ICASEL: + case ICASEC: + case INOOP: + if(i->op == INOOP && i->branch != nil){ + b = findb(i->next, ab); + predsucc(lastb, b); + b = findb(i->branch, ab); + predsucc(lastb, b); + break; + } + b = findb(i->d.decl->ty->cse->iwild, ab); + predsucc(lastb, b); + lab = i->d.decl->ty->cse->labs; + n = i->d.decl->ty->cse->nlab; + for(j = 0; j < n; j++){ + b = findb(lab[j].inst, ab); + predsucc(lastb, b); + } + break; + case IRET: + case IEXIT: + case IRAISE: + break; + case IJMP: + b = findb(i->branch, ab); + predsucc(lastb, b); + break; + default: + if(i->branch != nil){ + b = findb(i->next, ab); + predsucc(lastb, b); + b = findb(i->branch, ab); + predsucc(lastb, b); + } + break; + } + } + *nb = ab->n; + free(ab->a); + free(ab); + b = firstb->next; + b->prev = nil; + return b; +} + +static int +back(Block *b1, Block *b2) +{ + return b1->dfn >= b2->dfn; +} + +static void +pblocks(Block *b, int nb) +{ + Inst *i; + Blist *bl; + + print("--------------------%d blocks--------------------\n", nb); + print("------------------------------------------------\n"); + for( ; b != nil; b = b->next){ + print("dfn=%d\n", b->dfn); + print(" pred "); + for(bl = b->pred; bl != nil; bl = bl->next) + print("%d%s ", bl->block->dfn, back(bl->block, b) ? "*" : ""); + print("\n"); + print(" succ "); + for(bl = b->succ; bl != nil; bl = bl->next) + print("%d%s ", bl->block->dfn, back(b, bl->block) ? "*" : ""); + print("\n"); + for(i = b->first; i != nil; i = i->next){ + // print(" %I\n", i); + pins(i); + if(i == b->last) + break; + } + } + print("------------------------------------------------\n"); +} + +static void +ckblocks(Inst *in, Block *b, int nb) +{ + int n; + Block *lastb; + + if(b->first != in) + fatal("A - %d", b->dfn); + n = 0; + lastb = nil; + for( ; b != nil; b = b->next){ + n++; + if(b->prev != lastb) + fatal("a - %d\n", b->dfn); + if(b->prev != nil && b->prev->next != b) + fatal("b - %d\n", b->dfn); + if(b->next != nil && b->next->prev != b) + fatal("c - %d\n", b->dfn); + + if(b->prev != nil && b->prev->last->next != b->first) + fatal("B - %d\n", b->dfn); + if(b->next != nil && b->last->next != b->next->first) + fatal("C - %d\n", b->dfn); + if(b->next == nil && b->last->next != nil) + fatal("D - %d\n", b->dfn); + + if(b->last->branch != nil && b->succ->block->first != b->last->branch) + fatal("0 - %d\n", b->dfn); + + lastb = b; + } + if(n != nb) + fatal("N - %d %d\n", n, nb); +} + +static void +dfs0(Block *b, int *n) +{ + Block *s; + Blist *bl; + + b->flags = 1; + for(bl = b->succ; bl != nil; bl = bl->next){ + s = bl->block; + if(s->flags == 0) + dfs0(s, n); + } + b->dfn = --(*n); +} + +static int +dfs(Block *b, int nb) +{ + int n, u; + Block *b0; + + b0 = b; + n = nb; + dfs0(b0, &n); + u = 0; + for(b = b0; b != nil; b = b->next){ + if(b->flags == 0){ /* unreachable: see foldbranch */ + fatal("found unreachable code"); + u++; + b->prev->next = b->next; + if(b->next){ + b->next->prev = b->prev; + b->prev->last->next = b->next->first; + } + else + b->prev->last->next = nil; + } + b->flags = 0; + } + if(u){ + for(b = b0; b != nil; b = b->next) + b->dfn -= u; + } + return nb-u; +} + +static void +loop0(Block *b) +{ + Block *p; + Blist *bl; + + b->flags = 1; + for(bl = b->pred; bl != nil; bl = bl->next){ + p = bl->block; + if(p->flags == 0) + loop0(p); + } +} + +/* b1->b2 a back edge */ +static void +loop(Block *b, Block *b1, Block *b2) +{ + if(0 && debug['o']) + print("back edge %d->%d\n", b1->dfn, b2->dfn); + b2->flags = 1; + if(b1->flags == 0) + loop0(b1); + if(0 && debug['o']) + print(" loop "); + for( ; b != nil; b = b->next){ + if(b->flags && 0 && debug['o']) + print("%d ", b->dfn); + b->flags = 0; + } + if(0 && debug['o']) + print("\n"); +} + +static void +loops(Block *b) +{ + Block *b0; + Blist *bl; + + b0 = b; + for( ; b != nil; b = b->next){ + for(bl = b->succ; bl != nil; bl = bl->next){ + if(back(b, bl->block)) + loop(b0, b, bl->block); + } + } +} + +static int +imm(int m, Addr *a) +{ + if(m == Aimm) + return a->offset; + fatal("bad immediate value"); + return -1; +} + +static int +desc(int m, Addr *a) +{ + if(m == Adesc) + return a->decl->desc->size; + fatal("bad descriptor value"); + return -1; +} + +static int +fpoff(int m, Addr *a) +{ + int off; + Decl *d; + + if(m == Afp || m == Afpind){ + off = a->reg; + if((d = a->decl) != nil) + off += d->offset; + return off; + } + return -1; +} + +static int +size(Inst *i) +{ + switch(i->op){ + case ISEND: + case IRECV: + case IALT: + case INBALT: + case ILEA: + return i->m.offset; + case IMOVM: + case IHEADM: + case ICONSM: + return imm(i->mm, &i->m); + case IMOVMP: + case IHEADMP: + case ICONSMP: + return desc(i->mm, &i->m); + break; + } + fatal("bad op in size"); + return -1; +} + +static Decl* +mkdec(int o) +{ + Decl *d; + + d = mkdecl(&nosrc, Dlocal, tint); + d->offset = o; + return d; +} + +static void +mkdecls(void) +{ + regdecls = mkdec(REGRET*IBY2WD); + regdecls->next = mkdec(STemp); + regdecls->next->next = mkdec(DTemp); +} + +static Decl* +sharedecls(Decl *d) +{ + Decl *ld; + + ld = d; + for(d = d->next ; d != nil; d = d->next){ + if(d->offset <= ld->offset) + break; + ld = d; + } + return d; +} + +static int +finddec(int o, int s, Decl *vars, int *nv, Inst *i) +{ + int m, n; + Decl *d; + + n = 0; + for(d = vars; d != nil; d = d->next){ + if(o >= d->offset && o < d->offset+d->ty->size){ + m = 1; + while(o+s > d->offset+d->ty->size){ + m++; + d = d->next; + } + *nv = m; + return n; + } + n++; + } + // print("%d %d missing\n", o, s); + pins(i); + fatal("missing decl"); + return -1; +} + +static void +setud(Bits *b, int id, int n, int pc) +{ + if(id < 0) + return; + while(--n >= 0) + bset(b[id++], pc); +} + +static void +ud(Inst *i, Decl *vars, Bits *uses, Bits *defs) +{ + ushort f; + int id, j, nv, pc, sz, s, m, d, ss, sm, sd; + Optab *t; + Idlist *l; + + pc = i->pc; + ss = 0; + t = &opflags[i->op]; + f = t->flags; + sz = t->size; + s = fpoff(i->sm, &i->s); + m = fpoff(i->mm, &i->m); + d = fpoff(i->dm, &i->d); + if(f&Mduse && i->mm == Anone) + f |= Duse; + if(s >= 0){ + if(i->sm == Afp){ + ss = SS(sz); + if(ss == Mp) + ss = size(i); + } + else + ss = IBY2WD; + id = finddec(s, ss, vars, &nv, i); + if(f&Suse) + setud(uses, id, nv, pc); + if(f&Sdef){ + if(i->sm == Afp) + setud(defs, id, nv, pc); + else + setud(uses, id, nv, pc); + } + } + if(m >= 0){ + if(i->mm == Afp){ + sm = SM(sz); + if(sm == Mp) + sm = size(i); + } + else + sm = IBY2WD; + id = finddec(m, sm, vars, &nv, i); + if(f&Muse) + setud(uses, id, nv, pc); + if(f&Mdef){ + if(i->mm == Afp) + setud(defs, id, nv, pc); + else + setud(uses, id, nv, pc); + } + } + if(d >= 0){ + if(i->dm == Afp){ + sd = SD(sz); + if(sd == Mp) + sd = size(i); + } + else + sd = IBY2WD; + id = finddec(d, sd, vars, &nv, i); + if(f&Duse) + setud(uses, id, nv, pc); + if(f&Ddef){ + if(i->dm == Afp) + setud(defs, id, nv, pc); + else + setud(uses, id, nv, pc); + } + } + if(f&Tuse1){ + id = finddec(STemp, IBY2WD, vars, &nv, i); + setud(uses, id, nv, pc); + } + if(f&Tuse2){ + id = finddec(DTemp, IBY2WD, vars, &nv, i); + setud(uses, id, nv, pc); + } + if(i->op == ILEA){ + if(s >= 0){ + id = finddec(s, ss, vars, &nv, i); + if(i->sm == Afp && i->m.reg == 0) + setud(defs, id, nv, pc); + else + setud(uses, id, nv, pc); + } + } + if(0) + switch(i->op){ + case ILEA: + if(s >= 0){ + id = finddec(s, ss, vars, &nv, i); + if(id < 0) + break; + for(j = 0; j < nv; j++){ + if(i->sm == Afp && i->m.reg == 0) + addlist(&deflist, id++); + else + addlist(&uselist, id++); + } + } + break; + case IALT: + case INBALT: + case ICALL: + case IMCALL: + for(l = deflist; l != nil; l = l->next){ + id = l->id; + bset(defs[id], pc); + } + for(l = uselist; l != nil; l = l->next){ + id = l->id; + bset(uses[id], pc); + } + freelist(&deflist); + freelist(&uselist); + break; + } +} + +static void +usedef(Inst *in, Decl *vars, Bits *uses, Bits *defs) +{ + Inst *i; + + for(i = in; i != nil; i = i->next) + ud(i, vars, uses, defs); +} + +static void +pusedef(Bits *ud, int nv, Decl *d, char *s) +{ + int i; + + print("%s\n", s); + for(i = 0; i < nv; i++){ + if(!bzero(ud[i])){ + print("\t%s(%ld): ", decname(d), d->offset); + pbits(ud[i]); + print("\n"); + } + d = d->next; + } +} + +static void +dummydefs(Bits *defs, int nv, int npc) +{ + int i; + + for(i = 0; i < nv; i++) + bset(defs[i], npc++); +} + +static void +dogenkill(Block *b, Bits *defs, int nv) +{ + int i, n, t; + Bits v; + + n = defs[0].n; + v = bnew(n, 0); + for( ; b != nil; b = b->next){ + b->gen = bnew(n, 0); + b->kill = bnew(n, 0); + b->in = bnew(n, 0); + b->out = bnew(n, 0); + for(i = 0; i < nv; i++){ + boper(Bclr, v, v); + bsets(v, b->first->pc, b->last->pc); + boper(Band, defs[i], v); + t = topbit(v); + if(t >= 0) + bset(b->gen, t); + else + continue; + boper(Bclr, v, v); + bsets(v, b->first->pc, b->last->pc); + boper(Binv, v, v); + boper(Band, defs[i], v); + boper(Bor, v, b->kill); + } + } + bfree(v); +} + +static void +udflow(Block *b, int nv, int npc) +{ + int iter; + Block *b0, *p; + Blist *bl; + Bits newin; + + b0 = b; + for(b = b0; b != nil; b = b->next) + boper(Bstore, b->gen, b->out); + newin = bnew(b0->in.n, 0); + iter = 1; + while(iter){ + iter = 0; + for(b = b0; b != nil; b = b->next){ + boper(Bclr, newin, newin); + for(bl = b->pred; bl != nil; bl = bl->next){ + p = bl->block; + boper(Bor, p->out, newin); + } + if(b == b0) + bsets(newin, npc, npc+nv-1); + if(!beq(b->in, newin)) + iter = 1; + boper(Bstore, newin, b->in); + boper(Bstore, b->in, b->out); + boper(Bandrev, b->kill, b->out); + boper(Bor, b->gen, b->out); + } + } + bfree(newin); +} + +static void +pflows(Block *b) +{ + for( ; b != nil; b = b->next){ + print("block %d\n", b->dfn); + print(" gen: "); pbits(b->gen); print("\n"); + print(" kill: "); pbits(b->kill); print("\n"); + print(" in: "); pbits(b->in); print("\n"); + print(" out: "); pbits(b->out); print("\n"); + } +} + +static int +set(Decl *d) +{ + if(d->store == Darg) + return 1; + if(d->sym == nil) /* || d->sym->name[0] == '.') */ + return 1; + if(tattr[d->ty->kind].isptr || d->ty->kind == Texception) + return 1; + return 0; +} + +static int +used(Decl *d) +{ + if(d->sym == nil ) /* || d->sym->name[0] == '.') */ + return 1; + return 0; +} + +static void +udchain(Block *b, Decl *ds, int nv, int npc, Bits *defs, Bits *uses, Decl *sd) +{ + int i, n, p, q; + Bits d, u, dd, ud; + Block *b0; + Inst *in; + + b0 = b; + n = defs[0].n; + u = bnew(n, 0); + d = bnew(n, 0); + dd = bnew(n, 0); + ud = bnew(n, 0); + for(i = 0; i < nv; i++){ + boper(Bstore, defs[i], ud); + bclr(ud, npc+i); + for(b = b0 ; b != nil; b = b->next){ + boper(Bclr, u, u); + bsets(u, b->first->pc, b->last->pc); + boper(Band, uses[i], u); + boper(Bclr, d, d); + bsets(d, b->first->pc, b->last->pc); + boper(Band, defs[i], d); + for(;;){ + p = topbit(u); + if(p < 0) + break; + bclr(u, p); + bclrs(d, p, -1); + q = topbit(d); + if(q >= 0){ + bclr(ud, q); + if(debug['o']) + print("udc b=%d v=%d(%s/%ld) u=%d d=%d\n", b->dfn, i, decname(ds), ds->offset, p, q); + } + else{ + boper(Bstore, defs[i], dd); + boper(Band, b->in, dd); + boper(Bandrev, dd, ud); + if(!bzero(dd)){ + if(debug['o']){ + print("udc b=%d v=%d(%s/%ld) u=%d d=", b->dfn, i, decname(ds), ds->offset, p); + pbits(dd); + print("\n"); + } + if(bmem(dd, npc+i) && !set(ds)) + warning(pc2i(b0, p), "used and not set", ds, sd); + } + else + fatal("no defs in udchain"); + } + } + } + for(;;){ + p = topbit(ud); + if(p < 0) + break; + bclr(ud, p); + if(!used(ds)){ + in = pc2i(b0, p); + if(isnilsrc(&in->src)) /* nilling code */ + in->op = INOOP; /* elim p from bitmaps ? */ + else if(limbovar(ds) && !structure(ds->ty)) + warning(in, "set and not used", ds, sd); + } + } + ds = ds->next; + } + bfree(u); + bfree(d); + bfree(dd); + bfree(ud); +} + +static void +ckflags(void) +{ + int i, j, k, n; + Optab *o; + + n = nelem(opflags); + o = opflags; + for(i = 0; i < n; i++){ + j = (o->flags&(Suse|Sdef)) != 0; + k = SS(o->size) != 0; + if(j != k){ + if(!(j == 0 && k == 1 && i == ILEA)) + fatal("S %ld %s\n", o-opflags, instname[i]); + } + j = (o->flags&(Muse|Mdef)) != 0; + k = SM(o->size) != 0; + if(j != k) + fatal("M %ld %s\n", o-opflags, instname[i]); + j = (o->flags&(Duse|Ddef)) != 0; + k = SD(o->size) != 0; + if(j != k){ + if(!(j == 1 && k == 0 && (i == IGOTO || i == ICASE || i == ICASEC || i == ICASEL))) + fatal("D %ld %s\n", o-opflags, instname[i]); + } + o++; + } +} + +void +optim(Inst *in, Decl *d) +{ + int nb, npc, nv, nd, nu; + Block *b; + Bits *uses, *defs; + Decl *sd; + + ckflags(); + if(debug['o']) + print("************************************************\nfunction %s\n************************************************\n", d->sym->name); + if(in == nil || errors > 0) + return; + d = d->ty->ids; + if(regdecls == nil) + mkdecls(); + regdecls->next->next->next = d; + d = regdecls; + sd = sharedecls(d); + if(debug['o']) + printdecls(d); + b = mkblocks(in, &nb); + ckblocks(in, b, nb); + npc = inspc(in); + nb = dfs(b, nb); + if(debug['o']) + pblocks(b, nb); + loops(b); + nv = len(d); + uses = allocbits(nv, npc+nv); + defs = allocbits(nv, npc+nv); + dummydefs(defs, nv, npc); + usedef(in, d, uses, defs); + if(debug['o']){ + pusedef(uses, nv, d, "uses"); + pusedef(defs, nv, d, "defs"); + } + nu = bitcount(uses, nv); + nd = bitcount(defs, nv); + dogenkill(b, defs, nv); + udflow(b, nv, npc); + if(debug['o']) + pflows(b); + udchain(b, d, nv, npc, defs, uses, sd); + freeblks(b); + freebits(uses, nv); + freebits(defs, nv); + if(debug['o']) + print("nb=%d npc=%d nv=%d nd=%d nu=%d\n", nb, npc, nv, nd, nu); +} + |
