7l: add arm64 linker (initial sync)

This commit is contained in:
cinap_lenrek 2019-04-08 14:05:27 +02:00
parent 394d095ee0
commit d8d4802f80
15 changed files with 12923 additions and 0 deletions

615
sys/src/cmd/7l/asm.c Normal file
View file

@ -0,0 +1,615 @@
#include "l.h"
long OFFSET;
#define PADDR(a) ((a) & ~0xfffffffff0000000ull)
vlong
entryvalue(void)
{
char *a;
Sym *s;
a = INITENTRY;
if(*a >= '0' && *a <= '9')
return atolwhex(a);
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
switch(s->type) {
case STEXT:
case SLEAF:
break;
case SDATA:
if(dlm)
return s->value+INITDAT;
default:
diag("entry not text: %s", s->name);
}
return s->value;
}
void
cflush(void)
{
int n;
n = sizeof(buf.cbuf) - cbc;
if(n)
write(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
void
asmb(void)
{
Prog *p;
long magic, t, etext;
vlong vl;
Optab *o;
if(debug['v'])
Bprint(&bso, "%5.2f asm\n", cputime());
Bflush(&bso);
OFFSET = HEADR;
seek(cout, OFFSET, 0);
pc = INITTEXT;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
curtext = p;
autosize = p->to.offset + PCSZ;
}
if(p->as == ADWORD && (pc & 7) != 0) {
lputl(0);
pc += 4;
}
if(p->pc != pc) {
diag("phase error %llux sb %llux",
p->pc, pc);
if(!debug['a'])
prasm(curp);
pc = p->pc;
}
curp = p;
o = oplook(p); /* could probably avoid this call */
asmout(p, o);
pc += o->size;
}
if(debug['a'])
Bprint(&bso, "\n");
Bflush(&bso);
cflush();
/* output strings in text segment */
etext = INITTEXT + textsize;
for(t = pc; t < etext; t += sizeof(buf)-100) {
if(etext-t > sizeof(buf)-100)
datblk(t, sizeof(buf)-100, 1);
else
datblk(t, etext-t, 1);
}
curtext = P;
switch(HEADTYPE) {
case 0:
case 2:
case 7:
OFFSET = HEADR+textsize;
seek(cout, OFFSET, 0);
break;
case 6: /* no header, padded segments */
OFFSET = rnd(HEADR+textsize, 4096);
seek(cout, OFFSET, 0);
break;
}
if(dlm){
char buf[8];
write(cout, buf, INITDAT-textsize);
textsize = INITDAT;
}
for(t = 0; t < datsize; t += sizeof(buf)-100) {
if(datsize-t > sizeof(buf)-100)
datblk(t, sizeof(buf)-100, 0);
else
datblk(t, datsize-t, 0);
}
symsize = 0;
lcsize = 0;
if(!debug['s']) {
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
switch(HEADTYPE) {
case 0:
debug['s'] = 1;
break;
case 2:
OFFSET = HEADR+textsize+datsize;
seek(cout, OFFSET, 0);
break;
case 6: /* no header, padded segments */
OFFSET += rnd(datsize, 4096);
seek(cout, OFFSET, 0);
break;
case 7:
break;
}
if(!debug['s'])
asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
asmlc();
if(dlm)
asmdyn();
cflush();
}
else if(dlm){
seek(cout, HEADR+textsize+datsize, 0);
asmdyn();
cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
OFFSET = 0;
seek(cout, OFFSET, 0);
switch(HEADTYPE) {
case 0: /* no header */
case 6: /* no header, padded segments */
break;
case 2: /* plan 9 */
magic = 4*28*28+7;
magic |= 0x00008000; /* fat header */
if(dlm)
magic |= 0x80000000; /* dlm */
lput(magic); /* magic */
lput(textsize); /* sizes */
lput(datsize);
lput(bsssize);
lput(symsize); /* nsyms */
vl = entryvalue();
lput(PADDR(vl)); /* va of entry */
lput(0L);
lput(lcsize);
llput(vl); /* va of entry */
break;
}
cflush();
}
void
cput(int c)
{
cbp[0] = c;
cbp++;
cbc--;
if(cbc <= 0)
cflush();
}
void
wput(long l)
{
cbp[0] = l>>8;
cbp[1] = l;
cbp += 2;
cbc -= 2;
if(cbc <= 0)
cflush();
}
void
wputl(long l)
{
cbp[0] = l;
cbp[1] = l>>8;
cbp += 2;
cbc -= 2;
if(cbc <= 0)
cflush();
}
void
lput(long l)
{
cbp[0] = l>>24;
cbp[1] = l>>16;
cbp[2] = l>>8;
cbp[3] = l;
cbp += 4;
cbc -= 4;
if(cbc <= 0)
cflush();
}
void
lputl(long l)
{
cbp[3] = l>>24;
cbp[2] = l>>16;
cbp[1] = l>>8;
cbp[0] = l;
cbp += 4;
cbc -= 4;
if(cbc <= 0)
cflush();
}
void
llput(vlong v)
{
lput(v>>32);
lput(v);
}
void
llputl(vlong v)
{
lputl(v);
lputl(v>>32);
}
void
asmsym(void)
{
Prog *p;
Auto *a;
Sym *s;
int h;
s = lookup("etext", 0);
if(s->type == STEXT)
putsymb(s->name, 'T', s->value, s->version);
for(h=0; h<NHASH; h++)
for(s=hash[h]; s!=S; s=s->link)
switch(s->type) {
case SCONST:
putsymb(s->name, 'D', s->value, s->version);
continue;
case SDATA:
putsymb(s->name, 'D', s->value+INITDAT, s->version);
continue;
case SBSS:
putsymb(s->name, 'B', s->value+INITDAT, s->version);
continue;
case SSTRING:
putsymb(s->name, 'T', s->value, s->version);
continue;
case SFILE:
putsymb(s->name, 'f', s->value, s->version);
continue;
}
for(p=textp; p!=P; p=p->cond) {
s = p->from.sym;
if(s->type != STEXT && s->type != SLEAF)
continue;
/* filenames first */
for(a=p->to.autom; a; a=a->link)
if(a->type == D_FILE)
putsymb(a->asym->name, 'z', a->aoffset, 0);
else
if(a->type == D_FILE1)
putsymb(a->asym->name, 'Z', a->aoffset, 0);
if(s->type == STEXT)
putsymb(s->name, 'T', s->value, s->version);
else
putsymb(s->name, 'L', s->value, s->version);
/* frame, auto and param after */
putsymb(".frame", 'm', p->to.offset+PCSZ, 0);
for(a=p->to.autom; a; a=a->link)
if(a->type == D_AUTO)
putsymb(a->asym->name, 'a', -a->aoffset, 0);
else
if(a->type == D_PARAM)
putsymb(a->asym->name, 'p', a->aoffset, 0);
}
if(debug['v'] || debug['n'])
Bprint(&bso, "symsize = %lud\n", symsize);
Bflush(&bso);
}
void
putsymb(char *s, int t, vlong v, int ver)
{
int i, f, l;
if(t == 'f')
s++;
l = 4;
switch(HEADTYPE){
default:
break;
case 2:
lput(v>>32);
l = 8;
break;
}
lput(v);
if(ver)
t += 'a' - 'A';
cput(t+0x80); /* 0x80 is variable length */
if(t == 'Z' || t == 'z') {
cput(s[0]);
for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
cput(s[i]);
cput(s[i+1]);
}
cput(0);
cput(0);
i++;
}
else {
for(i=0; s[i]; i++)
cput(s[i]);
cput(0);
}
symsize += l + 1 + i + 1;
if(debug['n']) {
if(t == 'z' || t == 'Z') {
Bprint(&bso, "%c %.8llux ", t, v);
for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
Bprint(&bso, "/%x", f);
}
Bprint(&bso, "\n");
return;
}
if(ver)
Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
else
Bprint(&bso, "%c %.8llux %s\n", t, v, s);
}
}
#define MINLC 4
void
asmlc(void)
{
long oldpc, oldlc;
Prog *p;
long v, s;
oldpc = INITTEXT;
oldlc = 0;
for(p = firstp; p != P; p = p->link) {
if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
if(p->as == ATEXT)
curtext = p;
if(debug['V'])
Bprint(&bso, "%6llux %P\n",
p->pc, p);
continue;
}
if(debug['V'])
Bprint(&bso, "\t\t%6ld", lcsize);
v = (p->pc - oldpc) / MINLC;
while(v) {
s = 127;
if(v < 127)
s = v;
cput(s+128); /* 129-255 +pc */
if(debug['V'])
Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
v -= s;
lcsize++;
}
s = p->line - oldlc;
oldlc = p->line;
oldpc = p->pc + MINLC;
if(s > 64 || s < -64) {
cput(0); /* 0 vv +lc */
cput(s>>24);
cput(s>>16);
cput(s>>8);
cput(s);
if(debug['V']) {
if(s > 0)
Bprint(&bso, " lc+%ld(%d,%ld)\n",
s, 0, s);
else
Bprint(&bso, " lc%ld(%d,%ld)\n",
s, 0, s);
Bprint(&bso, "%6llux %P\n",
p->pc, p);
}
lcsize += 5;
continue;
}
if(s > 0) {
cput(0+s); /* 1-64 +lc */
if(debug['V']) {
Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
Bprint(&bso, "%6llux %P\n",
p->pc, p);
}
} else {
cput(64-s); /* 65-128 -lc */
if(debug['V']) {
Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
Bprint(&bso, "%6llux %P\n",
p->pc, p);
}
}
lcsize++;
}
while(lcsize & 1) {
s = 129;
cput(s);
lcsize++;
}
if(debug['v'] || debug['V'])
Bprint(&bso, "lcsize = %ld\n", lcsize);
Bflush(&bso);
}
void
datblk(long s, long n, int str)
{
Sym *v;
Prog *p;
char *cast;
long a, l, fl, j;
vlong d;
int i, c;
memset(buf.dbuf, 0, n+100);
for(p = datap; p != P; p = p->link) {
if(str != (p->from.sym->type == SSTRING))
continue;
curp = p;
a = p->from.sym->value + p->from.offset;
l = a - s;
c = p->reg;
i = 0;
if(l < 0) {
if(l+c <= 0)
continue;
while(l < 0) {
l++;
i++;
}
}
if(l >= n)
continue;
if(p->as != AINIT && p->as != ADYNT) {
for(j=l+(c-i)-1; j>=l; j--)
if(buf.dbuf[j]) {
print("%P\n", p);
diag("multiple initialization");
break;
}
}
switch(p->to.type) {
default:
diag("unknown mode in initialization%P", p);
break;
case D_FCONST:
switch(c) {
default:
case 4:
fl = ieeedtof(p->to.ieee);
cast = (char*)&fl;
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi4[i]];
l++;
}
break;
case 8:
cast = (char*)p->to.ieee;
for(; i<c; i++) {
buf.dbuf[l] = cast[fnuxi8[i]];
l++;
}
break;
}
break;
case D_SCONST:
for(; i<c; i++) {
buf.dbuf[l] = p->to.sval[i];
l++;
}
break;
case D_CONST:
d = p->to.offset;
v = p->to.sym;
if(v) {
switch(v->type) {
case SUNDEF:
ckoff(v, d);
case STEXT:
case SLEAF:
case SSTRING:
d += p->to.sym->value;
break;
case SDATA:
case SBSS:
d += p->to.sym->value + INITDAT;
}
if(dlm)
dynreloc(v, a+INITDAT, 1);
}
cast = (char*)&d;
switch(c) {
default:
diag("bad nuxi %d %d%P", c, i, curp);
break;
case 1:
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi1[i]];
l++;
}
break;
case 2:
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi2[i]];
l++;
}
break;
case 4:
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi4[i]];
l++;
}
break;
case 8:
for(; i<c; i++) {
buf.dbuf[l] = cast[inuxi8[i]];
l++;
}
break;
}
break;
}
}
write(cout, buf.dbuf, n);
}
static Ieee chipfloats[] = {
{0x00000000, 0x00000000}, /* 0 */
{0x00000000, 0x3ff00000}, /* 1 */
{0x00000000, 0x40000000}, /* 2 */
{0x00000000, 0x40080000}, /* 3 */
{0x00000000, 0x40100000}, /* 4 */
{0x00000000, 0x40140000}, /* 5 */
{0x00000000, 0x3fe00000}, /* .5 */
{0x00000000, 0x40240000}, /* 10 */
};
int
chipfloat(Ieee *e)
{
Ieee *p;
int n;
for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
p = &chipfloats[n];
if(p->l == e->l && p->h == e->h && 0)
return n; /* TO DO: return imm8 encoding */
}
return -1;
}

