diff options
| author | forsyth <forsyth@lavoro.terzarima.net> | 2013-06-03 21:01:14 +0000 |
|---|---|---|
| committer | forsyth <forsyth@lavoro.terzarima.net> | 2013-06-03 21:01:14 +0000 |
| commit | 45a20ab721a513710138340faff3d59a31c3e01e (patch) | |
| tree | eea29d2684c51cc73725b8992a2125bede48e118 /utils/5l | |
| parent | cd8e99851af33e52bcdf8faf34f9d4e62fa0cbaf (diff) | |
sync compilers with Plan 9
remove 1[acl] 2[acl]
Diffstat (limited to 'utils/5l')
| -rw-r--r-- | utils/5l/Nt.c | 77 | ||||
| -rw-r--r-- | utils/5l/Plan9.c | 57 | ||||
| -rw-r--r-- | utils/5l/Posix.c | 80 | ||||
| -rw-r--r-- | utils/5l/asm.c | 319 | ||||
| -rw-r--r-- | utils/5l/l.h | 71 | ||||
| -rw-r--r-- | utils/5l/list.c | 10 | ||||
| -rw-r--r-- | utils/5l/mkfile | 9 | ||||
| -rw-r--r-- | utils/5l/noop.c | 445 | ||||
| -rw-r--r-- | utils/5l/obj.c | 337 | ||||
| -rw-r--r-- | utils/5l/optab.c | 12 | ||||
| -rw-r--r-- | utils/5l/pass.c | 353 | ||||
| -rw-r--r-- | utils/5l/span.c | 361 | ||||
| -rw-r--r-- | utils/5l/thumb.c | 1636 |
13 files changed, 496 insertions, 3271 deletions
diff --git a/utils/5l/Nt.c b/utils/5l/Nt.c deleted file mode 100644 index 73c6f795..00000000 --- a/utils/5l/Nt.c +++ /dev/null @@ -1,77 +0,0 @@ -#include <windows.h> -#include "l.h" - -/* - * fake malloc - */ -void* -malloc(uint n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(uint m, uint n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void *p, uint n) -{ - void *new; - - new = malloc(n); - if(new && p) - memmove(new, p, n); - return new; -} - -#define Chunk (1*1024*1024) - -void* -mysbrk(ulong size) -{ - void *v; - static int chunk; - static uchar *brk; - - if(chunk < size) { - chunk = Chunk; - if(chunk < size) - chunk = Chunk + size; - brk = VirtualAlloc(NULL, chunk, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if(brk == 0) - return (void*)-1; - } - v = brk; - chunk -= size; - brk += size; - return v; -} - -double -cputime(void) -{ - return ((double)0); -} diff --git a/utils/5l/Plan9.c b/utils/5l/Plan9.c deleted file mode 100644 index f4cf23f4..00000000 --- a/utils/5l/Plan9.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "l.h" - -/* - * fake malloc - */ -void* -malloc(ulong n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(ulong m, ulong n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void *p, ulong n) -{ - USED(p); - USED(n); - fprint(2, "realloc called\n"); - abort(); - return 0; -} - -void* -mysbrk(ulong size) -{ - return sbrk(size); -} - -void -setmalloctag(void*, ulong) -{ -} diff --git a/utils/5l/Posix.c b/utils/5l/Posix.c deleted file mode 100644 index 0da0ee0c..00000000 --- a/utils/5l/Posix.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "l.h" -#include <sys/types.h> -#include <sys/times.h> -#undef getwd -#include <unistd.h> /* For sysconf() and _SC_CLK_TCK */ - -/* - * fake malloc - */ -void* -malloc(size_t n) -{ - void *p; - - while(n & 7) - n++; - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; - return p; -} - -void -free(void *p) -{ - USED(p); -} - -void* -calloc(size_t m, size_t n) -{ - void *p; - - n *= m; - p = malloc(n); - memset(p, 0, n); - return p; -} - -void* -realloc(void *p, size_t n) -{ - fprint(2, "realloc called\n", p, n); - abort(); - return 0; -} - -void* -mysbrk(ulong size) -{ - return (void*)sbrk(size); -} - -double -cputime(void) -{ - - struct tms tmbuf; - double ret_val; - - /* - * times() only fails if &tmbuf is invalid. - */ - (void)times(&tmbuf); - /* - * Return the total time (in system clock ticks) - * spent in user code and system - * calls by both the calling process and its children. - */ - ret_val = (double)(tmbuf.tms_utime + tmbuf.tms_stime + - tmbuf.tms_cutime + tmbuf.tms_cstime); - /* - * Convert to seconds. - */ - ret_val *= sysconf(_SC_CLK_TCK); - return ret_val; - -} diff --git a/utils/5l/asm.c b/utils/5l/asm.c index 66a7f0c6..53d51c45 100644 --- a/utils/5l/asm.c +++ b/utils/5l/asm.c @@ -43,7 +43,6 @@ asmb(void) seek(cout, OFFSET, 0); pc = INITTEXT; for(p = firstp; p != P; p = p->link) { - setarch(p); if(p->as == ATEXT) { curtext = p; autosize = p->to.offset + 4; @@ -57,16 +56,9 @@ asmb(void) } curp = p; o = oplook(p); /* could probably avoid this call */ - if(thumb) - thumbasmout(p, o); - else - asmout(p, o); + asmout(p, o); pc += o->size; } - while(pc-INITTEXT < textsize) { - cput(0); - pc++; - } if(debug['a']) Bprint(&bso, "\n"); @@ -88,10 +80,12 @@ asmb(void) case 1: case 2: case 5: + case 7: OFFSET = HEADR+textsize; seek(cout, OFFSET, 0); break; case 3: + case 6: /* no header, padded segments */ OFFSET = rnd(HEADR+textsize, 4096); seek(cout, OFFSET, 0); break; @@ -108,7 +102,6 @@ asmb(void) else datblk(t, datsize-t, 0); } - cflush(); symsize = 0; lcsize = 0; @@ -128,9 +121,12 @@ asmb(void) seek(cout, OFFSET, 0); break; case 3: + case 6: /* no header, padded segments */ OFFSET += rnd(datsize, 4096); seek(cout, OFFSET, 0); break; + case 7: + break; } if(!debug['s']) asmsym(); @@ -139,8 +135,6 @@ asmb(void) Bflush(&bso); if(!debug['s']) asmlc(); - if(!debug['s']) - asmthumbmap(); if(dlm) asmdyn(); cflush(); @@ -151,7 +145,6 @@ asmb(void) cflush(); } - curtext = P; if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); @@ -159,6 +152,7 @@ asmb(void) seek(cout, OFFSET, 0); switch(HEADTYPE) { case 0: /* no header */ + case 6: /* no header, padded segments */ break; case 1: /* aif for risc os */ lputl(0xe1a00000); /* NOP - decompress code */ @@ -221,16 +215,12 @@ asmb(void) lputl(0xe3300000); /* nop */ lputl(0xe3300000); /* nop */ break; + case 7: /* elf */ + debug['S'] = 1; /* symbol table */ + elf32(ARM, ELFDATA2LSB, 0, nil); + break; } cflush(); - if(debug['c']){ - print("textsize=%ld\n", textsize); - print("datsize=%ld\n", datsize); - print("bsssize=%ld\n", bsssize); - print("symsize=%ld\n", symsize); - print("lcsize=%ld\n", lcsize); - print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize); - } } void @@ -254,16 +244,6 @@ cput(int c) cflush(); } -/* -void -cput(long c) -{ - *cbp++ = c; - if(--cbc <= 0) - cflush(); -} -*/ - void wput(long l) { @@ -277,11 +257,11 @@ wput(long l) } void -hput(long l) +wputl(long l) { - cbp[0] = l>>8; - cbp[1] = l; + cbp[0] = l; + cbp[1] = l>>8; cbp += 2; cbc -= 2; if(cbc <= 0) @@ -317,11 +297,24 @@ lputl(long l) } void +llput(vlong v) +{ + lput(v>>32); + lput(v); +} + +void +llputl(vlong v) +{ + lputl(v); + lputl(v>>32); +} + +void cflush(void) { int n; - /* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */ n = sizeof(buf.cbuf) - cbc; if(n) write(cout, buf.cbuf, n); @@ -463,16 +456,15 @@ asmlc(void) oldpc = INITTEXT; oldlc = 0; for(p = firstp; p != P; p = p->link) { - setarch(p); if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { if(p->as == ATEXT) curtext = p; - if(debug['L']) + if(debug['V']) Bprint(&bso, "%6lux %P\n", p->pc, p); continue; } - if(debug['L']) + if(debug['V']) Bprint(&bso, "\t\t%6ld", lcsize); v = (p->pc - oldpc) / MINLC; while(v) { @@ -480,7 +472,7 @@ asmlc(void) if(v < 127) s = v; cput(s+128); /* 129-255 +pc */ - if(debug['L']) + if(debug['V']) Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128); v -= s; lcsize++; @@ -494,7 +486,7 @@ asmlc(void) cput(s>>16); cput(s>>8); cput(s); - if(debug['L']) { + if(debug['V']) { if(s > 0) Bprint(&bso, " lc+%ld(%d,%ld)\n", s, 0, s); @@ -509,14 +501,14 @@ asmlc(void) } if(s > 0) { cput(0+s); /* 1-64 +lc */ - if(debug['L']) { + if(debug['V']) { Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s); Bprint(&bso, "%6lux %P\n", p->pc, p); } } else { cput(64-s); /* 65-128 -lc */ - if(debug['L']) { + if(debug['V']) { Bprint(&bso, " lc%ld(%ld)\n", s, 64-s); Bprint(&bso, "%6lux %P\n", p->pc, p); @@ -529,62 +521,11 @@ asmlc(void) cput(s); lcsize++; } - if(debug['v'] || debug['L']) + if(debug['v'] || debug['V']) Bprint(&bso, "lcsize = %ld\n", lcsize); Bflush(&bso); } -static void -outt(long f, long l) -{ - if(debug['L']) - Bprint(&bso, "tmap: %lux-%lux\n", f, l); - lput(f); - lput(l); -} - -void -asmthumbmap(void) -{ - long pc, lastt; - Prog *p; - - if(!seenthumb) - return; - pc = 0; - lastt = -1; - for(p = firstp; p != P; p = p->link){ - pc = p->pc - INITTEXT; - if(p->as == ATEXT){ - setarch(p); - if(thumb){ - if(p->from.sym->foreign){ // 8 bytes of ARM first - if(lastt >= 0){ - outt(lastt, pc-1); - lastt = -1; - } - pc += 8; - } - if(lastt < 0) - lastt = pc; - } - else{ - if(p->from.sym->foreign){ // 4 bytes of THUMB first - if(lastt < 0) - lastt = pc; - pc += 4; - } - if(lastt >= 0){ - outt(lastt, pc-1); - lastt = -1; - } - } - } - } - if(lastt >= 0) - outt(lastt, pc+1); -} - void datblk(long s, long n, int str) { @@ -661,25 +602,14 @@ datblk(long s, long n, int str) switch(v->type) { case SUNDEF: ckoff(v, d); - d += v->value; - break; case STEXT: case SLEAF: - d += v->value; -#ifdef CALLEEBX - d += fnpinc(v); -#else - if(v->thumb) - d++; // T bit -#endif - break; case SSTRING: - d += v->value; + d += p->to.sym->value; break; case SDATA: case SBSS: - d += v->value + INITDAT; - break; + d += p->to.sym->value + INITDAT; } if(dlm) dynreloc(v, a+INITDAT, 1); @@ -728,8 +658,6 @@ PP = p; o4 = 0; o5 = 0; o6 = 0; - armsize += o->size; -if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type); switch(o->type) { default: diag("unknown asm %d", o->type); @@ -737,7 +665,6 @@ if(debug['P']) print("%ulx: %P type %d\n", (ulong)(p->pc), p, o->type); break; case 0: /* pseudo ops */ -if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used); break; case 1: /* op R,[R],R */ @@ -807,10 +734,6 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym- } else if(p->cond != P) v = (p->cond->pc - pc) - 8; -#ifdef CALLEEBX - if(p->as == ABL) - v += fninc(p->to.sym); -#endif o1 = opbra(p->as, p->scond); o1 |= (v >> 2) & 0xffffff; break; @@ -1237,6 +1160,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym- o1 |= rf | (rt<<12); break; + /* old arm 7500 fp using coproc 1 (1<<8) */ case 56: /* move to FP[CS]R */ o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); @@ -1417,49 +1341,58 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (ulong)(p->pc), p->from.sym- else if(p->as == AMOVH) o2 ^= (1<<6); break; - case 74: /* bx $I */ -#ifdef CALLEEBX - diag("bx $i case (arm)"); -#endif - if(!seenthumb) - diag("ABX $I and seenthumb==0"); - v = p->cond->pc; - if(p->to.sym->thumb) - v |= 1; // T bit - o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp - o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR - o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp - o4 = opbra(AB, 14); // B over o6 - o5 = v; - break; - case 75: /* bx O(R) */ - aclass(&p->to); - if(instoffset != 0) - diag("non-zero offset in ABX"); -/* - o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R -*/ - // p->to.reg may be REGLINK - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGTMP << 12; - o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp + + /* VFP ops: */ + case 74: /* vfp floating point arith */ + o1 = opvfprrr(p->as, p->scond); + rf = p->from.reg; + if(p->from.type == D_FCONST) { + diag("invalid floating-point immediate\n%P", p); + rf = 0; + } + rt = p->to.reg; + r = p->reg; + if(r == NREG) + r = rt; + o1 |= rt<<12; + if(((o1>>20)&0xf) == 0xb) + o1 |= rf<<0; + else + o1 |= r<<16 | rf<<0; break; - case 76: /* bx O(R) when returning from fn*/ - if(!seenthumb) - diag("ABXRET and seenthumb==0"); - aclass(&p->to); -// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg); - if(instoffset != 0) - diag("non-zero offset in ABXRET"); - // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp - o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R + case 75: /* vfp floating point compare */ + o1 = opvfprrr(p->as, p->scond); + rf = p->from.reg; + if(p->from.type == D_FCONST) { + if(p->from.ieee->h != 0 || p->from.ieee->l != 0) + diag("invalid floating-point immediate\n%P", p); + o1 |= 1<<16; + rf = 0; + } + rt = p->reg; + o1 |= rt<<12 | rf<<0; + o2 = 0x0ef1fa10; /* MRS APSR_nzcv, FPSCR */ + o2 |= (p->scond & C_SCOND) << 28; + break; + case 76: /* vfp floating point fix and float */ + o1 = opvfprrr(p->as, p->scond); + rf = p->from.reg; + rt = p->to.reg; + if(p->from.type == D_REG) { + o2 = o1 | rt<<12 | rt<<0; + o1 = 0x0e000a10; /* VMOV F,R */ + o1 |= (p->scond & C_SCOND) << 28 | rt<<16 | rf<<12; + } else { + o1 |= FREGTMP<<12 | rf<<0; + o2 = 0x0e100a10; /* VMOV R,F */ + o2 |= (p->scond & C_SCOND) << 28 | FREGTMP<<16 | rt<<12; + } break; } + if(debug['a'] > 1) + Bprint(&bso, "%2d ", o->type); + v = p->pc; switch(o->size) { default: @@ -1556,6 +1489,7 @@ oprrr(int a, int sc) case ASRA: return o | (0xd<<21) | (2<<5); case ASWI: return o | (0xf<<24); + /* old arm 7500 fp using coproc 1 (1<<8) */ 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); @@ -1583,6 +1517,40 @@ oprrr(int a, int sc) } long +opvfprrr(int a, int sc) +{ + long o; + + o = (sc & C_SCOND) << 28; + if(sc & (C_SBIT|C_PBIT|C_WBIT)) + diag(".S/.P/.W on vfp instruction"); + o |= 0xe<<24; + switch(a) { + case AMOVWD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7; + case AMOVWF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7; + case AMOVDW: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7; + case AMOVFW: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7; + case AMOVFD: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7; + case AMOVDF: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7; + case AMOVF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7; + case AMOVD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7; + case ACMPF: return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7; + case ACMPD: return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7; + case AADDF: return o | 0xa<<8 | 0x3<<20; + case AADDD: return o | 0xb<<8 | 0x3<<20; + case ASUBF: return o | 0xa<<8 | 0x3<<20 | 1<<6; + case ASUBD: return o | 0xb<<8 | 0x3<<20 | 1<<6; + case AMULF: return o | 0xa<<8 | 0x2<<20; + case AMULD: return o | 0xb<<8 | 0x2<<20; + case ADIVF: return o | 0xa<<8 | 0x8<<20; + case ADIVD: return o | 0xb<<8 | 0x8<<20; + } + diag("bad vfp rrr %d", a); + prasm(curp); + return 0; +} + +long opbra(int a, int sc) { @@ -1637,7 +1605,7 @@ olr(long v, int b, int r, int sc) o ^= 1 << 23; } if(v >= (1<<12)) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); + diag("literal span too large: %ld (R%d)\n%P", v, b, PP); o |= v; o |= b << 16; o |= r << 12; @@ -1662,7 +1630,7 @@ olhr(long v, int b, int r, int sc) o ^= 1 << 23; } if(v >= (1<<8)) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); + diag("literal span too large: %ld (R%d)\n%P", v, b, PP); o |= (v&0xf)|((v>>4)<<8)|(1<<22); o |= b << 16; o |= r << 12; @@ -1717,10 +1685,45 @@ olhrr(int i, int b, int r, int sc) } long +ovfpmem(int a, int r, long v, int b, int sc, Prog *p) +{ + long o; + + if(sc & (C_SBIT|C_PBIT|C_WBIT)) + diag(".S/.P/.W on VLDR/VSTR instruction"); + o = (sc & C_SCOND) << 28; + o |= 0xd<<24 | (1<<23); + if(v < 0) { + v = -v; + o ^= 1 << 23; + } + if(v & 3) + diag("odd offset for floating point op: %ld\n%P", v, p); + else if(v >= (1<<10)) + diag("literal span too large: %ld\n%P", v, p); + o |= (v>>2) & 0xFF; + o |= b << 16; + o |= r << 12; + switch(a) { + default: + diag("bad fst %A", a); + case AMOVD: + o |= 0xb<<8; + break; + case AMOVF: + o |= 0xa<<8; + break; + } + return o; +} + +long ofsr(int a, int r, long v, int b, int sc, Prog *p) { long o; + if(vfp) + return ovfpmem(a, r, v, b, sc, p); if(sc & C_SBIT) diag(".S on FLDR/FSTR instruction"); o = (sc & C_SCOND) << 28; @@ -1734,9 +1737,9 @@ ofsr(int a, int r, long v, int b, int sc, Prog *p) o ^= 1 << 23; } if(v & 3) - diag("odd offset for floating point op: %d\n%P", v, p); + diag("odd offset for floating point op: %ld\n%P", v, p); else if(v >= (1<<10)) - diag("literal span too large: %d\n%P", v, p); + diag("literal span too large: %ld\n%P", v, p); o |= (v>>2) & 0xFF; o |= b << 16; o |= r << 12; @@ -1792,6 +1795,8 @@ chipfloat(Ieee *e) Ieee *p; int n; + if(vfp) + return -1; for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){ p = &chipfloats[n]; if(p->l == e->l && p->h == e->h) diff --git a/utils/5l/l.h b/utils/5l/l.h index a7c322be..bd734f1e 100644 --- a/utils/5l/l.h +++ b/utils/5l/l.h @@ -1,13 +1,17 @@ #include <lib9.h> #include <bio.h> #include "../5c/5.out.h" +#include "../8l/elf.h" #ifndef EXTERN #define EXTERN extern #endif -/* do not undefine this - code will be removed eventually */ -#define CALLEEBX +#define LIBNAMELEN 300 + +void addlibpath(char*); +int fileexists(char*); +char* findlib(char*); typedef struct Adr Adr; typedef struct Sym Sym; @@ -17,11 +21,9 @@ typedef struct Optab Optab; typedef struct Oprang Oprang; typedef uchar Opcross[32][2][32]; typedef struct Count Count; -typedef struct Use Use; #define P ((Prog*)0) #define S ((Sym*)0) -#define U ((Use*)0) #define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname) struct Adr @@ -68,7 +70,6 @@ struct Prog uchar as; uchar scond; uchar reg; - uchar align; }; #define regused u0.u0regused #define forwd u0.u0forwd @@ -81,14 +82,10 @@ struct Sym short become; short frame; uchar subtype; + uchar used; ushort file; long value; long sig; - uchar used; - uchar thumb; // thumb code - uchar foreign; // called by arm if thumb, by thumb if arm - uchar fnptr; // used as fn ptr - Use* use; Sym* link; }; @@ -122,12 +119,6 @@ struct Count long count; long outof; }; -struct Use -{ - Prog* p; /* use */ - Prog* ct; /* curtext */ - Use* link; -}; enum { @@ -141,7 +132,6 @@ enum SCONST, SSTRING, SUNDEF, - SREMOVED, SIMPORT, SEXPORT, @@ -150,6 +140,7 @@ enum LTO = 1<<1, LPOOL = 1<<2, V4 = 1<<3, /* arm v4 arch */ + VFP = 1<<4, /* arm vfpv3 floating point */ C_NONE = 0, C_REG, @@ -162,22 +153,17 @@ enum C_RCON, /* 0xff rotated */ C_NCON, /* ~RCON */ C_SCON, /* 0xffff */ - C_BCON, /* thumb */ C_LCON, C_FCON, - C_GCON, /* thumb */ C_RACON, - C_SACON, /* thumb */ C_LACON, - C_GACON, /* thumb */ C_RECON, C_LECON, C_SBRA, C_LBRA, - C_GBRA, /* thumb */ C_HAUTO, /* halfword insn offset (-0xff to 0xff) */ C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */ @@ -198,12 +184,6 @@ enum C_ROREG, C_SROREG, /* both S and R */ C_LOREG, - C_GOREG, /* thumb */ - - C_PC, - C_SP, - C_HREG, - C_OFFPC, /* thumb */ C_ADDR, /* relocatable address */ @@ -240,9 +220,6 @@ EXTERN union #define cbuf u.obuf #define xbuf u.ibuf -#define setarch(p) if((p)->as==ATEXT) thumb=(p)->reg&ALLTHUMBS -#define setthumb(p) if((p)->as==ATEXT) seenthumb|=(p)->reg&ALLTHUMBS - #ifndef COFFCVT EXTERN long HEADR; /* length of header */ @@ -250,6 +227,7 @@ EXTERN int HEADTYPE; /* type of header */ EXTERN long INITDAT; /* data location */ EXTERN long INITRND; /* data round above text location */ EXTERN long INITTEXT; /* text location */ +EXTERN long INITTEXTP; /* text location (physical) */ EXTERN char* INITENTRY; /* entry point */ EXTERN long autosize; EXTERN Biobuf bso; @@ -289,7 +267,6 @@ EXTERN long nhunk; EXTERN long instoffset; EXTERN Opcross opcross[8]; EXTERN Oprang oprange[ALAST]; -EXTERN Oprang thumboprange[ALAST]; EXTERN char* outfile; EXTERN long pc; EXTERN uchar repop[ALAST]; @@ -302,9 +279,7 @@ EXTERN char xcmp[C_GOK+1][C_GOK+1]; EXTERN Prog zprg; EXTERN int dtype; EXTERN int armv4; -EXTERN int thumb; -EXTERN int seenthumb; -EXTERN int armsize; +EXTERN int vfp; EXTERN int doexp, dlm; EXTERN int imports, nimports; @@ -316,7 +291,6 @@ EXTERN Prog undefp; extern char* anames[]; extern Optab optab[]; -extern Optab thumboptab[]; void addpool(Prog*, Adr*); EXTERN Prog* blitrl; @@ -329,12 +303,15 @@ EXTERN Prog* prog_mod; EXTERN Prog* prog_modu; #pragma varargck type "A" int +#pragma varargck type "A" uint #pragma varargck type "C" int #pragma varargck type "D" Adr* #pragma varargck type "N" Adr* #pragma varargck type "P" Prog* #pragma varargck type "S" char* +#pragma varargck argpos diag 1 + int Aconv(Fmt*); int Cconv(Fmt*); int Dconv(Fmt*); @@ -342,20 +319,17 @@ int Nconv(Fmt*); int Pconv(Fmt*); int Sconv(Fmt*); int aclass(Adr*); -int thumbaclass(Adr*, Prog*); void addhist(long, int); +void addlibpath(char*); void append(Prog*, Prog*); void asmb(void); void asmdyn(void); void asmlc(void); -void asmthumbmap(void); void asmout(Prog*, Optab*); -void thumbasmout(Prog*, Optab*); void asmsym(void); long atolwhex(char*); Prog* brloop(Prog*); void buildop(void); -void thumbbuildop(void); void buildrep(int, int); void cflush(void); void ckoff(Sym*, long); @@ -374,11 +348,12 @@ long entryvalue(void); void errorexit(void); void exchange(Prog*); void export(void); +int fileexists(char*); int find1(long, int); +char* findlib(char*); void follow(void); void gethunk(void); void histtoauto(void); -void hputl(int); double ieeedtod(Ieee*); long ieeedtof(Ieee*); void import(void); @@ -388,7 +363,8 @@ void loadlib(void); void listinit(void); Sym* lookup(char*, int); void cput(int); -void hput(long); +void llput(vlong); +void llputl(vlong); void lput(long); void lputl(long); void mkfwd(void); @@ -397,10 +373,11 @@ void names(void); void nocache(Prog*); void nuxiinit(void); void objfile(char*); -int ocmp(const void*, const void*); +int ocmp(void*, void*); long opirr(int); Optab* oplook(Prog*); long oprrr(int, int); +long opvfprrr(int, int); long olr(long, int, int, int); long olhr(long, int, int, int); long olrr(int, int, int, int); @@ -426,6 +403,7 @@ void strnput(char*, int); void undef(void); void undefsym(Sym*); void wput(long); +void wputl(long); void xdefine(char*, int, long); void xfol(Prog*); void zerosig(char*); @@ -433,12 +411,5 @@ void noops(void); long immrot(ulong); long immaddr(long); long opbra(int, int); -int brextra(Prog*); -int isbranch(Prog*); -int fnpinc(Sym *); -int fninc(Sym *); -void thumbcount(void); -void reachable(void); -void fnptrs(void); #endif diff --git a/utils/5l/list.c b/utils/5l/list.c index 5d2e7b49..173f3031 100644 --- a/utils/5l/list.c +++ b/utils/5l/list.c @@ -56,14 +56,6 @@ Pconv(Fmt *fp) sprint(str, "(%ld) %A%C %D/%d,%D", p->line, a, p->scond, &p->from, p->reg, &p->to); break; - - case AWORD: - sprint(str, "WORD %ld", p->to.offset); - break; - - case ADWORD: - sprint(str, "DWORD %ld %ld", p->from.offset, p->to.offset); - break; } return fmtstrcpy(fp, str); } @@ -75,7 +67,7 @@ Aconv(Fmt *fp) int a; a = va_arg(fp->args, int); - s = "???"; + s = "?"; if(a >= AXXX && a < ALAST) s = anames[a]; return fmtstrcpy(fp, s); diff --git a/utils/5l/mkfile b/utils/5l/mkfile index 4be81d08..75fa0678 100644 --- a/utils/5l/mkfile +++ b/utils/5l/mkfile @@ -12,7 +12,7 @@ OFILES=\ span.$O\ enam.$O\ $TARGMODEL.$O\ - thumb.$O\ + elf.$O\ HFILES=\ l.h\ @@ -21,7 +21,7 @@ HFILES=\ LIBS=bio 9 # order is important -CFLAGS=$CFLAGS -I../include +CFLAGS=$CFLAGS -I../include -I. BIN=$ROOT/$OBJDIR/bin @@ -30,3 +30,8 @@ BIN=$ROOT/$OBJDIR/bin enam.$O: ../5c/enam.c $CC $CFLAGS ../5c/enam.c +elf.$O: ../ld/elf.c + $CC $CFLAGS ../ld/elf.c + +$TARGMODEL.$O: ../ld/$TARGMODEL.c + $CC $CFLAGS ../ld/$TARGMODEL.c diff --git a/utils/5l/noop.c b/utils/5l/noop.c index 08ef6dbe..e68c08f6 100644 --- a/utils/5l/noop.c +++ b/utils/5l/noop.c @@ -5,76 +5,11 @@ 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; + Prog *p, *q, *q1; + int o, curframe, curbecome, maxbecome; /* * find leaf subroutines @@ -96,7 +31,6 @@ noops(void) 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) @@ -134,7 +68,6 @@ noops(void) initdiv(); if(curtext != P) curtext->mark &= ~LEAF; - setdiv(p->as); continue; case ANOP: @@ -144,7 +77,6 @@ noops(void) continue; case ABL: - case ABX: if(curtext != P) curtext->mark &= ~LEAF; @@ -193,13 +125,11 @@ noops(void) 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) @@ -219,7 +149,6 @@ noops(void) } for(p = firstp; p != P; p = p->link) { - setarch(p); o = p->as; switch(o) { case ATEXT: @@ -238,16 +167,7 @@ noops(void) 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; @@ -271,36 +191,6 @@ noops(void) #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; @@ -310,24 +200,18 @@ noops(void) 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->as = AB; p->from = zprg.from; p->to.type = D_OREG; p->to.offset = 0; @@ -341,13 +225,9 @@ noops(void) 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->as = AB; q->scond = p->scond; q->line = p->line; q->to.type = D_OREG; @@ -360,100 +240,16 @@ noops(void) 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; - } + 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) { @@ -493,29 +289,7 @@ noops(void) 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; @@ -528,6 +302,30 @@ noops(void) break; + /* + * 5c code generation for unsigned -> double made the + * unfortunate assumption that single and double floating + * point registers are aliased - true for emulated 7500 + * but not for vfp. Now corrected, but this test is + * insurance against old 5c compiled code in libraries. + */ + case AMOVWD: + if((q = p->link) != P && q->as == ACMP) + if((q = q->link) != P && q->as == AMOVF) + if((q1 = q->link) != P && q1->as == AADDF) + if(q1->to.type == D_FREG && q1->to.reg == p->to.reg) { + q1->as = AADDD; + q1 = prg(); + q1->scond = q->scond; + q1->line = q->line; + q1->as = AMOVFD; + q1->from = q->to; + q1->to = q1->from; + q1->link = q->link; + q->link = q1; + } + break; + case ADIV: case ADIVU: case AMOD: @@ -567,7 +365,7 @@ noops(void) 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.reg = REGTMP; p->to.offset = 0; /* CALL appropriate */ @@ -576,14 +374,7 @@ noops(void) 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; @@ -615,7 +406,7 @@ noops(void) 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.reg = REGTMP; p->from.offset = 0; p->to.type = D_REG; p->to.reg = q1->to.reg; @@ -642,145 +433,6 @@ noops(void) 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; } } @@ -870,21 +522,6 @@ initdiv(void) } } -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) { diff --git a/utils/5l/obj.c b/utils/5l/obj.c index 35c5f558..202f8eec 100644 --- a/utils/5l/obj.c +++ b/utils/5l/obj.c @@ -11,14 +11,28 @@ char symname[] = SYMDEF; char thechar = '5'; char *thestring = "arm"; +char** libdir; +int nlibdir = 0; +static int maxlibdir = 0; + /* + * -H0 no header * -H1 -T0x10005000 -R4 is aif for risc os * -H2 -T4128 -R4096 is plan9 format * -H3 -T0xF0000020 -R4 is NetBSD format * -H4 is IXP1200 (raw) * -H5 -T0xC0008010 -R1024 is ipaq + * -H6 -R4096 no header with segments padded to pages + * -H7 is elf */ +void +usage(void) +{ + diag("usage: %s [-options] objects", argv0); + errorexit(); +} + static int isobjfile(char *f) { @@ -46,9 +60,9 @@ main(int argc, char *argv[]) { int c; char *a; + char name[LIBNAMELEN]; Binit(&bso, 1, OWRITE); - srand(time(0)); cout = -1; listinit(); outfile = 0; @@ -56,6 +70,7 @@ main(int argc, char *argv[]) curtext = P; HEADTYPE = -1; INITTEXT = -1; + INITTEXTP = -1; INITDAT = -1; INITRND = -1; INITENTRY = 0; @@ -74,11 +89,19 @@ main(int argc, char *argv[]) if(a) INITENTRY = a; break; + case 'L': + addlibpath(EARGF(usage())); + break; case 'T': a = ARGF(); if(a) INITTEXT = atolwhex(a); break; + case 'P': + a = ARGF(); + if(a) + INITTEXTP = atolwhex(a); + break; case 'D': a = ARGF(); if(a) @@ -102,7 +125,6 @@ main(int argc, char *argv[]) break; case 'u': /* produce dynamically loadable module */ dlm = 1; - debug['l']++; if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1])) readundefs(ARGF(), SIMPORT); break; @@ -110,12 +132,20 @@ main(int argc, char *argv[]) USED(argc); - if(*argv == 0) { - diag("usage: 5l [-options] objects"); - errorexit(); - } + if(*argv == 0) + usage(); if(!debug['9'] && !debug['U'] && !debug['B']) debug[DEFAULT] = 1; + a = getenv("ccroot"); + if(a != nil && *a != '\0') { + if(!fileexists(a)) { + diag("nonexistent $ccroot: %s", a); + errorexit(); + } + }else + a = ""; + snprint(name, sizeof(name), "%s/%s/lib", a, thestring); + addlibpath(name); if(HEADTYPE == -1) { if(debug['U']) HEADTYPE = 0; @@ -129,6 +159,7 @@ main(int argc, char *argv[]) diag("unknown -H option"); errorexit(); case 0: /* no header */ + case 6: /* no header, padded segments */ HEADR = 0L; if(INITTEXT == -1) INITTEXT = 0; @@ -182,7 +213,18 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 1024; break; + case 7: /* elf executable */ + HEADR = rnd(Ehdr32sz+3*Phdr32sz, 16); + if(INITTEXT == -1) + INITTEXT = 4096+HEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = 4; + break; } + if (INITTEXTP == -1) + INITTEXTP = INITTEXT; if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%lux is ignored because of -R0x%lux\n", INITDAT, INITRND); @@ -198,7 +240,6 @@ main(int argc, char *argv[]) zprg.from.reg = NREG; zprg.to = zprg.from; buildop(); - thumbbuildop(); // could build on demand histgen = 0; textp = P; datap = P; @@ -208,7 +249,7 @@ main(int argc, char *argv[]) outfile = "5.out"; cout = create(outfile, 1, 0775); if(cout < 0) { - diag("%s: cannot create", outfile); + diag("cannot create %s: %r", outfile); errorexit(); } nuxiinit(); @@ -225,7 +266,7 @@ main(int argc, char *argv[]) INITENTRY = "_mainp"; if(!debug['l']) lookup(INITENTRY, 0)->type = SXREF; - } else + } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9')) lookup(INITENTRY, 0)->type = SXREF; while(*argv) @@ -259,11 +300,7 @@ main(int argc, char *argv[]) doprof1(); else doprof2(); - if(debug['u']) - reachable(); dodata(); - if(seenthumb && debug['f']) - fnptrs(); follow(); if(firstp == P) goto out; @@ -273,10 +310,6 @@ main(int argc, char *argv[]) undef(); out: - if(debug['c']){ - thumbcount(); - print("ARM size = %d\n", armsize); - } if(debug['v']) { Bprint(&bso, "%5.2f cpu time\n", cputime()); Bprint(&bso, "%ld memory used\n", thunk); @@ -288,6 +321,42 @@ out: } void +addlibpath(char *arg) +{ + char **p; + + if(nlibdir >= maxlibdir) { + if(maxlibdir == 0) + maxlibdir = 8; + else + maxlibdir *= 2; + p = malloc(maxlibdir*sizeof(*p)); + if(p == nil) { + diag("out of memory"); + errorexit(); + } + memmove(p, libdir, nlibdir*sizeof(*p)); + free(libdir); + libdir = p; + } + libdir[nlibdir++] = strdup(arg); +} + +char* +findlib(char *file) +{ + int i; + char name[LIBNAMELEN]; + + for(i = 0; i < nlibdir; i++) { + snprint(name, sizeof(name), "%s/%s", libdir[i], file); + if(fileexists(name)) + return libdir[i]; + } + return nil; +} + +void loadlib(void) { int i; @@ -298,7 +367,7 @@ loop: xrefresolv = 0; for(i=0; i<libraryp; i++) { if(debug['v']) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]); + Bprint(&bso, "%5.2f autolib: %s\n", cputime(), library[i]); objfile(library[i]); } if(xrefresolv) @@ -312,7 +381,6 @@ void errorexit(void) { - Bflush(&bso); if(nerrors) { if(cout >= 0) remove(outfile); @@ -328,25 +396,26 @@ objfile(char *file) int f, work; Sym *s; char magbuf[SARMAG]; - char name[100], pname[150]; + char name[LIBNAMELEN], pname[LIBNAMELEN]; struct ar_hdr arhdr; char *e, *start, *stop; - if(file[0] == '-' && file[1] == 'l') { - if(debug['9']) - sprint(name, "/%s/lib/lib", thestring); - else - sprint(name, "/usr/%clib/lib", thechar); - strcat(name, file+2); - strcat(name, ".a"); - file = name; - } if(debug['v']) Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); Bflush(&bso); + if(file[0] == '-' && file[1] == 'l') { + snprint(pname, sizeof(pname), "lib%s.a", file+2); + e = findlib(pname); + if(e == nil) { + diag("cannot find library: %s", file); + errorexit(); + } + snprint(name, sizeof(name), "%s/%s", e, pname); + file = name; + } f = open(file, 0); if(f < 0) { - diag("cannot open file: %s", file); + diag("cannot open %s: %r", file); errorexit(); } l = read(f, magbuf, SARMAG); @@ -407,7 +476,8 @@ objfile(char *file) l |= (e[3] & 0xff) << 16; l |= (e[4] & 0xff) << 24; seek(f, l, 0); - l = read(f, &arhdr, SAR_HDR); + /* need readn to read the dumps (at least) */ + l = readn(f, &arhdr, SAR_HDR); if(l != SAR_HDR) goto bad; if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) @@ -434,7 +504,7 @@ int zaddr(uchar *p, Adr *a, Sym *h[]) { int i, c; - long l; + int l; Sym *s; Auto *u; @@ -456,17 +526,6 @@ zaddr(uchar *p, Adr *a, Sym *h[]) return 0; /* force real diagnostic */ } - if(a->type == D_CONST || a->type == D_OCONST) { - if(a->name == D_EXTERN || a->name == D_STATIC) { - s = a->sym; - if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) { - if(0 && !s->fnptr && s->name[0] != '.') - print("%s used as function pointer\n", s->name); - s->fnptr = 1; // over the top cos of SXREF - } - } - } - switch(a->type) { default: print("unknown type %d\n", a->type); @@ -553,25 +612,24 @@ zaddr(uchar *p, Adr *a, Sym *h[]) void addlib(char *obj) { - char name[1024], comp[256], *p; - int i; + char fn1[LIBNAMELEN], fn2[LIBNAMELEN], comp[LIBNAMELEN], *p, *name; + int i, search; if(histfrogp <= 0) return; + name = fn1; + search = 0; if(histfrog[0]->name[1] == '/') { sprint(name, ""); i = 1; - } else - if(histfrog[0]->name[1] == '.') { + } else if(histfrog[0]->name[1] == '.') { sprint(name, "."); i = 0; } else { - if(debug['9']) - sprint(name, "/%s/lib", thestring); - else - sprint(name, "/usr/%clib", thechar); + sprint(name, ""); i = 0; + search = 1; } for(; i<histfrogp; i++) { @@ -594,13 +652,25 @@ addlib(char *obj) memmove(p+strlen(thestring), p+2, strlen(p+2)+1); memmove(p, thestring, strlen(thestring)); } - if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { + if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) { diag("library component too long"); return; } - strcat(name, "/"); - strcat(name, comp); + if(i > 0 || !search) + strcat(fn1, "/"); + strcat(fn1, comp); + } + + cleanname(name); + + if(search){ + p = findlib(name); + if(p != nil){ + snprint(fn2, sizeof(fn2), "%s/%s", p, name); + name = fn2; + } } + for(i=0; i<libraryp; i++) if(strcmp(name, library[i]) == 0) return; @@ -719,8 +789,6 @@ readsome(int f, uchar *buf, uchar *good, uchar *stop, int max) return stop + n; } -static void puntfp(Prog *); - void ldobj(int f, long c, char *pn) { @@ -955,9 +1023,6 @@ loop: break; case ATEXT: - setarch(p); - setthumb(p); - p->align = 4; if(curtext != P) { histtoauto(); curtext->to.autom = curauto; @@ -982,7 +1047,6 @@ loop: } s->type = STEXT; s->value = pc; - s->thumb = thumb; lastp->link = p; lastp = p; p->pc = pc; @@ -1014,31 +1078,7 @@ loop: } goto casedef; - case AMOVWD: - case AMOVWF: - case AMOVDW: - case AMOVFW: - case AMOVFD: - case AMOVDF: - // case AMOVF: - // case AMOVD: - case ACMPF: - case ACMPD: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - if(thumb) - puntfp(p); - goto casedef; - case AMOVF: - if(thumb) - puntfp(p); if(skip) goto casedef; @@ -1068,8 +1108,6 @@ loop: goto casedef; case AMOVD: - if(thumb) - puntfp(p); if(skip) goto casedef; @@ -1130,8 +1168,7 @@ lookup(char *symb, int v) for(p=symb; c = *p; p++) h = h+h+h + c; l = (p - symb) + 1; - if(h < 0) - h = ~h; + h &= 0xffffff; h %= NHASH; for(s = hash[h]; s != S; s = s->link) if(s->version == v) @@ -1152,8 +1189,6 @@ lookup(char *symb, int v) s->version = v; s->value = 0; s->sig = 0; - s->used = s->thumb = s->foreign = s->fnptr = 0; - s->use = nil; hash[h] = s; return s; } @@ -1208,7 +1243,6 @@ doprof1(void) s = lookup("__mcount", 0); n = 1; for(p = firstp->link; p != P; p = p->link) { - setarch(p); if(p->as == ATEXT) { q = prg(); q->line = p->line; @@ -1235,7 +1269,7 @@ doprof1(void) p->from.sym = s; p->from.offset = n*4 + 4; p->to.type = D_REG; - p->to.reg = thumb ? REGTMPT : REGTMP; + p->to.reg = REGTMP; q = prg(); q->line = p->line; @@ -1247,7 +1281,7 @@ doprof1(void) p->from.type = D_CONST; p->from.offset = 1; p->to.type = D_REG; - p->to.reg = thumb ? REGTMPT : REGTMP; + p->to.reg = REGTMP; q = prg(); q->line = p->line; @@ -1257,7 +1291,7 @@ doprof1(void) p = q; p->as = AMOVW; p->from.type = D_REG; - p->from.reg = thumb ? REGTMPT : REGTMP; + p->from.reg = REGTMP; p->to.type = D_OREG; p->to.name = D_EXTERN; p->to.sym = s; @@ -1284,25 +1318,36 @@ doprof1(void) s->value = n*4; } +static int brcond[] = {ABEQ, ABNE, ABCS, ABCC, ABMI, ABPL, ABVS, ABVC, ABHI, ABLS, ABGE, ABLT, ABGT, ABLE}; + void doprof2(void) { Sym *s2, *s4; - Prog *p, *q, *ps2, *ps4; + Prog *p, *q, *q2, *ps2, *ps4; if(debug['v']) Bprint(&bso, "%5.2f profile 2\n", cputime()); Bflush(&bso); - s2 = lookup("_profin", 0); - s4 = lookup("_profout", 0); + + if(debug['e']){ + s2 = lookup("_tracein", 0); + s4 = lookup("_traceout", 0); + }else{ + s2 = lookup("_profin", 0); + s4 = lookup("_profout", 0); + } if(s2->type != STEXT || s4->type != STEXT) { - diag("_profin/_profout not defined"); + if(debug['e']) + diag("_tracein/_traceout not defined %d %d", s2->type, s4->type); + else + diag("_profin/_profout not defined"); return; } + ps2 = P; ps4 = P; for(p = firstp; p != P; p = p->link) { - setarch(p); if(p->as == ATEXT) { if(p->from.sym == s2) { ps2 = p; @@ -1315,7 +1360,6 @@ doprof2(void) } } for(p = firstp; p != P; p = p->link) { - setarch(p); if(p->as == ATEXT) { if(p->reg & NOPROF) { for(;;) { @@ -1330,13 +1374,26 @@ doprof2(void) } /* - * BL profin, R2 + * BL profin */ q = prg(); q->line = p->line; q->pc = p->pc; q->link = p->link; - p->link = q; + if(debug['e']){ /* embedded tracing */ + q2 = prg(); + p->link = q2; + q2->link = q; + + q2->line = p->line; + q2->pc = p->pc; + + q2->as = AB; + q2->to.type = D_BRANCH; + q2->to.sym = p->to.sym; + q2->cond = q->link; + }else + p->link = q; p = q; p->as = ABL; p->to.type = D_BRANCH; @@ -1347,27 +1404,64 @@ doprof2(void) } if(p->as == ARET) { /* + * RET (default) + */ + if(debug['e']){ /* embedded tracing */ + q = prg(); + q->line = p->line; + q->pc = p->pc; + q->link = p->link; + p->link = q; + p = q; + } + + /* * RET */ q = prg(); q->as = ARET; q->from = p->from; q->to = p->to; + q->cond = p->cond; q->link = p->link; + q->reg = p->reg; p->link = q; - /* - * BL profout - */ - p->as = ABL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->cond = ps4; - p->to.sym = s4; - - p = q; - + if(p->scond != 14) { + q = prg(); + q->as = ABL; + q->from = zprg.from; + q->to = zprg.to; + q->to.type = D_BRANCH; + q->cond = ps4; + q->to.sym = s4; + q->link = p->link; + p->link = q; + + p->as = brcond[p->scond^1]; /* complement */ + p->scond = 14; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = q->link->link; /* successor of RET */ + p->to.offset = q->link->link->pc; + + p = q->link->link; + } else { + + /* + * BL profout + */ + p->as = ABL; + p->from = zprg.from; + p->to = zprg.to; + p->to.type = D_BRANCH; + p->cond = ps4; + p->to.sym = s4; + p->scond = 14; + + p = q; + } continue; } } @@ -1387,7 +1481,7 @@ nuxiinit(void) inuxi1[i] = c; inuxi4[i] = c; fnuxi4[i] = c; - if(!debug['d']){ + if(debug['d'] == 0){ fnuxi8[i] = c; fnuxi8[i+4] = c+4; } @@ -1481,17 +1575,6 @@ ieeedtod(Ieee *ieeep) return ldexp(fr, exp); } -static void -puntfp(Prog *p) -{ - USED(p); - /* floating point - punt for now */ - curtext->reg = NREG; /* ARM */ - curtext->from.sym->thumb = 0; - thumb = 0; - // print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line); -} - void undefsym(Sym *s) { @@ -1544,7 +1627,7 @@ readundefs(char *f, int t) diag("%s: bad format", f); errorexit(); } - for(i = 0; i < n; i++){ + for(i = 0; i < n; i++) { s = lookup(fields[i], 0); s->type = SXREF; s->subtype = t; diff --git a/utils/5l/optab.c b/utils/5l/optab.c index 65ad3447..e9a566fd 100644 --- a/utils/5l/optab.c +++ b/utils/5l/optab.c @@ -29,13 +29,10 @@ Optab optab[] = { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 }, - { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, - { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, @@ -47,7 +44,6 @@ Optab optab[] = { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 }, { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 }, { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, @@ -215,6 +211,14 @@ Optab optab[] = { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 }, { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 }, + { AADDF, C_FREG, C_NONE, C_FREG, 74, 4, 0, VFP }, + { AADDF, C_FREG, C_REG, C_FREG, 74, 4, 0, VFP }, + { AMOVF, C_FREG, C_NONE, C_FREG, 74, 4, 0, VFP }, + { ACMPF, C_FREG, C_REG, C_NONE, 75, 8, 0, VFP }, + { ACMPF, C_FCON, C_REG, C_NONE, 75, 8, 0, VFP }, + { AMOVFW, C_FREG, C_NONE, C_REG, 76, 8, 0, VFP }, + { AMOVFW, C_REG, C_NONE, C_FREG, 76, 8, 0, VFP }, + { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 }, { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 }, { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 }, diff --git a/utils/5l/pass.c b/utils/5l/pass.c index e4322df5..8ce7b6d0 100644 --- a/utils/5l/pass.c +++ b/utils/5l/pass.c @@ -24,11 +24,6 @@ dodata(void) if(v > s->value) diag("initialize bounds (%ld): %s\n%P", s->value, s->name, p); - if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){ - s = p->to.sym; - if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) - s->fnptr = 1; - } } if(debug['t']) { @@ -187,7 +182,6 @@ xfol(Prog *p) loop: if(p == P) return; - setarch(p); a = p->as; if(a == ATEXT) curtext = p; @@ -260,7 +254,7 @@ loop: return; } if(p->cond != P) - if(a != ABL && a != ABX && p->link != P) { + if(a != ABL && p->link != P) { q = brchain(p->link); if(a != ATEXT && a != ABCASE) if(q != P && (q->mark&FOLL)) { @@ -288,7 +282,7 @@ patch(void) { long c, vexit; Prog *p, *q; - Sym *s, *s1; + Sym *s; int a; if(debug['v']) @@ -298,17 +292,10 @@ patch(void) s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { - setarch(p); a = p->as; if(a == ATEXT) curtext = p; - if(seenthumb && a == ABL){ - // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S) - // print("%s calls %s\n", s1->name, s->name); - if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb) - s->foreign = 1; - } - if((a == ABL || a == ABX || a == AB || a == ARET) && + if((a == ABL || a == AB || a == ARET) && p->to.type != D_BRANCH && p->to.sym != S) { s = p->to.sym; switch(s->type) { @@ -351,21 +338,8 @@ patch(void) } for(p = firstp; p != P; p = p->link) { - setarch(p); - a = p->as; if(p->as == ATEXT) curtext = p; - if(seenthumb && a == ABL) { -#ifdef CALLEEBX - if(0) - {} -#else - if((s = p->to.sym) != S && (s->foreign || s->fnptr)) - p->as = ABX; -#endif - else if(p->to.type == D_OREG) - p->as = ABX; - } if(p->cond != P && p->cond != UP) { p->cond = brloop(p->cond); if(p->cond != P) @@ -483,327 +457,6 @@ rnd(long v, long r) return v; } -#define Reachable(n) if((s = lookup(n, 0)) != nil) s->used++ - -static void -rused(Adr *a) -{ - Sym *s = a->sym; - - if(s == S) - return; - if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){ - if(a->name == D_EXTERN || a->name == D_STATIC){ - if(s->used == 0) - s->used = 1; - } - } - else if(a->type == D_BRANCH){ - if(s->used == 0) - s->used = 1; - } -} - -void -reachable() -{ - Prog *p, *prev, *prevt, *nextt, *q; - Sym *s, *s0; - int i, todo; - char *a; - - Reachable("_div"); - Reachable("_divu"); - Reachable("_mod"); - Reachable("_modu"); - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return; - s = lookup(a, 0); - if(s == nil) - return; - if(s->type == 0){ - s->used = 1; // to stop asm complaining - for(p = firstp; p != P && p->as != ATEXT; p = p->link) - ; - if(p == nil) - return; - s = p->from.sym; - } - s->used = 1; - do{ - todo = 0; - for(p = firstp; p != P; p = p->link){ - if(p->as == ATEXT && (s0 = p->from.sym)->used == 1){ - todo = 1; - for(q = p->link; q != P && q->as != ATEXT; q = q->link){ - rused(&q->from); - rused(&q->to); - } - s0->used = 2; - } - } - for(p = datap; p != P; p = p->link){ - if((s0 = p->from.sym)->used == 1){ - todo = 1; - for(q = p; q != P; q = q->link){ // data can be scattered - if(q->from.sym == s0) - rused(&q->to); - } - s0->used = 2; - } - } - }while(todo); - prev = nil; - prevt = nextt = nil; - for(p = firstp; p != P; ){ - if(p->as == ATEXT){ - prevt = nextt; - nextt = p; - } - if(p->as == ATEXT && (s0 = p->from.sym)->used == 0){ - s0->type = SREMOVED; - for(q = p->link; q != P && q->as != ATEXT; q = q->link) - ; - if(q != p->cond) - diag("bad ptr in reachable()"); - if(prev == nil) - firstp = q; - else - prev->link = q; - if(q == nil) - lastp = prev; - if(prevt == nil) - textp = q; - else - prevt->cond = q; - if(q == nil) - etextp = prevt; - nextt = prevt; - if(debug['V']) - print("%s unused\n", s0->name); - p = q; - } - else{ - prev = p; - p = p->link; - } - } - prevt = nil; - for(p = datap; p != nil; ){ - if((s0 = p->from.sym)->used == 0){ - s0->type = SREMOVED; - prev = prevt; - for(q = p; q != nil; q = q->link){ - if(q->from.sym == s0){ - if(prev == nil) - datap = q->link; - else - prev->link = q->link; - } - else - prev = q; - } - if(debug['V']) - print("%s unused (data)\n", s0->name); - p = prevt->link; - } - else{ - prevt = p; - p = p->link; - } - } - for(i=0; i<NHASH; i++){ - for(s = hash[i]; s != S; s = s->link){ - if(s->used == 0) - s->type = SREMOVED; - } - } -} - -static void -fused(Adr *a, Prog *p, Prog *ct) -{ - Sym *s = a->sym; - Use *u; - - if(s == S) - return; - if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){ - if(a->name == D_EXTERN || a->name == D_STATIC){ - u = malloc(sizeof(Use)); - u->p = p; - u->ct = ct; - u->link = s->use; - s->use = u; - } - } - else if(a->type == D_BRANCH){ - u = malloc(sizeof(Use)); - u->p = p; - u->ct = ct; - u->link = s->use; - s->use = u; - } -} - -static int -ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r) -{ - int reg; - - USED(fp); - USED(ct); - if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ - reg = p->to.reg; - for(p = p->link; p != P && p->as != ATEXT; p = p->link){ - if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg) - return 1; - if(!debug['F'] && (isbranch(p) || p->as == ARET)){ - // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name); - return 0; - } - if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ - if(!debug['F'] && p->to.type != D_REG){ - // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name); - return 0; - } - reg = p->to.reg; - } - } - } - // print("%s: no MOVW O(R), R\n", fp->name); - return debug['F']; -} - -static void -setfpuse(Prog *p, Sym *fp, Sym *r) -{ - int reg; - - if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){ - reg = p->to.reg; - for(p = p->link; p != P && p->as != ATEXT; p = p->link){ - if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){ - fp->fnptr = 0; - p->as = ABL; // safe to do so -// print("simplified %s call\n", fp->name); - break; - } - if(!debug['F'] && (isbranch(p) || p->as == ARET)) - diag("bad setfpuse call"); - if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){ - if(!debug['F'] && p->to.type != D_REG) - diag("bad setfpuse call"); - reg = p->to.reg; - } - } - } -} - -static int -cksymuse(Sym *s, int t) -{ - Prog *p; - - for(p = datap; p != P; p = p->link){ - if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){ - // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t); - return 0; - } - } - return 1; -} - -/* check the use of s at the given point */ -static int -ckuse(Sym *s, Sym *s0, Use *u) -{ - Sym *s1; - - s1 = u->p->from.sym; -// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil"); - if(u->ct == nil){ /* in data area */ - if(s0 == s && !cksymuse(s1, s0->thumb)){ - // print("%s: cksymuse fails\n", s0->name); - return 0; - } - for(u = s1->use; u != U; u = u->link) - if(!ckuse(s1, s0, u)) - return 0; - } - else{ /* in text area */ - if(u->ct->from.sym->thumb != s0->thumb){ - // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb); - return 0; - } - return ckfpuse(u->p, u->ct, s0, s); - } - return 1; -} - -static void -setuse(Sym *s, Sym *s0, Use *u) -{ - Sym *s1; - - s1 = u->p->from.sym; - if(u->ct == nil){ /* in data area */ - for(u = s1->use; u != U; u = u->link) - setuse(s1, s0, u); - } - else{ /* in text area */ - setfpuse(u->p, s0, s); - } -} - -/* detect BX O(R) which can be done as BL O(R) */ -void -fnptrs() -{ - int i; - Sym *s; - Prog *p; - Use *u; - - for(i=0; i<NHASH; i++){ - for(s = hash[i]; s != S; s = s->link){ - if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ - // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign); - } - } - } - /* record use of syms */ - for(p = firstp; p != P; p = p->link){ - if(p->as == ATEXT) - curtext = p; - else{ - fused(&p->from, p, curtext); - fused(&p->to, p, curtext); - } - } - for(p = datap; p != P; p = p->link) - fused(&p->to, p, nil); - - /* now look for fn ptrs */ - for(i=0; i<NHASH; i++){ - for(s = hash[i]; s != S; s = s->link){ - if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){ - for(u = s->use; u != U; u = u->link){ - if(!ckuse(s, s, u)) - break; - } - if(u == U){ // can simplify - for(u = s->use; u != U; u = u->link) - setuse(s, s, u); - } - } - } - } - - /* now free Use structures */ -} - void import(void) { diff --git a/utils/5l/span.c b/utils/5l/span.c index 0b69a96f..d086f592 100644 --- a/utils/5l/span.c +++ b/utils/5l/span.c @@ -3,140 +3,19 @@ static struct { ulong start; ulong size; - ulong extra; } pool; -int checkpool(Prog*, int); -int flushpool(Prog*, int, int); - -int -isbranch(Prog *p) -{ - int as = p->as; - return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; -} - -static int -ispad(Prog *p) -{ - if(p->as != AMOVW) - return 0; - if(p->from.type != D_REG || p->from.reg != REGSB) - return 0; - if(p->to.type != D_REG || p->to.reg != REGSB) - return 0; - return 1; -} - -int -fninc(Sym *s) -{ - if(thumb){ - if(s->thumb){ - if(s->foreign) - return 8; - else - return 0; - } - else{ - if(s->foreign) - return 0; - else - diag("T A !foreign in fninc"); - } - } - else{ - if(s->thumb){ - if(s->foreign) - return 0; - else - diag("A T !foreign in fninc"); - } - else{ - if(s->foreign) - return 4; - else - return 0; - } - } - return 0; -} - -int -fnpinc(Sym *s) -{ - if(!s->fnptr){ // a simplified case BX O(R) -> BL O(R) - if(!debug['f']) - diag("fnptr == 0 in fnpinc"); - if(s->foreign) - diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb); - return 0; - } - /* 0, 1, 2, 3 squared */ - if(s->thumb) - return s->foreign ? 9 : 1; - else - return s->foreign ? 4 : 0; -} - -static Prog * -pad(Prog *p, int pc) -{ - Prog *q; - - q = prg(); - q->as = AMOVW; - q->line = p->line; - q->from.type = D_REG; - q->from.reg = REGSB; - q->to.type = D_REG; - q->to.reg = REGSB; - q->pc = pc; - q->link = p->link; - return q; -} - -static int -scan(Prog *op, Prog *p, int c) -{ - Prog *q; - - for(q = op->link; q != p; q = q->link){ - q->pc = c; - c += oplook(q)->size; - nocache(q); - } - return c; -} - -/* size of a case statement including jump table */ -static long -casesz(Prog *p) -{ - int jt = 0; - long n = 0; - Optab *o; - - for( ; p != P; p = p->link){ - if(p->as == ABCASE) - jt = 1; - else if(jt) - break; - o = oplook(p); - n += o->size; - } - return n; -} +void checkpool(Prog*); +void flushpool(Prog*, int); void span(void) { - Prog *p, *op; + Prog *p; Sym *setext, *s; Optab *o; int m, bflag, i; long c, otxt, v; - int lastthumb = -1; if(debug['v']) Bprint(&bso, "%5.2f span\n", cputime()); @@ -144,27 +23,13 @@ span(void) bflag = 0; c = INITTEXT; - op = nil; otxt = c; - for(p = firstp; p != P; op = p, p = p->link) { - setarch(p); + for(p = firstp; p != P; p = p->link) { p->pc = c; o = oplook(p); m = o->size; - // must check literal pool here in case p generates many instructions - if(blitrl){ - if(thumb && isbranch(p)) - pool.extra += brextra(p); - if(checkpool(op, p->as == ACASE ? casesz(p) : m)) - c = p->pc = scan(op, p, c); - } if(m == 0) { if(p->as == ATEXT) { - if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool - if(flushpool(op, 0, 1)) - c = p->pc = scan(op, p, c); - } - lastthumb = thumb; curtext = p; autosize = p->to.offset + 4; if(p->from.sym != S) @@ -173,8 +38,6 @@ span(void) if(c-otxt >= 1L<<17) bflag = 1; otxt = c; - if(thumb && blitrl) - pool.extra += brextra(p); continue; } diag("zero-width instruction\n%P", p); @@ -189,17 +52,14 @@ span(void) break; case LPOOL: if ((p->scond&C_SCOND) == 14) - flushpool(p, 0, 0); + 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, 0); + flushpool(p, 0); c += m; - if(blitrl && p->link == P){ - if(thumb && isbranch(p)) - pool.extra += brextra(p); - checkpool(p, 0); - } + if(blitrl) + checkpool(p); } /* @@ -214,10 +74,7 @@ span(void) bflag = 0; c = INITTEXT; for(p = firstp; p != P; p = p->link) { - setarch(p); p->pc = c; - if(thumb && isbranch(p)) - nocache(p); o = oplook(p); /* very larg branches if(o->type == 6 && p->cond) { @@ -258,93 +115,6 @@ span(void) } } - if(seenthumb){ // branch resolution - int passes = 0; - int lastc = 0; - int again; - Prog *oop; - - loop: - passes++; - if(passes > 150){ - diag("span looping !"); - errorexit(); - } - c = INITTEXT; - oop = op = nil; - again = 0; - for(p = firstp; p != P; oop = op, op = p, p = p->link){ - setarch(p); - if(p->pc != c) - again = 1; - p->pc = c; - if(thumb && isbranch(p)) - nocache(p); - o = oplook(p); - m = o->size; - if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added - if(p->as == ABL) - m = 4; - else - m = 2; - p->align = 0; - } - if(p->align){ - if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){ - if(ispad(op)){ - oop->link = p; - op = oop; - c -= 2; - p->pc = c; - } - else{ - op->link = pad(op, c); - op = op->link; - c += 2; - p->pc = c; - } - again = 1; - } - } - 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; - } - } - c += m; - } - if(c != lastc || again){ - lastc = c; - goto loop; - } - } - - if(0 && seenthumb){ // rm redundant padding - obsolete - int d; - - op = nil; - d = 0; - for(p = firstp; p != P; op = p, p = p->link){ - p->pc -= d; - if(p->as == ATEXT){ - if(p->from.sym != S) - p->from.sym->value -= d; -// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr); - } - if(ispad(p) && p->link != P && ispad(p->link)){ - op->link = p->link->link; - d += 4; - p = op; - } - } - // print("%d bytes removed (padding)\n", d); - c -= d; - } - if(debug['t']) { /* * add strings to text segment @@ -361,7 +131,7 @@ span(void) c += v; } } - + c = rnd(c, 8); setext = lookup("etext", 0); @@ -382,31 +152,24 @@ span(void) * drop the pool now, and branch round it. * this happens only in extended basic blocks that exceed 4k. */ -int -checkpool(Prog *p, int sz) +void +checkpool(Prog *p) { - if(thumb){ - if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc) - return flushpool(p, 1, 0); - else if(p->link == P) - return flushpool(p, 2, 0); - return 0; - } - if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) - return flushpool(p, 1, 0); + if(pool.size >= 0xffc || immaddr((p->pc+4)+4+pool.size - pool.start+8) == 0) + flushpool(p, 1); else if(p->link == P) - return flushpool(p, 2, 0); - return 0; + flushpool(p, 2); } -int -flushpool(Prog *p, int skip, int force) +void +flushpool(Prog *p, int skip) { Prog *q; if(blitrl) { if(skip){ - if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start); + 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; @@ -414,18 +177,15 @@ flushpool(Prog *p, int skip, int force) q->link = blitrl; blitrl = q; } - else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048))) - return 0; + 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; - pool.extra = 0; - return 1; } - return 0; } void @@ -434,10 +194,7 @@ addpool(Prog *p, Adr *a) Prog *q, t; int c; - if(thumb) - c = thumbaclass(a, p); - else - c = aclass(a); + c = aclass(a); t = zprg; t.as = AWORD; @@ -447,18 +204,15 @@ addpool(Prog *p, Adr *a) t.to = *a; break; - case C_SROREG: + case C_SROREG: case C_LOREG: case C_ROREG: case C_FOREG: case C_SOREG: - case C_HOREG: - case C_GOREG: case C_FAUTO: case C_SAUTO: case C_LAUTO: case C_LACON: - case C_GACON: t.to.type = D_CONST; t.to.offset = instoffset; break; @@ -477,7 +231,6 @@ addpool(Prog *p, Adr *a) if(blitrl == P) { blitrl = q; pool.start = p->pc; - q->align = 4; } else elitrl->link = q; elitrl = q; @@ -678,16 +431,8 @@ aclass(Adr *a) s->type = SDATA; } instoffset = s->value + a->offset + INITDAT; - if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) { + if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) instoffset = s->value + a->offset; -#ifdef CALLEEBX - instoffset += fnpinc(s); -#else - if(s->thumb) - instoffset++; // T bit -#endif - return C_LCON; - } return C_LCON; } return C_GOK; @@ -730,12 +475,6 @@ aclass(Adr *a) case SCONST: case SLEAF: instoffset = s->value + a->offset; -#ifdef CALLEEBX - instoffset += fnpinc(s); -#else - if(s->thumb) - instoffset++; // T bit -#endif return C_LCON; } if(!dlm) { @@ -773,35 +512,19 @@ oplook(Prog *p) int a1, a2, a3, r; char *c1, *c3; Optab *o, *e; - Optab *otab; - Oprang *orange; - if(thumb){ - otab = thumboptab; - orange = thumboprange; - } - else{ - otab = optab; - orange = oprange; - } a1 = p->optab; if(a1) - return otab+(a1-1); + return optab+(a1-1); a1 = p->from.class; if(a1 == 0) { - if(thumb) - a1 = thumbaclass(&p->from, p) + 1; - else - a1 = aclass(&p->from) + 1; + a1 = aclass(&p->from) + 1; p->from.class = a1; } a1--; a3 = p->to.class; if(a3 == 0) { - if(thumb) - a3 = thumbaclass(&p->to, p) + 1; - else - a3 = aclass(&p->to) + 1; + a3 = aclass(&p->to) + 1; p->to.class = a3; } a3--; @@ -809,35 +532,35 @@ oplook(Prog *p) if(p->reg != NREG) a2 = C_REG; r = p->as; - o = orange[r].start; + o = oprange[r].start; if(o == 0) { a1 = opcross[repop[r]][a1][a2][a3]; if(a1) { p->optab = a1+1; - return otab+a1; + return optab+a1; } - o = orange[r].stop; /* just generate an error */ + 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 = orange[r].stop; + 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-otab)+1; + p->optab = (o-optab)+1; return o; } diag("illegal combination %A %d %d %d", p->as, a1, a2, a3); prasm(p); if(o == 0) - o = otab; + o = optab; return o; } @@ -898,19 +621,12 @@ cmp(int a, int b) if(b == C_SBRA) return 1; break; - case C_GBRA: - if(b == C_SBRA || b == C_LBRA) - return 1; - - case C_HREG: - return cmp(C_SP, b) || cmp(C_PC, b); - } return 0; } int -ocmp(const void *a1, const void *a2) +ocmp(void *a1, void *a2) { Optab *p1, *p2; int n; @@ -923,6 +639,9 @@ ocmp(const void *a1, const void *a2) n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */ if(n) return n; + n = (p2->flag&VFP) - (p1->flag&VFP); /* floating point arch */ + if(n) + return n; n = p1->a1 - p2->a1; if(n) return n; @@ -941,14 +660,18 @@ buildop(void) int i, n, r; armv4 = !debug['h']; + vfp = debug['f']; 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++) + for(n=0; optab[n].as != AXXX; n++) { + if((optab[n].flag & VFP) && !vfp) + optab[n].as = AXXX; 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; @@ -963,6 +686,8 @@ buildop(void) default: diag("unknown op in build: %A", r); errorexit(); + case AXXX: + break; case AADD: oprange[AAND] = oprange[r]; oprange[AEOR] = oprange[r]; diff --git a/utils/5l/thumb.c b/utils/5l/thumb.c deleted file mode 100644 index f16175ea..00000000 --- a/utils/5l/thumb.c +++ /dev/null @@ -1,1636 +0,0 @@ -#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 -mv(Prog *p, int r, int off) -{ - int v, o; - if(p != nil && p->cond != nil){ // in literal pool - v = p->cond->pc - p->pc - 4; - if(p->cond->pc & 3) - diag("mv: bad literal pool alignment"); - if(v & 3) - v += 2; // ensure M(4) offset - mult(p, v, 4); - off = v/4; - numr(p, off, 0, 255); - o = 0x9<<11; - } - else{ - numr(p, off, 0, 255); - o = 0x4<<11; - } - o |= (r<<8) | off; - return o; -} - -static void -mvcon(Prog *p, int r, int c, long *o1, long *o2) -{ - int op = 0, n = 0; - - if(c >= 0 && c <= 255) - diag("bad c in mvcon"); - if(c >= -255 && c < 0) // mv, neg - c = -c; - else if(c >= 256 && c <= 510){ // mv, add - n = rand()%(511-c) + (c-255); - c -= n; - // n = c-255; - // c = 255; - op = AADD; - } - else{ - if(c < 0) - diag("-ve in mvcon"); - while(!(c & 1)){ - n++; - c >>= 1; - } - if(c >= 0 && c <= 255) // mv, lsl - op = ASLL; - else - diag("bad shift in mvcon"); - } - *o1 = mv(p, r, c); - switch(op){ - case 0: - *o2 = (1<<14) | (9<<6) | (r<<3) | r; - break; - case AADD: - *o2 = (6<<11) | (r<<8) | n; - break; - case ASLL: - *o2 = (n<<6) | (r<<3) | r; - break; - } -} - -static long -mvlh(int rs, int rd) -{ - int o = 0x46<<8; - - if(high(rs)){ - rs -= 8; - o |= 1<<6; - } - if(high(rd)){ - rd -= 8; - o |= 1<<7; - } - o |= (rs<<3) | rd; - return o; -} - -void -thumbbuildop() -{ - int i, n, r; - Optab *optab = thumboptab; - Oprang *oprange = thumboprange; - - for(n=0; optab[n].as != AXXX; n++) - ; - 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: - 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 AMVN: - oprange[AADC] = oprange[r]; - oprange[ASBC] = oprange[r]; - oprange[AMUL] = oprange[r]; - oprange[AAND] = oprange[r]; - oprange[AEOR] = oprange[r]; - oprange[AORR] = oprange[r]; - oprange[ABIC] = oprange[r]; - oprange[AMULU] = oprange[r]; - break; - case ACMN: - oprange[ATST] = oprange[r]; - break; - case ASRL: - oprange[ASRA] = oprange[r]; - oprange[ASLL] = oprange[r]; - break; - case AADD: - oprange[ASUB] = oprange[r]; - break; - } - } -} - -void -thumbasmout(Prog *p, Optab *o) -{ - long o1, o2, o3, o4, o5, o6, o7, v; - int r, rf, rt; - - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0; -if(debug['P']) print("%ulx: %P type %d %d\n", (ulong)(p->pc), p, o->type, p->align); - opcount[o->type] += o->size; - switch(o->type) { - default: - diag("unknown asm %d", o->type); - prasm(p); - break; - case 0: /* pseudo ops */ -if(debug['G']) print("%ulx: %s: thumb\n", (ulong)(p->pc), p->from.sym->name); - break; - case 1: /* op R, -, R or op R, R, - */ - o1 = thumboprr(p->as); - if(rt == NREG) - rt = r; - lowreg(p, rf); - lowreg(p, rt); - o1 |= (0x10<<10) | (rf<<3) | rt; - break; - case 2: /* add/sub R, R, R or add/sub R, -, R */ - o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; - if(r == NREG) - r = rt; - lowreg(p, rf); - lowreg(p, r); - lowreg(p, rt); - o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt; - break; - case 3: /* add/sub $I, R, R or add/sub $I, -, R */ - thumbaclass(&p->from, p); - o1 = p->as == AADD ? 0x0<<9 : 0x1<<9; - if(r == NREG) - r = rt; - numr(p, instoffset, 0, 7); - lowreg(p, r); - lowreg(p, rt); - o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt; - break; - case 4: /* shift $I, R, R or shift $I, -, R */ - thumbaclass(&p->from, p); - if(instoffset < 0) - diag("negative shift in thumbasmout"); - instoffset %= 32; - o1 = thumbopri(p->as); - if(r == NREG) - r = rt; - numr(p, instoffset, 0, 31); - lowreg(p, r); - lowreg(p, rt); - o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt; - break; - case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */ - thumbaclass(&p->from, p); - o1 = thumbopri(p->as); - if(rt == NREG) - rt = r; - numr(p, instoffset, 0, 255); - lowreg(p, rt); - o1 |= (0x1<<13) | (rt<<8) | instoffset; - break; - case 6: /* add $I, PC/SP, R */ - if(p->as == ASUB) - diag("subtract in add $I, PC/SP, R"); - thumbaclass(&p->from, p); - o1 = r == REGSP ? 0x1<<11 : 0x0<<11; - numr(p, instoffset, 0, 255); - regis(p, r, REGSP, REGPC); - lowreg(p, rt); - o1 |= (0xa<<12) | (rt<<8) | instoffset; - break; - case 7: /* add, sub $I, SP */ - thumbaclass(&p->from, p); - o1 = p->as == AADD ? 0x0<<7 : 0x1<<7; - numr(p, instoffset, 0, 508); - mult(p, instoffset, 4); - regis(p, rt, REGSP, REGSP); - o1 |= (0xb0<<8) | (instoffset>>2); - break; - case 8: /* add/mov/cmp R, R where at least 1 reg is high */ - o1 = 0; - if(rt == NREG) - rt = r; - if(high(rf)){ - o1 |= 1<<6; - rf -= 8; - } - if(high(rt)){ - o1 |= 2<<6; - rt -= 8; - } - if(o1 == 0) - diag("no high register(%P)", p); - o1 |= thumbophh(p->as); - o1 |= (0x11<<10) | (rf<<3) | rt; - break; - case 9: /* B $I */ - thumbaclass(&p->to, p); - numr(p, instoffset, -2048, 2046); - o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff); - break; - case 10: /* Bcc $I */ - thumbaclass(&p->to, p); - numr(p, instoffset, -256, 254); - o1 = thumbopbra(p->as); - o1 |= (0xd<<12) | ((instoffset>>1)&0xff); - break; - case 11: /* BL $I */ - thumbaclass(&p->to, p); - numr(p, instoffset, -4194304, 4194302); - o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff); - o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff); - break; - case 12: /* BX $I */ -#ifdef CALLEEBX - diag("BX $I case"); -#endif - thumbaclass(&p->to, p); - if(p->to.sym->thumb) - instoffset |= 1; // T bit - o1 = mvlh(REGPC, REGTMPT); - o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset) - o3 = mvlh(REGTMPT, REGLINK); - o4 = mv(nil, REGTMPT, instoffset); - o5 = (0x11c<<6) | (REGTMPT<<3); - // o1 = mv(nil, REGTMPT, v); - // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK; - // o3 = (0x11c<<6) | (REGTMPT<<3); - break; - case 13: /* B O(R) */ - diag("B O(R)"); - break; - case 14: /* BL O(R) */ - diag("BL O(R)"); - break; - case 15: /* BX R */ - o1 = mvlh(REGPC, REGTMPT); - o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset) - o3 = mvlh(REGTMPT, REGLINK); - o4 = 0; - if(high(rt)){ - rt -= 8; - o4 |= 1<<6; - } - o4 |= (0x8e<<7) | (rt<<3); - // o1 = (0x11c<<6) | (rt<<3); - break; - case 16: /* SWI $I */ - thumbaclass(&p->to, p); - numr(p, instoffset, 0, 255); - o1 = (0xdf<<8) | instoffset; - break; - case 17: /* AWORD */ - thumbaclass(&p->to, p); - o1 = instoffset&0xffff; - o2 = (instoffset>>16)&0xffff; - break; - case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */ - thumbaclass(&p->from, p); - rf = o->param; - o1 = rf == REGSP ? 0x13<<11 : 0x9<<11; - regis(p, rf, REGSP, REGPC); - lowreg(p, rt); - mult(p, instoffset, 4); - numr(p, instoffset/4, 0, 255); - o1 |= (rt<<8) | (instoffset/4); - break; - case 19: /* AMOVW... O(R), R */ - thumbaclass(&p->from, p); - o1 = thumbopmv(p->as, 1); - v = 4; - if(p->as == AMOVHU) - v = 2; - else if(p->as == AMOVBU) - v = 1; - mult(p, instoffset, v); - lowreg(p, rf); - lowreg(p, rt); - numr(p, instoffset/v, 0, 31); - o1 |= ((instoffset/v)<<6) | (rf<<3) | rt; - break; - case 20: /* AMOVW R, O(SP) */ - thumbaclass(&p->to, p); - o1 = 0x12<<11; - if(rt != NREG) regis(p, rt, REGSP, REGSP); - lowreg(p, rf); - mult(p, instoffset, 4); - numr(p, instoffset/4, 0, 255); - o1 |= (rf<<8) | (instoffset/4); - break; - case 21: /* AMOVW... R, O(R) */ - thumbaclass(&p->to, p); - o1 = thumbopmv(p->as, 0); - v = 4; - if(p->as == AMOVHU || p->as == AMOVH) - v = 2; - else if(p->as == AMOVBU || p->as == AMOVB) - v = 1; - lowreg(p, rf); - lowreg(p, rt); - mult(p, instoffset, v); - numr(p, instoffset/v, 0, 31); - o1 |= ((instoffset/v)<<6) | (rt<<3) | rf; - break; - case 22: /* AMOVW R, R -> ASLL $0, R, R */ - o1 = thumbopri(ASLL); - lowreg(p, rf); - lowreg(p, rt); - o1 |= (0x0<<13) | (rf<<3) | rt; - break; - case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */ - o1 = thumbopri(ASLL); - o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL); - v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16; - lowreg(p, rf); - lowreg(p, rt); - o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt; - o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt; - break; - case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */ - thumbaclass(&p->from, p); - lowreg(p, rf); - lowreg(p, rt); - if(rf == rt) - r = REGTMPT; - else - r = rt; - if(p->as == AMOVB) - numr(p, instoffset, 0, 31); - else{ - mult(p, instoffset, 2); - numr(p, instoffset, 0, 62); - } - o1 = mv(p, r, instoffset); - o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; - o2 |= (r<<6) | (rf<<3) | rt; - break; - case 25: /* MOVW $sacon, R */ - thumbaclass(&p->from, p); -// print("25: %d %d %d %d\n", instoffset, rf, r, rt); - if(rf == NREG) - rf = REGSP; - lowreg(p, rt); - if(rf == REGSP){ - mult(p, instoffset, 4); - numr(p, instoffset>>2, 0, 255); - o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R - } - else if(rf == rt){ - numr(p, instoffset, 0, 255); - o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R - } - else{ - lowreg(p, rf); - numr(p, instoffset, 0, 7); - o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd - } - break; - case 26: /* AMOVM $c, oreg -> stmia */ - lowreg(p, rt); - numr(p, p->from.offset, -256, 255); - o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff); - break; - case 27: /* AMOVM oreg, $c ->ldmia */ - lowreg(p, rf); - numr(p, p->to.offset, -256, 256); - o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff); - break; - case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */ - thumbaclass(&p->from, p); - lowreg(p, rf); - lowreg(p, rt); - if(rf == rt) - r = REGTMPT; - else - r = rt; - o1 = mv(p, r, instoffset); - o2 = thumboprrr(p->as, 1); - o2 |= (r<<6) | (rf<<3) | rt; - break; - case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */ - thumbaclass(&p->to, p); - lowreg(p, rf); - lowreg(p, rt); - if(rt == REGTMPT){ // used as tmp reg - if(instoffset >= 0 && instoffset <= 255){ - o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7 - o2 = thumbopirr(p->as, 0); - o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R) - } - else - diag("big offset - case 29"); - } - else{ - o1 = mv(p, REGTMPT, instoffset); - o2 = thumboprrr(p->as, 0); - o2 |= (REGTMPT<<6) | (rt<<3) | rf; - } - break; - case 30: /* AMOVW... *addr, R */ - thumbaclass(&p->from, p); - o1 = mv(p, rt, instoffset); // MOV addr, rtmp - o2 = thumbopmv(p->as, 1); - lowreg(p, rt); - o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R - break; - case 31: /* AMOVW... R, *addr */ - thumbaclass(&p->to, p); - o1 = mv(p, REGTMPT, instoffset); - o2 = thumbopmv(p->as, 0); - lowreg(p, rf); - o2 |= (REGTMPT<<3) | rf; - break; - case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */ - thumbaclass(&p->from, p); - o1 = mv(p, rt, instoffset); - lowreg(p, rt); - o2 = mv(nil, REGTMPT, 0); - o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9; - o3 |= (REGTMPT<<6) | (rt<<3) | rt; - break; - case 33: /* AMOVW O(SP), R (O large) */ - thumbaclass(&p->from, p); - lowreg(p, rt); - o1 = mv(p, rt, instoffset); - o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt - o3 = thumbopmv(p->as, 1); - o3 |= (rt<<3) | rt; - break; - case 34: /* AMOVW R, O(SP) (O large) */ - thumbaclass(&p->to, p); - lowreg(p, rf); - o1 = mv(p, REGTMPT, instoffset); - o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP - o3 = thumbopmv(p->as, 0); - o3 |= (REGTMPT<<3) | rf; - break; - case 35: /* AMOVW $lacon, R */ - thumbaclass(&p->from, p); - lowreg(p, rt); - if(rf == NREG) - rf = REGSP; - if(rf == rt) - rf = r = REGTMPT; - else - r = rt; -// print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt); - o1 = mv(p, r, instoffset); // mov O, Rd - if(high(rf)) - o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd - else - o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd - break; - case 36: /* AADD/ASUB $i, r, r when $i too big */ - thumbaclass(&p->from, p); - lowreg(p, r); - lowreg(p, rt); - o1 = mv(p, REGTMPT, instoffset); - o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; - o2 |= (REGTMPT<<6) | (r<<3) | rt; - break; - case 37: /* AADD/ASUB $i, r when $i too big */ - thumbaclass(&p->from, p); - lowreg(p, rt); - o1 = mv(p, REGTMPT, instoffset); - o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; - o2 |= (REGTMPT<<6) | (rt<<3) | rt; - break; - case 38: /* AMOVW $i, r when $i too big */ - thumbaclass(&p->from, p); - lowreg(p, rt); - o1 = mv(p, rt, instoffset); - break; - case 39: /* ACMP $i, r when $i too big */ - thumbaclass(&p->from, p); - lowreg(p, r); - o1 = mv(p, REGTMPT, instoffset); - o2 = (0x10a<<6) | (REGTMPT<<3) | r; - break; - case 40: /* add, sub $I, SP when $I large*/ - thumbaclass(&p->from, p); - if(p->as == ASUB) - instoffset = -instoffset; - o1 = mv(p, REGTMPT, instoffset); - o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8); - regis(p, rt, REGSP, REGSP); - break; - case 41: /* BL LBRA */ - thumbaclass(&p->to, p); - o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 - o2 = mvlh(REGTMPT, REGPC); // mov r7, pc - o3 = instoffset&0xffff; // $lab - o4 = (instoffset>>16)&0xffff; - break; - case 42: /* Bcc GBRA */ - thumbaclass(&p->to, p); - o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot - // ab lbra - o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7 - o3 = mvlh(REGTMPT, REGPC); // mov r7, pc - o4 = instoffset&0xffff; // $lab - o5 = (instoffset>>16)&0xffff; - break; - case 43: /* BL LBRA */ - thumbaclass(&p->to, p); - o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 - o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7 - o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr - o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 - o5 = mvlh(REGTMPT, REGPC); // mov r7, pc - o6 = instoffset&0xffff; // $lab - o7 = (instoffset>>16)&0xffff; - break; - case 44: /* BX LBRA */ -#ifdef CALLEEBX - diag("BX LBRA case"); -#endif - thumbaclass(&p->to, p); - if(p->to.sym->thumb) - instoffset |= 1; // T bit - o1 = mvlh(REGPC, REGTMPT); // mov pc, r7 - o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7 - o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr - o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7 - o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7 - o6 = instoffset&0xffff; // $lab - o7 = (instoffset>>16)&0xffff; - break; - case 45: /* BX R when returning from fn */ - o1 = 0; - if(high(rt)){ - rt -= 8; - o1 |= 1<<6; - } - o1 |= (0x8e<<7) | (rt<<3); - break; - case 46: /* Bcc LBRA */ - thumbaclass(&p->to, p); - o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot - // ab lbra - instoffset -= 2; - numr(p, instoffset, -2048, 2046); - o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff); - break; - case 47: /* mov $i, R where $i can be built */ - thumbaclass(&p->from, p); - mvcon(p, rt, instoffset, &o1, &o2); - break; - case 48: /* ACMP $i, r when $i built up */ - thumbaclass(&p->from, p); - lowreg(p, r); - mvcon(p, REGTMPT, instoffset, &o1, &o2); - o3 = (0x10a<<6) | (REGTMPT<<3) | r; - break; - case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */ - thumbaclass(&p->from, p); - lowreg(p, r); - lowreg(p, rt); - numr(p, instoffset, 0, 255); - o1 = mv(p, REGTMPT, instoffset); - o2 = p->as == AADD ? 0xc<<9 : 0xd<<9; - o2 |= (REGTMPT<<6) | (r<<3) | rt; - break; - case 50: /* ADWORD */ - thumbaclass(&p->from, p); - o1 = instoffset&0xffff; - o2 = (instoffset>>16)&0xffff; - thumbaclass(&p->to, p); - o3 = instoffset&0xffff; - o4 = (instoffset>>16)&0xffff; - break; - case 51: /* BL r */ - o1 = mvlh(REGPC, REGLINK); // mov pc, lr - o2 = mvlh(rt, REGPC); // mov r, pc - break; - } - - v = p->pc; - switch(o->size) { - default: - if(debug['a']) - Bprint(&bso, " %.8lux:\t\t%P\n", v, p); - break; - case 2: - if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p); - hputl(o1); - break; - case 4: - if(debug['a']) - Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p); - hputl(o1); - hputl(o2); - break; - case 6: - if(debug['a']) - Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p); - hputl(o1); - hputl(o2); - hputl(o3); - break; - case 8: - if(debug['a']) - Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p); - hputl(o1); - hputl(o2); - hputl(o3); - hputl(o4); - break; - case 10: - if(debug['a']) - Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p); - hputl(o1); - hputl(o2); - hputl(o3); - hputl(o4); - hputl(o5); - break; - case 12: - if(debug['a']) - Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p); - hputl(o1); - hputl(o2); - hputl(o3); - hputl(o4); - hputl(o5); - hputl(o6); - break; - case 14: - if(debug['a']) - Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p); - hputl(o1); - hputl(o2); - hputl(o3); - hputl(o4); - hputl(o5); - hputl(o6); - hputl(o7); - break; - } - if(debug['G']){ - if(o->type == 17){ - print("%lx: word %ld\n", p->pc, (o2<<16)+o1); - return; - } - if(o->type == 50){ - print("%lx: word %ld\n", p->pc, (o2<<16)+o1); - print("%lx: word %ld\n", p->pc, (o4<<16)+o3); - return; - } - if(o->size > 0) dis(o1, p->pc); - if(o->size > 2) dis(o2, p->pc+2); - if(o->size > 4) dis(o3, p->pc+4); - if(o->size > 6) dis(o4, p->pc+6); - if(o->size > 8) dis(o5, p->pc+8); - if(o->size > 10) dis(o6, p->pc+10); - if(o->size > 12) dis(o7, p->pc+12); - // if(o->size > 14) dis(o8, p->pc+14); - } -} - -static long -thumboprr(int a) -{ - switch(a) { - case AMVN: return 0xf<<6; - case ACMP: return 0xa<<6; - case ACMN: return 0xb<<6; - case ATST: return 0x8<<6; - case AADC: return 0x5<<6; - case ASBC: return 0x6<<6; - case AMUL: - case AMULU: return 0xd<<6; - case AAND: return 0x0<<6; - case AEOR: return 0x1<<6; - case AORR: return 0xc<<6; - case ABIC: return 0xe<<6; - case ASRL: return 0x3<<6; - case ASRA: return 0x4<<6; - case ASLL: return 0x2<<6; - } - diag("bad thumbop oprr %d", a); - prasm(curp); - return 0; -} - -static long -thumbopirr(int a, int ld) -{ - if(ld) - diag("load in thumbopirr"); - switch(a){ - case AMOVW: return 0xc<<11; - case AMOVH: - case AMOVHU: return 0x10<<11; - case AMOVB: - case AMOVBU: return 0xe<<11; - } - return 0; -} - -static long -thumboprrr(int a, int ld) -{ - if(ld){ - switch(a){ - case AMOVW: return 0x2c<<9; - case AMOVH: return 0x2f<<9; - case AMOVB: return 0x2b<<9; - case AMOVHU: return 0x2d<<9; - case AMOVBU: return 0x2e<<9; - } - } - else{ - switch(a){ - case AMOVW: return 0x28<<9; - case AMOVHU: - case AMOVH: return 0x29<<9; - case AMOVBU: - case AMOVB: return 0x2a<<9; - } - } - diag("bad thumbop oprrr %d", a); - prasm(curp); - return 0; -} - -static long -thumbopri(int a) -{ - switch(a) { - case ASRL: return 0x1<<11; - case ASRA: return 0x2<<11; - case ASLL: return 0x0<<11; - case AADD: return 0x2<<11; - case ASUB: return 0x3<<11; - case AMOVW: return 0x0<<11; - case ACMP: return 0x1<<11; - } - diag("bad thumbop opri %d", a); - prasm(curp); - return 0; -} - -static long -thumbophh(int a) -{ - switch(a) { - case AADD: return 0x0<<8; - case AMOVW: return 0x2<<8; - case ACMP: return 0x1<<8; - } - diag("bad thumbop ophh %d", a); - prasm(curp); - return 0; -} - -static long -thumbopbra(int a) -{ - switch(a) { - case ABEQ: return 0x0<<8; - case ABNE: return 0x1<<8; - case ABCS: return 0x2<<8; - case ABHS: return 0x2<<8; - case ABCC: return 0x3<<8; - case ABLO: return 0x3<<8; - case ABMI: return 0x4<<8; - case ABPL: return 0x5<<8; - case ABVS: return 0x6<<8; - case ABVC: return 0x7<<8; - case ABHI: return 0x8<<8; - case ABLS: return 0x9<<8; - case ABGE: return 0xa<<8; - case ABLT: return 0xb<<8; - case ABGT: return 0xc<<8; - case ABLE: return 0xd<<8; - } - diag("bad thumbop opbra %d", a); - prasm(curp); - return 0; -} - -static long -thumbopmv(int a, int ld) -{ - switch(a) { - case AMOVW: return (ld ? 0xd : 0xc)<<11; - case AMOVH: - case AMOVHU: return (ld ? 0x11: 0x10)<<11; - case AMOVB: - case AMOVBU: return (ld ? 0xf : 0xe)<<11; - } - diag("bad thumbop opmv %d", a); - prasm(curp); - return 0; -} - -static void -lowreg(Prog *p, int r) -{ - if(high(r)) - diag("high reg [%P]", p); -} - -static void -mult(Prog *p, int n, int m) -{ - if(m*(n/m) != n) - diag("%d not M(%d) [%P]", n, m, p); -} - -static void -numr(Prog *p, int n, int min, int max) -{ - if(n < min || n > max) - diag("%d not in %d-%d [%P]", n, min, max, p); -} - -static void -regis(Prog *p, int r, int r1, int r2) -{ - if(r != r1 && r != r2) - diag("reg %d not %d or %d [%P]", r, r1, r2, p); -} - -void -hputl(int n) -{ - cbp[1] = n>>8; - cbp[0] = n; - cbp += 2; - cbc -= 2; - if(cbc <= 0) - cflush(); -} - -void -thumbcount() -{ - int i, c = 0, t = 0; - - for (i = 0; i < OPCNTSZ; i++) - t += opcount[i]; - if(t == 0) - return; - for (i = 0; i < OPCNTSZ; i++){ - c += opcount[i]; - print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t); - } -} - -char *op1[] = { "lsl", "lsr", "asr" }; -char *op2[] = { "add", "sub" }; -char *op3[] = { "movw", "cmp", "add", "sub" }; -char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", - "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" }; -char *op5[] = { "add", "cmp", "movw", "bx" }; -char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" }; -char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" }; -char *op8[] = { "smovh", "lmovhu" }; -char *op9[] = { "smovw", "lmovw" }; -char *op10[] = { "push", "pop" }; -char *op11[] = { "stmia", "ldmia" }; - -char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; - -#define B(h, l) bits(i, h, l) -#define IMM(h, l) B(h, l) -#define REG(h, l) reg(B(h, l)) -#define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh)) -#define COND(h, l) cond[B(h, l)] -#define OP1(h, l) op1[B(h, l)] -#define OP2(h, l) op2[B(h, l)] -#define OP3(h, l) op3[B(h, l)] -#define OP4(h, l) op4[B(h, l)] -#define OP5(h, l) op5[B(h, l)] -#define OP6(h, l) op6[B(h, l)] -#define OP7(h, l) op7[B(h, l)] -#define OP8(h, l) op8[B(h, l)] -#define OP9(h, l) op9[B(h, l)] -#define OP10(h, l) op10[B(h, l)] -#define OP11(h, l) op11[B(h, l)] -#define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l) -#define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l) -#define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l) - -static int -bits(int i, int h, int l) -{ - if(h < l) - diag("h < l in bits"); - return (i&(((1<<(h-l+1))-1)<<l))>>l; -} - -static char * -reg(int r) -{ - static char s[4][4]; - static int i = 0; - - if(r < 0 || r > 7) - diag("register %d out of range", r); - i++; - if(i == 4) - i = 0; - sprint(s[i], "r%d", r); - return s[i]; -} - -static char *regnames[] = { "sp", "lr", "pc" }; - -static char * -lhreg(int r, int lh) -{ - static char s[4][4]; - static int i = 0; - - if(lh == 0) - return reg(r); - if(r < 0 || r > 7) - diag("high register %d out of range", r); - i++; - if(i == 4) - i = 0; - if(r >= 5) - sprint(s[i], "%s", regnames[r-5]); - else - sprint(s[i], "r%d", r+8); - return s[i]; -} - -static void -illegal(int i, int pc) -{ - diag("%x: %x illegal instruction", pc, i); -} - -static void -dis(int i, int pc) -{ - static int lasto; - int o, l; - char *op; - - print("%x: %x: ", pc, i); - if(i&0xffff0000) - illegal(i, pc); - o = B(15, 13); - switch(o){ - case 0: - o = B(12, 11); - switch(o){ - case 0: - case 1: - case 2: - print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0)); - return; - case 3: - if(B(10, 10) == 0) - print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0)); - else - print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0)); - return; - } - case 1: - print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8)); - return; - case 2: - o = B(12, 10); - if(o == 0){ - print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0)); - return; - } - if(o == 1){ - o = B(9, 8); - if(o == 3){ - SBZ(7, 7); - SBZ(2, 0); - print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6)); - return; - } - SNBZ(7, 6); - print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7)); - return; - } - if(o == 2 || o == 3){ - print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8)); - return; - } - op = OP6(11, 9); - if(*op == 'l') - print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0)); - else - print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3)); - return; - case 3: - op = OP7(12, 11); - if(B(12, 11) == 0 || B(12,11) == 1) - l = 4; - else - l = 1; - if(*op == 'l') - print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0)); - else - print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3)); - return; - case 4: - if(B(12, 12) == 0){ - op = OP8(11, 11); - if(*op == 'l') - print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0)); - else - print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3)); - return; - } - op = OP9(11, 11); - if(*op == 'l') - print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8)); - else - print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0)); - return; - case 5: - if(B(12, 12) == 0){ - if(B(11, 11) == 0) - print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8)); - else - print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8)); - return; - } - if(B(11, 8) == 0){ - print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0)); - return; - } - SBO(10, 10); - SBZ(9, 9); - if(B(8, 8) == 0) - print("%s sp, %d\n", OP10(11, 11), IMM(7, 0)); - else - print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0)); - return; - case 6: - if(B(12, 12) == 0){ - print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0)); - return; - } - if(B(11, 8) == 0xf){ - print("swi %d\n", IMM(7, 0)); - return; - } - o = IMM(7, 0); - if(o&0x80) - o |= 0xffffff00; - o = pc+4+(o<<1); - print("b%s %x\n", COND(11, 8), o); - return; - case 7: - o = B(12, 11); - switch(o){ - case 0: - o = IMM(10, 0); - if(o&0x400) - o |= 0xfffff800; - o = pc+4+(o<<1); - print("b %x\n", o); - return; - case 1: - illegal(i, pc); - return; - case 2: - lasto = IMM(10, 0); - print("bl\n"); - return; - case 3: - if(lasto&0x400) - lasto |= 0xfffff800; - o = IMM(10, 0); - o = (pc-2)+4+(o<<1)+(lasto<<12); - print("bl %x\n", o); - return; - } - } -} |
