123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825 |
- #include "l.h"
- static struct {
- ulong start;
- ulong size;
- } pool;
- void checkpool(Prog*);
- void flushpool(Prog*, int);
- void
- span(void)
- {
- Prog *p;
- Sym *setext, *s;
- Optab *o;
- int m, bflag, i;
- long c, otxt, v;
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
- bflag = 0;
- c = INITTEXT;
- otxt = c;
- for(p = firstp; p != P; p = p->link) {
- p->pc = c;
- o = oplook(p);
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
- continue;
- }
- diag("zero-width instruction\n%P\n", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
- flushpool(p, 0);
- break;
- }
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0);
- c += m;
- if(blitrl)
- checkpool(p);
- }
- /*
- * if any procedure is large enough to
- * generate a large SBRA branch, then
- * generate extra passes putting branches
- * around jmps to fix. this is rare.
- */
- while(bflag) {
- if(debug['v'])
- Bprint(&bso, "%5.2f span1\n", cputime());
- bflag = 0;
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- p->pc = c;
- o = oplook(p);
- /* very larg branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
- }
- }
- */
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- diag("zero-width instruction\n%P\n", p);
- continue;
- }
- c += m;
- }
- }
- if(debug['t']) {
- /*
- * add strings to text segment
- */
- c = rnd(c, 8);
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SSTRING)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->value = c;
- c += v;
- }
- }
- c = rnd(c, 8);
- setext = lookup("etext", 0);
- if(setext != S) {
- setext->value = c;
- textsize = c - INITTEXT;
- }
- if(INITRND)
- INITDAT = rnd(c, INITRND);
- if(debug['v'])
- Bprint(&bso, "tsize = %lux\n", textsize);
- Bflush(&bso);
- }
- /*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
- void
- checkpool(Prog *p)
- {
- if(pool.size >= 0xffc || immaddr((p->pc+4)+4+pool.size - pool.start+8) == 0)
- flushpool(p, 1);
- else if(p->link == P)
- flushpool(p, 2);
- }
- void
- flushpool(Prog *p, int skip)
- {
- Prog *q;
- if(blitrl) {
- if(skip){
- if(debug['v'] && skip == 1)
- print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
- q = prg();
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->link;
- q->link = blitrl;
- blitrl = q;
- }
- else if(p->pc+pool.size-pool.start < 2048)
- return;
- elitrl->link = p->link;
- p->link = blitrl;
- blitrl = 0; /* BUG: should refer back to values until out-of-range */
- elitrl = 0;
- pool.size = 0;
- pool.start = 0;
- }
- }
- void
- addpool(Prog *p, Adr *a)
- {
- Prog *q, t;
- int c;
- c = aclass(a);
- t = zprg;
- t.as = AWORD;
- switch(c) {
- default:
- t.to = *a;
- break;
- case C_SROREG:
- case C_LOREG:
- case C_ROREG:
- case C_FOREG:
- case C_SOREG:
- case C_FAUTO:
- case C_SAUTO:
- case C_LAUTO:
- case C_LACON:
- t.to.type = D_CONST;
- t.to.offset = instoffset;
- break;
- }
- for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */
- if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
- p->cond = q;
- return;
- }
- q = prg();
- *q = t;
- q->pc = pool.size;
- if(blitrl == P) {
- blitrl = q;
- pool.start = p->pc;
- } else
- elitrl->link = q;
- elitrl = q;
- pool.size += 4;
- p->cond = q;
- }
- void
- xdefine(char *p, int t, long v)
- {
- Sym *s;
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- }
- long
- regoff(Adr *a)
- {
- instoffset = 0;
- aclass(a);
- return instoffset;
- }
- long
- immrot(ulong v)
- {
- int i;
- for(i=0; i<16; i++) {
- if((v & ~0xff) == 0)
- return (i<<8) | v | (1<<25);
- v = (v<<2) | (v>>30);
- }
- return 0;
- }
- long
- immaddr(long v)
- {
- if(v >= 0 && v <= 0xfff)
- return (v & 0xfff) |
- (1<<24) | /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xfff && v < 0)
- return (-v & 0xfff) |
- (1<<24); /* pre indexing */
- return 0;
- }
- int
- immfloat(long v)
- {
- return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */
- }
- int
- immhalf(long v)
- {
- if(v >= 0 && v <= 0xff)
- return v|
- (1<<24)| /* pre indexing */
- (1<<23); /* pre indexing, up */
- if(v >= -0xff && v < 0)
- return (-v & 0xff)|
- (1<<24); /* pre indexing */
- return 0;
- }
- int
- aclass(Adr *a)
- {
- Sym *s;
- int t;
- switch(a->type) {
- case D_NONE:
- return C_NONE;
- case D_REG:
- return C_REG;
- case D_REGREG:
- return C_REGREG;
- case D_SHIFT:
- return C_SHIFT;
- case D_FREG:
- return C_FREG;
- case D_FPCR:
- return C_FCR;
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- s = a->sym;
- t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(reloc) {
- switch(t) {
- default:
- instoffset = s->value + a->offset + INITDAT;
- break;
- case STEXT:
- if(s->value == -1)
- undefsym(s);
- case SCONST:
- case SLEAF:
- case SSTRING:
- instoffset = s->value + a->offset;
- break;
- }
- return C_ADDR;
- }
- instoffset = s->value + a->offset - BIG;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFEXT : C_HEXT;
- if(immfloat(t))
- return C_FEXT;
- return C_SEXT;
- }
- return C_LEXT;
- case D_AUTO:
- instoffset = autosize + a->offset;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- t = immaddr(instoffset);
- if(t){
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFAUTO : C_HAUTO;
- if(immfloat(t))
- return C_FAUTO;
- return C_SAUTO;
- }
- return C_LAUTO;
- case D_NONE:
- instoffset = a->offset;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */
- return immfloat(t) ? C_HFOREG : C_HOREG;
- if(immfloat(t))
- return C_FOREG; /* n.b. that it will also satisfy immrot */
- t = immrot(instoffset);
- if(t)
- return C_SROREG;
- if(immhalf(instoffset))
- return C_HOREG;
- return C_SOREG;
- }
- t = immrot(instoffset);
- if(t)
- return C_ROREG;
- return C_LOREG;
- }
- return C_GOK;
- case D_PSR:
- return C_PSR;
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- }
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF) {
- if(s->value == -1)
- undefsym(s);
- instoffset = s->value + a->offset;
- }
- return C_LCON;
- }
- return C_GOK;
- case D_FCONST:
- return C_FCON;
- case D_CONST:
- switch(a->name) {
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
- t = immrot(instoffset);
- if(t)
- return C_RCON;
- t = immrot(~instoffset);
- if(t)
- return C_NCON;
- return C_LCON;
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case STEXT:
- if(s->value == -1)
- undefsym(s);
- case SSTRING:
- case SCONST:
- case SLEAF:
- instoffset = s->value + a->offset;
- return C_LCON;
- }
- if(!reloc) {
- instoffset = s->value + a->offset - BIG;
- t = immrot(instoffset);
- if(t && instoffset != 0)
- return C_RECON;
- }
- instoffset = s->value + a->offset + INITDAT;
- return C_LCON;
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- t = immrot(instoffset);
- if(t)
- return C_RACON;
- return C_LACON;
- }
- return C_GOK;
- case D_BRANCH:
- return C_SBRA;
- }
- return C_GOK;
- }
- Optab*
- oplook(Prog *p)
- {
- int a1, a2, a3, r;
- char *c1, *c3;
- Optab *o, *e;
- a1 = p->optab;
- if(a1)
- return optab+(a1-1);
- a1 = p->from.class;
- if(a1 == 0) {
- a1 = aclass(&p->from) + 1;
- p->from.class = a1;
- }
- a1--;
- a3 = p->to.class;
- if(a3 == 0) {
- a3 = aclass(&p->to) + 1;
- p->to.class = a3;
- }
- a3--;
- a2 = C_NONE;
- if(p->reg != NREG)
- a2 = C_REG;
- r = p->as;
- o = oprange[r].start;
- if(o == 0) {
- a1 = opcross[repop[r]][a1][a2][a3];
- if(a1) {
- p->optab = a1+1;
- return optab+a1;
- }
- o = oprange[r].stop; /* just generate an error */
- }
- if(0) {
- print("oplook %A %d %d %d\n",
- (int)p->as, a1, a2, a3);
- print(" %d %d\n", p->from.type, p->to.type);
- }
- e = oprange[r].stop;
- c1 = xcmp[a1];
- c3 = xcmp[a3];
- for(; o<e; o++)
- if(o->a2 == a2)
- if(c1[o->a1])
- if(c3[o->a3]) {
- p->optab = (o-optab)+1;
- return o;
- }
- diag("illegal combination %A %d %d %d\n",
- p->as, a1, a2, a3);
- prasm(p);
- if(o == 0)
- o = optab;
- return o;
- }
- int
- cmp(int a, int b)
- {
- if(a == b)
- return 1;
- switch(a) {
- case C_LCON:
- if(b == C_RCON || b == C_NCON)
- return 1;
- break;
- case C_LACON:
- if(b == C_RACON)
- return 1;
- break;
- case C_LECON:
- if(b == C_RECON)
- return 1;
- break;
- case C_HFEXT:
- return b == C_HEXT || b == C_FEXT;
- case C_FEXT:
- case C_HEXT:
- return b == C_HFEXT;
- case C_SEXT:
- return cmp(C_HFEXT, b);
- case C_LEXT:
- return cmp(C_SEXT, b);
- case C_HFAUTO:
- return b == C_HAUTO || b == C_FAUTO;
- case C_FAUTO:
- case C_HAUTO:
- return b == C_HFAUTO;
- case C_SAUTO:
- return cmp(C_HFAUTO, b);
- case C_LAUTO:
- return cmp(C_SAUTO, b);
- case C_HFOREG:
- return b == C_HOREG || b == C_FOREG;
- case C_FOREG:
- case C_HOREG:
- return b == C_HFOREG;
- case C_SROREG:
- return cmp(C_SOREG, b) || cmp(C_ROREG, b);
- case C_SOREG:
- case C_ROREG:
- return b == C_SROREG || cmp(C_HFOREG, b);
- case C_LOREG:
- return cmp(C_SROREG, b);
- case C_LBRA:
- if(b == C_SBRA)
- return 1;
- break;
- }
- return 0;
- }
- int
- ocmp(const void *a1, const void *a2)
- {
- Optab *p1, *p2;
- int n;
- p1 = (Optab*)a1;
- p2 = (Optab*)a2;
- n = p1->as - p2->as;
- if(n)
- return n;
- n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */
- if(n)
- return n;
- n = p1->a1 - p2->a1;
- if(n)
- return n;
- n = p1->a2 - p2->a2;
- if(n)
- return n;
- n = p1->a3 - p2->a3;
- if(n)
- return n;
- return 0;
- }
- void
- buildop(void)
- {
- int i, n, r;
- armv4 = !debug['h'];
- for(i=0; i<C_GOK; i++)
- for(n=0; n<C_GOK; n++)
- xcmp[i][n] = cmp(n, i);
- for(n=0; optab[n].as != AXXX; n++)
- if((optab[n].flag & V4) && !armv4) {
- optab[n].as = AXXX;
- break;
- }
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
- switch(r)
- {
- default:
- diag("unknown op in build: %A\n", r);
- errorexit();
- case AADD:
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[ASUB] = oprange[r];
- oprange[ARSB] = oprange[r];
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[ARSC] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- break;
- case ACMP:
- oprange[ATST] = oprange[r];
- oprange[ATEQ] = oprange[r];
- oprange[ACMN] = oprange[r];
- break;
- case AMVN:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case ASLL:
- oprange[ASRL] = oprange[r];
- oprange[ASRA] = oprange[r];
- break;
- case AMUL:
- oprange[AMULU] = oprange[r];
- break;
- case ADIV:
- oprange[AMOD] = oprange[r];
- oprange[AMODU] = oprange[r];
- oprange[ADIVU] = oprange[r];
- break;
- case AMOVW:
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- break;
- case ASWPW:
- oprange[ASWPBU] = oprange[r];
- break;
- case AB:
- case ABL:
- case ASWI:
- case AWORD:
- case AMOVM:
- case ARFE:
- case ATEXT:
- case ACASE:
- case ABCASE:
- break;
- case AADDF:
- oprange[AADDD] = oprange[r];
- oprange[ASUBF] = oprange[r];
- oprange[ASUBD] = oprange[r];
- oprange[AMULF] = oprange[r];
- oprange[AMULD] = oprange[r];
- oprange[ADIVF] = oprange[r];
- oprange[ADIVD] = oprange[r];
- oprange[AMOVFD] = oprange[r];
- oprange[AMOVDF] = oprange[r];
- break;
-
- case ACMPF:
- oprange[ACMPD] = oprange[r];
- break;
- case AMOVF:
- oprange[AMOVD] = oprange[r];
- break;
- case AMOVFW:
- oprange[AMOVWF] = oprange[r];
- oprange[AMOVWD] = oprange[r];
- oprange[AMOVDW] = oprange[r];
- break;
- case AMULL:
- oprange[AMULA] = oprange[r];
- oprange[AMULAL] = oprange[r];
- oprange[AMULLU] = oprange[r];
- oprange[AMULALU] = oprange[r];
- break;
- }
- }
- }
- /*
- void
- buildrep(int x, int as)
- {
- Opcross *p;
- Optab *e, *s, *o;
- int a1, a2, a3, n;
- if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
- diag("assumptions fail in buildrep");
- errorexit();
- }
- repop[as] = x;
- p = (opcross + x);
- s = oprange[as].start;
- e = oprange[as].stop;
- for(o=e-1; o>=s; o--) {
- n = o-optab;
- for(a2=0; a2<2; a2++) {
- if(a2) {
- if(o->a2 == C_NONE)
- continue;
- } else
- if(o->a2 != C_NONE)
- continue;
- for(a1=0; a1<32; a1++) {
- if(!xcmp[a1][o->a1])
- continue;
- for(a3=0; a3<32; a3++)
- if(xcmp[a3][o->a3])
- (*p)[a1][a2][a3] = n;
- }
- }
- }
- oprange[as].start = 0;
- }
- */
|