1709
sys/src/cmd/7l/asmout.c Normal file

File diff suppressed because it is too large Load diff

5359
sys/src/cmd/7l/bits.c Normal file

File diff suppressed because it is too large Load diff

56
sys/src/cmd/7l/compat.c Normal file
View file

@ -0,0 +1,56 @@
#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)
{
fprint(2, "realloc(0x%p %ld) called\n", p, n);
abort();
return 0;
}
void*
mysbrk(ulong size)
{
return sbrk(size);
}
void
setmalloctag(void *v, uintptr pc)
{
USED(v, pc);
}

157
sys/src/cmd/7l/dyn.c Normal file
View file

@ -0,0 +1,157 @@
#include "l.h"
enum{
ABSD = 0,
ABSU = 1,
RELD = 2,
RELU = 3,
};
int modemap[4] = { 0, 1, -1, 2, };
typedef struct Reloc Reloc;
struct Reloc
{
int n;
int t;
uchar *m;
ulong *a;
};
Reloc rels;
static void
grow(Reloc *r)
{
int t;
uchar *m, *nm;
ulong *a, *na;
t = r->t;
r->t += 64;
m = r->m;
a = r->a;
r->m = nm = malloc(r->t*sizeof(uchar));
r->a = na = malloc(r->t*sizeof(ulong));
memmove(nm, m, t*sizeof(uchar));
memmove(na, a, t*sizeof(ulong));
free(m);
free(a);
}
void
dynreloc(Sym *s, long v, int abs)
{
int i, k, n;
uchar *m;
ulong *a;
Reloc *r;
if(v&3)
diag("bad relocation address");
v >>= 2;
if(s != S && s->type == SUNDEF)
k = abs ? ABSU : RELU;
else
k = abs ? ABSD : RELD;
/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
k = modemap[k];
r = &rels;
n = r->n;
if(n >= r->t)
grow(r);
m = r->m;
a = r->a;
for(i = n; i > 0; i--){
if(v < a[i-1]){ /* happens occasionally for data */
m[i] = m[i-1];
a[i] = a[i-1];
}
else
break;
}
m[i] = k;
a[i] = v;
r->n++;
}
static int
sput(char *s)
{
char *p;
p = s;
while(*s)
cput(*s++);
cput(0);
return s-p+1;
}
void
asmdyn(void)
{
int i, n, t, c;
Sym *s;
ulong la, ra, *a;
vlong off;
uchar *m;
Reloc *r;
cflush();
off = seek(cout, 0, 1);
lput(0);
t = 0;
lput(imports);
t += 4;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SUNDEF){
lput(s->sig);
t += 4;
t += sput(s->name);
}
la = 0;
r = &rels;
n = r->n;
m = r->m;
a = r->a;
lput(n);
t += 4;
for(i = 0; i < n; i++){
ra = *a-la;
if(*a < la)
diag("bad relocation order");
if(ra < 256)
c = 0;
else if(ra < 65536)
c = 1;
else
c = 2;
cput((c<<6)|*m++);
t++;
if(c == 0){
cput(ra);
t++;
}
else if(c == 1){
wput(ra);
t += 2;
}
else{
lput(ra);
t += 4;
}
la = *a++;
}
cflush();
seek(cout, off, 0);
lput(t);
if(debug['v']){
Bprint(&bso, "import table entries = %d\n", imports);
Bprint(&bso, "export table entries = %d\n", exports);
}
}

430
sys/src/cmd/7l/l.h Normal file
View file

