Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        "l.h"

void
pagebug(Prog *p)
{
        Prog *q;

        switch(p->as) {
        case ABGEZAL:
        case ABLTZAL:
        case AJAL:
        case ABEQ:
        case ABGEZ:
        case ABGTZ:
        case ABLEZ:
        case ABLTZ:
        case ABNE:
        case ABFPT:
        case ABFPF:
        case AJMP:
                q = prg();
                *q = *p;
                p->link = q;
                p->as = ANOR;
                p->optab = 0;
                p->from = zprg.from;
                p->from.type = D_REG;
                p->from.reg = REGZERO;
                p->to = p->from;
        }
}

void
span(void)
{
        Prog *p, *q;
        Sym *setext, *s;
        Optab *o;
        int m, bflag, i;
        vlong c, otxt, v;

        if(debug['v'])
                Bprint(&bso, "%5.2f span\n", cputime());
        Bflush(&bso);

        bflag = 0;
        c = INITTEXT;
        otxt = c;
        for(p = firstp; p != P; p = p->link) {
                /* bug in early 4000 chips delayslot on page boundary */
                if((c&(0x1000-1)) == 0xffc)
                        pagebug(p);
                p->pc = c;
                o = oplook(p);
                m = o->size;
                if(m == 0) {
                        if(p->as == ATEXT) {
                                curtext = p;
                                autosize = p->to.offset + 4;
                                if(p->from.sym != S)
                                        p->from.sym->value = c;
                                /* need passes to resolve branches */
                                if(c-otxt >= 1L<<17)
                                        bflag = 1;
                                otxt = c;
                                continue;
                        }
                        diag("zero-width instruction\n%P", p);
                        continue;
                }
                c += m;
        }

        /*
         * if any procedure is large enough to
         * generate a large SBRA branch, then
         * generate extra passes putting branches
         * around jmps to fix. this is rare.
         */
        while(bflag) {
                if(debug['v'])
                        Bprint(&bso, "%5.2f span1\n", cputime());
                bflag = 0;
                c = INITTEXT;
                for(p = firstp; p != P; p = p->link) {
                        /* bug in early 4000 chips delayslot on page boundary */
                        if((c&(0x1000-1)) == 0xffc)
                                pagebug(p);
                        p->pc = c;
                        o = oplook(p);
                        if(o->type == 6 && p->cond) {
                                otxt = p->cond->pc - c;
                                if(otxt < 0)
                                        otxt = -otxt;
                                if(otxt >= (1L<<17) - 10) {
                                        q = prg();
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = AJMP;
                                        q->to.type = D_BRANCH;
                                        q->cond = p->cond;
                                        p->cond = q;
                                        q = prg();
                                        q->link = p->link;
                                        p->link = q;
                                        q->as = AJMP;
                                        q->to.type = D_BRANCH;
                                        q->cond = q->link->link;
                                        addnop(p->link);
                                        addnop(p);
                                        bflag = 1;
                                }
                        }
                        m = o->size;
                        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;
                                }
                                diag("zero-width instruction\n%P", p);
                                continue;
                        }
                        c += m;
                }
        }

        if(debug['t']) {
                /* 
                 * add strings to text segment
                 */
                c = rnd(c, 8);
                for(i=0; i<NHASH; i++)
                for(s = hash[i]; s != S; s = s->link) {
                        if(s->type != SSTRING)
                                continue;
                        v = s->value;
                        while(v & 3)
                                v++;
                        s->value = c;
                        c += v;
                }
        }

        c = rnd(c, 8);

        setext = lookup("etext", 0);
        if(setext != S) {
                setext->value = c;
                textsize = c - INITTEXT;
        }
        if(INITRND)
                INITDAT = rnd(c, INITRND);
        if(debug['v'])
                Bprint(&bso, "tsize = %llux\n", textsize);
        Bflush(&bso);
}
                
