Exemplo n.º 1
0
void
regopt(Prog *p)
{
    Reg *r, *r1, *r2;
    Prog *p1;
    int i, z;
    long initpc, val, npc;
    ulong vreg;
    Bits bit;
    struct
    {
        long	m;
        long	c;
        Reg*	p;
    } log5[6], *lp;

    firstr = R;
    lastr = R;
    nvar = 0;
    regbits = 0;
    for(z=0; z<BITS; z++) {
        externs.b[z] = 0;
        params.b[z] = 0;
        consts.b[z] = 0;
        addrs.b[z] = 0;
    }

    /*
     * pass 1
     * build aux data structure
     * allocate pcs
     * find use and set of variables
     */
    val = 5L * 5L * 5L * 5L * 5L;
    lp = log5;
    for(i=0; i<5; i++) {
        lp->m = val;
        lp->c = 0;
        lp->p = R;
        val /= 5L;
        lp++;
    }
    val = 0;
    for(; p != P; p = p->link) {
        switch(p->as) {
        case ADATA:
        case AGLOBL:
        case ANAME:
        case ASIGNAME:
            continue;
        }
        r = rega();
        if(firstr == R) {
            firstr = r;
            lastr = r;
        } else {
            lastr->link = r;
            r->p1 = lastr;
            lastr->s1 = r;
            lastr = r;
        }
        r->prog = p;
        r->pc = val;
        val++;

        lp = log5;
        for(i=0; i<5; i++) {
            lp->c--;
            if(lp->c <= 0) {
                lp->c = lp->m;
                if(lp->p != R)
                    lp->p->log5 = r;
                lp->p = r;
                (lp+1)->c = 0;
                break;
            }
            lp++;
        }

        r1 = r->p1;
        if(r1 != R)
            switch(r1->prog->as) {
            case ARET:
            case AB:
            case ARFE:
                r->p1 = R;
                r1->s1 = R;
            }

        /*
         * left side always read
         */
        bit = mkvar(&p->from, p->as==AMOVW);
        for(z=0; z<BITS; z++)
            r->use1.b[z] |= bit.b[z];

        /*
         * right side depends on opcode
         */
        bit = mkvar(&p->to, 0);
        if(bany(&bit))
            switch(p->as) {
            default:
                diag(Z, "reg: unknown asop: %A", p->as);
                break;

            /*
             * right side write
             */
            case ANOP:
            case AMOVB:
            case AMOVBU:
            case AMOVH:
            case AMOVHU:
            case AMOVW:
            case AMOVF:
            case AMOVD:
                for(z=0; z<BITS; z++)
                    r->set.b[z] |= bit.b[z];
                break;

            /*
             * funny
             */
            case ABL:
                for(z=0; z<BITS; z++)
                    addrs.b[z] |= bit.b[z];
                break;
            }

        if(p->as == AMOVM) {
            if(p->from.type == D_CONST)
                z = p->from.offset;
            else
                z = p->to.offset;
            for(i=0; z; i++) {
                if(z&1)
                    regbits |= RtoB(i);
                z >>= 1;
            }
        }
    }
    if(firstr == R)
        return;
    initpc = pc - val;
    npc = val;

    /*
     * pass 2
     * turn branch references to pointers
     * build back pointers
     */
    for(r = firstr; r != R; r = r->link) {
        p = r->prog;
        if(p->to.type == D_BRANCH) {
            val = p->to.offset - initpc;
            r1 = firstr;
            while(r1 != R) {
                r2 = r1->log5;
                if(r2 != R && val >= r2->pc) {
                    r1 = r2;
                    continue;
                }
                if(r1->pc == val)
                    break;
                r1 = r1->link;
            }
            if(r1 == R) {
                nearln = p->lineno;
                diag(Z, "ref not found\n%P", p);
                continue;
            }
            if(r1 == r) {
                nearln = p->lineno;
                diag(Z, "ref to self\n%P", p);
                continue;
            }
            r->s2 = r1;
            r->p2link = r1->p2;
            r1->p2 = r;
        }
    }
    if(debug['R']) {
        p = firstr->prog;
        print("\n%L %D\n", p->lineno, &p->from);
    }

    /*
     * pass 2.5
     * find looping structure
     */
    for(r = firstr; r != R; r = r->link)
        r->active = 0;
    change = 0;
    loopit(firstr, npc);

    /*
     * pass 3
     * iterate propagating usage
     * 	back until flow graph is complete
     */
loop1:
    change = 0;
    for(r = firstr; r != R; r = r->link)
        r->active = 0;
    for(r = firstr; r != R; r = r->link)
        if(r->prog->as == ARET)
            prop(r, zbits, zbits);
loop11:
    /* pick up unreachable code */
    i = 0;
    for(r = firstr; r != R; r = r1) {
        r1 = r->link;
        if(r1 && r1->active && !r->active) {
            prop(r, zbits, zbits);
            i = 1;
        }
    }
    if(i)
        goto loop11;
    if(change)
        goto loop1;


    /*
     * pass 4
     * iterate propagating register/variable synchrony
     * 	forward until graph is complete
     */
loop2:
    change = 0;
    for(r = firstr; r != R; r = r->link)
        r->active = 0;
    synch(firstr, zbits);
    if(change)
        goto loop2;

    addsplits();

    if(debug['R'] && debug['v']) {
        print("\nprop structure:\n");
        for(r = firstr; r != R; r = r->link) {
            print("%ld:%P", r->loop, r->prog);
            for(z=0; z<BITS; z++)
                bit.b[z] = r->set.b[z] |
                           r->refahead.b[z] | r->calahead.b[z] |
                           r->refbehind.b[z] | r->calbehind.b[z] |
                           r->use1.b[z] | r->use2.b[z];
            if(bany(&bit)) {
                print("\t");
                if(bany(&r->use1))
                    print(" u1=%B", r->use1);
                if(bany(&r->use2))
                    print(" u2=%B", r->use2);
                if(bany(&r->set))
                    print(" st=%B", r->set);
                if(bany(&r->refahead))
                    print(" ra=%B", r->refahead);
                if(bany(&r->calahead))
                    print(" ca=%B", r->calahead);
                if(bany(&r->refbehind))
                    print(" rb=%B", r->refbehind);
                if(bany(&r->calbehind))
                    print(" cb=%B", r->calbehind);
            }
            print("\n");
        }
    }

    /*
     * pass 5
     * isolate regions
     * calculate costs (paint1)
     */
    r = firstr;
    if(r) {
        for(z=0; z<BITS; z++)
            bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
                       ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
        if(bany(&bit)) {
            nearln = r->prog->lineno;
            warn(Z, "used and not set: %B", bit);
            if(debug['R'] && !debug['w'])
                print("used and not set: %B\n", bit);
        }
    }

    for(r = firstr; r != R; r = r->link)
        r->act = zbits;
    rgp = region;
    nregion = 0;
    for(r = firstr; r != R; r = r->link) {
        for(z=0; z<BITS; z++)
            bit.b[z] = r->set.b[z] &
                       ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
        if(bany(&bit)) {
            nearln = r->prog->lineno;
            warn(Z, "set and not used: %B", bit);
            if(debug['R'])
                print("set and not used: %B\n", bit);
            excise(r);
        }
        for(z=0; z<BITS; z++)
            bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
        while(bany(&bit)) {
            i = bnum(bit);
            rgp->enter = r;
            rgp->varno = i;
            change = 0;
            if(debug['R'] && debug['v'])
                print("\n");
            paint1(r, i);
            bit.b[i/32] &= ~(1L<<(i%32));
            if(change <= 0) {
                if(debug['R'])
                    print("%L $%d: %B\n",
                          r->prog->lineno, change, blsh(i));
                continue;
            }
            rgp->cost = change;
            nregion++;
            if(nregion >= NRGN) {
                warn(Z, "too many regions");
                goto brk;
            }
            rgp++;
        }
    }
brk:
    qsort(region, nregion, sizeof(region[0]), rcmp);

    /*
     * pass 6
     * determine used registers (paint2)
     * replace code (paint3)
     */
    rgp = region;
    for(i=0; i<nregion; i++) {
        bit = blsh(rgp->varno);
        vreg = paint2(rgp->enter, rgp->varno);
        vreg = allreg(vreg, rgp);
        if(debug['R']) {
            if(rgp->regno >= NREG)
                print("%L $%d F%d: %B\n",
                      rgp->enter->prog->lineno,
                      rgp->cost,
                      rgp->regno-NREG,
                      bit);
            else
                print("%L $%d R%d: %B\n",
                      rgp->enter->prog->lineno,
                      rgp->cost,
                      rgp->regno,
                      bit);
        }
        if(rgp->regno != 0)
            paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
        rgp++;
    }
    /*
     * pass 7
     * peep-hole on basic block
     */
    if(!debug['R'] || debug['P'])
        peep();

    /*
     * pass 8
     * recalculate pc
     */
    val = initpc;
    for(r = firstr; r != R; r = r1) {
        r->pc = val;
        p = r->prog;
        p1 = P;
        r1 = r->link;
        if(r1 != R)
            p1 = r1->prog;
        for(; p != p1; p = p->link) {
            switch(p->as) {
            default:
                val++;
                break;

            case ANOP:
            case ADATA:
            case AGLOBL:
            case ANAME:
            case ASIGNAME:
                break;
            }
        }
    }
    pc = val;

    /*
     * fix up branches
     */
    if(debug['R'])
        if(bany(&addrs))
            print("addrs: %B\n", addrs);

    r1 = 0; /* set */
    for(r = firstr; r != R; r = r->link) {
        p = r->prog;
        if(p->to.type == D_BRANCH)
            p->to.offset = r->s2->pc;
        r1 = r;
    }

    /*
     * last pass
     * eliminate nops
     * free aux structures
     */
    for(p = firstr->prog; p != P; p = p->link) {
        while(p->link && p->link->as == ANOP)
            p->link = p->link->link;
    }
    if(r1 != R) {
        r1->link = freer;
        freer = firstr;
    }
}
Exemplo n.º 2
0
void
regopt(Prog *firstp)
{
	Reg *r, *r1;
	Prog *p;
	Graph *g;
	int i, z;
	uint32 vreg;
	Bits bit;
	ProgInfo info;

	if(first) {
		fmtinstall('Q', Qconv);
		first = 0;
	}
	
	fixjmp(firstp);
	mergetemp(firstp);

	/*
	 * control flow is more complicated in generated go code
	 * than in generated c code.  define pseudo-variables for
	 * registers, so we have complete register usage information.
	 */
	nvar = NREGVAR;
	memset(var, 0, NREGVAR*sizeof var[0]);
	for(i=0; i<NREGVAR; i++) {
		if(regnodes[i] == N)
			regnodes[i] = newname(lookup(regname[i]));
		var[i].node = regnodes[i];
	}

	regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
	for(z=0; z<BITS; z++) {
		externs.b[z] = 0;
		params.b[z] = 0;
		consts.b[z] = 0;
		addrs.b[z] = 0;
		ovar.b[z] = 0;
	}

	// build list of return variables
	setoutvar();

	/*
	 * pass 1
	 * build aux data structure
	 * allocate pcs
	 * find use and set of variables
	 */
	g = flowstart(firstp, sizeof(Reg));
	if(g == nil)
		return;
	firstr = (Reg*)g->start;

	for(r = firstr; r != R; r = (Reg*)r->f.link) {
		p = r->f.prog;
		proginfo(&info, p);

		// Avoid making variables for direct-called functions.
		if(p->as == ABL && p->to.type == D_EXTERN)
			continue;

		bit = mkvar(r, &p->from);
		if(info.flags & LeftRead)
			for(z=0; z<BITS; z++)
				r->use1.b[z] |= bit.b[z];
		if(info.flags & LeftAddr)
			setaddrs(bit);

		if(info.flags & RegRead) {	
			if(p->from.type != D_FREG)
				r->use1.b[0] |= RtoB(p->reg);
			else
				r->use1.b[0] |= FtoB(p->reg);
		}

		if(info.flags & (RightAddr | RightRead | RightWrite)) {
			bit = mkvar(r, &p->to);
			if(info.flags & RightAddr)
				setaddrs(bit);
			if(info.flags & RightRead)
				for(z=0; z<BITS; z++)
					r->use2.b[z] |= bit.b[z];
			if(info.flags & RightWrite)
				for(z=0; z<BITS; z++)
					r->set.b[z] |= bit.b[z];
		}
	}
	if(firstr == R)
		return;

	for(i=0; i<nvar; i++) {
		Var *v = var+i;
		if(v->addr) {
			bit = blsh(i);
			for(z=0; z<BITS; z++)
				addrs.b[z] |= bit.b[z];
		}

		if(debug['R'] && debug['v'])
			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
				i, v->addr, v->etype, v->width, v->node, v->offset);
	}

	if(debug['R'] && debug['v'])
		dumpit("pass1", &firstr->f, 1);

	/*
	 * pass 2
	 * find looping structure
	 */
	flowrpo(g);

	if(debug['R'] && debug['v'])
		dumpit("pass2", &firstr->f, 1);

	/*
	 * pass 3
	 * iterate propagating usage
	 * 	back until flow graph is complete
	 */