@ -0,0 +1,430 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../7c/7.out.h"
#ifndef EXTERN
#define EXTERN extern
#endif
#define LIBNAMELEN 300
void addlibpath(char*);
int fileexists(char*);
int find1(long, int);
char* findlib(char*);
typedef struct Adr Adr;
typedef struct Autom Auto;
typedef struct Count Count;
typedef struct Ieee Ieee;
typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Mask Mask;
typedef struct Optab Optab;
typedef struct Oprang Oprang;
typedef uchar Opcross[32][2][32];
#define P ((Prog*)0)
#define S ((Sym*)0)
#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
struct Adr
{
union
{
vlong u0offset;
char* u0sval;
Ieee* u0ieee;
} u0;
union
{
Auto* u1autom;
Sym* u1sym;
} u1;
char type;
char reg;
char name;
char class;
};
#define offset u0.u0offset
#define sval u0.u0sval
#define ieee u0.u0ieee
#define autom u1.u1autom
#define sym u1.u1sym
struct Prog
{
Adr from;
Adr from3; /* third register operand */
Adr to;
union
{
long u0regused;
Prog* u0forwd;
} u0;
Prog* cond;
Prog* link;
vlong pc;
long line;
uchar mark;
ushort optab;
ushort as;
uchar reg;
};
#define regused u0.u0regused
#define forwd u0.u0forwd
struct Sym
{
char *name;
short type;
short version;
short become;
short frame;
uchar subtype;
ushort file;
vlong value;
long sig;
Sym* link;
};
#define SIGNINTERN (1729*325*1729) /* signature of internal functions such as _div */
struct Autom
{
Sym* asym;
Auto* link;
long aoffset;
short type;
};
struct Optab
{
ushort as;
char a1;
char a2;
char a3;
char type;
char size;
char param;
char flag;
};
struct Oprang
{
Optab* start;
Optab* stop;
};
struct Mask
{
uchar s;
uchar e;
uchar r;
uvlong v;
};
enum
{
STEXT = 1,
SDATA,
SBSS,
SDATA1,
SXREF,
SLEAF,
SFILE,
SCONST,
SSTRING,
SUNDEF,
SIMPORT,
SEXPORT,
LFROM = 1<<0,
LTO = 1<<1,
LPOOL = 1<<2,
C_NONE = 0,
C_REG,
C_RSP, /* D_REG or D_SP */
C_SHIFT, /* D_SHIFT: shift type, amount, value */
C_EXTREG, /* D_EXTREG: reg, ext type, shift */
C_FREG,
C_SPR,
C_COND,
C_ZCON, /* 0 (matching C_REG, not C_RSP, allowing REGZERO) */
C_ADDCON0, /* 12-bit unsigned, unshifted */
C_ADDCON, /* 12-bit unsigned, shifted left by 0 or 12 */
C_MOVCON, /* generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16 */
C_BITCON, /* bimm32 */
C_ABCON, /* could be C_ADDCON or C_BITCON */
C_MBCON, /* could be C_MOVCON or C_BITCON */
C_LCON, /* 32-bit constant */
C_FCON, /* floating-point constant */
C_VCON, /* 64-bit constant */
C_AACON, /* ADDCON offset in auto constant $a(FP) */
C_LACON, /* 32-bit offset in auto constant $a(FP) */
C_AECON, /* ADDCON offset in extern constant $e(SB) */
C_SBRA,
C_LBRA,
C_NPAUTO, /* -512 <= x < 0, 0 mod 8 */
C_NSAUTO, /* -256 <= x < 0 */
C_PSAUTO, /* 0 to 255 */
C_PPAUTO, /* 0 to 504, 0 mod 8 */
C_UAUTO4K, /* 0 to 4095 */
C_UAUTO8K, /* 0 to 8190, 0 mod 2 */
C_UAUTO16K, /* 0 to 16380, 0 mod 4 */
C_UAUTO32K, /* 0 to 32760, 0 mod 8 */
C_UAUTO64K, /* 0 to 65520, 0 mod 16 */
C_LAUTO, /* any other 32-bit constant */
C_SEXT1, /* 0 to 4095, direct */
C_SEXT2, /* 0 to 8190 */
C_SEXT4, /* 0 to 16380 */
C_SEXT8, /* 0 to 32760 */
C_SEXT16, /* 0 to 65520 */
C_LEXT,
C_NPOREG, /* mirror NPAUTO etc, except for ZOREG */
C_NSOREG,
C_ZOREG,
C_PSOREG,
C_PPOREG,
C_UOREG4K,
C_UOREG8K,
C_UOREG16K,
C_UOREG32K,
C_UOREG64K,
C_LOREG,
C_ADDR, /* relocatable address for dynamic loading */
C_ROFF, /* register offset (inc register extended) */
C_XPOST,
C_XPRE,
C_VREG,
C_GOK,
C_NCLASS, /* must be last */
/* mark flags */
FOLL = 1<<0,
LABEL = 1<<1,
LEAF = 1<<2,
FLOAT = 1<<3,
BRANCH = 1<<4,
LOAD = 1<<5,
SYNC = 1<<6,
NOSCHED = 1<<7,
MINSIZ = 64,
Roffset = 22, /* no. bits for offset in relocation address */
Rindex = 10, /* no. bits for index in relocation address */
STACKALIGN = 16, /* alignment of stack */
PCSZ= 8, /* size of PC */
};
enum
{
STRINGSZ = 200,
NHASH = 10007,
NHUNK = 100000,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
};
EXTERN union
{
struct
{
uchar obuf[MAXIO]; /* output buffer */
uchar ibuf[MAXIO]; /* input buffer */
} u;
char dbuf[1];
} buf;
#define cbuf u.obuf
#define xbuf u.ibuf
EXTERN long HEADR; /* length of header */
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;
EXTERN long bsssize;
EXTERN int cbc;
EXTERN uchar* cbp;
EXTERN int cout;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Prog* curtext;
EXTERN Prog* datap;
EXTERN long datsize;
EXTERN char debug[128];
EXTERN Prog* etextp;
EXTERN Prog* firstp;
EXTERN char fnuxi4[4];
EXTERN char fnuxi8[8];
EXTERN char inuxi1[1];
EXTERN char inuxi2[2];
EXTERN char inuxi4[4];
EXTERN uchar inuxi8[8];
EXTERN Sym* hash[NHASH];
EXTERN Sym* histfrog[MAXHIST];
EXTERN int histfrogp;
EXTERN int histgen;
EXTERN char* hunk;
EXTERN char* library[50];
EXTERN char* libraryobj[50];
EXTERN int libraryp;
EXTERN Prog* lastp;
EXTERN long lcsize;
EXTERN char literal[32];
EXTERN int nerrors;
EXTERN long nhunk;
EXTERN char* noname;
EXTERN vlong instoffset;
EXTERN Opcross opcross[8];
EXTERN char* outfile;
EXTERN vlong pc;
EXTERN uchar repop[ALAST];
EXTERN long symsize;
EXTERN Prog* textp;
EXTERN vlong textsize;
EXTERN long thunk;
EXTERN int version;
EXTERN char xcmp[C_NCLASS][C_NCLASS];
EXTERN int xrefresolv;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int doexp, dlm;
EXTERN int imports, nimports;
EXTERN int exports, nexports;
EXTERN char* EXPTAB;
EXTERN Prog undefp;
#define UP (&undefp)
extern char* anames[];
extern char* cnames[];
extern Optab optab[];
EXTERN Prog* blitrl;
EXTERN Prog* elitrl;
#pragma varargck argpos diag 1
#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*
int Aconv(Fmt*);
int Cconv(Fmt*);
int Dconv(Fmt*);
int Nconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
int aclass(Adr*);
void addpool(Prog*, Adr*);
vlong atolwhex(char*);
void asmb(void);
void asmdyn(void);
void asmlc(void);
void asmout(Prog*, Optab*);
void asmsym(void);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
void buildrep(int, int);
void cflush(void);
void ckoff(Sym*, long);
int chipfloat(Ieee*);
int cmp(int, int);
int compound(Prog*);
void cput(int);
void datblk(long, long, int);
void diag(char*, ...);
void dodata(void);
void doprof1(void);
void doprof2(void);
void dynreloc(Sym*, long, int);
vlong entryvalue(void);
void errorexit(void);
void export(void);
void follow(void);
void gethunk(void);
void histtoauto(void);
void* halloc(usize);
int isnop(Prog*);
double ieeedtod(Ieee*);
long ieeedtof(Ieee*);
void import(void);
void ldobj(int, long, char*);
void listinit(void);
void llput(vlong);
void llputl(vlong);
void loadlib(void);
Sym* lookup(char*, int);
void lput(long);
void lputl(long);
void mkfwd(void);
int movcon(vlong);
void* mysbrk(ulong);
void names(void);
void nocache(Prog*);
void nuxiinit(void);
void objfile(char*);
vlong offsetshift(vlong, int);
Optab* oplook(Prog*);
void patch(void);
int pseudo(Prog*);
void prasm(Prog*);
Prog* prg(void);
void putsymb(char*, int, vlong, int);
void readundefs(char*, int);
long regoff(Adr*);
int relinv(int);
vlong rnd(vlong, long);
void span(void);
void undef(void);
void wput(long);
void wputl(long);
void noops(void);
Mask* findmask(uvlong);
void xdefine(char*, int, long);
void xfol(Prog*);
void zerosig(char*);
#pragma varargck type "R" int
/* for ../ld */
#define isbranch(a) ((a) == AB)
#define iscall(a) ((a) == ABL)
#define isreturn(a) ((a) == ARETURN || (a) == ARET || (a) == AERET)
#define branchop() AB
#define canfollow(a) ((a) != ATEXT && (a) != ABCASE)

362
sys/src/cmd/7l/list.c Normal file
View file

