diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 18:03:45 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 18:03:45 +0100 |
commit | ea0f58090923bd7e435c4f48eb751854a4292b9a (patch) | |
tree | 8b138cec9ef636d436bae9d5a128643779b95754 /sys/src/cmd | |
parent | bc610a1b1c32f6e2e9b034217bb3ce9a7defa739 (diff) |
add arm vfp support to compiler and linker (from sources)
Diffstat (limited to 'sys/src/cmd')
-rw-r--r-- | sys/src/cmd/5c/txt.c | 12 | ||||
-rw-r--r-- | sys/src/cmd/5l/asm.c | 132 | ||||
-rw-r--r-- | sys/src/cmd/5l/l.h | 11 | ||||
-rw-r--r-- | sys/src/cmd/5l/noop.c | 24 | ||||
-rw-r--r-- | sys/src/cmd/5l/optab.c | 8 | ||||
-rw-r--r-- | sys/src/cmd/5l/span.c | 11 |
6 files changed, 187 insertions, 11 deletions
diff --git a/sys/src/cmd/5c/txt.c b/sys/src/cmd/5c/txt.c index ad88cf496..9ee8cb5b6 100644 --- a/sys/src/cmd/5c/txt.c +++ b/sys/src/cmd/5c/txt.c @@ -721,8 +721,13 @@ gmove(Node *f, Node *t) regfree(&nod1); p1 = p; regalloc(&nod, t, Z); - gins(AMOVF, nodfconst(2147483648.), &nod); - gins(AADDF, &nod, t); + if(tt == TFLOAT) { + gins(AMOVF, nodfconst(2147483648.), &nod); + gins(AADDF, &nod, t); + } else { + gins(AMOVD, nodfconst(2147483648.), &nod); + gins(AADDD, &nod, t); + } regfree(&nod); patch(p1, pc); return; @@ -1056,7 +1061,8 @@ gopcode(int o, Node *f1, Node *f2, Node *t) nextpc(); p->as = a; naddr(f1, &p->from); - if(a == ACMP && f1->op == OCONST && p->from.offset < 0 && p->from.offset != -p->from.offset) { + if(a == ACMP && f1->op == OCONST && p->from.offset < 0 && + p->from.offset != 0x80000000) { p->as = ACMN; p->from.offset = -p->from.offset; } diff --git a/sys/src/cmd/5l/asm.c b/sys/src/cmd/5l/asm.c index dcc9a987b..3dd6e1fe8 100644 --- a/sys/src/cmd/5l/asm.c +++ b/sys/src/cmd/5l/asm.c @@ -483,12 +483,12 @@ asmlc(void) 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) { @@ -496,7 +496,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++; @@ -510,7 +510,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); @@ -525,14 +525,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); @@ -545,7 +545,7 @@ asmlc(void) cput(s); lcsize++; } - if(debug['v'] || debug['L']) + if(debug['v'] || debug['V']) Bprint(&bso, "lcsize = %ld\n", lcsize); Bflush(&bso); } @@ -1365,6 +1365,53 @@ PP = p; else if(p->as == AMOVH) o2 ^= (1<<6); break; + + /* 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 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) @@ -1494,6 +1541,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) { @@ -1628,10 +1709,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; @@ -1703,6 +1819,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/sys/src/cmd/5l/l.h b/sys/src/cmd/5l/l.h index 6d004ae8e..1db0ce9c6 100644 --- a/sys/src/cmd/5l/l.h +++ b/sys/src/cmd/5l/l.h @@ -7,6 +7,11 @@ #define EXTERN extern #endif +#define LIBNAMELEN 300 + +void addlibpath(char*); +int fileexists(char*); +char* findlib(char*); typedef struct Adr Adr; typedef struct Sym Sym; @@ -134,6 +139,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, @@ -269,6 +275,7 @@ EXTERN char xcmp[C_GOK+1][C_GOK+1]; EXTERN Prog zprg; EXTERN int dtype; EXTERN int armv4; +EXTERN int vfp; EXTERN int doexp, dlm; EXTERN int imports, nimports; @@ -309,6 +316,7 @@ int Pconv(Fmt*); int Sconv(Fmt*); int aclass(Adr*); void addhist(long, int); +void addlibpath(char*); void append(Prog*, Prog*); void asmb(void); void asmdyn(void); @@ -336,7 +344,9 @@ 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); @@ -361,6 +371,7 @@ int ocmp(const void*, const 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); diff --git a/sys/src/cmd/5l/noop.c b/sys/src/cmd/5l/noop.c index 87cc851d0..e68c08f6f 100644 --- a/sys/src/cmd/5l/noop.c +++ b/sys/src/cmd/5l/noop.c @@ -302,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: diff --git a/sys/src/cmd/5l/optab.c b/sys/src/cmd/5l/optab.c index c4eb59db5..e9a566fd6 100644 --- a/sys/src/cmd/5l/optab.c +++ b/sys/src/cmd/5l/optab.c @@ -211,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/sys/src/cmd/5l/span.c b/sys/src/cmd/5l/span.c index c1a643452..b41b0e0c8 100644 --- a/sys/src/cmd/5l/span.c +++ b/sys/src/cmd/5l/span.c @@ -639,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; @@ -657,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; @@ -679,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]; |