Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "gc.h"

void
peep(void)
{
        Reg *r, *r1, *r2;
        Prog *p, *p1;
        int t;
/*
 * complete R structure
 */
        t = 0;
        for(r=firstr; r!=R; r=r1) {
                r1 = r->link;
                if(r1 == R)
                        break;
                p = r->prog->link;
                while(p != r1->prog)
                switch(p->as) {
                default:
                        r2 = rega();
                        r->link = r2;
                        r2->link = r1;

                        r2->prog = p;
                        r2->p1 = r;
                        r->s1 = r2;
                        r2->s1 = r1;
                        r1->p1 = r2;

                        r = r2;
                        t++;

                case ADATA:
                case AGLOBL:
                case ANAME:
                case ASIGNAME:
                        p = p->link;
                }
        }

loop1:
        t = 0;
        for(r=firstr; r!=R; r=r->link) {
                p = r->prog;
                if(p->as == AMOVW || p->as == AFMOVS || p->as == AFMOVD)
                if(regtyp(&p->to)) {
                        if(regtyp(&p->from))
                        if(p->from.type == p->to.type) {
                                if(copyprop(r)) {
                                        excise(r);
                                        t++;
                                } else
                                if(subprop(r) && copyprop(r)) {
                                        excise(r);
                                        t++;
                                }
                        }
                        if(regzer(&p->from))
                        if(p->to.type == D_REG) {
                                p->from.type = D_REG;
                                p->from.reg = REGZERO;
                                if(copyprop(r)) {
                                        excise(r);
                                        t++;
                                } else
                                if(subprop(r) && copyprop(r)) {
                                        excise(r);
                                        t++;
                                }
                        }
                }
        }
        if(t)
                goto loop1;
        /*
         * look for MOVB x,R; MOVB R,R
         */
        for(r=firstr; r!=R; r=r->link) {
                p = r->prog;
                switch(p->as) {
                default:
                        continue;
                case AMOVH:
                case AMOVHZ:
                case AMOVB:
                case AMOVBZ:
                        if(p->to.type != D_REG)
                                continue;
                        break;
                }
                r1 = r->link;
                if(r1 == R)
                        continue;
                p1 = r1->prog;
                if(p1->as != p->as)
                        continue;
                if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
                        continue;
                if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
                        continue;
                excise(r1);
        }

        if(debug['Q'] > 1)
                return; /* allow following code improvement to be suppressed */

        /*
         * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
         * when OP can set condition codes correctly
         */
        for(r=firstr; r!=R; r=r->link) {
                p = r->prog;
                switch(p->as) {
                case ACMP:
                        if(!regzer(&p->to))
                                continue;
                        r1 = r->s1;
                        if(r1 == R)
                                continue;
                        switch(r1->prog->as) {
                        default:
                                continue;
                        case ABCL:
                        case ABC:
                                /* the conditions can be complex and these are currently little used */
                                continue;
                        case ABEQ:
                        case ABGE:
                        case ABGT:
                        case ABLE:
                        case ABLT:
                        case ABNE:
                        case ABVC:
                        case ABVS:
                                break;
                        }
                        r1 = r;
                        do
                                r1 = uniqp(r1);
                        while (r1 != R && r1->prog->as == ANOP);
                        if(r1 == R)
                                continue;
                        p1 = r1->prog;
                        if(p1->to.type != D_REG || p1->to.reg != p->from.reg)
                                continue;
                        switch(p1->as) {
                        case ASUB:
                        case AADD:
                        case AXOR:
                        case AOR:
                                /* irregular instructions */
                                if(p1->from.type == D_CONST)
                                        continue;
                                break;
                        }
                        switch(p1->as) {
                        default:
                                continue;
                        case AMOVW:
                                if(p1->from.type != D_REG)
                                        continue;
                                continue;
                        case AANDCC:
                        case AANDNCC:
                        case AORCC:
                        case AORNCC:
                        case AXORCC:
                        case ASUBCC:
                        case ASUBECC:
                        case ASUBMECC:
                        case ASUBZECC:
                        case AADDCC:
                        case AADDCCC:
                        case AADDECC:
                        case AADDMECC:
                        case AADDZECC:
                        case ARLWMICC:
                        case ARLWNMCC:
                                t = p1->as;
                                break;
                        /* don't deal with floating point instructions for now */
/*
                        case AFABS:     t = AFABSCC; break;
                        case AFADD:     t = AFADDCC; break;
                        case AFADDS:    t = AFADDSCC; break;
                        case AFCTIW:    t = AFCTIWCC; break;
                        case AFCTIWZ:   t = AFCTIWZCC; break;
                        case AFDIV:     t = AFDIVCC; break;
                        case AFDIVS:    t = AFDIVSCC; break;
                        case AFMADD:    t = AFMADDCC; break;
                        case AFMADDS:   t = AFMADDSCC; break;
                        case AFMOVD:    t = AFMOVDCC; break;
                        case AFMSUB:    t = AFMSUBCC; break;
                        case AFMSUBS:   t = AFMSUBSCC; break;
                        case AFMUL:     t = AFMULCC; break;
                        case AFMULS:    t = AFMULSCC; break;
                        case AFNABS:    t = AFNABSCC; break;
                        case AFNEG:     t = AFNEGCC; break;
                        case AFNMADD:   t = AFNMADDCC; break;
                        case AFNMADDS:  t = AFNMADDSCC; break;
                        case AFNMSUB:   t = AFNMSUBCC; break;
                        case AFNMSUBS:  t = AFNMSUBSCC; break;
                        case AFRSP:     t = AFRSPCC; break;
                        case AFSUB:     t = AFSUBCC; break;
                        case AFSUBS:    t = AFSUBSCC; break;
                        case ACNTLZW:   t = ACNTLZWCC; break;
                        case AMTFSB0:   t = AMTFSB0CC; break;
                        case AMTFSB1:   t = AMTFSB1CC; break;
*/
                        case AADD:      t = AADDCC; break;
                        case AADDV:     t = AADDVCC; break;
                        case AADDC:     t = AADDCCC; break;
                        case AADDCV:    t = AADDCVCC; break;
                        case AADDME:    t = AADDMECC; break;
                        case AADDMEV:   t = AADDMEVCC; break;
                        case AADDE:     t = AADDECC; break;
                        case AADDEV:    t = AADDEVCC; break;
                        case AADDZE:    t = AADDZECC; break;
                        case AADDZEV:   t = AADDZEVCC; break;
                        case AAND:      t = AANDCC; break;
                        case AANDN:     t = AANDNCC; break;
                        case ADIVW:     t = ADIVWCC; break;
                        case ADIVWV:    t = ADIVWVCC; break;
                        case ADIVWU:    t = ADIVWUCC; break;
                        case ADIVWUV:   t = ADIVWUVCC; break;
                        case AEQV:      t = AEQVCC; break;
                        case AEXTSB:    t = AEXTSBCC; break;
                        case AEXTSH:    t = AEXTSHCC; break;
                        case AMULHW:    t = AMULHWCC; break;
                        case AMULHWU:   t = AMULHWUCC; break;
                        case AMULLW:    t = AMULLWCC; break;
                        case AMULLWV:   t = AMULLWVCC; break;
                        case ANAND:     t = ANANDCC; break;
                        case ANEG:      t = ANEGCC; break;
                        case ANEGV:     t = ANEGVCC; break;
                        case ANOR:      t = ANORCC; break;
                        case AOR:       t = AORCC; break;
                        case AORN:      t = AORNCC; break;
                        case AREM:      t = AREMCC; break;
                        case AREMV:     t = AREMVCC; break;
                        case AREMU:     t = AREMUCC; break;
                        case AREMUV:    t = AREMUVCC; break;
                        case ARLWMI:    t = ARLWMICC; break;
                        case ARLWNM:    t = ARLWNMCC; break;
                        case ASLW:      t = ASLWCC; break;
                        case ASRAW:     t = ASRAWCC; break;
                        case ASRW:      t = ASRWCC; break;
                        case ASUB:      t = ASUBCC; break;
                        case ASUBV:     t = ASUBVCC; break;
                        case ASUBC:     t = ASUBCCC; break;
                        case ASUBCV:    t = ASUBCVCC; break;
                        case ASUBME:    t = ASUBMECC; break;
                        case ASUBMEV:   t = ASUBMEVCC; break;
                        case ASUBE:     t = ASUBECC; break;
                        case ASUBEV:    t = ASUBEVCC; break;
                        case ASUBZE:    t = ASUBZECC; break;
                        case ASUBZEV:   t = ASUBZEVCC; break;
                        case AXOR:      t = AXORCC; break;
                                break;
                        }
                        if(debug['Q'])
                                print("cmp %P; %P -> ", p1, p);
                        p1->as = t;
                        if(debug['Q'])
                                print("%P\n", p1);
                        excise(r);
                        continue;
                }
        }
}

