Beispiel #1
0
Reg*
findinc(Reg *r, Reg *r2, Adr *v)
{
	Reg *r1;
	Prog *p;


	for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
		if(uniqp(r1) != r)
			return R;
		switch(copyu(r1->prog, v, A)) {
		case 0: /* not touched */
			continue;
		case 4: /* set and used */
			p = r1->prog;
			if(p->as == AADD)
			if(p->from.type == D_CONST)
			if(p->from.offset > -4096 && p->from.offset < 4096)
				return r1;
		default:
			return R;
		}
	}
	return R;
}
Beispiel #2
0
/*
 * findinc finds ADD instructions with a constant
 * argument which falls within the immed_12 range.
 */
static Flow*
findinc(Flow *r, Flow *r2, Adr *v)
{
	Flow *r1;
	Prog *p;


	for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
		if(uniqp(r1) != r)
			return nil;
		switch(copyu(r1->prog, v, A)) {
		case 0: /* not touched */
			continue;
		case 4: /* set and used */
			p = r1->prog;
			if(p->as == AADD)
			if(isdconst(&p->from))
			if(p->from.offset > -4096 && p->from.offset < 4096)
				return r1;
		default:
			return nil;
		}
	}
	return nil;
}
Beispiel #3
0
/*
 * The idea is to remove redundant constants.
 *	$c1->v1
 *	($c1->v2 s/$c1/v1)*
 *	set v1  return
 * The v1->v2 should be eliminated by copy propagation.
 */
void
constprop(Adr *c1, Adr *v1, Reg *r)
{
	Prog *p;

	if(debug['C'])
		print("constprop %D->%D\n", c1, v1);
	for(; r != R; r = r->s1) {
		p = r->prog;
		if(debug['C'])
			print("%P", p);
		if(uniqp(r) == R) {
			if(debug['C'])
				print("; merge; return\n");
			return;
		}
		if(p->as == AMOVW && copyas(&p->from, c1)) {
				if(debug['C'])
					print("; sub%D/%D", &p->from, v1);
				p->from = *v1;
		} else if(copyu(p, v1, A) > 1) {
			if(debug['C'])
				print("; %Dset; return\n", v1);
			return;
		}
		if(debug['C'])
			print("\n");
		if(r->s2)
			constprop(c1, v1, r->s2);
	}
}
Beispiel #4
0
Reg*
findpre(Reg *r, Adr *v)
{
	Reg *r1;

	for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
		if(uniqs(r1) != r)
			return R;
		switch(copyu(r1->prog, v, A)) {
		case 1: /* used */
		case 2: /* read-alter-rewrite */
			return R;
		case 3: /* set */
		case 4: /* set and used */
			return r1;
		}
	}
	return R;
}
Beispiel #5
0
/*
 * findpre returns the last instruction mentioning v
 * before r. It must be a set, and there must be
 * a unique path from that instruction to r.
 */