@ -0,0 +1,362 @@
#include "l.h"
void
listinit(void)
{
fmtinstall('A', Aconv);
fmtinstall('D', Dconv);
fmtinstall('P', Pconv);
fmtinstall('S', Sconv);
fmtinstall('N', Nconv);
fmtinstall('R', Rconv);
}
int
Pconv(Fmt *fp)
{
char str[STRINGSZ], *s;
Prog *p;
int a;
p = va_arg(fp->args, Prog*);
curp = p;
a = p->as;
switch(a) {
default:
s = str;
s += sprint(s, "(%ld)", p->line);
if(p->reg == NREG && p->from3.type == D_NONE)
sprint(s, " %A %D,%D",
a, &p->from, &p->to);
else if(p->from.type != D_FREG){
s += sprint(s, " %A %D", a, &p->from);
if(p->from3.type != D_NONE)
s += sprint(s, ",%D", &p->from3);
if(p->reg != NREG)
s += sprint(s, ",R%d", p->reg);
sprint(s, ",%D", &p->to);
}else
sprint(s, " %A %D,F%d,%D",
a, &p->from, p->reg, &p->to);
break;
case ADATA:
case AINIT:
case ADYNT:
sprint(str, "(%ld) %A %D/%d,%D",
p->line, a, &p->from, p->reg, &p->to);
break;
}
return fmtstrcpy(fp, str);
}
int
Aconv(Fmt *fp)
{
char *s;
int a;
a = va_arg(fp->args, int);
s = "???";
if(a >= AXXX && a < ALAST && anames[a])
s = anames[a];
return fmtstrcpy(fp, s);
}
char* strcond[16] =
{
"EQ",
"NE",
"HS",
"LO",
"MI",
"PL",
"VS",
"VC",
"HI",
"LS",
"GE",
"LT",
"GT",
"LE",
"AL",
"NV"
};
int
Dconv(Fmt *fp)
{
char str[STRINGSZ];
char *op;
Adr *a;
long v;
static char *extop[] = {".UB", ".UH", ".UW", ".UX", ".SB", ".SH", ".SW", ".SX"};
a = va_arg(fp->args, Adr*);
switch(a->type) {
default:
sprint(str, "GOK-type(%d)", a->type);
break;
case D_NONE:
str[0] = 0;
if(a->name != D_NONE || a->reg != NREG || a->sym != S)
sprint(str, "%N(R%d)(NONE)", a, a->reg);
break;
case D_CONST:
if(a->reg == NREG || a->reg == REGZERO)
sprint(str, "$%N", a);
else
sprint(str, "$%N(R%d)", a, a->reg);
break;
case D_SHIFT:
v = a->offset;
op = "<<>>->@>" + (((v>>22) & 3) << 1);
sprint(str, "R%ld%c%c%ld", (v>>16)&0x1F, op[0], op[1], (v>>10)&0x3F);
if(a->reg != NREG)
sprint(str+strlen(str), "(R%d)", a->reg);
break;
case D_OCONST:
sprint(str, "$*$%N", a);
if(a->reg != NREG)
sprint(str, "%N(R%d)(CONST)", a, a->reg);
break;
case D_OREG:
if(a->reg != NREG)
sprint(str, "%N(R%d)", a, a->reg);
else
sprint(str, "%N", a);
break;
case D_XPRE:
if(a->reg != NREG)
sprint(str, "%N(R%d)!", a, a->reg);
else
sprint(str, "%N!", a);
break;
case D_XPOST:
if(a->reg != NREG)
sprint(str, "(R%d)%N!", a->reg, a);
else
sprint(str, "%N!", a);
break;
case D_EXTREG:
v = a->offset;
if(v & (7<<10))
snprint(str, sizeof(str), "R%ld%s<<%ld", (v>>16)&31, extop[(v>>13)&7], (v>>10)&7);
else
snprint(str, sizeof(str), "R%ld%s", (v>>16)&31, extop[(v>>13)&7]);
break;
case D_ROFF:
v = a->offset;
if(v & (1<<16))
snprint(str, sizeof(str), "(R%d)[R%ld%s]", a->reg, v&31, extop[(v>>8)&7]);
else
snprint(str, sizeof(str), "(R%d)(R%ld%s)", a->reg, v&31, extop[(v>>8)&7]);
break;
case D_REG:
sprint(str, "R%d", a->reg);
if(a->name != D_NONE || a->sym != S)
sprint(str, "%N(R%d)(REG)", a, a->reg);
break;
case D_SP:
if(a->name != D_NONE || a->sym != S)
sprint(str, "%N(R%d)(REG)", a, a->reg);
else
strcpy(str, "SP");
break;
case D_COND:
strcpy(str, strcond[a->reg & 0xF]);
break;
case D_FREG:
sprint(str, "F%d", a->reg);
if(a->name != D_NONE || a->sym != S)
sprint(str, "%N(R%d)(REG)", a, a->reg);
break;
case D_SPR:
switch((ulong)a->offset){
case D_FPSR:
sprint(str, "FPSR");
break;
case D_FPCR:
sprint(str, "FPCR");
break;
case D_NZCV:
sprint(str, "NZCV");
break;
default:
sprint(str, "SPR(%#llux)", a->offset);
break;
}
if(a->name != D_NONE || a->sym != S)
sprint(str, "%N(SPR%lld)(REG)", a, a->offset);
break;
case D_BRANCH: /* botch */
if(curp->cond != P) {
v = curp->cond->pc;
if(a->sym != S)
sprint(str, "%s+%#.5lux(BRANCH)", a->sym->name, v);
else
sprint(str, "%.5lux(BRANCH)", v);
} else
if(a->sym != S)
sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
else
sprint(str, "%lld(APC)", a->offset);
break;
case D_FCONST:
sprint(str, "$%e", ieeedtod(a->ieee));
break;
case D_SCONST:
sprint(str, "$\"%S\"", a->sval);
break;
}
return fmtstrcpy(fp, str);
}
int
Nconv(Fmt *fp)
{
char str[STRINGSZ];
Adr *a;
Sym *s;
a = va_arg(fp->args, Adr*);
s = a->sym;
switch(a->name) {
default:
sprint(str, "GOK-name(%d)", a->name);
break;
case D_NONE:
sprint(str, "%lld", a->offset);
break;
case D_EXTERN:
if(s == S)
sprint(str, "%lld(SB)", a->offset);
else
sprint(str, "%s+%lld(SB)", s->name, a->offset);
break;
case D_STATIC:
if(s == S)
sprint(str, "<>+%lld(SB)", a->offset);
else
sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
break;
case D_AUTO:
if(s == S)
sprint(str, "%lld(SP)", a->offset);
else
sprint(str, "%s-%lld(SP)", s->name, -a->offset);
break;
case D_PARAM:
if(s == S)
sprint(str, "%lld(FP)", a->offset);
else
sprint(str, "%s+%lld(FP)", s->name, a->offset);
break;
}
return fmtstrcpy(fp, str);
}
int
Rconv(Fmt *fp)
{
char *s;
int a;
a = va_arg(fp->args, int);
s = "C_??";
if(a >= C_NONE && a <= C_NCLASS)
s = cnames[a];
return fmtstrcpy(fp, s);
}
void
prasm(Prog *p)
{
print("%P\n", p);
}
int
Sconv(Fmt *fp)
{
int i, c;
char str[STRINGSZ], *p, *a;
a = va_arg(fp->args, char*);
p = str;
for(i=0; i<sizeof(long); i++) {
c = a[i] & 0xff;
if(c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == ' ' || c == '%') {
*p++ = c;
continue;
}
*p++ = '\\';
switch(c) {
case 0:
*p++ = 'z';
continue;
case '\\':
case '"':
*p++ = c;
continue;
case '\n':
*p++ = 'n';
continue;
case '\t':
*p++ = 't';
continue;
}
*p++ = (c>>6) + '0';
*p++ = ((c>>3) & 7) + '0';
*p++ = (c & 7) + '0';
}
*p = 0;
return fmtstrcpy(fp, str);
}
void
diag(char *fmt, ...)
{
char buf[STRINGSZ], *tn;
va_list arg;
tn = "??none??";
if(curtext != P && curtext->from.sym != S)
tn = curtext->from.sym->name;
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
print("%s: %s\n", tn, buf);
nerrors++;
if(nerrors > 10) {
print("too many errors\n");
errorexit();
}
}

17
sys/src/cmd/7l/mkcname Normal file
View file

@ -0,0 +1,17 @@
ed - l.h <<'!'
v/^ C_/d
g/^ C_NCLASS/s//&,/
g/[ ]*=.*,/s//,/
v/,/p
,s/^ C_/ "/
,s/,.*$/",/
1i
char *cnames[] =
{
.
,a
};
.
w cnam.c
Q
!

37
sys/src/cmd/7l/mkfile Normal file
View file

@ -0,0 +1,37 @@
</$objtype/mkfile
TARG=7l
OFILES=\
asm.$O\
asmout.$O\
enam.$O\
bits.$O\
cnam.$O\
compat.$O\
dyn.$O\
list.$O\
noop.$O\
obj.$O\
optab.$O\
span.$O\
pass.$O\
mod.$O\
HFILES=\
l.h\
../7c/7.out.h\
BIN=/$objtype/bin
</sys/src/cmd/mkone
../7c/enam.c: ../7c/7.out.h
@ { cd ../7c; mk enam.c }
cnam.c: l.h mkcname
rc mkcname
enam.$O: ../7c/enam.c
$CC $CFLAGS ../7c/enam.c
x:V: $O.out
$O.out -la -o/dev/null x.7

203
sys/src/cmd/7l/mod.c Normal file
View file