void
excise(Reg *r)
{
        Prog *p;

        p = r->prog;
        p->as = ANOP;
        p->from = zprog.from;
        p->from3 = zprog.from3;
        p->to = zprog.to;
        p->reg = zprog.reg; /**/
}

Reg*
uniqp(Reg *r)
{
        Reg *r1;

        r1 = r->p1;
        if(r1 == R) {
                r1 = r->p2;
                if(r1 == R || r1->p2link != R)
                        return R;
        } else
                if(r->p2 != R)
                        return R;
        return r1;
}

Reg*
uniqs(Reg *r)
{
        Reg *r1;

        r1 = r->s1;
        if(r1 == R) {
                r1 = r->s2;
                if(r1 == R)
                        return R;
        } else
                if(r->s2 != R)
                        return R;
        return r1;
}

/*
 * if the system forces R0 to be zero,
 * convert references to $0 to references to R0.
 */
regzer(Adr *a)
{
        if(R0ISZERO) {
                if(a->type == D_CONST)
                        if(a->sym == S)
                                if(a->offset == 0)
                                        return 1;
                if(a->type == D_REG)
                        if(a->reg == REGZERO)
                                return 1;
        }
        return 0;
}

regtyp(Adr *a)
{

        if(a->type == D_REG) {
                if(!R0ISZERO || a->reg != REGZERO)
                        return 1;
                return 0;
        }
        if(a->type == D_FREG)
                return 1;
        return 0;
}