static Flow*
findpre(Flow *r, Adr *v)
{
	Flow *r1;

	for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
		if(uniqs(r1) != r)
			return nil;
		switch(copyu(r1->prog, v, A)) {
		case 1: /* used */
		case 2: /* read-alter-rewrite */
			return nil;
		case 3: /* set */
		case 4: /* set and used */
			return r1;
		}
	}
	return nil;
}
Beispiel #6
0
// is reg guaranteed to be truncated by a previous L instruction?
static int
prevl(Flow *r0, int reg)
{
	Prog *p;
	Flow *r;
	ProgInfo info;

	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
		p = r->prog;
		if(p->to.type == reg) {
			proginfo(&info, p);
			if(info.flags & RightWrite) {
				if(info.flags & SizeL)
					return 1;
				return 0;
			}
		}
	}
	return 0;
}
Beispiel #7
0
// is reg guaranteed to be truncated by a previous L instruction?
static int
prevl(Reg *r0, int reg)
{
	Prog *p;
	Reg *r;

	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
		p = r->prog;
		if(p->to.type == reg) {
			switch(p->as) {
			case AADDL:
			case AANDL:
			case ADECL:
			case ADIVL:
			case AIDIVL:
			case AIMULL:
			case AINCL:
			case AMOVL:
			case AMULL:
			case AORL:
			case ARCLL:
			case ARCRL:
			case AROLL:
			case ARORL:
			case ASALL:
			case ASARL:
			case ASHLL:
			case ASHRL:
			case ASUBL:
			case AXORL:
				return 1;
			}
			return 0;
		}
	}
	return 0;
}
Beispiel #8
0
static void
conprop(Reg *r0)
{
	Reg *r;
	Prog *p, *p0;
	int t;
	Adr *v0;

	p0 = r0->prog;
	v0 = &p0->to;
	r = r0;

loop:
	r = uniqs(r);
	if(r == R || r == r0)
		return;
	if(uniqp(r) == R)
		return;

	p = r->prog;
	t = copyu(p, v0, A);
	switch(t) {
	case 0:	// miss
	case 1:	// use
		goto loop;

	case 2:	// rar
	case 4:	// use and set
		break;

	case 3:	// set
		if(p->as == p0->as)
		if(p->from.type == p0->from.type)
		if(p->from.sym == p0->from.sym)
		if(p->from.offset == p0->from.offset)
		if(p->from.scale == p0->from.scale)
		if(p->from.dval == p0->from.dval)
		if(p->from.index == p0->from.index) {
			excise(r);
			t++;
			goto loop;
		}
		break;
	}
}
Beispiel #9
0
Datei: peep.c Projekt: 8l/go
static void
conprop(Flow *r0)
{
	Flow *r;
	Prog *p, *p0;
	int t;
	Adr *v0;

	p0 = r0->prog;
	v0 = &p0->to;
	r = r0;

loop:
	r = uniqs(r);
	if(r == nil || r == r0)
		return;
	if(uniqp(r) == nil)
		return;

	p = r->prog;
	t = copyu(p, v0, nil);
	switch(t) {
	case 0:	// miss
	case 1:	// use
		goto loop;

	case 2:	// rar
	case 4:	// use and set
		break;

	case 3:	// set
		if(p->as == p0->as)
		if(p->from.type == p0->from.type)
		if(p->from.node == p0->from.node)
		if(p->from.offset == p0->from.offset)
		if(p->from.scale == p0->from.scale)
		if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval)
		if(p->from.index == p0->from.index) {
			excise(r);
			goto loop;
		}
		break;
	}
}
Beispiel #10
0
static void
pushback(Reg *r0)
{
	Reg *r, *b;
	Prog *p0, *p, t;
	
	b = R;
	p0 = r0->prog;
	for(r=uniqp(r0); r!=R && uniqs(r)!=R; r=uniqp(r)) {
		p = r->prog;
		if(p->as != ANOP) {
			if(!regconsttyp(&p->from) || !regtyp(&p->to))
				break;
			if(copyu(p, &p0->to, A) || copyu(p0, &p->to, A))
				break;
		}
		if(p->as == ACALL)
			break;
		b = r;
	}
	
	if(b == R) {
		if(debug['v']) {
			print("no pushback: %P\n", r0->prog);
			if(r)
				print("\t%P [%d]\n", r->prog, uniqs(r)!=R);
		}
		return;
	}

	if(debug['v']) {
		print("pushback\n");
		for(r=b;; r=r->link) {
			print("\t%P\n", r->prog);
			if(r == r0)
				break;
		}
	}

	t = *r0->prog;
	for(r=uniqp(r0);; r=uniqp(r)) {
		p0 = r->link->prog;
		p = r->prog;
		p0->as = p->as;
		p0->lineno = p->lineno;
		p0->from = p->from;
		p0->to = p->to;

		if(r == b)
			break;
	}
	p0 = r->prog;
	p0->as = t.as;
	p0->lineno = t.lineno;
	p0->from = t.from;
	p0->to = t.to;

	if(debug['v']) {
		print("\tafter\n");
		for(r=b;; r=r->link) {
			print("\t%P\n", r->prog);
			if(r == r0)
				break;
		}
	}
}
Beispiel #11
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.
 */