@ -0,0 +1,203 @@
#include "l.h"
void
readundefs(char *f, int t)
{
int i, n;
Sym *s;
Biobuf *b;
char *l, buf[256], *fields[64];
if(f == nil)
return;
b = Bopen(f, OREAD);
if(b == nil){
diag("could not open %s: %r", f);
errorexit();
}
while((l = Brdline(b, '\n')) != nil){
n = Blinelen(b);
if(n >= sizeof(buf)){
diag("%s: line too long", f);
errorexit();
}
memmove(buf, l, n);
buf[n-1] = '\0';
n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
if(n == nelem(fields)){
diag("%s: bad format", f);
errorexit();
}
for(i = 0; i < n; i++){
s = lookup(fields[i], 0);
s->type = SXREF;
s->subtype = t;
if(t == SIMPORT)
nimports++;
else
nexports++;
}
}
Bterm(b);
}
void
undefsym(Sym *s)
{
int n;
n = imports;
if(s->value != 0)
diag("value != 0 on SXREF");
if(n >= 1<<Rindex)
diag("import index %d out of range", n);
s->value = n<<Roffset;
s->type = SUNDEF;
imports++;
}
void
zerosig(char *sp)
{
Sym *s;
s = lookup(sp, 0);
s->sig = 0;
}
void
import(void)
{
int i;
Sym *s;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
undefsym(s);
Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, (vlong)s->value);
}
}
void
ckoff(Sym *s, long v)
{
if(v < 0 || v >= 1<<Roffset)
diag("relocation offset %ld for %s out of range", v, s->name);
}
static Prog*
newdata(Sym *s, int o, int w, int t)
{
Prog *p;
p = prg();
p->link = datap;
datap = p;
p->as = ADATA;
p->reg = w;
p->from.type = D_OREG;
p->from.name = t;
p->from.sym = s;
p->from.offset = o;
p->to.type = D_CONST;
p->to.name = D_NONE;
return p;
}
void
export(void)
{
int i, j, n, off, nb, sv, ne;
Sym *s, *et, *str, **esyms;
Prog *p;
char buf[NSNAME], *t;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
n++;
esyms = malloc(n*sizeof(Sym*));
ne = n;
n = 0;
for(i = 0; i < NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
esyms[n++] = s;
for(i = 0; i < ne-1; i++)
for(j = i+1; j < ne; j++)
if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
s = esyms[i];
esyms[i] = esyms[j];
esyms[j] = s;
}
nb = 0;
off = 0;
et = lookup(EXPTAB, 0);
if(et->type != 0 && et->type != SXREF)
diag("%s already defined", EXPTAB);
et->type = SDATA;
str = lookup(".string", 0);
if(str->type == 0)
str->type = SDATA;
sv = str->value;
for(i = 0; i < ne; i++){
s = esyms[i];
Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
/* signature */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.offset = s->sig;
/* address */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.name = D_EXTERN;
p->to.sym = s;
/* string */
t = s->name;
n = strlen(t)+1;
for(;;){
buf[nb++] = *t;
sv++;
if(nb >= NSNAME){
p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
p->to.type = D_SCONST;
p->to.sval = malloc(NSNAME);
memmove(p->to.sval, buf, NSNAME);
nb = 0;
}
if(*t++ == 0)
break;
}
/* name */
p = newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
p->to.name = D_STATIC;
p->to.sym = str;
p->to.offset = sv-n;
}
if(nb > 0){
p = newdata(str, sv-nb, nb, D_STATIC);
p->to.type = D_SCONST;
p->to.sval = malloc(NSNAME);
memmove(p->to.sval, buf, nb);
}
for(i = 0; i < 3; i++){
newdata(et, off, sizeof(long), D_EXTERN);
off += sizeof(long);
}
et->value = off;
if(sv == 0)
sv = 1;
str->value = sv;
exports = ne;
free(esyms);
}

324
sys/src/cmd/7l/noop.c Normal file
View file