/*
 * the idea is to substitute
 * one register for another
 * from one MOV to another
 *      MOV     a, R0
 *      ADD     b, R0   / no use of R1
 *      MOV     R0, R1
 * would be converted to
 *      MOV     a, R1
 *      ADD     b, R1
 *      MOV     R1, R0
 * hopefully, then the former or latter MOV
 * will be eliminated by copy propagation.
 */
int
subprop(Reg *r0)
{
        Prog *p;
        Adr *v1, *v2;
        Reg *r;
        int t;

        p = r0->prog;
        v1 = &p->from;
        if(!regtyp(v1))
                return 0;
        v2 = &p->to;
        if(!regtyp(v2))
                return 0;
        for(r=uniqp(r0); r!=R; r=uniqp(r)) {
                if(uniqs(r) == R)
                        break;
                p = r->prog;
                switch(p->as) {
                case ABL:
                        return 0;

                case AADD:
                case AADDC:
                case AADDCC:
                case AADDE:
                case AADDECC:
                case ASUB:
                case ASUBCC:
                case ASUBC:
                case ASUBCCC:
                case ASUBE:
                case ASUBECC:
                case ASLW:
                case ASLWCC:
                case ASRW:
                case ASRWCC:
                case ASRAW:
                case ASRAWCC:
                case AOR:
                case AORCC:
                case AORN:
                case AORNCC:
                case AAND:
                case AANDCC:
                case AANDN:
                case AANDNCC:
                case ANAND:
                case ANANDCC:
                case ANOR:
                case ANORCC:
                case AXOR:
                case AXORCC:
                case AMULHW:
                case AMULHWU:
                case AMULLW:
                case ADIVW:
                case ADIVWU:
                case AREM:
                case AREMU:
                case ARLWNM:
                case ARLWNMCC:

                case AFADD:
                case AFADDS:
                case AFSUB:
                case AFSUBS:
                case AFMUL:
                case AFMULS:
                case AFDIV:
                case AFDIVS:
                        if(p->to.type == v1->type)
                        if(p->to.reg == v1->reg) {
                                if(p->reg == NREG)
                                        p->reg = p->to.reg;
                                goto gotit;
                        }
                        break;

                case AADDME:
                case AADDMECC:
                case AADDZE:
                case AADDZECC:
                case ASUBME:
                case ASUBMECC:
                case ASUBZE:
                case ASUBZECC:
                case ANEG:
                case ANEGCC:
                case AFNEG:
                case AFNEGCC:
                case AFMOVS:
                case AFMOVD:
                case AMOVW:
                        if(p->to.type == v1->type)
                        if(p->to.reg == v1->reg)
                                goto gotit;
                        break;
                }
                if(copyau(&p->from, v2) ||
                   copyau1(p, v2) ||
                   copyau(&p->to, v2))
                        break;
                if(copysub(&p->from, v1, v2, 0) ||
                   copysub1(p, v1, v2, 0) ||
                   copysub(&p->to, v1, v2, 0))
                        break;
        }
        return 0;

gotit:
        copysub(&p->to, v1, v2, 1);
        if(debug['P']) {
                print("gotit: %D->%D\n%P", v1, v2, r->prog);
                if(p->from.type == v2->type)
                        print(" excise");
                print("\n");
        }
        for(r=uniqs(r); r!=r0; r=uniqs(r)) {
                p = r->prog;
                copysub(&p->from, v1, v2, 1);
                copysub1(p, v1, v2, 1);
                copysub(&p->to, v1, v2, 1);
                if(debug['P'])
                        print("%P\n", r->prog);
        }
        t = v1->reg;
        v1->reg = v2->reg;
        v2->reg = t;
        if(debug['P'])
                print("%P last\n", r->prog);
        return 1;
}