static int
subprop(Flow *r0)
{
	Prog *p;
	Adr *v1, *v2;
	Flow *r;
	int t;
	ProgInfo info;

	p = r0->prog;
	v1 = &p->from;
	if(!regtyp(v1))
		return 0;
	v2 = &p->to;
	if(!regtyp(v2))
		return 0;
	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
		if(uniqs(r) == nil)
			break;
		p = r->prog;
		proginfo(&info, p);
		if(info.flags & Call)
			return 0;

		if((info.flags & CanRegRead) && p->to.type == D_REG) {
			info.flags |= RegRead;
			info.flags &= ~(CanRegRead | RightRead);
			p->reg = p->to.reg;
		}

		switch(p->as) {
		case AMULLU:
		case AMULA:
		case AMVN:
			return 0;
		}
		
		if((info.flags & (RightRead|RightWrite)) == RightWrite) {
			if(p->to.type == v1->type)
			if(p->to.reg == v1->reg)
			if(p->scond == C_SCOND_NONE)
				goto gotit;
		}

		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;
}
Beispiel #12
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.
 */
static int
subprop(Flow *r0)
{
	Prog *p;
	ProgInfo info;
	Adr *v1, *v2;
	Flow *r;
	int t;

	if(debug['P'] && debug['v'])
		print("subprop %P\n", r0->prog);
	p = r0->prog;
	v1 = &p->from;
	if(!regtyp(v1)) {
		if(debug['P'] && debug['v'])
			print("\tnot regtype %D; return 0\n", v1);
		return 0;
	}
	v2 = &p->to;
	if(!regtyp(v2)) {
		if(debug['P'] && debug['v'])
			print("\tnot regtype %D; return 0\n", v2);
		return 0;
	}
	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
		if(debug['P'] && debug['v'])
			print("\t? %P\n", r->prog);
		if(uniqs(r) == nil) {
			if(debug['P'] && debug['v'])
				print("\tno unique successor\n");
			break;
		}
		p = r->prog;
		proginfo(&info, p);
		if(info.flags & Call) {
			if(debug['P'] && debug['v'])
				print("\tfound %P; return 0\n", p);
			return 0;
		}

		if(info.reguse | info.regset) {
			if(debug['P'] && debug['v'])
				print("\tfound %P; return 0\n", p);
			return 0;
		}

		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
			goto gotit;

		if(copyau(&p->from, v2) ||
		   copyau(&p->to, v2)) {
		   	if(debug['P'] && debug['v'])
		   		print("\tcopyau %D failed\n", v2);
			break;
		}
		if(copysub(&p->from, v1, v2, 0) ||
		   copysub(&p->to, v1, v2, 0)) {
		   	if(debug['P'] && debug['v'])
		   		print("\tcopysub failed\n");
			break;
		}
	}
	if(debug['P'] && debug['v'])
		print("\tran off end; return 0\n");
	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);
		copysub(&p->to, v1, v2, 1);
		if(debug['P'])
			print("%P\n", r->prog);
	}
	t = v1->type;
	v1->type = v2->type;
	v2->type = t;
	if(debug['P'])
		print("%P last\n", r->prog);
	return 1;
}
Beispiel #13
0
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 AADDCC:
				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;
		}
	}
}
Beispiel #14
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 AJMPL:
			return 0;

		case AADD:
		case ASUB:
		case ASLL:
		case ASRL:
		case ASRA:
		case AOR:
		case AAND:
		case AXOR:
		case AMUL:
		case ADIV:
		case ADIVL:
		case AMOD:
		case AMODL:

		case AFADDD:
		case AFADDF:
		case AFSUBD:
		case AFSUBF:
		case AFMULD:
		case AFMULF:
		case AFDIVD:
		case AFDIVF:
			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 AFMOVF:
		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;
}
Beispiel #15
0
int
shiftprop(Reg *r)
{
	Reg *r1;
	Prog *p, *p1, *p2;
	int n, o;
	Adr a;

	p = r->prog;
	if(p->to.type != D_REG)
		FAIL("BOTCH: result not reg");
	n = p->to.reg;
	a = zprog.from;
	if(p->reg != NREG && p->reg != p->to.reg) {
		a.type = D_REG;
		a.reg = p->reg;
	}
	if(debug['H'])
		print("shiftprop\n%P", p);
	r1 = r;
	for(;;) {
		/* find first use of shift result; abort if shift operands or result are changed */
		r1 = uniqs(r1);
		if(r1 == R)
			FAIL("branch");
		if(uniqp(r1) == R)
			FAIL("merge");
		p1 = r1->prog;
		if(debug['H'])
			print("\n%P", p1);
		switch(copyu(p1, &p->to, A)) {
		case 0:	/* not used or set */
			if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
			   (a.type == D_REG && copyu(p1, &a, A) > 1))
				FAIL("args modified");
			continue;
		case 3:	/* set, not used */
			FAIL("BOTCH: noref");
		}
		break;
	}
	/* check whether substitution can be done */
	switch(p1->as) {
	default:
		FAIL("non-dpi");
	case AAND:
	case AEOR:
	case AADD:
	case AADC:
	case AORR:
	case ASUB:
	case ARSB:
	case ASBC:
	case ARSC:
		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
			if(p1->from.type != D_REG)
				FAIL("can't swap");
			p1->reg = p1->from.reg;
			p1->from.reg = n;
			switch(p1->as) {
			case ASUB:
				p1->as = ARSB;
				break;
			case ARSB:
				p1->as = ASUB;
				break;
			case ASBC:
				p1->as = ARSC;
				break;
			case ARSC:
				p1->as = ASBC;
				break;
			}
			if(debug['H'])
				print("\t=>%P", p1);
		}
	case ABIC:
	case ACMP:
	case ACMN:
		if(p1->reg == n)
			FAIL("can't swap");
		if(p1->reg == NREG && p1->to.reg == n)
			FAIL("shift result used twice");
	case AMVN:
		if(p1->from.type == D_SHIFT)
			FAIL("shift result used in shift");
		if(p1->from.type != D_REG || p1->from.reg != n)
			FAIL("BOTCH: where is it used?");
		break;
	}
	/* check whether shift result is used subsequently */
	p2 = p1;
	if(p1->to.reg != n)
	for (;;) {
		r1 = uniqs(r1);
		if(r1 == R)
			FAIL("inconclusive");
		p1 = r1->prog;
		if(debug['H'])
			print("\n%P", p1);
		switch(copyu(p1, &p->to, A)) {
		case 0:	/* not used or set */
			continue;
		case 3: /* set, not used */
			break;
		default:/* used */
			FAIL("reused");
		}
		break;
	}
	/* make the substitution */
	p2->from.type = D_SHIFT;
	p2->from.reg = NREG;
	o = p->reg;
	if(o == NREG)
		o = p->to.reg;
	switch(p->from.type){
	case D_CONST:
		o |= (p->from.offset&0x1f)<<7;
		break;
	case D_REG:
		o |= (1<<4) | (p->from.reg<<8);
		break;
	}
	switch(p->as){
	case ASLL:
		o |= 0<<5;
		break;
	case ASRL:
		o |= 1<<5;
		break;
	case ASRA:
		o |= 2<<5;
		break;
	}
	p2->from.offset = o;
	if(debug['H'])
		print("\t=>%P\tSUCCEED\n", p2);
	return 1;
}
Beispiel #16
0
void
mergetemp(Prog *firstp)
{
	int i, j, nvar, ninuse, nfree, nkill;
	TempVar *var, *v, *v1, **bystart, **inuse;
	TempFlow *r;
	NodeList *l, **lp;
	Node *n;
	Prog *p, *p1;
	Type *t;
	ProgInfo info, info1;
	int32 gen;
	Graph *g;

	enum { Debug = 0 };

	g = flowstart(firstp, sizeof(TempFlow));
	if(g == nil)
		return;

	// Build list of all mergeable variables.
	nvar = 0;
	for(l = curfn->dcl; l != nil; l = l->next)
		if(canmerge(l->n))
			nvar++;
	
	var = calloc(nvar*sizeof var[0], 1);
	nvar = 0;
	for(l = curfn->dcl; l != nil; l = l->next) {
		n = l->n;
		if(canmerge(n)) {
			v = &var[nvar++];
			n->opt = v;
			v->node = n;
		}
	}
	
	// Build list of uses.
	// We assume that the earliest reference to a temporary is its definition.
	// This is not true of variables in general but our temporaries are all
	// single-use (that's why we have so many!).
	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
		p = r->f.prog;
		proginfo(&info, p);

		if(p->from.node != N && p->from.node->opt && p->to.node != N && p->to.node->opt)
			fatal("double node %P", p);
		if((n = p->from.node) != N && (v = n->opt) != nil ||
		   (n = p->to.node) != N && (v = n->opt) != nil) {
		   	if(v->def == nil)
		   		v->def = r;
			r->uselink = v->use;
			v->use = r;
			if(n == p->from.node && (info.flags & LeftAddr))
				v->addr = 1;
		}
	}
	
	if(Debug > 1)
		dumpit("before", g->start, 0);
	
	nkill = 0;

	// Special case.
	for(v = var; v < var+nvar; v++) {
		if(v->addr)
			continue;
		// Used in only one instruction, which had better be a write.
		if((r = v->use) != nil && r->uselink == nil) {
			p = r->f.prog;
			proginfo(&info, p);
			if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
				p->as = ANOP;
				p->to = zprog.to;
				v->removed = 1;
				if(Debug)
					print("drop write-only %S\n", v->node->sym);
			} else
				fatal("temp used and not set: %P", p);
			nkill++;
			continue;
		}
		
		// Written in one instruction, read in the next, otherwise unused,
		// no jumps to the next instruction. Happens mainly in 386 compiler.
		if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) {
			p = r->f.prog;
			proginfo(&info, p);
			p1 = r->f.link->prog;
			proginfo(&info1, p1);
			enum {
				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
			};
			if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) &&
			   !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
			   (info.flags & SizeAny) == (info1.flags & SizeAny)) {
				p1->from = p->from;
				excise(&r->f);
				v->removed = 1;
				if(Debug)
					print("drop immediate-use %S\n", v->node->sym);
			}
			nkill++;
			continue;
		}			   
	}

	// Traverse live range of each variable to set start, end.
	// Each flood uses a new value of gen so that we don't have
	// to clear all the r->f.active words after each variable.
	gen = 0;
	for(v = var; v < var+nvar; v++) {
		gen++;
		for(r = v->use; r != nil; r = r->uselink)
			mergewalk(v, r, gen);
	}

	// Sort variables by start.
	bystart = malloc(nvar*sizeof bystart[0]);
	for(i=0; i<nvar; i++)
		bystart[i] = &var[i];
	qsort(bystart, nvar, sizeof bystart[0], startcmp);

	// List of in-use variables, sorted by end, so that the ones that
	// will last the longest are the earliest ones in the array.
	// The tail inuse[nfree:] holds no-longer-used variables.
	// In theory we should use a sorted tree so that insertions are
	// guaranteed O(log n) and then the loop is guaranteed O(n log n).
	// In practice, it doesn't really matter.
	inuse = malloc(nvar*sizeof inuse[0]);
	ninuse = 0;
	nfree = nvar;
	for(i=0; i<nvar; i++) {
		v = bystart[i];
		if(v->addr || v->removed)
			continue;

		// Expire no longer in use.
		while(ninuse > 0 && inuse[ninuse-1]->end < v->start) {
			v1 = inuse[--ninuse];
			inuse[--nfree] = v1;
		}

		// Find old temp to reuse if possible.
		t = v->node->type;
		for(j=nfree; j<nvar; j++) {
			v1 = inuse[j];
			if(eqtype(t, v1->node->type)) {
				inuse[j] = inuse[nfree++];
				if(v1->merge)
					v->merge = v1->merge;
				else
					v->merge = v1;
				nkill++;
				break;
			}
		}

		// Sort v into inuse.
		j = ninuse++;
		while(j > 0 && inuse[j-1]->end < v->end) {
			inuse[j] = inuse[j-1];
			j--;
		}
		inuse[j] = v;
	}

	if(Debug) {
		print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
		for(v=var; v<var+nvar; v++) {
			print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
			if(v->addr)
				print(" addr=1");
			if(v->removed)
				print(" dead=1");
			if(v->merge)
				print(" merge %#N", v->merge->node);
			if(v->start == v->end)
				print(" %P", v->def->f.prog);
			print("\n");
		}
	
		if(Debug > 1)
			dumpit("after", g->start, 0);
	}

	// Update node references to use merged temporaries.
	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
		p = r->f.prog;
		if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
			p->from.node = v->merge->node;
		if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
			p->to.node = v->merge->node;
	}

	// Delete merged nodes from declaration list.
	for(lp = &curfn->dcl; (l = *lp); ) {
		curfn->dcl->end = l;
		n = l->n;
		v = n->opt;
		if(v && (v->merge || v->removed)) {
			*lp = l->next;
			continue;
		}
		lp = &l->next;
	}

	// Clear aux structures.
	for(v=var; v<var+nvar; v++)
		v->node->opt = nil;
	free(var);
	free(bystart);
	free(inuse);
	flowend(g);
}
Beispiel #17
0
static void
nilwalkback(NilFlow *rcheck)
{
	Prog *p;
	ProgInfo info;
	NilFlow *r;
	
	for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
		p = r->f.prog;
		proginfo(&info, p);
		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
			// Found initialization of value we're checking for nil.
			// without first finding the check, so this one is unchecked.
			return;
		}
		if(r != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) {
			rcheck->kill = 1;
			return;
		}
	}

	// Here is a more complex version that scans backward across branches.
	// It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason
	// to keep the check (setting rcheck->kill = 0).
	// It doesn't handle copying of aggregates as well as I would like,
	// nor variables with their address taken,
	// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
	/*
	for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) {
		if(r1->f.active == gen)
			break;
		r1->f.active = gen;
		p = r1->f.prog;
		
		// If same check, stop this loop but still check
		// alternate predecessors up to this point.
		if(r1 != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from))
			break;

		proginfo(&info, p);
		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
			// Found initialization of value we're checking for nil.
			// without first finding the check, so this one is unchecked.
			rcheck->kill = 0;
			return;
		}
		
		if(r1->f.p1 == nil && r1->f.p2 == nil) {
			print("lost pred for %P\n", rcheck->f.prog);
			for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
				proginfo(&info, r1->f.prog);
				print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
			}
			fatal("lost pred trail");
		}
	}

	for(r = r0; r != r1; r = (NilFlow*)r->f.p1)
		for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link)
			nilwalkback(rcheck, r2, gen);
	*/
}
Beispiel #18
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 AMULLU:
		case AMULA:
		case AMVN:
			return 0;

		case ACMN:
		case AADD:
		case ASUB:
		case ASBC:
		case ARSB:
		case ASLL:
		case ASRL:
		case ASRA:
		case AORR:
		case AAND:
		case AEOR:
		case AMUL:
		case AMULU:
		case ADIV:
		case ADIVU:
		case AMOD:
		case AMODU:

		case AADDD:
		case AADDF:
		case ASUBD:
		case ASUBF:
		case AMULD:
		case AMULF:
		case ADIVD:
		case ADIVF:
			if(p->to.type == v1->type)
			if(p->to.reg == v1->reg)
			if(p->scond == C_SCOND_NONE) {
				if(p->reg == NREG)
					p->reg = p->to.reg;
				goto gotit;
			}
			break;

		case AMOVF:
		case AMOVD:
		case AMOVW:
			if(p->to.type == v1->type)
			if(p->to.reg == v1->reg)
			if(p->scond == C_SCOND_NONE)
				goto gotit;
			break;

		case AMOVM:
			t = 1<<v2->reg;
			if((p->from.type == D_CONST && (p->from.offset&t)) ||
			   (p->to.type == D_CONST && (p->to.offset&t)))
				return 0;
			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;
}
Beispiel #19
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;

	if(debug['P'] && debug['v'])
		print("subprop %P\n", r0->prog);
	p = r0->prog;
	v1 = &p->from;
	if(!regtyp(v1)) {
		if(debug['P'] && debug['v'])
			print("\tnot regtype %D; return 0\n", v1);
		return 0;
	}
	v2 = &p->to;
	if(!regtyp(v2)) {
		if(debug['P'] && debug['v'])
			print("\tnot regtype %D; return 0\n", v2);
		return 0;
	}
	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
		if(debug['P'] && debug['v'])
			print("\t? %P\n", r->prog);
		if(uniqs(r) == R) {
			if(debug['P'] && debug['v'])
				print("\tno unique successor\n");
			break;
		}
		p = r->prog;
		switch(p->as) {
		case ACALL:
			if(debug['P'] && debug['v'])
				print("\tfound %P; return 0\n", p);
			return 0;

		case AIMULL:
		case AIMULQ:
		case AIMULW:
			if(p->to.type != D_NONE)
				break;
			goto giveup;

		case ARCLB:
		case ARCLL:
		case ARCLQ:
		case ARCLW:
		case ARCRB:
		case ARCRL:
		case ARCRQ:
		case ARCRW:
		case AROLB:
		case AROLL:
		case AROLQ:
		case AROLW:
		case ARORB:
		case ARORL:
		case ARORQ:
		case ARORW:
		case ASALB:
		case ASALL:
		case ASALQ:
		case ASALW:
		case ASARB:
		case ASARL:
		case ASARQ:
		case ASARW:
		case ASHLB:
		case ASHLL:
		case ASHLQ:
		case ASHLW:
		case ASHRB:
		case ASHRL:
		case ASHRQ:
		case ASHRW:
			if(p->from.type == D_CONST)
				break;
			goto giveup;

		case ADIVB:
		case ADIVL:
		case ADIVQ:
		case ADIVW:
		case AIDIVB:
		case AIDIVL:
		case AIDIVQ:
		case AIDIVW:
		case AIMULB:
		case AMULB:
		case AMULL:
		case AMULQ:
		case AMULW:

		case AREP:
		case AREPN:

		case ACWD:
		case ACDQ:
		case ACQO:

		case ASTOSB:
		case ASTOSL:
		case ASTOSQ:
		case AMOVSB:
		case AMOVSL:
		case AMOVSQ:
		giveup:
			if(debug['P'] && debug['v'])
				print("\tfound %P; return 0\n", p);
			return 0;

		case AMOVL:
		case AMOVQ:
		case AMOVSS:
		case AMOVSD:
			if(p->to.type == v1->type)
				goto gotit;
			break;
		}
		if(copyau(&p->from, v2) ||
		   copyau(&p->to, v2)) {
		   	if(debug['P'] && debug['v'])
		   		print("\tcopyau %D failed\n", v2);
			break;
		}
		if(copysub(&p->from, v1, v2, 0) ||
		   copysub(&p->to, v1, v2, 0)) {
		   	if(debug['P'] && debug['v'])
		   		print("\tcopysub failed\n");
			break;
		}
	}
	if(debug['P'] && debug['v'])
		print("\tran off end; return 0\n");
	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);
		copysub(&p->to, v1, v2, 1);
		if(debug['P'])
			print("%P\n", r->prog);
	}
	t = v1->type;
	v1->type = v2->type;
	v2->type = t;
	if(debug['P'])
		print("%P last\n", r->prog);
	return 1;
}
Beispiel #20
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 ACALL:
			return 0;

		case AIMULL:
		case AIMULQ:
		case AIMULW:
			if(p->to.type != D_NONE)
				break;

		case ADIVB:
		case ADIVL:
		case ADIVQ:
		case ADIVW:
		case AIDIVB:
		case AIDIVL:
		case AIDIVQ:
		case AIDIVW:
		case AIMULB:
		case AMULB:
		case AMULL:
		case AMULQ:
		case AMULW:

		case ARCLB:
		case ARCLL:
		case ARCLQ:
		case ARCLW:
		case ARCRB:
		case ARCRL:
		case ARCRQ:
		case ARCRW:
		case AROLB:
		case AROLL:
		case AROLQ:
		case AROLW:
		case ARORB:
		case ARORL:
		case ARORQ:
		case ARORW:
		case ASALB:
		case ASALL:
		case ASALQ:
		case ASALW:
		case ASARB:
		case ASARL:
		case ASARQ:
		case ASARW:
		case ASHLB:
		case ASHLL:
		case ASHLQ:
		case ASHLW:
		case ASHRB:
		case ASHRL:
		case ASHRQ:
		case ASHRW:

		case AREP:
		case AREPN:

		case ACWD:
		case ACDQ:
		case ACQO:

		case ASTOSB:
		case ASTOSL:
		case ASTOSQ:
		case AMOVSB:
		case AMOVSL:
		case AMOVSQ:
			return 0;

		case AMOVL:
		case AMOVQ:
			if(p->to.type == v1->type)
				goto gotit;
			break;
		}
		if(copyau(&p->from, v2) ||
		   copyau(&p->to, v2))
			break;
		if(copysub(&p->from, 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);
		copysub(&p->to, v1, v2, 1);
		if(debug['P'])
			print("%P\n", r->prog);
	}
	t = v1->type;
	v1->type = v2->type;
	v2->type = t;
	if(debug['P'])
		print("%P last\n", r->prog);
	return 1;
}
Beispiel #21
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.
 */