loop1:
	change = 0;
	for(r = firstr; r != R; r = (Reg*)r->f.link)
		r->f.active = 0;
	for(r = firstr; r != R; r = (Reg*)r->f.link)
		if(r->f.prog->as == ARET)
			prop(r, zbits, zbits);
loop11:
	/* pick up unreachable code */
	i = 0;
	for(r = firstr; r != R; r = r1) {
		r1 = (Reg*)r->f.link;
		if(r1 && r1->f.active && !r->f.active) {
			prop(r, zbits, zbits);
			i = 1;
		}
	}
	if(i)
		goto loop11;
	if(change)
		goto loop1;

	if(debug['R'] && debug['v'])
		dumpit("pass3", &firstr->f, 1);


	/*
	 * pass 4
	 * iterate propagating register/variable synchrony
	 * 	forward until graph is complete
	 */
loop2:
	change = 0;
	for(r = firstr; r != R; r = (Reg*)r->f.link)
		r->f.active = 0;
	synch(firstr, zbits);
	if(change)
		goto loop2;

	addsplits();

	if(debug['R'] && debug['v'])
		dumpit("pass4", &firstr->f, 1);

	if(debug['R'] > 1) {
		print("\nprop structure:\n");
		for(r = firstr; r != R; r = (Reg*)r->f.link) {
			print("%d:%P", r->f.loop, r->f.prog);
			for(z=0; z<BITS; z++) {
				bit.b[z] = r->set.b[z] |
					r->refahead.b[z] | r->calahead.b[z] |
					r->refbehind.b[z] | r->calbehind.b[z] |
					r->use1.b[z] | r->use2.b[z];
				bit.b[z] &= ~addrs.b[z];
			}

			if(bany(&bit)) {
				print("\t");
				if(bany(&r->use1))
					print(" u1=%Q", r->use1);
				if(bany(&r->use2))
					print(" u2=%Q", r->use2);
				if(bany(&r->set))
					print(" st=%Q", r->set);
				if(bany(&r->refahead))
					print(" ra=%Q", r->refahead);
				if(bany(&r->calahead))
					print(" ca=%Q", r->calahead);
				if(bany(&r->refbehind))
					print(" rb=%Q", r->refbehind);
				if(bany(&r->calbehind))
					print(" cb=%Q", r->calbehind);
			}
			print("\n");
		}
	}

	/*
	 * pass 4.5
	 * move register pseudo-variables into regu.
	 */
	for(r = firstr; r != R; r = (Reg*)r->f.link) {
		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;

		r->set.b[0] &= ~REGBITS;
		r->use1.b[0] &= ~REGBITS;
		r->use2.b[0] &= ~REGBITS;
		r->refbehind.b[0] &= ~REGBITS;
		r->refahead.b[0] &= ~REGBITS;
		r->calbehind.b[0] &= ~REGBITS;
		r->calahead.b[0] &= ~REGBITS;
		r->regdiff.b[0] &= ~REGBITS;
		r->act.b[0] &= ~REGBITS;
	}

	if(debug['R'] && debug['v'])
		dumpit("pass4.5", &firstr->f, 1);

	/*
	 * pass 5
	 * isolate regions
	 * calculate costs (paint1)
	 */
	r = firstr;
	if(r) {
		for(z=0; z<BITS; z++)
			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
		if(bany(&bit) & !r->f.refset) {
			// should never happen - all variables are preset
			if(debug['w'])
				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
			r->f.refset = 1;
		}
	}

	for(r = firstr; r != R; r = (Reg*)r->f.link)
		r->act = zbits;
	rgp = region;
	nregion = 0;
	for(r = firstr; r != R; r = (Reg*)r->f.link) {
		for(z=0; z<BITS; z++)
			bit.b[z] = r->set.b[z] &
			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
		if(bany(&bit) && !r->f.refset) {
			if(debug['w'])
				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
			r->f.refset = 1;
			excise(&r->f);
		}
		for(z=0; z<BITS; z++)
			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
		while(bany(&bit)) {
			i = bnum(bit);
			rgp->enter = r;
			rgp->varno = i;
			change = 0;
			if(debug['R'] > 1)
				print("\n");
			paint1(r, i);
			bit.b[i/32] &= ~(1L<<(i%32));
			if(change <= 0) {
				if(debug['R'])
					print("%L $%d: %Q\n",
						r->f.prog->lineno, change, blsh(i));
				continue;
			}
			rgp->cost = change;
			nregion++;
			if(nregion >= NRGN) {
				if(debug['R'] > 1)
					print("too many regions\n");
				goto brk;
			}
			rgp++;
		}
	}