/*
 * The idea is to remove redundant copies.
 *      v1->v2  F=0
 *      (use v2 s/v2/v1/)*
 *      set v1  F=1
 *      use v2  return fail
 *      -----------------
 *      v1->v2  F=0
 *      (use v2 s/v2/v1/)*
 *      set v1  F=1
 *      set v2  return success
 */
int
copyprop(Reg *r0)
{
        Prog *p;
        Adr *v1, *v2;
        Reg *r;

        p = r0->prog;
        v1 = &p->from;
        v2 = &p->to;
        if(copyas(v1, v2))
                return 1;
        for(r=firstr; r!=R; r=r->link)
                r->active = 0;
        return copy1(v1, v2, r0->s1, 0);
}

copy1(Adr *v1, Adr *v2, Reg *r, int f)
{
        int t;
        Prog *p;

        if(r->active) {
                if(debug['P'])
                        print("act set; return 1\n");
                return 1;
        }
        r->active = 1;
        if(debug['P'])
                print("copy %D->%D f=%d\n", v1, v2, f);
        for(; r != R; r = r->s1) {
                p = r->prog;
                if(debug['P'])
                        print("%P", p);
                if(!f && uniqp(r) == R) {
                        f = 1;
                        if(debug['P'])
                                print("; merge; f=%d", f);
                }
                t = copyu(p, v2, A);
                switch(t) {
                case 2: /* rar, cant split */
                        if(debug['P'])
                                print("; %Drar; return 0\n", v2);
                        return 0;

                case 3: /* set */
                        if(debug['P'])
                                print("; %Dset; return 1\n", v2);
                        return 1;

                case 1: /* used, substitute */
                case 4: /* use and set */
                        if(f) {
                                if(!debug['P'])
                                        return 0;
                                if(t == 4)
                                        print("; %Dused+set and f=%d; return 0\n", v2, f);
                                else
                                        print("; %Dused and f=%d; return 0\n", v2, f);
                                return 0;
                        }
                        if(copyu(p, v2, v1)) {
                                if(debug['P'])
                                        print("; sub fail; return 0\n");
                                return 0;
                        }
                        if(debug['P'])
                                print("; sub%D/%D", v2, v1);
                        if(t == 4) {
                                if(debug['P'])
                                        print("; %Dused+set; return 1\n", v2);
                                return 1;
                        }
                        break;
                }
                if(!f) {
                        t = copyu(p, v1, A);
                        if(!f && (t == 2 || t == 3 || t == 4)) {
                                f = 1;
                                if(debug['P'])
                                        print("; %Dset and !f; f=%d", v1, f);
                        }
                }
                if(debug['P'])
                        print("\n");
                if(r->s2)
                        if(!copy1(v1, v2, r->s2, f))
                                return 0;
        }
        return 1;
}