@ -0,0 +1,324 @@
#include "l.h"
void
noops(void)
{
Prog *p, *q, *q1;
int o, aoffset, curframe, curbecome, maxbecome;
/*
* find leaf subroutines
* become sizes
* frame sizes
* strip NOPs
* expand RET
* expand BECOME pseudo
*/
if(debug['v'])
Bprint(&bso, "%5.2f noops\n", cputime());
Bflush(&bso);
curframe = 0;
curbecome = 0;
maxbecome = 0;
curtext = 0;
q = P;
for(p = firstp; p != P; p = p->link) {
/* find out how much arg space is used in this TEXT */
if(p->to.type == D_OREG && p->to.reg == REGSP)
if(p->to.offset > curframe)
curframe = p->to.offset;
switch(p->as) {
case ATEXT:
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
curframe = 0;
curbecome = 0;
p->mark |= LEAF;
curtext = p;
break;
case ARETURN:
/* special form of RETURN is BECOME */
if(p->from.type == D_CONST)
if(p->from.offset > curbecome)
curbecome = p->from.offset;
break;
case ANOP:
q1 = p->link;
q->link = q1; /* q is non-nop */
q1->mark |= p->mark;
continue;
case ABL:
if(curtext != P)
curtext->mark &= ~LEAF;
case ACBNZ:
case ACBZ:
case ACBNZW:
case ACBZW:
case ATBZ:
case ATBNZ:
case ABCASE:
case AB:
case ABEQ:
case ABNE:
case ABCS:
case ABHS:
case ABCC:
case ABLO:
case ABMI:
case ABPL:
case ABVS:
case ABVC:
case ABHI:
case ABLS:
case ABGE:
case ABLT:
case ABGT:
case ABLE:
case AADR: /* strange */
case AADRP:
q1 = p->cond;
if(q1 != P) {
while(q1->as == ANOP) {
q1 = q1->link;
p->cond = q1;
}
}
break;
}
q = p;
}
if(curtext && curtext->from.sym) {
curtext->from.sym->frame = curframe;
curtext->from.sym->become = curbecome;
if(curbecome > maxbecome)
maxbecome = curbecome;
}
if(debug['b'])
print("max become = %d\n", maxbecome);
xdefine("ALEFbecome", STEXT, maxbecome);
curtext = 0;
for(p = firstp; p != P; p = p->link) {
switch(p->as) {
case ATEXT:
curtext = p;
break;
case ABL:
if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
o = maxbecome - curtext->from.sym->frame;
if(o <= 0)
break;
/* calling a become or calling a variable */
if(p->to.sym == S || p->to.sym->become) {
curtext->to.offset += o;
if(debug['b']) {
curp = p;
print("%D calling %D increase %d\n",
&curtext->from, &p->to, o);
}
}
}
break;
}
}
for(p = firstp; p != P; p = p->link) {
o = p->as;
switch(o) {
case ATEXT:
curtext = p;
if(p->to.offset < 0)
autosize = 0;
else
autosize = p->to.offset + PCSZ;
if((curtext->mark & LEAF) && autosize <= PCSZ)
autosize = 0;
else if(autosize & (STACKALIGN-1))
autosize += STACKALIGN - (autosize&(STACKALIGN-1));
p->to.offset = autosize - PCSZ;
if(autosize == 0 && !(curtext->mark & LEAF)) {
if(debug['v'])
Bprint(&bso, "save suppressed in: %s\n",
curtext->from.sym->name);
Bflush(&bso);
curtext->mark |= LEAF;
}
aoffset = autosize;
if(aoffset > 0xF0)
aoffset = 0xF0;
if(curtext->mark & LEAF) {
if(curtext->from.sym)
curtext->from.sym->type = SLEAF;
if(autosize == 0)
break;
aoffset = 0;
}
q = p;
if(autosize > aoffset){
q = prg();
q->as = ASUB;
q->line = p->line;
q->from.type = D_CONST;
q->from.offset = autosize - aoffset;
q->to.type = D_REG;
q->to.reg = REGSP;
q->link = p->link;
p->link = q;
if(curtext->mark & LEAF)
break;
}
q1 = prg();
q1->as = AMOV;
q1->line = p->line;
q1->from.type = D_REG;
q1->from.reg = REGLINK;
q1->to.type = D_XPRE;
q1->to.offset = -aoffset;
q1->to.reg = REGSP;
q1->link = q->link;
q->link = q1;
break;
case ARETURN:
nocache(p);
if(p->from.type == D_CONST)
goto become;
if(curtext->mark & LEAF) {
if(autosize != 0){
p->as = AADD;
p->from.type = D_CONST;
p->from.offset = autosize;
p->to.type = D_REG;
p->to.reg = REGSP;
}
}else{
/* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
aoffset = autosize;
if(aoffset > 0xF0)
aoffset = 0xF0;
p->as = AMOV;
p->from.type = D_XPOST;
p->from.offset = aoffset;
p->from.reg = REGSP;
p->to.type = D_REG;
p->to.reg = REGLINK;
if(autosize > aoffset) {
q = prg();
q->as = AADD;
q->from.type = D_CONST;
q->from.offset = autosize - aoffset;
q->to.type = D_REG;
q->to.reg = REGSP;
q->link = p->link;
p->link = q;
p = q;
}
}
if(p->as != ARETURN) {
q = prg();
q->line = p->line;
q->link = p->link;
p->link = q;
p = q;
}
p->as = ARET;
p->line = p->line;
p->to.type = D_OREG;
p->to.offset = 0;
p->to.reg = REGLINK;
break;
become:
if(curtext->mark & LEAF) {
if(!autosize) {
p->as = AB;
p->from = zprg.from;
break;
}
#ifdef optimise_time
q = prg();
q->line = p->line;
q->as = AB;
q->from = zprg.from;
q->to = p->to;
q->cond = p->cond;
q->link = p->link;
p->link = q;
p->as = AADD;
p->from = zprg.from;
p->from.type = D_CONST;
p->from.offset = autosize;
p->to = zprg.to;
p->to.type = D_REG;
p->to.reg = REGSP;
break;
#endif
}
q = prg();
q->line = p->line;
q->as = AB;
q->from = zprg.from;
q->to = p->to;
q->cond = p->cond;
q->link = p->link;
p->link = q;
p->as = AMOV;
p->from = zprg.from;
p->from.type = D_XPRE;
p->from.offset = -autosize;
p->from.reg = REGSP;
p->to = zprg.to;
p->to.type = D_REG;
p->to.reg = REGLINK;
break;
}
}
}
void
nocache(Prog *p)
{
p->optab = 0;
p->from.class = 0;
p->to.class = 0;
}

1502
sys/src/cmd/7l/obj.c Normal file

File diff suppressed because it is too large Load diff

388
sys/src/cmd/7l/optab.c Normal file
View file

@ -0,0 +1,388 @@
#include "l.h"
Optab optab[] =
{
{ ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
{ ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
/* arithmetic operations */
{ AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
{ AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
{ AADC, C_REG, C_REG, C_REG, 1, 4, 0 },
{ AADC, C_REG, C_NONE, C_REG, 1, 4, 0 },
{ ANEG, C_REG, C_NONE, C_REG, 25, 4, 0 },
{ ANGC, C_REG, C_NONE, C_REG, 17, 4, 0 },
{ ACMP, C_REG, C_RSP, C_NONE, 1, 4, 0 },
{ AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0 },
{ AADD, C_ADDCON, C_NONE, C_RSP, 2, 4, 0 },
{ ACMP, C_ADDCON, C_RSP, C_NONE, 2, 4, 0 },
{ AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM },
{ AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM },
{ ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM },
{ AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
{ AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
{ ANEG, C_SHIFT,C_NONE, C_REG, 26, 4, 0 },
{ AADD, C_REG, C_RSP, C_RSP, 27, 4, 0 },
{ AADD, C_REG, C_NONE, C_RSP, 27, 4, 0 },
{ AADD, C_EXTREG,C_RSP, C_RSP, 27, 4, 0 },
{ AADD, C_EXTREG,C_NONE, C_RSP, 27, 4, 0 },
{ AMVN, C_EXTREG,C_NONE, C_RSP, 27, 4, 0 },
{ ACMP, C_EXTREG,C_RSP, C_NONE, 27, 4, 0 },
{ AADD, C_REG, C_REG, C_REG, 1, 4, 0 },
{ AADD, C_REG, C_NONE, C_REG, 1, 4, 0 },
/* logical operations */
{ AAND, C_REG, C_REG, C_REG, 1, 4, 0 },
{ AAND, C_REG, C_NONE, C_REG, 1, 4, 0 },
{ ABIC, C_REG, C_REG, C_REG, 1, 4, 0 },
{ ABIC, C_REG, C_NONE, C_REG, 1, 4, 0 },
{ AAND, C_BITCON, C_REG, C_REG, 53, 4, 0 },
{ AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0 },
{ ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0 },
{ ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0 },
{ AAND, C_LCON, C_REG, C_REG, 28, 8, 0, LFROM },
{ AAND, C_LCON, C_NONE, C_REG, 28, 8, 0, LFROM },
{ ABIC, C_LCON, C_REG, C_REG, 28, 8, 0, LFROM },
{ ABIC, C_LCON, C_NONE, C_REG, 28, 8, 0, LFROM },
{ AAND, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
{ AAND, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ ABIC, C_SHIFT,C_REG, C_REG, 3, 4, 0 },
{ ABIC, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ AMOV, C_RSP, C_NONE, C_RSP, 24, 4, 0 },
{ AMVN, C_REG, C_NONE, C_REG, 24, 4, 0 },
{ AMOVB, C_REG, C_NONE, C_REG, 45, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_REG, 45, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_REG, 45, 4, 0 }, /* also MOVHU */
{ AMOVW, C_REG, C_NONE, C_REG, 45, 4, 0 }, /* also MOVWU */
/* TO DO: MVN C_SHIFT */
/* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */
{ AMOVW, C_MOVCON, C_NONE, C_REG, 32, 4, 0 },
{ AMOV, C_MOVCON, C_NONE, C_REG, 32, 4, 0 },
// { AMOVW, C_ADDCON, C_NONE, C_REG, 2, 4, 0 },
// { AMOV, C_ADDCON, C_NONE, C_REG, 2, 4, 0 },
// { AMOVW, C_BITCON, C_NONE, C_REG, 53, 4, 0 },
// { AMOV, C_BITCON, C_NONE, C_REG, 53, 4, 0 },
{ AMOVK, C_LCON, C_NONE, C_REG, 33, 4, 0 },
{ AMOV, C_AECON,C_NONE, C_REG, 4, 4, REGSB },
{ AMOV, C_AACON,C_NONE, C_REG, 4, 4, REGSP },
{ ASDIV, C_REG, C_NONE, C_REG, 1, 4, 0 },
{ ASDIV, C_REG, C_REG, C_REG, 1, 4, 0 },
{ AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
{ ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
{ AB, C_NONE, C_NONE, C_ZOREG, 6, 4, 0 },
{ ABL, C_NONE, C_NONE, C_ZOREG, 6, 4, 0 },
{ ARET, C_NONE, C_NONE, C_REG, 6, 4, 0 },
{ ARET, C_NONE, C_NONE, C_ZOREG, 6, 4, 0 },
{ AADRP, C_SBRA, C_NONE, C_REG, 60, 4, 0 },
{ AADR, C_SBRA, C_NONE, C_REG, 61, 4, 0 },
{ ABFM, C_LCON, C_REG, C_REG, 42, 4, 0 },
{ ABFI, C_LCON, C_REG, C_REG, 43, 4, 0 },
{ AEXTR, C_LCON, C_REG, C_REG, 44, 4, 0 },
{ ASXTB, C_REG, C_NONE, C_REG, 45, 4, 0 },
{ ACLS, C_REG, C_NONE, C_REG, 46, 4, 0 },
{ ABEQ, C_NONE, C_NONE, C_SBRA, 7, 4, 0 },
{ ALSL, C_LCON, C_REG, C_REG, 8, 4, 0 },
{ ALSL, C_LCON, C_NONE, C_REG, 8, 4, 0 },
{ ALSL, C_REG, C_NONE, C_REG, 9, 4, 0 },
{ ALSL, C_REG, C_REG, C_REG, 9, 4, 0 },
{ ASVC, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
{ ASVC, C_NONE, C_NONE, C_NONE, 10, 4, 0 },
{ ADWORD, C_NONE, C_NONE, C_VCON, 11, 8, 0 },
{ ADWORD, C_NONE, C_NONE, C_LEXT, 11, 8, 0 },
{ ADWORD, C_NONE, C_NONE, C_ADDR, 11, 8, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 14, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_LEXT, 14, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 14, 4, 0 },
{ AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
{ AMOV, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM },
{ AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
{ AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
{ AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
{ AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
{ AMUL, C_REG, C_REG, C_REG, 15, 4, 0 },
{ AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 },
{ AMADD, C_REG, C_REG, C_REG, 15, 4, 0 },
{ AREM, C_REG, C_REG, C_REG, 16, 8, 0 },
{ AREM, C_REG, C_NONE, C_REG, 16, 8, 0 },
{ ACSEL, C_COND, C_REG, C_REG, 18, 4, 0 }, /* from3 optional */
{ ACSET, C_COND, C_NONE, C_REG, 18, 4, 0 },
{ ACCMN, C_COND, C_REG, C_LCON, 19, 4, 0 }, /* from3 either C_REG or C_LCON */
/* scaled 12-bit unsigned displacement store */
{ AMOVB, C_REG, C_NONE, C_SEXT1, 20, 4, REGSB }, //
{ AMOVB, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP }, //
{ AMOVB, C_REG, C_NONE, C_UOREG4K, 20, 4, 0 }, //
{ AMOVBU, C_REG, C_NONE, C_SEXT1, 20, 4, REGSB }, //
{ AMOVBU, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP }, //
{ AMOVBU, C_REG, C_NONE, C_UOREG4K, 20, 4, 0 }, //
{ AMOVH, C_REG, C_NONE, C_SEXT2, 20, 4, REGSB }, //
{ AMOVH, C_REG, C_NONE, C_UAUTO8K, 20, 4, REGSP }, //
{ AMOVH, C_REG, C_NONE, C_ZOREG, 20, 4, 0 }, //
{ AMOVH, C_REG, C_NONE, C_UOREG8K, 20, 4, 0 }, //
{ AMOVW, C_REG, C_NONE, C_SEXT4, 20, 4, REGSB }, //
{ AMOVW, C_REG, C_NONE, C_UAUTO16K, 20, 4, REGSP }, //
{ AMOVW, C_REG, C_NONE, C_ZOREG, 20, 4, 0 }, //
{ AMOVW, C_REG, C_NONE, C_UOREG16K, 20, 4, 0 }, //
/* unscaled 9-bit signed displacement store */
{ AMOVB, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP }, //
{ AMOVB, C_REG, C_NONE, C_NSOREG, 20, 4, 0 }, //
{ AMOVBU, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP }, //
{ AMOVBU, C_REG, C_NONE, C_NSOREG, 20, 4, 0 }, //
{ AMOVH, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP }, //
{ AMOVH, C_REG, C_NONE, C_NSOREG, 20, 4, 0 }, //
{ AMOVW, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP }, //
{ AMOVW, C_REG, C_NONE, C_NSOREG, 20, 4, 0 }, //
{ AMOV, C_REG, C_NONE, C_SEXT8, 20, 4, REGSB },
{ AMOV, C_REG, C_NONE, C_UAUTO32K, 20, 4, REGSP },
{ AMOV, C_REG, C_NONE, C_ZOREG, 20, 4, 0 },
{ AMOV, C_REG, C_NONE, C_UOREG32K, 20, 4, 0 },
{ AMOV, C_REG, C_NONE, C_NSOREG, 20, 4, 0 }, //
{ AMOV, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP }, //
/* short displacement load */
{ AMOVB, C_SEXT1, C_NONE, C_REG, 21, 4, REGSB }, //
{ AMOVB, C_UAUTO4K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVB, C_NSAUTO,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVB, C_ZOREG,C_NONE, C_REG, 21, 4, 0 }, //
{ AMOVB, C_UOREG4K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVB, C_NSOREG,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVBU, C_SEXT1, C_NONE, C_REG, 21, 4, REGSB }, //
{ AMOVBU, C_UAUTO4K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVBU, C_NSAUTO,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVBU, C_ZOREG,C_NONE, C_REG, 21, 4, 0 }, //
{ AMOVBU, C_UOREG4K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVBU, C_NSOREG,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVH, C_SEXT2, C_NONE, C_REG, 21, 4, REGSB }, //
{ AMOVH, C_UAUTO8K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVH, C_NSAUTO,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVH, C_ZOREG,C_NONE, C_REG, 21, 4, 0 }, //
{ AMOVH, C_UOREG8K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVH, C_NSOREG,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVW, C_SEXT4, C_NONE, C_REG, 21, 4, REGSB }, //
{ AMOVW, C_UAUTO16K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVW, C_NSAUTO,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVW, C_ZOREG,C_NONE, C_REG, 21, 4, 0 }, //
{ AMOVW, C_UOREG16K,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOVW, C_NSOREG,C_NONE, C_REG, 21, 4, REGSP }, //
{ AMOV, C_SEXT8, C_NONE, C_REG, 21, 4, REGSB },
{ AMOV, C_UAUTO32K,C_NONE, C_REG, 21, 4, REGSP },
{ AMOV, C_NSAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOV, C_ZOREG,C_NONE, C_REG, 21, 4, 0 },
{ AMOV, C_UOREG32K,C_NONE, C_REG, 21, 4, REGSP },
{ AMOV, C_NSOREG,C_NONE, C_REG, 21, 4, REGSP },
/* long displacement store */
{ AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB }, //
{ AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP }, //
{ AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0 }, //
{ AMOVH, C_REG, C_NONE, C_LEXT, 30, 8, REGSB }, //
{ AMOVH, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP }, //
{ AMOVH, C_REG, C_NONE, C_LOREG, 30, 8, 0 }, //
{ AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB }, //
{ AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP }, //
{ AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0 }, //
{ AMOV, C_REG, C_NONE, C_LEXT, 30, 8, REGSB }, //
{ AMOV, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP }, //
{ AMOV, C_REG, C_NONE, C_LOREG, 30, 8, 0 }, //
/* long displacement load */
{ AMOVB, C_LEXT, C_NONE, C_REG, 31, 8, REGSB }, //
{ AMOVB, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP }, //
{ AMOVB, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOVB, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOVH, C_LEXT, C_NONE, C_REG, 31, 8, REGSB }, //
{ AMOVH, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP }, //
{ AMOVH, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOVH, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB }, //
{ AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP }, //
{ AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOV, C_LEXT, C_NONE, C_REG, 31, 8, REGSB }, //
{ AMOV, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP }, //
{ AMOV, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
{ AMOV, C_LOREG,C_NONE, C_REG, 31, 8, 0 }, //
/* load long effective stack address (load long offset and add) */
{ AMOV, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, //
/* pre/post-indexed load (unscaled, signed 9-bit offset) */
{ AMOV, C_XPOST, C_NONE, C_REG, 22, 4, 0 },
{ AMOVW, C_XPOST, C_NONE, C_REG, 22, 4, 0 },
{ AMOVH, C_XPOST, C_NONE, C_REG, 22, 4, 0 },
{ AMOVB, C_XPOST, C_NONE, C_REG, 22, 4, 0 },
{ AMOVBU, C_XPOST, C_NONE, C_REG, 22, 4, 0 },
{ AFMOVS, C_XPOST, C_NONE, C_FREG, 22, 4, 0 },
{ AFMOVD, C_XPOST, C_NONE, C_FREG, 22, 4, 0 },
{ AMOV, C_XPRE, C_NONE, C_REG, 22, 4, 0 },
{ AMOVW, C_XPRE, C_NONE, C_REG, 22, 4, 0 },
{ AMOVH, C_XPRE, C_NONE, C_REG, 22, 4, 0 },
{ AMOVB, C_XPRE, C_NONE, C_REG, 22, 4, 0 },
{ AMOVBU, C_XPRE, C_NONE, C_REG, 22, 4, 0 },
{ AFMOVS, C_XPRE, C_NONE, C_FREG, 22, 4, 0 },
{ AFMOVD, C_XPRE, C_NONE, C_FREG, 22, 4, 0 },
/* pre/post-indexed store (unscaled, signed 9-bit offset) */
{ AMOV, C_REG, C_NONE, C_XPOST, 23, 4, 0 },
{ AMOVW, C_REG, C_NONE, C_XPOST, 23, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_XPOST, 23, 4, 0 },
{ AMOVB, C_REG, C_NONE, C_XPOST, 23, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_XPOST, 23, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_XPOST, 23, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_XPOST, 23, 4, 0 },
{ AMOV, C_REG, C_NONE, C_XPRE, 23, 4, 0 },
{ AMOVW, C_REG, C_NONE, C_XPRE, 23, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_XPRE, 23, 4, 0 },
{ AMOVB, C_REG, C_NONE, C_XPRE, 23, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_XPRE, 23, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_XPRE, 23, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_XPRE, 23, 4, 0 },
/* special */
{ AMOV, C_SPR, C_NONE, C_REG, 35, 4, 0 },
{ AMRS, C_SPR, C_NONE, C_REG, 35, 4, 0 },
{ AMOV, C_REG, C_NONE, C_SPR, 36, 4, 0 },
{ AMSR, C_REG, C_NONE, C_SPR, 36, 4, 0 },
{ AMOV, C_LCON, C_NONE, C_SPR, 37, 4, 0 },
{ AMSR, C_LCON, C_NONE, C_SPR, 37, 4, 0 },
{ AERET, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_SEXT4, 20, 4, REGSB },
{ AFMOVS, C_FREG, C_NONE, C_UAUTO16K, 20, 4, REGSP },
{ AFMOVS, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP },
{ AFMOVS, C_FREG, C_NONE, C_ZOREG, 20, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_UOREG16K, 20, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_NSOREG, 20, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_SEXT8, 20, 4, REGSB },
{ AFMOVD, C_FREG, C_NONE, C_UAUTO32K, 20, 4, REGSP },
{ AFMOVD, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP },
{ AFMOVD, C_FREG, C_NONE, C_ZOREG, 20, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_UOREG32K, 20, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_NSOREG, 20, 4, 0 },
{ AFMOVS, C_SEXT4, C_NONE, C_FREG, 21, 4, REGSB },
{ AFMOVS, C_UAUTO16K,C_NONE, C_FREG, 21, 4, REGSP },
{ AFMOVS, C_NSAUTO,C_NONE, C_FREG, 21, 4, REGSP },
{ AFMOVS, C_ZOREG,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVS, C_UOREG16K,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVS, C_NSOREG,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVD, C_SEXT8, C_NONE, C_FREG, 21, 4, REGSB },
{ AFMOVD, C_UAUTO32K,C_NONE, C_FREG, 21, 4, REGSP },
{ AFMOVD, C_NSAUTO,C_NONE, C_FREG, 21, 4, REGSP },
{ AFMOVD, C_ZOREG,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVD, C_UOREG32K,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVD, C_NSOREG,C_NONE, C_FREG, 21, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AFMOVS, C_FREG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AFMOVS, C_FREG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AFMOVS, C_LEXT, C_NONE, C_FREG, 31, 8, REGSB, LFROM },
{ AFMOVS, C_LAUTO,C_NONE, C_FREG, 31, 8, REGSP, LFROM },
{ AFMOVS, C_LOREG,C_NONE, C_FREG, 31, 8, 0, LFROM },
{ AFMOVS, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO },
{ AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM },
{ AFADDS, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AFADDS, C_FREG, C_REG, C_FREG, 54, 4, 0 },
{ AFADDS, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AFADDS, C_FCON, C_REG, C_FREG, 54, 4, 0 },
{ AFMOVS, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AFMOVS, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AFMOVD, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AFMOVD, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AFCVTZSD, C_FREG, C_NONE, C_REG, 29, 4, 0 },
{ ASCVTFD, C_REG, C_NONE, C_FREG, 29, 4, 0 },
{ AFCMPS, C_FREG, C_REG, C_NONE, 56, 4, 0 },
{ AFCMPS, C_FCON, C_REG, C_NONE, 56, 4, 0 },
{ AFCCMPS, C_COND, C_REG, C_LCON, 57, 4, 0 },
{ AFCSELD, C_COND, C_REG, C_FREG, 18, 4, 0 },
{ AFCVTSD, C_FREG, C_NONE, C_FREG, 29, 4, 0 },
{ ACASE, C_REG, C_NONE, C_REG, 62, 4*4, 0 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
{ ACLREX, C_NONE, C_NONE, C_LCON, 38, 4, 0 },
{ ACLREX, C_NONE, C_NONE, C_NONE, 38, 4, 0 },
{ ACBZ, C_REG, C_NONE, C_SBRA, 39, 4, 0 },
{ ATBZ, C_LCON, C_REG, C_SBRA, 40, 4, 0 },
{ ASYS, C_LCON, C_NONE, C_NONE, 50, 4, 0 },
{ ASYS, C_LCON, C_REG, C_NONE, 50, 4, 0 },
{ ASYSL, C_LCON, C_NONE, C_REG, 50, 4, 0 },
{ ADMB, C_LCON, C_NONE, C_NONE, 51, 4, 0 },
{ AHINT, C_LCON, C_NONE, C_NONE, 52, 4, 0 },
{ ALDXR, C_ZOREG, C_NONE, C_REG, 58, 4, 0 },
{ ALDXP, C_ZOREG, C_REG, C_REG, 58, 4, 0 },
{ ASTXR, C_REG, C_REG, C_ZOREG, 59, 4, 0 },
{ ASTXP, C_REG, C_REG, C_ZOREG, 59, 4, 0 },
{ AAESD, C_VREG, C_NONE, C_VREG, 29, 4, 0 },
{ ASHA1C, C_VREG, C_REG, C_VREG, 1, 4, 0 },
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};

448
sys/src/cmd/7l/pass.c Normal file
View file

@ -0,0 +1,448 @@
#include "l.h"
vlong
atolwhex(char *s)
{
vlong n;
int f;
n = 0;
f = 0;
while(*s == ' ' || *s == '\t')
s++;
if(*s == '-' || *s == '+') {
if(*s++ == '-')
f = 1;
while(*s == ' ' || *s == '\t')
s++;
}
if(s[0]=='0' && s[1]){
if(s[1]=='x' || s[1]=='X'){
s += 2;
for(;;){
if(*s >= '0' && *s <= '9')
n = n*16 + *s++ - '0';
else if(*s >= 'a' && *s <= 'f')
n = n*16 + *s++ - 'a' + 10;
else if(*s >= 'A' && *s <= 'F')
n = n*16 + *s++ - 'A' + 10;
else
break;
}
} else
while(*s >= '0' && *s <= '7')
n = n*8 + *s++ - '0';
} else
while(*s >= '0' && *s <= '9')
n = n*10 + *s++ - '0';
if(f)
n = -n;
return n;
}
vlong
rnd(vlong v, long r)
{
long c;
if(r <= 0)
return v;
v += r - 1;
c = v % r;
if(c < 0)
c += r;
v -= c;
return v;
}
void
dodata(void)
{
int i, t;
Sym *s;
Prog *p;
long orig, v;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
for(p = datap; p != P; p = p->link) {
s = p->from.sym;
if(p->as == ADYNT || p->as == AINIT)
s->value = dtype;
if(s->type == SBSS)
s->type = SDATA;
if(s->type != SDATA)
diag("initialize non-data (%d): %s\n%P",
s->type, s->name, p);
v = p->from.offset + p->reg;
if(v > s->value)
diag("initialize bounds (%lld): %s\n%P",
(vlong)s->value, s->name, p);
}
if(debug['t']) {
/*
* pull out string constants
*/
for(p = datap; p != P; p = p->link) {
s = p->from.sym;
if(p->to.type == D_SCONST)
s->type = SSTRING;
}
}
/*
* pass 1
* assign 'small' variables to data segment
* (rationale is that data segment is more easily
* addressed through offset on REGSB)
*/
orig = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
t = s->type;
if(t != SDATA && t != SBSS)
continue;
v = s->value;
if(v == 0) {
diag("%s: no size", s->name);
v = 1;
}
v = rnd(v, 4);
s->value = v;
if(v > MINSIZ)
continue;
if(v >= 16)
orig = rnd(orig, 16);
else if(v >= 8)
orig = rnd(orig, 8);
s->value = orig;
orig += v;
s->type = SDATA1;
}
/*
* pass 2
* assign large 'data' variables to data segment
*/
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
t = s->type;
if(t != SDATA) {
if(t == SDATA1)
s->type = SDATA;
continue;
}
v = s->value;
if(v >= 16)
orig = rnd(orig, 16);
else if(v >= 8)
orig = rnd(orig, 8);
s->value = orig;
orig += v;
}
while(orig & 7)
orig++;
datsize = orig;
/*
* pass 3
* everything else to bss segment
*/
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type != SBSS)
continue;
v = s->value;
if(v >= 16)
orig = rnd(orig, 16);
else if(v >= 8)
orig = rnd(orig, 8);
s->value = orig;
orig += v;
}
while(orig & 7)
orig++;
bsssize = orig-datsize;
xdefine("setSB", SDATA, 0L);
xdefine("bdata", SDATA, 0L);
xdefine("edata", SDATA, datsize);
xdefine("end", SBSS, datsize+bsssize);
xdefine("etext", STEXT, 0L);
}
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || !isbranch(p->as))
return p;
p = p->cond;
}
return P;
}
void
follow(void)
{
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
firstp = prg();
lastp = firstp;
xfol(textp);
firstp = firstp->link;
lastp->link = P;
}
void
xfol(Prog *p)
{
Prog *q, *r;
int a, i;
loop:
if(p == P)
return;
a = p->as;
if(a == ATEXT)
curtext = p;
if(isbranch(a)) {
q = p->cond;
if(q != P) {
p->mark |= FOLL;
p = q;
if(!(p->mark & FOLL))
goto loop;
}
}
if(p->mark & FOLL) {
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == lastp)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
if(isbranch(a) || isreturn(a))
goto copy;
if(q->cond == nil || (q->cond->mark&FOLL))
continue;
if(a != ABEQ && a != ABNE)
continue;
copy:
for(;;) {
r = prg();
*r = *p;
if(!(r->mark&FOLL))
print("cant happen 1\n");
r->mark |= FOLL;
if(p != q) {
p = p->link;
lastp->link = r;
lastp = r;
continue;
}
lastp->link = r;
lastp = r;
if(isbranch(a) || isreturn(a))
return;
r->as = a == ABNE? ABEQ: ABNE;
r->cond = p->link;
r->link = p->cond;
if(!(r->link->mark&FOLL))
xfol(r->link);
if(!(r->cond->mark&FOLL))
print("cant happen 2\n");
return;
}
}
a = branchop();
q = prg();
q->as = a;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->cond = p;
p = q;
}
p->mark |= FOLL;
lastp->link = p;
lastp = p;
if(isbranch(a) || isreturn(a))
return;
if(p->cond != P)
if(!iscall(a) && p->link != P) {
q = brchain(p->link);
if(canfollow(a))
if(q != P && (q->mark&FOLL)) {
p->as = relinv(a);
p->link = p->cond;
p->cond = q;
}
xfol(p->link);
q = brchain(p->cond);
if(q == P)
q = p->cond;
if(q->mark&FOLL) {
p->cond = q;
return;
}
p = q;
goto loop;
}
p = p->link;
goto loop;
}
void
patch(void)
{
long c, vexit;
Prog *p, *q;
Sym *s;
int a;
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
mkfwd();
s = lookup("exit", 0);
vexit = s->value;
for(p = firstp; p != P; p = p->link) {
a = p->as;
if(a == ATEXT)
curtext = p;
if((iscall(a) || isbranch(a) || isreturn(a)) &&
p->to.type != D_BRANCH && p->to.sym != S) {
s = p->to.sym;
switch(s->type) {
default:
diag("undefined: %s\n%P", s->name, p);
s->type = STEXT;
s->value = vexit;
break;
case STEXT:
p->to.offset = s->value;
break;
case SUNDEF:
if(!iscall(p->as))
diag("help: SUNDEF in AB || ARET");
p->to.offset = 0;
p->cond = UP;
break;
}
p->to.type = D_BRANCH;
}
if(p->cond == UP)
continue;
if(p->to.type == D_BRANCH)
c = p->to.offset;
else if(p->from.type == D_BRANCH)
c = p->from.offset;
else
continue;
for(q = firstp; q != P;) {
if(q->forwd != P)
if(c >= q->forwd->pc) {
q = q->forwd;
continue;
}
if(c == q->pc)
break;
q = q->link;
}
if(q == P) {
diag("branch out of range %ld\n%P", c, p);
p->to.type = D_NONE;
}
p->cond = q;
}
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
if(p->cond != P && p->cond != UP) {
p->cond = brloop(p->cond);
if(p->cond != P){
if(p->to.type == D_BRANCH)
p->to.offset = p->cond->pc;
if(p->from.type == D_BRANCH)
p->from.offset = p->cond->pc;
}
}
}
}
#define LOG 6
void
mkfwd(void)
{
Prog *p;
long dwn[LOG], cnt[LOG], i;
Prog *lst[LOG];
for(i=0; i<LOG; i++) {
if(i == 0)
cnt[i] = 1; else
cnt[i] = LOG * cnt[i-1];
dwn[i] = 1;
lst[i] = P;
}
i = 0;
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT)
curtext = p;
i--;
if(i < 0)
i = LOG-1;
p->forwd = P;
dwn[i]--;
if(dwn[i] <= 0) {
dwn[i] = cnt[i];
if(lst[i] != P)
lst[i]->forwd = p;
lst[i] = p;
}
}
}
Prog*
brloop(Prog *p)
{
Prog *q;
int c;
for(c=0; p!=P;) {
if(!isbranch(p->as))
return p;
q = p->cond;
if(q <= p) {
c++;
if(q == p || c > 5000)
break;
}
p = q;
}
return P;
}
void
undef(void)
{
int i;
Sym *s;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}

1316
sys/src/cmd/7l/span.c Normal file

File diff suppressed because it is too large Load diff