diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /utils/5l/noop.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'utils/5l/noop.c')
| -rw-r--r-- | utils/5l/noop.c | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/utils/5l/noop.c b/utils/5l/noop.c new file mode 100644 index 00000000..08ef6dbe --- /dev/null +++ b/utils/5l/noop.c @@ -0,0 +1,894 @@ +#include "l.h" + +static Sym* sym_div; +static Sym* sym_divu; +static Sym* sym_mod; +static Sym* sym_modu; + +static void setdiv(int); + +static Prog * +movrr(Prog *q, int rs, int rd, Prog *p) +{ + if(q == nil) + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = rs; + q->to.type = D_REG; + q->to.reg = rd; + q->link = p->link; + return q; +} + +static Prog * +fnret(Prog *q, int rs, int foreign, Prog *p) +{ + q = movrr(q, rs, REGPC, p); + if(foreign){ // BX rs + q->as = ABXRET; + q->from.type = D_NONE; + q->from.reg = NREG; + q->to.reg = rs; + } + return q; +} + +static Prog * +aword(long w, Prog *p) +{ + Prog *q; + + q = prg(); + q->as = AWORD; + q->line = p->line; + q->from.type = D_NONE; + q->reg = NREG; + q->to.type = D_CONST; + q->to.offset = w; + q->link = p->link; + p->link = q; + return q; +} + +static Prog * +adword(long w1, long w2, Prog *p) +{ + Prog *q; + + q = prg(); + q->as = ADWORD; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = w1; + q->reg = NREG; + q->to.type = D_CONST; + q->to.offset = w2; + q->link = p->link; + p->link = q; + return q; +} + +void +noops(void) +{ + Prog *p, *q, *q1, *q2; + int o, curframe, curbecome, maxbecome, foreign; + + /* + * find leaf subroutines + * become sizes + * frame sizes + * strip NOPs + * expand RET + * expand BECOME pseudo + */ + + if(debug['v']) + Bprint(&bso, "%5.2f noops\n", cputime()); + Bflush(&bso); + + curframe = 0; + curbecome = 0; + maxbecome = 0; + curtext = 0; + + q = P; + for(p = firstp; p != P; p = p->link) { + setarch(p); + + /* find out how much arg space is used in this TEXT */ + if(p->to.type == D_OREG && p->to.reg == REGSP) + if(p->to.offset > curframe) + curframe = p->to.offset; + + switch(p->as) { + case ATEXT: + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + curframe = 0; + curbecome = 0; + + p->mark |= LEAF; + curtext = p; + break; + + case ARET: + /* special form of RET is BECOME */ + if(p->from.type == D_CONST) + if(p->from.offset > curbecome) + curbecome = p->from.offset; + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + q = p; + if(prog_div == P) + initdiv(); + if(curtext != P) + curtext->mark &= ~LEAF; + setdiv(p->as); + continue; + + case ANOP: + q1 = p->link; + q->link = q1; /* q is non-nop */ + q1->mark |= p->mark; + continue; + + case ABL: + case ABX: + if(curtext != P) + curtext->mark &= ~LEAF; + + case ABCASE: + case AB: + + case ABEQ: + case ABNE: + case ABCS: + case ABHS: + case ABCC: + case ABLO: + case ABMI: + case ABPL: + case ABVS: + case ABVC: + case ABHI: + case ABLS: + case ABGE: + case ABLT: + case ABGT: + case ABLE: + + q1 = p->cond; + if(q1 != P) { + while(q1->as == ANOP) { + q1 = q1->link; + p->cond = q1; + } + } + break; + } + q = p; + } + + if(curtext && curtext->from.sym) { + curtext->from.sym->frame = curframe; + curtext->from.sym->become = curbecome; + if(curbecome > maxbecome) + maxbecome = curbecome; + } + + if(debug['b']) + print("max become = %d\n", maxbecome); + xdefine("ALEFbecome", STEXT, maxbecome); + + curtext = 0; + for(p = firstp; p != P; p = p->link) { + setarch(p); + switch(p->as) { + case ATEXT: + curtext = p; + break; + case ABL: + // case ABX: + if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { + o = maxbecome - curtext->from.sym->frame; + if(o <= 0) + break; + /* calling a become or calling a variable */ + if(p->to.sym == S || p->to.sym->become) { + curtext->to.offset += o; + if(debug['b']) { + curp = p; + print("%D calling %D increase %d\n", + &curtext->from, &p->to, o); + } + } + } + break; + } + } + + for(p = firstp; p != P; p = p->link) { + setarch(p); + o = p->as; + switch(o) { + case ATEXT: + curtext = p; + autosize = p->to.offset + 4; + if(autosize <= 4) + if(curtext->mark & LEAF) { + p->to.offset = -4; + autosize = 0; + } + + if(!autosize && !(curtext->mark & LEAF)) { + if(debug['v']) + Bprint(&bso, "save suppressed in: %s\n", + curtext->from.sym->name); + Bflush(&bso); + curtext->mark |= LEAF; + } +#ifdef CALLEEBX + if(p->from.sym->foreign){ + if(thumb) + // don't allow literal pool to seperate these + p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7 + // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7 + else + p = aword(0x4778, p); // thumb bx pc and 2 bytes padding + } +#endif + if(curtext->mark & LEAF) { + if(curtext->from.sym) + curtext->from.sym->type = SLEAF; +#ifdef optimise_time + if(autosize) { + q = prg(); + q->as = ASUB; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + + q->link = p->link; + p->link = q; + } + break; +#else + if(!autosize) + break; +#endif + } + + if(thumb){ + if(!(curtext->mark & LEAF)){ + q = movrr(nil, REGLINK, REGTMPT-1, p); + p->link = q; + q1 = prg(); + q1->as = AMOVW; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGTMPT-1; + q1->to.type = D_OREG; + q1->to.name = D_NONE; + q1->to.reg = REGSP; + q1->to.offset = 0; + q1->link = q->link; + q->link = q1; + } + if(autosize){ + q2 = prg(); + q2->as = ASUB; + q2->line = p->line; + q2->from.type = D_CONST; + q2->from.offset = autosize; + q2->to.type = D_REG; + q2->to.reg = REGSP; + q2->link = p->link; + p->link = q2; + } + break; + } + + q1 = prg(); + q1->as = AMOVW; + q1->scond |= C_WBIT; + q1->line = p->line; + q1->from.type = D_REG; + q1->from.reg = REGLINK; + q1->to.type = D_OREG; + q1->to.offset = -autosize; + q1->to.reg = REGSP; + q1->link = p->link; + p->link = q1; + break; + + case ARET: + nocache(p); + foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr); +// print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr); + if(p->from.type == D_CONST) + goto become; + if(curtext->mark & LEAF) { + if(!autosize) { + if(thumb){ + p = fnret(p, REGLINK, foreign, p); + break; + } +// if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name); + p->as = foreign ? ABXRET : AB; + p->from = zprg.from; + p->to.type = D_OREG; + p->to.offset = 0; + p->to.reg = REGLINK; + break; + } + +#ifdef optimise_time + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + if(thumb){ + p->link = fnret(nil, REGLINK, foreign, p); + break; + } + q = prg(); +// if(foreign) print("ABXRET 2 %s\n", curtext->from.sym->name); + q->as = foreign ? ABXRET : AB; + q->scond = p->scond; + q->line = p->line; + q->to.type = D_OREG; + q->to.offset = 0; + q->to.reg = REGLINK; + + q->link = p->link; + p->link = q; + + break; +#endif + } + if(thumb){ + if(curtext->mark & LEAF){ + if(autosize){ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to.type = D_REG; + p->to.reg = REGSP; + q = nil; + } + else + q = p; + q = fnret(q, REGLINK, foreign, p); + if(q != p) + p->link = q; + } + else{ + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + if(autosize){ + q = prg(); + q->as = AADD; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + } + else + q = p; + q1 = fnret(nil, REGTMPT-1, foreign, p); + q1->link = q->link; + q->link = q1; + } + break; + } + if(foreign) { +// if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name); +#define R 1 + p->as = AMOVW; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = R; + q = prg(); + q->as = AADD; + q->scond = p->scond; + q->line = p->line; + q->from.type = D_CONST; + q->from.offset = autosize; + q->to.type = D_REG; + q->to.reg = REGSP; + q->link = p->link; + p->link = q; + q1 = prg(); + q1->as = ABXRET; + q1->scond = p->scond; + q1->line = p->line; + q1->to.type = D_OREG; + q1->to.offset = 0; + q1->to.reg = R; + q1->link = q->link; + q->link = q1; +#undef R + } + else { + p->as = AMOVW; + p->scond |= C_PBIT; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to.type = D_REG; + p->to.reg = REGPC; + } + break; + + become: + if(foreign){ + diag("foreign become - help"); + break; + } + if(thumb){ + diag("thumb become - help"); + break; + } + print("arm become\n"); + if(curtext->mark & LEAF) { + + if(!autosize) { + p->as = AB; + p->from = zprg.from; + break; + } + +#ifdef optimise_time + q = prg(); + q->scond = p->scond; + q->line = p->line; + q->as = AB; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + p->link = q; + + p->as = AADD; + p->from = zprg.from; + p->from.type = D_CONST; + p->from.offset = autosize; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGSP; + + break; +#endif + } + q = prg(); + q->scond = p->scond; + q->line = p->line; + q->as = AB; + q->from = zprg.from; + q->to = p->to; + q->cond = p->cond; + q->link = p->link; + p->link = q; + if(thumb){ + q1 = prg(); + q1->line = p->line; + q1->as = AADD; + q1->from.type = D_CONST; + q1->from.offset = autosize; + q1->to.type = D_REG; + q1->to.reg = REGSP; + p->as = AMOVW; + p->line = p->line; + p->from.type = D_OREG; + p->from.name = D_NONE; + p->from.reg = REGSP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q1->link = q; + p->link = q1; + q2 = movrr(nil, REGTMPT-1, REGLINK, p); + q2->link = q; + q1->link = q2; + break; + } + p->as = AMOVW; + p->scond |= C_PBIT; + p->from = zprg.from; + p->from.type = D_OREG; + p->from.offset = autosize; + p->from.reg = REGSP; + p->to = zprg.to; + p->to.type = D_REG; + p->to.reg = REGLINK; + + break; + + case ADIV: + case ADIVU: + case AMOD: + case AMODU: + if(debug['M']) + break; + if(p->from.type != D_REG) + break; + if(p->to.type != D_REG) + break; + q1 = p; + + /* MOV a,4(SP) */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->from.reg; + p->to.type = D_OREG; + p->to.reg = REGSP; + p->to.offset = 4; + + /* MOV b,REGTMP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = q1->reg; + if(q1->reg == NREG) + p->from.reg = q1->to.reg; + p->to.type = D_REG; + p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; + p->to.offset = 0; + + /* CALL appropriate */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + +#ifdef CALLEEBX + p->as = ABL; +#else + if(prog_div != UP && prog_div->from.sym->thumb) + p->as = thumb ? ABL : ABX; + else + p->as = thumb ? ABX : ABL; +#endif + p->line = q1->line; + p->to.type = D_BRANCH; + p->cond = p; + switch(o) { + case ADIV: + p->cond = prog_div; + p->to.sym = sym_div; + break; + case ADIVU: + p->cond = prog_divu; + p->to.sym = sym_divu; + break; + case AMOD: + p->cond = prog_mod; + p->to.sym = sym_mod; + break; + case AMODU: + p->cond = prog_modu; + p->to.sym = sym_modu; + break; + } + + /* MOV REGTMP, b */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AMOVW; + p->line = q1->line; + p->from.type = D_REG; + p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP; + p->from.offset = 0; + p->to.type = D_REG; + p->to.reg = q1->to.reg; + + /* ADD $8,SP */ + q = prg(); + q->link = p->link; + p->link = q; + p = q; + + p->as = AADD; + p->from.type = D_CONST; + p->from.reg = NREG; + p->from.offset = 8; + p->reg = NREG; + p->to.type = D_REG; + p->to.reg = REGSP; + + /* SUB $8,SP */ + q1->as = ASUB; + q1->from.type = D_CONST; + q1->from.offset = 8; + q1->from.reg = NREG; + q1->reg = NREG; + q1->to.type = D_REG; + q1->to.reg = REGSP; + + break; + case AMOVW: + if(thumb){ + Adr *a = &p->from; + + if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3)) + diag("SP offset not multiple of 4"); + } + break; + case AMOVB: + case AMOVBU: + case AMOVH: + case AMOVHU: + if(thumb){ + if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){ + q = prg(); + *q = *p; + if(p->from.name == D_AUTO) + q->from.offset += autosize; + else if(p->from.name == D_PARAM) + q->from.offset += autosize+4; + q->from.name = D_NONE; + q->from.reg = REGTMPT; + p = movrr(p, REGSP, REGTMPT, p); + q->link = p->link; + p->link = q; + } + if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){ + q = prg(); + *q = *p; + if(p->to.name == D_AUTO) + q->to.offset += autosize; + else if(p->to.name == D_PARAM) + q->to.offset += autosize+4; + q->to.name = D_NONE; + q->to.reg = REGTMPT; + p = movrr(p, REGSP, REGTMPT, p); + q->link = p->link; + p->link = q; + if(q->to.offset < 0 || q->to.offset > 255){ // complicated + p->to.reg = REGTMPT+1; // mov sp, r8 + q1 = prg(); + q1->line = p->line; + q1->as = AMOVW; + q1->from.type = D_CONST; + q1->from.offset = q->to.offset; + q1->to.type = D_REG; + q1->to.reg = REGTMPT; // mov $o, r7 + p->link = q1; + q1->link = q; + q1 = prg(); + q1->line = p->line; + q1->as = AADD; + q1->from.type = D_REG; + q1->from.reg = REGTMPT+1; + q1->to.type = D_REG; + q1->to.reg = REGTMPT; // add r8, r7 + p->link->link = q1; + q1->link = q; + q->to.offset = 0; // mov* r, 0(r7) + /* phew */ + } + } + } + break; + case AMOVM: + if(thumb){ + if(p->from.type == D_OREG){ + if(p->from.offset == 0) + p->from.type = D_REG; + else + diag("non-zero AMOVM offset"); + } + else if(p->to.type == D_OREG){ + if(p->to.offset == 0) + p->to.type = D_REG; + else + diag("non-zero AMOVM offset"); + } + } + break; + case AB: + if(thumb && p->to.type == D_OREG){ + if(p->to.offset == 0){ + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGPC; + } + else{ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = p->to.offset; + p->reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q = prg(); + q->as = AMOVW; + q->line = p->line; + q->from.type = D_REG; + q->from.reg = REGTMPT-1; + q->to.type = D_REG; + q->to.reg = REGPC; + q->link = p->link; + p->link = q; + } + } + if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){ + // print("warn %s: b (R%d) assuming a return\n", curtext->from.sym->name, p->to.reg); + p->as = ABXRET; + } + break; + case ABL: + case ABX: + if(thumb && p->to.type == D_OREG){ + if(p->to.offset == 0){ + p->as = o; + p->from.type = D_NONE; + p->to.type = D_REG; + } + else{ + p->as = AADD; + p->from.type = D_CONST; + p->from.offset = p->to.offset; + p->reg = p->to.reg; + p->to.type = D_REG; + p->to.reg = REGTMPT-1; + q = prg(); + q->as = o; + q->line = p->line; + q->from.type = D_NONE; + q->to.type = D_REG; + q->to.reg = REGTMPT-1; + q->link = p->link; + p->link = q; + } + } + break; + } + } +} + +static void +sigdiv(char *n) +{ + Sym *s; + + s = lookup(n, 0); + if(s->type == STEXT){ + if(s->sig == 0) + s->sig = SIGNINTERN; + } + else if(s->type == 0 || s->type == SXREF) + s->type = SUNDEF; +} + +void +divsig(void) +{ + sigdiv("_div"); + sigdiv("_divu"); + sigdiv("_mod"); + sigdiv("_modu"); +} + +static void +sdiv(Sym *s) +{ + if(s->type == 0 || s->type == SXREF){ + /* undefsym(s); */ + s->type = SXREF; + if(s->sig == 0) + s->sig = SIGNINTERN; + s->subtype = SIMPORT; + } + else if(s->type != STEXT) + diag("undefined: %s", s->name); +} + +void +initdiv(void) +{ + Sym *s2, *s3, *s4, *s5; + Prog *p; + + if(prog_div != P) + return; + sym_div = s2 = lookup("_div", 0); + sym_divu = s3 = lookup("_divu", 0); + sym_mod = s4 = lookup("_mod", 0); + sym_modu = s5 = lookup("_modu", 0); + if(dlm) { + sdiv(s2); if(s2->type == SXREF) prog_div = UP; + sdiv(s3); if(s3->type == SXREF) prog_divu = UP; + sdiv(s4); if(s4->type == SXREF) prog_mod = UP; + sdiv(s5); if(s5->type == SXREF) prog_modu = UP; + } + for(p = firstp; p != P; p = p->link) + if(p->as == ATEXT) { + if(p->from.sym == s2) + prog_div = p; + if(p->from.sym == s3) + prog_divu = p; + if(p->from.sym == s4) + prog_mod = p; + if(p->from.sym == s5) + prog_modu = p; + } + if(prog_div == P) { + diag("undefined: %s", s2->name); + prog_div = curtext; + } + if(prog_divu == P) { + diag("undefined: %s", s3->name); + prog_divu = curtext; + } + if(prog_mod == P) { + diag("undefined: %s", s4->name); + prog_mod = curtext; + } + if(prog_modu == P) { + diag("undefined: %s", s5->name); + prog_modu = curtext; + } +} + +static void +setdiv(int as) +{ + Prog *p = nil; + + switch(as){ + case ADIV: p = prog_div; break; + case ADIVU: p = prog_divu; break; + case AMOD: p = prog_mod; break; + case AMODU: p = prog_modu; break; + } + if(p != UP && thumb != p->from.sym->thumb) + p->from.sym->foreign = 1; +} + +void +nocache(Prog *p) +{ + p->optab = 0; + p->from.class = 0; + p->to.class = 0; +} |