/*
 * return
 * 1 if v only used (and substitute),
 * 2 if read-alter-rewrite
 * 3 if set
 * 4 if set and used
 * 0 otherwise (not touched)
 */
int
copyu(Prog *p, Adr *v, Adr *s)
{

        switch(p->as) {

        default:
                if(debug['P'])
                        print(" (???)");
                return 2;

        case ANOP:      /* read, write */
        case AMOVW:
        case AMOVH:
        case AMOVHZ:
        case AMOVB:
        case AMOVBZ:

        case ANEG:
        case ANEGCC:
        case AADDME:
        case AADDMECC:
        case AADDZE:
        case AADDZECC:
        case ASUBME:
        case ASUBMECC:
        case ASUBZE:
        case ASUBZECC:

        case AFCTIW:
        case AFCTIWZ:
        case AFMOVS:
        case AFMOVD:
        case AFRSP:
        case AFNEG:
        case AFNEGCC:
                if(s != A) {
                        if(copysub(&p->from, v, s, 1))
                                return 1;
                        if(!copyas(&p->to, v))
                                if(copysub(&p->to, v, s, 1))
                                        return 1;
                        return 0;
                }
                if(copyas(&p->to, v)) {
                        if(copyau(&p->from, v))
                                return 4;
                        return 3;
                }
                if(copyau(&p->from, v))
                        return 1;
                if(copyau(&p->to, v))
                        return 1;
                return 0;

        case ARLWMI:    /* read read rar */
        case ARLWMICC:
                if(copyas(&p->to, v))
                        return 2;
                /* fall through */

        case AADD:      /* read read write */
        case AADDC:
        case AADDE:
        case ASUB:
        case ASLW:
        case ASRW:
        case ASRAW:
        case AOR:
        case AORCC:
        case AORN:
        case AORNCC:
        case AAND:
        case AANDCC:
        case AANDN:
        case AANDNCC:
        case ANAND:
        case ANANDCC:
        case ANOR:
        case ANORCC:
        case AXOR:
        case AMULHW:
        case AMULHWU:
        case AMULLW:
        case ADIVW:
        case ADIVWU:
        case AREM:
        case AREMU:
        case ARLWNM:
        case ARLWNMCC:

        case AFADDS:
        case AFADD:
        case AFSUBS:
        case AFSUB:
        case AFMULS:
        case AFMUL:
        case AFDIVS:
        case AFDIV:
                if(s != A) {
                        if(copysub(&p->from, v, s, 1))
                                return 1;
                        if(copysub1(p, v, s, 1))
                                return 1;
                        if(!copyas(&p->to, v))
                                if(copysub(&p->to, v, s, 1))
                                        return 1;
                        return 0;
                }
                if(copyas(&p->to, v)) {
                        if(p->reg == NREG)
                                p->reg = p->to.reg;
                        if(copyau(&p->from, v))
                                return 4;
                        if(copyau1(p, v))
                                return 4;
                        return 3;
                }
                if(copyau(&p->from, v))
                        return 1;
                if(copyau1(p, v))
                        return 1;
                if(copyau(&p->to, v))
                        return 1;
                return 0;

        case ABEQ:
        case ABGT:
        case ABGE:
        case ABLT:
        case ABLE:
        case ABNE:
        case ABVC:
        case ABVS:
                break;

        case ACMP:      /* read read */
        case ACMPU:
        case AFCMPO:
        case AFCMPU:
                if(s != A) {
                        if(copysub(&p->from, v, s, 1))
                                return 1;
                        return copysub(&p->to, v, s, 1);
                }
                if(copyau(&p->from, v))
                        return 1;
                if(copyau(&p->to, v))
                        return 1;
                break;

        case ABR:       /* funny */
                if(s != A) {
                        if(copysub(&p->to, v, s, 1))
                                return 1;
                        return 0;
                }
                if(copyau(&p->to, v))
                        return 1;
                return 0;

        case ARETURN:   /* funny */
                if(v->type == D_REG)
                        if(v->reg == REGRET)
                                return 2;
                if(v->type == D_FREG)
                        if(v->reg == FREGRET)
                                return 2;

        case ABL:       /* funny */
                if(v->type == D_REG) {
                        if(v->reg <= REGEXT && v->reg > exregoffset)
                                return 2;
                        if(v->reg == REGARG)
                                return 2;
                }
                if(v->type == D_FREG) {
                        if(v->reg <= FREGEXT && v->reg > exfregoffset)
                                return 2;
                }

                if(s != A) {
                        if(copysub(&p->to, v, s, 1))
                                return 1;
                        return 0;
                }
                if(copyau(&p->to, v))
                        return 4;
                return 3;

        case ATEXT:     /* funny */
                if(v->type == D_REG)
                        if(v->reg == REGARG)
                                return 3;
                return 0;
        }
        return 0;
}