static int
subprop(Flow *r0)
{
	Prog *p;
	Adr *v1, *v2;
	Flow *r;
	int t;
	ProgInfo info;

	p = r0->prog;
	v1 = &p->from;
	if(!regtyp(v1))
		return 0;
	v2 = &p->to;
	if(!regtyp(v2))
		return 0;
	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
		if(debug['P'] && debug['v'])
			print("\t? %P\n", r->prog);
		if(uniqs(r) == nil)
			break;
		p = r->prog;
		proginfo(&info, p);
		if(info.flags & Call)
			return 0;

		if(info.reguse | info.regset)
			return 0;

		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
			goto gotit;

		if(copyau(&p->from, v2) || copyau(&p->to, v2))
			break;
		if(copysub(&p->from, 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);
		copysub(&p->to, v1, v2, 1);
		if(debug['P'])
			print("%P\n", r->prog);
	}
	t = v1->type;
	v1->type = v2->type;
	v2->type = t;
	if(debug['P'])
		print("%P last\n", r->prog);
	return 1;
}
Beispiel #22
0
int
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("; %D rar; return 0\n", v2);
			return 0;

		case 3:	/* set */
			if(debug['P'])
				print("; %D set; 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("; %D used+set and f=%d; return 0\n", v2, f);
				else
					print("; %D used 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("; %D used+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("; %D set 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;
}
Beispiel #23
0
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 == ASLL || p->as == ASRL || p->as == ASRA) {
			/*
			 * elide shift into D_SHIFT operand of subsequent instruction
			 */
			if(shiftprop(r)) {
				excise(r);
				t++;
			}
		}
		if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
		if(regtyp(&p->to)) {
			if(p->from.type == D_CONST)
				constprop(&p->from, &p->to, r->s1);
			else 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(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 AEOR:
			/*
			 * EOR -1,x,y => MVN x,y
			 */
			if(p->from.type == D_CONST && p->from.offset == -1) {
				p->as = AMVN;
				p->from.type = D_REG;
				if(p->reg != NREG)
					p->from.reg = p->reg;
				else
					p->from.reg = p->to.reg;
				p->reg = NREG;
			}
			continue;
		case AMOVH:
		case AMOVHU:
		case AMOVB:
		case AMOVBU:
			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);
	}

	for(r=firstr; r!=R; r=r->link) {
		p = r->prog;
		switch(p->as) {
		case AMOVW:
		case AMOVB:
		case AMOVBU:
			if(p->from.type == D_OREG && p->from.offset == 0)
				xtramodes(r, &p->from);
			else if(p->to.type == D_OREG && p->to.offset == 0)
				xtramodes(r, &p->to);
			else
				continue;
			break;
		case ACMP:
			/*
			 * elide CMP $0,x if calculation of x can set condition codes
			 */
			if(p->from.type != D_CONST || p->from.offset != 0)
				continue;
			r2 = r->s1;
			if(r2 == R)
				continue;
			t = r2->prog->as;
			switch(t) {
			default:
				continue;
			case ABEQ:
			case ABNE:
			case ABMI:
			case ABPL:
				break;
			case ABGE:
				t = ABPL;
				break;
			case ABLT:
				t = ABMI;
				break;
			case ABHI:
				t = ABNE;
				break;
			case ABLS:
				t = ABEQ;
				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)
				continue;
			if(p1->to.reg != p->reg)
			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
				continue;
			switch(p1->as) {
			default:
				continue;
			case AMOVW:
				if(p1->from.type != D_REG)
					continue;
			case AAND:
			case AEOR:
			case AORR:
			case ABIC:
			case AMVN:
			case ASUB:
			case ARSB:
			case AADD:
			case AADC:
			case ASBC:
			case ARSC:
				break;
			}
			p1->scond |= C_SBIT;
			r2->prog->as = t;
			excise(r);
			continue;
		}
	}

	predicate();
}