void
xdefine(char *p, int t, long v)
{
        Sym *s;

        s = lookup(p, 0);
        if(s->type == 0 || s->type == SXREF) {
                s->type = t;
                s->value = v;
        }
}

long
regoff(Adr *a)
{

        instoffset = 0;
        aclass(a);
        return instoffset;
}

aclass(Adr *a)
{
        Sym *s;
        int t;

        switch(a->type) {
        case D_NONE:
                return C_NONE;

        case D_REG:
                return C_REG;

        case D_FREG:
                return C_FREG;

        case D_FCREG:
                return C_FCREG;

        case D_MREG:
                return C_MREG;

        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",
                                        a->sym->name, TNAME);
                                a->sym->type = SDATA;
                        }
                        instoffset = a->sym->value + a->offset - BIG;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SEXT;
                        return C_LEXT;
                case D_AUTO:
                        instoffset = autosize + a->offset;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SAUTO;
                        return C_LAUTO;

                case D_PARAM:
                        instoffset = autosize + a->offset + 4L;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SAUTO;
                        return C_LAUTO;
                case D_NONE:
                        instoffset = a->offset;
                        if(instoffset == 0)
                                return C_ZOREG;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SOREG;
                        return C_LOREG;
                }
                return C_GOK;

        case D_HI:
                return C_LO;
        case D_LO:
                return C_HI;

        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",
                                        s->name, TNAME);
                                s->type = SDATA;
                        }
                        instoffset = s->value + a->offset + INITDAT;
                        if(s->type == STEXT || s->type == SLEAF)
                                instoffset = s->value + a->offset;
                        return C_LCON;
                }
                return C_GOK;

        case D_CONST:
                switch(a->name) {

                case D_NONE:
                        instoffset = a->offset;
                consize:
                        if(instoffset > 0) {
                                if(instoffset <= 0x7fff)
                                        return C_SCON;
                                if(instoffset <= 0xffff)
                                        return C_ANDCON;
                                if((instoffset & 0xffff) == 0)
                                        return C_UCON;
                                return C_LCON;
                        }
                        if(instoffset == 0)
                                return C_ZCON;
                        if(instoffset >= -0x8000)
                                return C_ADDCON;
                        if((instoffset & 0xffff) == 0)
                                return C_UCON;
                        return C_LCON;

                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",
                                        s->name, TNAME);
                                s->type = SDATA;
                                break;
                        case SCONST:
                                instoffset = s->value + a->offset;
                                goto consize;
                        case STEXT:
                        case SLEAF:
                        case SSTRING:
                                instoffset = s->value + a->offset;
                                return C_LCON;
                        }
                        instoffset = s->value + a->offset - BIG;
                        if(instoffset >= -BIG && instoffset < BIG && instoffset != 0L)
                                return C_SECON;
                        instoffset = s->value + a->offset + INITDAT;
                        return C_LCON;

                case D_AUTO:
                        instoffset = autosize + a->offset;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SACON;
                        return C_LACON;

                case D_PARAM:
                        instoffset = autosize + a->offset + 4L;
                        if(instoffset >= -BIG && instoffset < BIG)
                                return C_SACON;
                        return C_LACON;
                }
                return C_GOK;

        case D_BRANCH:
                return C_SBRA;
        }
        return C_GOK;
}

Optab*
oplook(Prog *p)
{
        int a1, a2, a3, r;
        char *c1, *c3;
        Optab *o, *e;

        a1 = p->optab;
        if(a1)
                return optab+(a1-1);
        a1 = p->from.class;
        if(a1 == 0) {
                a1 = aclass(&p->from) + 1;
                p->from.class = a1;
        }
        a1--;
        a3 = p->to.class;
        if(a3 == 0) {
                a3 = aclass(&p->to) + 1;
                p->to.class = a3;
        }
        a3--;
        a2 = C_NONE;
        if(p->reg != NREG)
                a2 = C_REG;
        r = p->as;
        o = oprange[r].start;
        if(o == 0) {
                a1 = opcross[repop[r]][a1][a2][a3];
                if(a1) {
                        p->optab = a1+1;
                        return optab+a1;
                }
                o = oprange[r].stop; /* just generate an error */
        }
        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-optab)+1;
                        return o;
                }
        diag("illegal combination %A %d %d %d",
                p->as, a1, a2, a3);
        if(!debug['a'])
                prasm(p);
        o = optab;
        p->optab = (o-optab)+1;
        return o;
}