int
a2type(Prog *p)
{

        switch(p->as) {
        case AADD:
        case AADDC:
        case AADDCC:
        case AADDCCC:
        case AADDE:
        case AADDECC:
        case AADDME:
        case AADDMECC:
        case AADDZE:
        case AADDZECC:
        case ASUB:
        case ASUBC:
        case ASUBCC:
        case ASUBCCC:
        case ASUBE:
        case ASUBECC:
        case ASUBME:
        case ASUBMECC:
        case ASUBZE:
        case ASUBZECC:
        case ASLW:
        case ASLWCC:
        case ASRW:
        case ASRWCC:
        case ASRAW:
        case ASRAWCC:
        case AOR:
        case AORCC:
        case AORN:
        case AORNCC:
        case AAND:
        case AANDCC:
        case AANDN:
        case AANDNCC:
        case AXOR:
        case AXORCC:
        case ANEG:
        case ANEGCC:
        case AMULHW:
        case AMULHWU:
        case AMULLW:
        case AMULLWCC:
        case ADIVW:
        case ADIVWCC:
        case ADIVWU:
        case ADIVWUCC:
        case AREM:
        case AREMCC:
        case AREMU:
        case AREMUCC:
        case ANAND:
        case ANANDCC:
        case ANOR:
        case ANORCC:
        case ARLWMI:
        case ARLWMICC:
        case ARLWNM:
        case ARLWNMCC:
                return D_REG;

        case AFADDS:
        case AFADDSCC:
        case AFADD:
        case AFADDCC:
        case AFSUBS:
        case AFSUBSCC:
        case AFSUB:
        case AFSUBCC:
        case AFMULS:
        case AFMULSCC:
        case AFMUL:
        case AFMULCC:
        case AFDIVS:
        case AFDIVSCC:
        case AFDIV:
        case AFDIVCC:
        case AFNEG:
        case AFNEGCC:
                return D_FREG;
        }
        return D_NONE;
}

/*
 * direct reference,
 * could be set/use depending on
 * semantics
 */
int
copyas(Adr *a, Adr *v)
{

        if(regtyp(v))
                if(a->type == v->type)
                if(a->reg == v->reg)
                        return 1;
        return 0;
}

/*
 * either direct or indirect
 */
int
copyau(Adr *a, Adr *v)
{

        if(copyas(a, v))
                return 1;
        if(v->type == D_REG)
                if(a->type == D_OREG)
                        if(v->reg == a->reg)
                                return 1;
        return 0;
}

int
copyau1(Prog *p, Adr *v)
{

        if(regtyp(v))
                if(p->from.type == v->type || p->to.type == v->type)
                if(p->reg == v->reg) {
                        if(a2type(p) != v->type)
                                print("botch a2type %P\n", p);
                        return 1;
                }
        return 0;
}

/*
 * substitute s for v in a
 * return failure to substitute
 */
int
copysub(Adr *a, Adr *v, Adr *s, int f)
{

        if(f)
        if(copyau(a, v))
                a->reg = s->reg;
        return 0;
}

int
copysub1(Prog *p1, Adr *v, Adr *s, int f)
{

        if(f)
        if(copyau1(p1, v))
                p1->reg = s->reg;
        return 0;
}