#include "l.h" static long thumboprr(int);static long thumboprrr(int, int);static long thumbopirr(int , int);static long thumbopri(int);static long thumbophh(int);static long thumbopbra(int);static long thumbopmv(int, int);static void lowreg(Prog *, int);static void mult(Prog *, int, int);static void numr(Prog *, int, int, int);static void regis(Prog *, int, int, int);static void dis(int, int); // build a constant using neg, add and shift - only worth it if < 6 bytes */static intimmbuildcon(int c, Prog *p){ int n = 0; USED(p); if(c >= 0 && c <= 255) return 0; // mv if(c >= -255 && c < 0) // mv, neg return 1; if(c >= 256 && c <= 510) // mv, add return 1; if(c < 0) return 0; while(!(c & 1)){ n++; c >>= 1; } if(c >= 0 && c <= 255) // mv, lsl return 1; return 0;} // positive 5 bit offset from register - O(R)// positive 8 bit offset from register - mov O, R then [R, R]// otherwise O goes in literal pool - mov O1(PC), R then [R, R]static intimmoreg(int off, Prog *p){ int v = 1; int as = p->as; if(off < 0) return C_GOREG; if(as == AMOVW) v = 4; else if(as == AMOVH || as == AMOVHU) v = 2; else if(as == AMOVB || as == AMOVBU) v = 1; else diag("bad op in immoreg"); if(off/v <= 31) return C_SOREG; if(off <= 255) return C_LOREG; return C_GOREG;} // positive 8 bit - mov O, R then 0(R)// otherwise O goes in literal pool - mov O1(PC), R then 0(R)static intimmacon(int off, Prog *p, int t1, int t2){ USED(p); if(off < 0) return t2; if(off <= 255) return t1; return t2;} // unsigned 8 bit in wordsstatic intimmauto(int off, Prog *p){ if(p->as != AMOVW) diag("bad op in immauto"); mult(p, off, 4); if(off >= 0 && off <= 1020) return C_SAUTO; return C_LAUTO;} static intimmsmall(int off, Prog *p, int t1, int t2, int t3){ USED(p); if(off >= 0 && off <= 7) return t1; if(off >= 0 && off <= 255) return t2; return t3;} static intimmcon(int off, Prog *p){ int as = p->as; if(as == ASLL || as == ASRL || as == ASRA) return C_SCON; if(p->to.type == D_REG && p->to.reg == REGSP){ if(as == AADD || as == ASUB){ if(off >= 0 && off <= 508) return C_SCON; if(as == ASUB){ p->as = AADD; p->from.offset = -p->from.offset; } return C_LCON; } diag("unknown type in immcon"); } if(as == AADD || as == ASUB){ if(p->reg != NREG) return immsmall(off, p, C_SCON, C_LCON, C_GCON); return immacon(off, p, C_SCON, C_LCON); } if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p)) return C_BCON; if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p)) return C_BCON; if(as == ACMP || as == AMOVW) return immacon(off, p, C_SCON, C_LCON); return C_LCON;} intthumbaclass(Adr *a, Prog *p){ Sym *s; int t; switch(a->type) { case D_NONE: return C_NONE; case D_REG: if(a->reg == REGSP) return C_SP; if(a->reg == REGPC) return C_PC; if(a->reg >= 8) return C_HREG; return C_REG; case D_SHIFT: diag("D_SHIFT in thumbaclass"); return C_SHIFT; case D_FREG: diag("D_FREG in thumbaclass"); return C_FREG; case D_FPCR: diag("D_FPCR in thumbaclass"); 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; } t = a->sym->type; if(t == 0 || t == SXREF) { diag("undefined external: %s in %s\n", a->sym->name, TNAME); a->sym->type = SDATA; } instoffset = a->sym->value + a->offset + INITDAT; return C_LEXT; /* INITDAT unknown at this stage */ // return immacon(instoffset, p, C_SEXT, C_LEXT); case D_AUTO: instoffset = autosize + a->offset; return immauto(instoffset, p); case D_PARAM: instoffset = autosize + a->offset + 4L;// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4); return immauto(instoffset, p); case D_NONE: instoffset = a->offset; if(a->reg == REGSP) return immauto(instoffset, p); else return immoreg(instoffset, p); } return C_GOK; case D_PSR: diag("D_PSR in thumbaclass"); 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){ instoffset = s->value + a->offset;#ifdef CALLEEBX instoffset += fnpinc(s);#else if(s->thumb) instoffset++; // T bit#endif return C_LCON; } return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); } return C_GOK; case D_FCONST: diag("D_FCONST in thumaclass"); return C_FCON; case D_CONST: switch(a->name) { case D_NONE: instoffset = a->offset; if(a->reg != NREG) goto aconsize; return immcon(instoffset, p); 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 SCONST: case STEXT: case SLEAF: instoffset = s->value + a->offset;#ifdef CALLEEBX instoffset += fnpinc(s);#else if(s->thumb) instoffset++; // T bit#endif return C_LCON; } instoffset = s->value + a->offset + INITDAT; return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); case D_AUTO: instoffset = autosize + a->offset; goto aconsize; case D_PARAM: instoffset = autosize + a->offset + 4L; aconsize: if(p->from.reg == REGSP || p->from.reg == NREG) return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON; else if(p->from.reg == p->to.reg) return immacon(instoffset, p, C_SACON, C_GACON); return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON); } return C_GOK; case D_BRANCH: { int v, va; p->align = 0; v = -4; va = 0; if(p->cond != P){ v = (p->cond->pc - p->pc) - 4; va = p->cond->pc; } instoffset = v; if(p->as == AB){ if(v >= -2048 && v <= 2046) return C_SBRA; p->align = 4; instoffset = va; return C_LBRA; } if(p->as == ABL){#ifdef CALLEEBX int e; if((e = fninc(p->to.sym))) { v += e; va += e; instoffset += e; } #endif if(v >= -4194304 && v <= 4194302) return C_SBRA; p->align = 2; instoffset = va; return C_LBRA; } if(p->as == ABX){ v = va; if(v >= 0 && v <= 255) return C_SBRA; p->align = 2; instoffset = va; return C_LBRA; } if(v >= -256 && v <= 254) return C_SBRA; if(v >= -(2048-2) && v <= (2046+2)) return C_LBRA; p->align = 2; instoffset = va; return C_GBRA; } } return C_GOK;} // as a1 a2 a3 type size param lit versOptab thumboptab[] ={ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 }, { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 }, { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 }, { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 }, { AADD, C_REG, C_REG, C_REG, 2, 2, 0 }, { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 }, { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 }, { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 }, { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM }, // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM }, { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 }, { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 }, { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 }, { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM }, { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 }, { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 }, { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM }, { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 }, { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 }, { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM }, // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM }, // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM }, { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 }, { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM }, { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 }, { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 }, { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 }, { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 }, { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 }, { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 }, { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 }, { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL }, { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 }, { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 }, { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 }, { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL }, { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 }, { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 }, { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 }, { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 }, // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 }, // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 }, { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 }, { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 }, { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 }, { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 }, { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 }, { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 }, { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 }, { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 }, { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 }, { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 }, { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP }, { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM }, // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM }, { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 }, { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO }, { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 }, { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 }, { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 }, { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM }, { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 }, { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 }, { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },}; #define OPCNTSZ 52int opcount[OPCNTSZ]; // is this too pessimistic ?intbrextra(Prog *p){ int c; // +2 is for padding if(p->as == ATEXT) return 0-0+2; if(!isbranch(p)) diag("bad op in brextra()"); c = thumbaclass(&p->to, p); switch(p->as){ case AB: if(c != C_SBRA) return 0; return 8-2+2; case ABL: if(c != C_SBRA) return 0; return 14-4+2; case ABX: if(c == C_REG || c == C_HREG) return 0;#ifdef CALLEEBX diag("ABX $I in brextra");#endif if(c != C_SBRA) return 0; return 14-10+2; default: if(c == C_GBRA) return 0; if(c == C_LBRA) return 10-4+2; return 10-2+2; }} #define high(r) ((r)>=8) static longLines 1–500 of 1636. Load more
#include "l.h" static long thumboprr(int); static long thumboprrr(int, int); static long thumbopirr(int , int); static long thumbopri(int); static long thumbophh(int); static long thumbopbra(int); static long thumbopmv(int, int); static void lowreg(Prog *, int); static void mult(Prog *, int, int); static void numr(Prog *, int, int, int); static void regis(Prog *, int, int, int); static void dis(int, int); // build a constant using neg, add and shift - only worth it if < 6 bytes */ static int immbuildcon(int c, Prog *p) { int n = 0; USED(p); if(c >= 0 && c <= 255) return 0; // mv if(c >= -255 && c < 0) // mv, neg return 1; if(c >= 256 && c <= 510) // mv, add return 1; if(c < 0) return 0; while(!(c & 1)){ n++; c >>= 1; } if(c >= 0 && c <= 255) // mv, lsl return 1; return 0; } // positive 5 bit offset from register - O(R) // positive 8 bit offset from register - mov O, R then [R, R] // otherwise O goes in literal pool - mov O1(PC), R then [R, R] static int immoreg(int off, Prog *p) { int v = 1; int as = p->as; if(off < 0) return C_GOREG; if(as == AMOVW) v = 4; else if(as == AMOVH || as == AMOVHU) v = 2; else if(as == AMOVB || as == AMOVBU) v = 1; else diag("bad op in immoreg"); if(off/v <= 31) return C_SOREG; if(off <= 255) return C_LOREG; return C_GOREG; } // positive 8 bit - mov O, R then 0(R) // otherwise O goes in literal pool - mov O1(PC), R then 0(R) static int immacon(int off, Prog *p, int t1, int t2) { USED(p); if(off < 0) return t2; if(off <= 255) return t1; return t2; } // unsigned 8 bit in words static int immauto(int off, Prog *p) { if(p->as != AMOVW) diag("bad op in immauto"); mult(p, off, 4); if(off >= 0 && off <= 1020) return C_SAUTO; return C_LAUTO; } static int immsmall(int off, Prog *p, int t1, int t2, int t3) { USED(p); if(off >= 0 && off <= 7) return t1; if(off >= 0 && off <= 255) return t2; return t3; } static int immcon(int off, Prog *p) { int as = p->as; if(as == ASLL || as == ASRL || as == ASRA) return C_SCON; if(p->to.type == D_REG && p->to.reg == REGSP){ if(as == AADD || as == ASUB){ if(off >= 0 && off <= 508) return C_SCON; if(as == ASUB){ p->as = AADD; p->from.offset = -p->from.offset; } return C_LCON; } diag("unknown type in immcon"); } if(as == AADD || as == ASUB){ if(p->reg != NREG) return immsmall(off, p, C_SCON, C_LCON, C_GCON); return immacon(off, p, C_SCON, C_LCON); } if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p)) return C_BCON; if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p)) return C_BCON; if(as == ACMP || as == AMOVW) return immacon(off, p, C_SCON, C_LCON); return C_LCON; } int thumbaclass(Adr *a, Prog *p) { Sym *s; int t; switch(a->type) { case D_NONE: return C_NONE; case D_REG: if(a->reg == REGSP) return C_SP; if(a->reg == REGPC) return C_PC; if(a->reg >= 8) return C_HREG; return C_REG; case D_SHIFT: diag("D_SHIFT in thumbaclass"); return C_SHIFT; case D_FREG: diag("D_FREG in thumbaclass"); return C_FREG; case D_FPCR: diag("D_FPCR in thumbaclass"); 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; } t = a->sym->type; if(t == 0 || t == SXREF) { diag("undefined external: %s in %s\n", a->sym->name, TNAME); a->sym->type = SDATA; } instoffset = a->sym->value + a->offset + INITDAT; return C_LEXT; /* INITDAT unknown at this stage */ // return immacon(instoffset, p, C_SEXT, C_LEXT); case D_AUTO: instoffset = autosize + a->offset; return immauto(instoffset, p); case D_PARAM: instoffset = autosize + a->offset + 4L; // print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4); return immauto(instoffset, p); case D_NONE: instoffset = a->offset; if(a->reg == REGSP) return immauto(instoffset, p); else return immoreg(instoffset, p); } return C_GOK; case D_PSR: diag("D_PSR in thumbaclass"); 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){ instoffset = s->value + a->offset; #ifdef CALLEEBX instoffset += fnpinc(s); #else if(s->thumb) instoffset++; // T bit #endif return C_LCON; } return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); } return C_GOK; case D_FCONST: diag("D_FCONST in thumaclass"); return C_FCON; case D_CONST: switch(a->name) { case D_NONE: instoffset = a->offset; if(a->reg != NREG) goto aconsize; return immcon(instoffset, p); 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 SCONST: case STEXT: case SLEAF: instoffset = s->value + a->offset; #ifdef CALLEEBX instoffset += fnpinc(s); #else if(s->thumb) instoffset++; // T bit #endif return C_LCON; } instoffset = s->value + a->offset + INITDAT; return C_LCON; /* INITDAT unknown at this stage */ // return immcon(instoffset, p); case D_AUTO: instoffset = autosize + a->offset; goto aconsize; case D_PARAM: instoffset = autosize + a->offset + 4L; aconsize: if(p->from.reg == REGSP || p->from.reg == NREG) return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON; else if(p->from.reg == p->to.reg) return immacon(instoffset, p, C_SACON, C_GACON); return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON); } return C_GOK; case D_BRANCH: { int v, va; p->align = 0; v = -4; va = 0; if(p->cond != P){ v = (p->cond->pc - p->pc) - 4; va = p->cond->pc; } instoffset = v; if(p->as == AB){ if(v >= -2048 && v <= 2046) return C_SBRA; p->align = 4; instoffset = va; return C_LBRA; } if(p->as == ABL){ #ifdef CALLEEBX int e; if((e = fninc(p->to.sym))) { v += e; va += e; instoffset += e; } #endif if(v >= -4194304 && v <= 4194302) return C_SBRA; p->align = 2; instoffset = va; return C_LBRA; } if(p->as == ABX){ v = va; if(v >= 0 && v <= 255) return C_SBRA; p->align = 2; instoffset = va; return C_LBRA; } if(v >= -256 && v <= 254) return C_SBRA; if(v >= -(2048-2) && v <= (2046+2)) return C_LBRA; p->align = 2; instoffset = va; return C_GBRA; } } return C_GOK; } // as a1 a2 a3 type size param lit vers Optab thumboptab[] = { { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 }, { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 }, { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 }, { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 }, { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 }, { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 }, { AADD, C_REG, C_REG, C_REG, 2, 2, 0 }, { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 }, { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 }, { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 }, { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM }, // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM }, { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 }, { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 }, { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 }, { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM }, { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 }, { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 }, { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM }, { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 }, { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 }, { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM }, // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM }, // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM }, { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 }, { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM }, { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 }, { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 }, { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 }, { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 }, { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 }, { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 }, { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 }, { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 }, { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL }, { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 }, { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 }, { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 }, { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL }, { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 }, { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 }, { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 }, { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 }, // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 }, // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 }, { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 }, { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 }, { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 }, { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 }, { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 }, { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 }, { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 }, { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 }, { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 }, { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 }, { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP }, { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM }, // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM }, { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 }, { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 }, { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 }, { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO }, { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 }, { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 }, { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 }, { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 }, { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 }, { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 }, { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 }, { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM }, { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 }, { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 }, { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 }, { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 }, { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM }, { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO }, { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM }, { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM }, { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO }, { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 }, }; #define OPCNTSZ 52 int opcount[OPCNTSZ]; // is this too pessimistic ? int brextra(Prog *p) { int c; // +2 is for padding if(p->as == ATEXT) return 0-0+2; if(!isbranch(p)) diag("bad op in brextra()"); c = thumbaclass(&p->to, p); switch(p->as){ case AB: if(c != C_SBRA) return 0; return 8-2+2; case ABL: if(c != C_SBRA) return 0; return 14-4+2; case ABX: if(c == C_REG || c == C_HREG) return 0; #ifdef CALLEEBX diag("ABX $I in brextra"); #endif if(c != C_SBRA) return 0; return 14-10+2; default: if(c == C_GBRA) return 0; if(c == C_LBRA) return 10-4+2; return 10-2+2; } } #define high(r) ((r)>=8) static long