int
cmp(int a, int b)
{

        if(a == b)
                return 1;
        switch(a) {
        case C_LCON:
                if(b == C_ZCON || b == C_SCON || b == C_UCON ||
                   b == C_ADDCON || b == C_ANDCON)
                        return 1;
                break;
        case C_ADD0CON:
                if(b == C_ADDCON)
                        return 1;
        case C_ADDCON:
                if(b == C_ZCON || b == C_SCON)
                        return 1;
                break;
        case C_AND0CON:
                if(b == C_ANDCON)
                        return 1;
        case C_ANDCON:
                if(b == C_ZCON || b == C_SCON)
                        return 1;
                break;
        case C_UCON:
                if(b == C_ZCON)
                        return 1;
                break;
        case C_SCON:
                if(b == C_ZCON)
                        return 1;
                break;
        case C_LACON:
                if(b == C_SACON)
                        return 1;
                break;
        case C_LBRA:
                if(b == C_SBRA)
                        return 1;
                break;
        case C_LEXT:
                if(b == C_SEXT)
                        return 1;
                break;
        case C_LAUTO:
                if(b == C_SAUTO)
                        return 1;
                break;
        case C_REG:
                if(b == C_ZCON)
                        return 1;
                break;
        case C_LOREG:
                if(b == C_ZOREG || b == C_SOREG)
                        return 1;
                break;
        case C_SOREG:
                if(b == C_ZOREG)
                        return 1;
                break;
        }
        return 0;
}

int
ocmp(const void *a1, const void *a2)
{
        Optab *p1, *p2;
        int n;

        p1 = (Optab*)a1;
        p2 = (Optab*)a2;
        n = p1->as - p2->as;
        if(n)
                return n;
        n = p1->a1 - p2->a1;
        if(n)
                return n;
        n = p1->a2 - p2->a2;
        if(n)
                return n;
        n = p1->a3 - p2->a3;
        if(n)
                return n;
        return 0;
}