brk:
	qsort(region, nregion, sizeof(region[0]), rcmp);

	if(debug['R'] && debug['v'])
		dumpit("pass5", &firstr->f, 1);

	/*
	 * pass 6
	 * determine used registers (paint2)
	 * replace code (paint3)
	 */
	rgp = region;
	for(i=0; i<nregion; i++) {
		bit = blsh(rgp->varno);
		vreg = paint2(rgp->enter, rgp->varno);
		vreg = allreg(vreg, rgp);
		if(debug['R']) {
			if(rgp->regno >= NREG)
				print("%L $%d F%d: %Q\n",
					rgp->enter->f.prog->lineno,
					rgp->cost,
					rgp->regno-NREG,
					bit);
			else
				print("%L $%d R%d: %Q\n",
					rgp->enter->f.prog->lineno,
					rgp->cost,
					rgp->regno,
					bit);
		}
		if(rgp->regno != 0)
			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
		rgp++;
	}

	if(debug['R'] && debug['v'])
		dumpit("pass6", &firstr->f, 1);

	/*
	 * pass 7
	 * peep-hole on basic block
	 */
	if(!debug['R'] || debug['P']) {
		peep(firstp);
	}

	if(debug['R'] && debug['v'])
		dumpit("pass7", &firstr->f, 1);

	/*
	 * last pass
	 * eliminate nops
	 * free aux structures
	 * adjust the stack pointer
	 *	MOVW.W 	R1,-12(R13)			<<- start
	 *	MOVW   	R0,R1
	 *	MOVW   	R1,8(R13)
	 *	MOVW   	$0,R1
	 *	MOVW   	R1,4(R13)
	 *	BL     	,runtime.newproc+0(SB)
	 *	MOVW   	&ft+-32(SP),R7			<<- adjust
	 *	MOVW   	&j+-40(SP),R6			<<- adjust
	 *	MOVW   	autotmp_0003+-24(SP),R5		<<- adjust
	 *	MOVW   	$12(R13),R13			<<- finish
	 */
	vreg = 0;
	for(p = firstp; p != P; p = p->link) {
		while(p->link != P && p->link->as == ANOP)
			p->link = p->link->link;
		if(p->to.type == D_BRANCH)
			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
				p->to.u.branch = p->to.u.branch->link;
		if(p->as == AMOVW && p->to.reg == 13) {
			if(p->scond & C_WBIT) {
				vreg = -p->to.offset;		// in adjust region
//				print("%P adjusting %d\n", p, vreg);
				continue;
			}
			if(p->from.type == D_CONST && p->to.type == D_REG) {
				if(p->from.offset != vreg)
					print("in and out different\n");
//				print("%P finish %d\n", p, vreg);
				vreg = 0;	// done adjust region
				continue;
			}

//			print("%P %d %d from type\n", p, p->from.type, D_CONST);
//			print("%P %d %d to type\n\n", p, p->to.type, D_REG);
		}

		if(p->as == AMOVW && vreg != 0) {
			if(p->from.sym != S)
			if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
				p->from.offset += vreg;
//				print("%P adjusting from %d %d\n", p, vreg, p->from.type);
			}
			if(p->to.sym != S)
			if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
				p->to.offset += vreg;
//				print("%P adjusting to %d %d\n", p, vreg, p->from.type);
			}
		}
	}

	flowend(g);
}