diff options
Diffstat (limited to 'src/cmd/8l/span.c')
-rw-r--r-- | src/cmd/8l/span.c | 156 |
1 files changed, 141 insertions, 15 deletions
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index 81c1d37eb..b828d8645 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -194,7 +194,7 @@ instinit(void) for(i=1; optab[i].as; i++) if(i != optab[i].as) { - diag("phase error in optab: %d", i); + diag("phase error in optab: at %A found %A", i, optab[i].as); errorexit(); } maxop = i; @@ -238,6 +238,16 @@ instinit(void) ycover[Yrl*Ymax + Yml] = 1; ycover[Ym*Ymax + Yml] = 1; + ycover[Yax*Ymax + Ymm] = 1; + ycover[Ycx*Ymax + Ymm] = 1; + ycover[Yrx*Ymax + Ymm] = 1; + ycover[Yrl*Ymax + Ymm] = 1; + ycover[Ym*Ymax + Ymm] = 1; + ycover[Ymr*Ymax + Ymm] = 1; + + ycover[Ym*Ymax + Yxm] = 1; + ycover[Yxr*Ymax + Yxm] = 1; + for(i=0; i<D_NONE; i++) { reg[i] = -1; if(i >= D_AL && i <= D_BH) @@ -246,6 +256,8 @@ instinit(void) reg[i] = (i-D_AX) & 7; if(i >= D_F0 && i <= D_F0+7) reg[i] = (i-D_F0) & 7; + if(i >= D_X0 && i <= D_X0+7) + reg[i] = (i-D_X0) & 7; } } @@ -333,6 +345,16 @@ oclass(Adr *a) case D_F0+7: return Yrf; + case D_X0+0: + case D_X0+1: + case D_X0+2: + case D_X0+3: + case D_X0+4: + case D_X0+5: + case D_X0+6: + case D_X0+7: + return Yxr; + case D_NONE: return Ynone; @@ -585,7 +607,7 @@ asmand(Adr *a, int r) asmidx(a->scale, a->index, t); goto putrelv; } - if(t >= D_AL && t <= D_F0+7) { + if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) { if(v) goto bad; *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); @@ -772,19 +794,71 @@ uchar ymovtab[] = 0 }; +// byteswapreg returns a byte-addressable register (AX, BX, CX, DX) +// which is not referenced in a->type. +// If a is empty, it returns BX to account for MULB-like instructions +// that might use DX and AX. int -isax(Adr *a) +byteswapreg(Adr *a) { + int cana, canb, canc, cand; + + cana = canb = canc = cand = 1; switch(a->type) { + case D_NONE: + cana = cand = 0; + break; case D_AX: case D_AL: case D_AH: case D_INDIR+D_AX: - return 1; + cana = 0; + break; + case D_BX: + case D_BL: + case D_BH: + case D_INDIR+D_BX: + canb = 0; + break; + case D_CX: + case D_CL: + case D_CH: + case D_INDIR+D_CX: + canc = 0; + break; + case D_DX: + case D_DL: + case D_DH: + case D_INDIR+D_DX: + cand = 0; + break; + } + switch(a->index) { + case D_AX: + cana = 0; + break; + case D_BX: + canb = 0; + break; + case D_CX: + canc = 0; + break; + case D_DX: + cand = 0; + break; } - if(a->index == D_AX) - return 1; + if(cana) + return D_AX; + if(canb) + return D_BX; + if(canc) + return D_CX; + if(cand) + return D_DX; + + diag("impossible byte register"); + errorexit(); return 0; } @@ -827,13 +901,37 @@ subreg(Prog *p, int from, int to) print("%P\n", p); } +static int +mediaop(Optab *o, int op, int osize, int z) +{ + switch(op){ + case Pm: + case Pe: + case Pf2: + case Pf3: + if(osize != 1){ + if(op != Pm) + *andptr++ = op; + *andptr++ = Pm; + op = o->op[++z]; + break; + } + default: + if(andptr == and || andptr[-1] != Pm) + *andptr++ = Pm; + break; + } + *andptr++ = op; + return z; +} + void doasm(Prog *p) { Optab *o; Prog *q, pp; uchar *t; - int z, op, ft, tt; + int z, op, ft, tt, breg; int32 v, pre; Reloc rel, *r; Adr *a; @@ -873,6 +971,12 @@ found: *andptr++ = Pm; break; + case Pf2: /* xmm opcode escape */ + case Pf3: + *andptr++ = o->prefix; + *andptr++ = Pm; + break; + case Pm: /* opcode escape */ *andptr++ = Pm; break; @@ -904,6 +1008,17 @@ found: asmand(&p->from, reg[p->to.type]); break; + case Zm_r_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, reg[p->to.type]); + break; + + case Zm_r_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->from, reg[p->to.type]); + *andptr++ = p->to.offset; + break; + case Zaut_r: *andptr++ = 0x8d; /* leal */ if(p->from.type != D_ADDR) @@ -927,6 +1042,17 @@ found: asmand(&p->to, reg[p->from.type]); break; + case Zr_m_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, reg[p->from.type]); + break; + + case Zr_m_i_xm: + mediaop(o, op, t[3], z); + asmand(&p->to, reg[p->from.type]); + *andptr++ = p->from.offset; + break; + case Zo_m: *andptr++ = op; asmand(&p->to, o->op[z+1]); @@ -1198,13 +1324,13 @@ bad: pp = *p; z = p->from.type; if(z >= D_BP && z <= D_DI) { - if(isax(&p->to)) { + if((breg = byteswapreg(&p->to)) != D_AX) { *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[D_BX]); - subreg(&pp, z, D_BX); + asmand(&p->from, reg[breg]); + subreg(&pp, z, breg); doasm(&pp); *andptr++ = 0x87; /* xchg lhs,bx */ - asmand(&p->from, reg[D_BX]); + asmand(&p->from, reg[breg]); } else { *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ subreg(&pp, z, D_AX); @@ -1215,13 +1341,13 @@ bad: } z = p->to.type; if(z >= D_BP && z <= D_DI) { - if(isax(&p->from)) { + if((breg = byteswapreg(&p->from)) != D_AX) { *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[D_BX]); - subreg(&pp, z, D_BX); + asmand(&p->to, reg[breg]); + subreg(&pp, z, breg); doasm(&pp); *andptr++ = 0x87; /* xchg rhs,bx */ - asmand(&p->to, reg[D_BX]); + asmand(&p->to, reg[breg]); } else { *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ subreg(&pp, z, D_AX); |