void
buildop(void)
{
        int i, n, r;

        for(i=0; i<32; i++)
                for(n=0; n<32; n++)
                        xcmp[i][n] = cmp(n, i);
        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:
                        diag("unknown op in build: %A", r);
                        errorexit();
                case AABSF:
                        oprange[AMOVFD] = oprange[r];
                        oprange[AMOVDF] = oprange[r];
                        oprange[AMOVWF] = oprange[r];
                        oprange[AMOVFW] = oprange[r];
                        oprange[AMOVWD] = oprange[r];
                        oprange[AMOVDW] = oprange[r];
                        oprange[ANEGF] = oprange[r];
                        oprange[ANEGD] = oprange[r];
                        oprange[AABSD] = oprange[r];
                        break;
                case AADD:
                        buildrep(1, AADD);
                        oprange[ASGT] = oprange[r];
                        repop[ASGT] = 1;
                        oprange[ASGTU] = oprange[r];
                        repop[ASGTU] = 1;
                        oprange[AADDU] = oprange[r];
                        repop[AADDU] = 1;
                        oprange[AADDVU] = oprange[r];
                        repop[AADDVU] = 1;
                        break;
                case AADDF:
                        oprange[ADIVF] = oprange[r];
                        oprange[ADIVD] = oprange[r];
                        oprange[AMULF] = oprange[r];
                        oprange[AMULD] = oprange[r];
                        oprange[ASUBF] = oprange[r];
                        oprange[ASUBD] = oprange[r];
                        oprange[AADDD] = oprange[r];
                        break;
                case AAND:
                        buildrep(2, AAND);
                        oprange[AXOR] = oprange[r];
                        repop[AXOR] = 2;
                        oprange[AOR] = oprange[r];
                        repop[AOR] = 2;
                        break;
                case ABEQ:
                        oprange[ABNE] = oprange[r];
                        break;
                case ABLEZ:
                        oprange[ABGEZ] = oprange[r];
                        oprange[ABGEZAL] = oprange[r];
                        oprange[ABLTZ] = oprange[r];
                        oprange[ABLTZAL] = oprange[r];
                        oprange[ABGTZ] = oprange[r];
                        break;
                case AMOVB:
                        buildrep(3, AMOVB);
                        oprange[AMOVH] = oprange[r];
                        repop[AMOVH] = 3;
                        break;
                case AMOVBU:
                        buildrep(4, AMOVBU);
                        oprange[AMOVHU] = oprange[r];
                        repop[AMOVHU] = 4;
                        break;
                case AMUL:
                        oprange[AREM] = oprange[r];
                        oprange[AREMU] = oprange[r];
                        oprange[ADIVU] = oprange[r];
                        oprange[AMULU] = oprange[r];
                        oprange[ADIV] = oprange[r];
                        oprange[ADIVVU] = oprange[r];
                        oprange[ADIVV] = oprange[r];
                        break;
                case ASLL:
                        oprange[ASRL] = oprange[r];
                        oprange[ASRA] = oprange[r];
                        oprange[ASLLV] = oprange[r];
                        oprange[ASRAV] = oprange[r];
                        oprange[ASRLV] = oprange[r];
                        break;
                case ASUB:
                        oprange[ASUBU] = oprange[r];
                        oprange[ANOR] = oprange[r];
                        break;
                case ASYSCALL:
                        oprange[ATLBP] = oprange[r];
                        oprange[ATLBR] = oprange[r];
                        oprange[ATLBWI] = oprange[r];
                        oprange[ATLBWR] = oprange[r];
                        break;
                case ACMPEQF:
                        oprange[ACMPGTF] = oprange[r];
                        oprange[ACMPGTD] = oprange[r];
                        oprange[ACMPGEF] = oprange[r];
                        oprange[ACMPGED] = oprange[r];
                        oprange[ACMPEQD] = oprange[r];
                        break;
                case ABFPT:
                        oprange[ABFPF] = oprange[r];
                        break;
                case AMOVWL:
                        oprange[AMOVWR] = oprange[r];
                        oprange[AMOVVR] = oprange[r];
                        oprange[AMOVVL] = oprange[r];
                        break;
                case AMOVW:
                        buildrep(5, AMOVW);
                        break;
                case AMOVD:
                        buildrep(6, AMOVD);
                        break;
                case AMOVF:
                        buildrep(7, AMOVF);
                        break;
                case AMOVV:
                        buildrep(8, AMOVV);
                        break;
                case ABREAK:
                case AWORD:
                case ARFE:
                case AJAL:
                case AJMP:
                case ATEXT:
                case ACASE:
                case ABCASE:
                        break;
                }
        }
}

void
buildrep(int x, int as)
{
        Opcross *p;
        Optab *e, *s, *o;
        int a1, a2, a3, n;

        if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
                diag("assumptions fail in buildrep");
                errorexit();
        }
        repop[as] = x;
        p = (opcross + x);
        s = oprange[as].start;
        e = oprange[as].stop;
        for(o=e-1; o>=s; o--) {
                n = o-optab;
                for(a2=0; a2<2; a2++) {
                        if(a2) {
                                if(o->a2 == C_NONE)
                                        continue;
                        } else
                                if(o->a2 != C_NONE)
                                        continue;
                        for(a1=0; a1<32; a1++) {
                                if(!xcmp[a1][o->a1])
                                        continue;
                                for(a3=0; a3<32; a3++)
                                        if(xcmp[a3][o->a3])
                                                (*p)[a1][a2][a3] = n;
                        }
                }
        }
        oprange[as].start = 0;
}