Example #1
0
File: peep.go Project: hurkgu/go
func peep(firstp *obj.Prog) {
	g := gc.Flowstart(firstp, nil)
	if g == nil {
		return
	}
	gactive = 0

	run := func(name string, pass func(r *gc.Flow) int) int {
		n := pass(g.Start)
		if gc.Debug['P'] != 0 {
			fmt.Println(name, ":", n)
		}
		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
			gc.Dumpit(name, g.Start, 0)
		}
		return n
	}

	for {
		n := 0
		n += run("constant propagation", constantPropagation)
		n += run("copy propagation", copyPropagation)
		n += run("cast propagation", castPropagation)
		n += run("remove load-hit-stores", removeLoadHitStores)
		n += run("dead code elimination", deadCodeElimination)
		if n == 0 {
			break
		}
	}
	run("fuse op moves", fuseOpMoves)
	run("fuse clears", fuseClear)
	run("load pipelining", loadPipelining)
	run("fuse compare branch", fuseCompareBranch)
	run("simplify ops", simplifyOps)
	run("dead code elimination", deadCodeElimination)

	// TODO(mundaym): load/store multiple aren't currently handled by copyu
	// so this pass must be last.
	run("fuse multiple", fuseMultiple)

	gc.Flowend(g)
}
Example #2
0
File: peep.go Project: hurkgu/go
func peep(firstp *obj.Prog) {
	g := gc.Flowstart(firstp, nil)
	if g == nil {
		return
	}
	gactive = 0

	var p *obj.Prog
	var r *gc.Flow
	var t obj.As
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog

		// TODO(austin) Handle smaller moves.  arm and amd64
		// distinguish between moves that moves that *must*
		// sign/zero extend and moves that don't care so they
		// can eliminate moves that don't care without
		// breaking moves that do care. This might let us
		// simplify or remove the next peep loop, too.
		if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD {
			if regtyp(&p.To) {
				// Try to eliminate reg->reg moves
				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++
						}
					}
				}

				// Convert uses to $0 to uses of R0 and
				// propagate R0
				if regzer(&p.From) {
					if p.To.Type == obj.TYPE_REG {
						p.From.Type = obj.TYPE_REG
						p.From.Reg = ppc64.REGZERO
						if copyprop(r) {
							excise(r)
							t++
						} else if subprop(r) && copyprop(r) {
							excise(r)
							t++
						}
					}
				}
			}
		}
	}

	if t != 0 {
		goto loop1
	}

	/*
	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
	 */
	var p1 *obj.Prog
	var r1 *gc.Flow
	for r := g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		default:
			continue

		case ppc64.AMOVH,
			ppc64.AMOVHZ,
			ppc64.AMOVB,
			ppc64.AMOVBZ,
			ppc64.AMOVW,
			ppc64.AMOVWZ:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
		}

		r1 = r.Link
		if r1 == nil {
			continue
		}
		p1 = r1.Prog
		if p1.As != p.As {
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}
		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
			continue
		}
		excise(r1)
	}

	if gc.Debug['D'] > 1 {
		goto ret /* 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 := g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case ppc64.ACMP,
			ppc64.ACMPW: /* always safe? */
			if !regzer(&p.To) {
				continue
			}
			r1 = r.S1
			if r1 == nil {
				continue
			}
			switch r1.Prog.As {
			default:
				continue

				/* the conditions can be complex and these are currently little used */
			case ppc64.ABCL,
				ppc64.ABC:
				continue

			case ppc64.ABEQ,
				ppc64.ABGE,
				ppc64.ABGT,
				ppc64.ABLE,
				ppc64.ABLT,
				ppc64.ABNE,
				ppc64.ABVC,
				ppc64.ABVS:
				break
			}

			r1 = r
			for {
				r1 = gc.Uniqp(r1)
				if r1 == nil || r1.Prog.As != obj.ANOP {
					break
				}
			}

			if r1 == nil {
				continue
			}
			p1 = r1.Prog
			if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg {
				continue
			}
			switch p1.As {
			/* irregular instructions */
			case ppc64.ASUB,
				ppc64.AADD,
				ppc64.AXOR,
				ppc64.AOR:
				if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR {
					continue
				}
			}

			switch p1.As {
			default:
				continue

			case ppc64.AMOVW,
				ppc64.AMOVD:
				if p1.From.Type != obj.TYPE_REG {
					continue
				}
				continue

			case ppc64.AANDCC,
				ppc64.AANDNCC,
				ppc64.AORCC,
				ppc64.AORNCC,
				ppc64.AXORCC,
				ppc64.ASUBCC,
				ppc64.ASUBECC,
				ppc64.ASUBMECC,
				ppc64.ASUBZECC,
				ppc64.AADDCC,
				ppc64.AADDCCC,
				ppc64.AADDECC,
				ppc64.AADDMECC,
				ppc64.AADDZECC,
				ppc64.ARLWMICC,
				ppc64.ARLWNMCC,
				/* don't deal with floating point instructions for now */
				/*
					case AFABS:
					case AFADD:
					case AFADDS:
					case AFCTIW:
					case AFCTIWZ:
					case AFDIV:
					case AFDIVS:
					case AFMADD:
					case AFMADDS:
					case AFMOVD:
					case AFMSUB:
					case AFMSUBS:
					case AFMUL:
					case AFMULS:
					case AFNABS:
					case AFNEG:
					case AFNMADD:
					case AFNMADDS:
					case AFNMSUB:
					case AFNMSUBS:
					case AFRSP:
					case AFSUB:
					case AFSUBS:
					case ACNTLZW:
					case AMTFSB0:
					case AMTFSB1:
				*/
				ppc64.AADD,
				ppc64.AADDV,
				ppc64.AADDC,
				ppc64.AADDCV,
				ppc64.AADDME,
				ppc64.AADDMEV,
				ppc64.AADDE,
				ppc64.AADDEV,
				ppc64.AADDZE,
				ppc64.AADDZEV,
				ppc64.AAND,
				ppc64.AANDN,
				ppc64.ADIVW,
				ppc64.ADIVWV,
				ppc64.ADIVWU,
				ppc64.ADIVWUV,
				ppc64.ADIVD,
				ppc64.ADIVDV,
				ppc64.ADIVDU,
				ppc64.ADIVDUV,
				ppc64.AEQV,
				ppc64.AEXTSB,
				ppc64.AEXTSH,
				ppc64.AEXTSW,
				ppc64.AMULHW,
				ppc64.AMULHWU,
				ppc64.AMULLW,
				ppc64.AMULLWV,
				ppc64.AMULHD,
				ppc64.AMULHDU,
				ppc64.AMULLD,
				ppc64.AMULLDV,
				ppc64.ANAND,
				ppc64.ANEG,
				ppc64.ANEGV,
				ppc64.ANOR,
				ppc64.AOR,
				ppc64.AORN,
				ppc64.AREM,
				ppc64.AREMV,
				ppc64.AREMU,
				ppc64.AREMUV,
				ppc64.AREMD,
				ppc64.AREMDV,
				ppc64.AREMDU,
				ppc64.AREMDUV,
				ppc64.ARLWMI,
				ppc64.ARLWNM,
				ppc64.ASLW,
				ppc64.ASRAW,
				ppc64.ASRW,
				ppc64.ASLD,
				ppc64.ASRAD,
				ppc64.ASRD,
				ppc64.ASUB,
				ppc64.ASUBV,
				ppc64.ASUBC,
				ppc64.ASUBCV,
				ppc64.ASUBME,
				ppc64.ASUBMEV,
				ppc64.ASUBE,
				ppc64.ASUBEV,
				ppc64.ASUBZE,
				ppc64.ASUBZEV,
				ppc64.AXOR:
				t = variant2as(p1.As, as2variant(p1.As)|V_CC)
			}

			if gc.Debug['D'] != 0 {
				fmt.Printf("cmp %v; %v -> ", p1, p)
			}
			p1.As = t
			if gc.Debug['D'] != 0 {
				fmt.Printf("%v\n", p1)
			}
			excise(r)
			continue
		}
	}

ret:
	gc.Flowend(g)
}
Example #3
0
// UNUSED
func peep(firstp *obj.Prog) {
	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
	if g == nil {
		return
	}
	gactive = 0

	var r *gc.Flow
	var p *obj.Prog
	var t int
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		/*
		 * elide shift into TYPE_SHIFT operand of subsequent instruction
		 */
		//			if(shiftprop(r)) {
		//				excise(r);
		//				t++;
		//				break;
		//			}
		case arm.ASLL,
			arm.ASRL,
			arm.ASRA:
			break

		case arm.AMOVB,
			arm.AMOVH,
			arm.AMOVW,
			arm.AMOVF,
			arm.AMOVD:
			if regtyp(&p.From) {
				if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) {
					if p.Scond == arm.C_SCOND_NONE {
						if copyprop(g, r) {
							excise(r)
							t++
							break
						}

						if subprop(r) && copyprop(g, r) {
							excise(r)
							t++
							break
						}
					}
				}
			}

		case arm.AMOVHS,
			arm.AMOVHU,
			arm.AMOVBS,
			arm.AMOVBU:
			if p.From.Type == obj.TYPE_REG {
				if shortprop(r) {
					t++
				}
			}
		}
	}

	/*
		if(p->scond == C_SCOND_NONE)
		if(regtyp(&p->to))
		if(isdconst(&p->from)) {
			constprop(&p->from, &p->to, r->s1);
		}
		break;
	*/
	if t != 0 {
		goto loop1
	}

	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		/*
		 * EOR -1,x,y => MVN x,y
		 */
		case arm.AEOR:
			if isdconst(&p.From) && p.From.Offset == -1 {
				p.As = arm.AMVN
				p.From.Type = obj.TYPE_REG
				if p.Reg != 0 {
					p.From.Reg = p.Reg
				} else {
					p.From.Reg = p.To.Reg
				}
				p.Reg = 0
			}
		}
	}

	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case arm.AMOVW,
			arm.AMOVB,
			arm.AMOVBS,
			arm.AMOVBU:
			if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 {
				xtramodes(g, r, &p.From)
			} else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 {
				xtramodes(g, r, &p.To)
			} else {
				continue
			}
		}
	}

	//		case ACMP:
	//			/*
	//			 * elide CMP $0,x if calculation of x can set condition codes
	//			 */
	//			if(isdconst(&p->from) || p->from.offset != 0)
	//				continue;
	//			r2 = r->s1;
	//			if(r2 == nil)
	//				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 != nil && r1->prog->as == ANOP);
	//			if(r1 == nil)
	//				continue;
	//			p1 = r1->prog;
	//			if(p1->to.type != TYPE_REG)
	//				continue;
	//			if(p1->to.reg != p->reg)
	//			if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
	//				continue;
	//
	//			switch(p1->as) {
	//			default:
	//				continue;
	//			case AMOVW:
	//				if(p1->from.type != TYPE_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(g);

	gc.Flowend(g)
}
Example #4
0
File: peep.go Project: danny8002/go
func peep(firstp *obj.Prog) {
	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
	if g == nil {
		return
	}
	gactive = 0

	// byte, word arithmetic elimination.
	elimshortmov(g)

	// constant propagation
	// find MOV $con,R followed by
	// another MOV $con,R without
	// setting R in the interim
	var p *obj.Prog
	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case x86.ALEAL,
			x86.ALEAQ:
			if regtyp(&p.To) {
				if p.From.Sym != nil {
					if p.From.Index == x86.REG_NONE {
						conprop(r)
					}
				}
			}

		case x86.AMOVB,
			x86.AMOVW,
			x86.AMOVL,
			x86.AMOVQ,
			x86.AMOVSS,
			x86.AMOVSD:
			if regtyp(&p.To) {
				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
					conprop(r)
				}
			}
		}
	}

	var r *gc.Flow
	var r1 *gc.Flow
	var p1 *obj.Prog
	var t int
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case x86.AMOVL,
			x86.AMOVQ,
			x86.AMOVSS,
			x86.AMOVSD:
			if regtyp(&p.To) {
				if regtyp(&p.From) {
					if copyprop(g, r) {
						excise(r)
						t++
					} else if subprop(r) && copyprop(g, r) {
						excise(r)
						t++
					}
				}
			}

		case x86.AMOVBLZX,
			x86.AMOVWLZX,
			x86.AMOVBLSX,
			x86.AMOVWLSX:
			if regtyp(&p.To) {
				r1 = rnops(gc.Uniqs(r))
				if r1 != nil {
					p1 = r1.Prog
					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
						p1.As = x86.AMOVL
						t++
					}
				}
			}

		case x86.AMOVBQSX,
			x86.AMOVBQZX,
			x86.AMOVWQSX,
			x86.AMOVWQZX,
			x86.AMOVLQSX,
			x86.AMOVLQZX,
			x86.AMOVQL:
			if regtyp(&p.To) {
				r1 = rnops(gc.Uniqs(r))
				if r1 != nil {
					p1 = r1.Prog
					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
						p1.As = x86.AMOVQ
						t++
					}
				}
			}

		case x86.AADDL,
			x86.AADDQ,
			x86.AADDW:
			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
				break
			}
			if p.From.Offset == -1 {
				if p.As == x86.AADDQ {
					p.As = x86.ADECQ
				} else if p.As == x86.AADDL {
					p.As = x86.ADECL
				} else {
					p.As = x86.ADECW
				}
				p.From = obj.Addr{}
				break
			}

			if p.From.Offset == 1 {
				if p.As == x86.AADDQ {
					p.As = x86.AINCQ
				} else if p.As == x86.AADDL {
					p.As = x86.AINCL
				} else {
					p.As = x86.AINCW
				}
				p.From = obj.Addr{}
				break
			}

		case x86.ASUBL,
			x86.ASUBQ,
			x86.ASUBW:
			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
				break
			}
			if p.From.Offset == -1 {
				if p.As == x86.ASUBQ {
					p.As = x86.AINCQ
				} else if p.As == x86.ASUBL {
					p.As = x86.AINCL
				} else {
					p.As = x86.AINCW
				}
				p.From = obj.Addr{}
				break
			}

			if p.From.Offset == 1 {
				if p.As == x86.ASUBQ {
					p.As = x86.ADECQ
				} else if p.As == x86.ASUBL {
					p.As = x86.ADECL
				} else {
					p.As = x86.ADECW
				}
				p.From = obj.Addr{}
				break
			}
		}
	}

	if t != 0 {
		goto loop1
	}

	// MOVLQZX removal.
	// The MOVLQZX exists to avoid being confused for a
	// MOVL that is just copying 32-bit data around during
	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
	// will have already cleared the high bits.
	//
	// MOVSD removal.
	// We never use packed registers, so a MOVSD between registers
	// can be replaced by MOVAPD, which moves the pair of float64s
	// instead of just the lower one.  We only use the lower one, but
	// the processor can do better if we do moves using both.
	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		if p.As == x86.AMOVLQZX {
			if regtyp(&p.From) {
				if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg {
					if prevl(r, int(p.From.Reg)) {
						excise(r)
					}
				}
			}
		}

		if p.As == x86.AMOVSD {
			if regtyp(&p.From) {
				if regtyp(&p.To) {
					p.As = x86.AMOVAPD
				}
			}
		}
	}

	// load pipelining
	// push any load from memory as early as possible
	// to give it time to complete before use.
	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case x86.AMOVB,
			x86.AMOVW,
			x86.AMOVL,
			x86.AMOVQ,
			x86.AMOVLQZX:
			if regtyp(&p.To) && !regconsttyp(&p.From) {
				pushback(r)
			}
		}
	}

	gc.Flowend(g)
}
Example #5
0
File: peep.go Project: ckeyer/gosrc
func peep(firstp *obj.Prog) {
	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
	if g == nil {
		return
	}
	gactive = 0

	var p *obj.Prog
	var r *gc.Flow
	var t int
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog

		// TODO(austin) Handle smaller moves.  arm and amd64
		// distinguish between moves that moves that *must*
		// sign/zero extend and moves that don't care so they
		// can eliminate moves that don't care without
		// breaking moves that do care.  This might let us
		// simplify or remove the next peep loop, too.
		if p.As == mips.AMOVV || p.As == mips.AMOVF || p.As == mips.AMOVD {
			if regtyp(&p.To) {
				// Try to eliminate reg->reg moves
				if regtyp(&p.From) {
					if isfreg(&p.From) == isfreg(&p.To) {
						if copyprop(r) {
							excise(r)
							t++
						} else if subprop(r) && copyprop(r) {
							excise(r)
							t++
						}
					}
				}

				// Convert uses to $0 to uses of R0 and
				// propagate R0
				if regzer(&p.From) != 0 {
					if p.To.Type == obj.TYPE_REG && !isfreg(&p.To) {
						p.From.Type = obj.TYPE_REG
						p.From.Reg = mips.REGZERO
						if copyprop(r) {
							excise(r)
							t++
						} else if subprop(r) && copyprop(r) {
							excise(r)
							t++
						}
					}
				}
			}
		}
	}

	if t != 0 {
		goto loop1
	}

	/*
	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
	 */
	var p1 *obj.Prog
	var r1 *gc.Flow
	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		default:
			continue

		case mips.AMOVH,
			mips.AMOVHU,
			mips.AMOVB,
			mips.AMOVBU,
			mips.AMOVW,
			mips.AMOVWU:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
		}

		r1 = r.Link
		if r1 == nil {
			continue
		}
		p1 = r1.Prog
		if p1.As != p.As {
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}
		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
			continue
		}
		excise(r1)
	}

	gc.Flowend(g)
}
Example #6
0
File: peep.go Project: sreis/go
func peep(firstp *obj.Prog) {
	g := gc.Flowstart(firstp, nil)
	if g == nil {
		return
	}
	gactive = 0

	// byte, word arithmetic elimination.
	elimshortmov(g)

	// constant propagation
	// find MOV $con,R followed by
	// another MOV $con,R without
	// setting R in the interim
	var p *obj.Prog
	for r := g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case x86.ALEAL:
			if regtyp(&p.To) {
				if p.From.Sym != nil {
					if p.From.Index == x86.REG_NONE {
						conprop(r)
					}
				}
			}

		case x86.AMOVB,
			x86.AMOVW,
			x86.AMOVL,
			x86.AMOVSS,
			x86.AMOVSD:
			if regtyp(&p.To) {
				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
					conprop(r)
				}
			}
		}
	}

	var r1 *gc.Flow
	var p1 *obj.Prog
	var r *gc.Flow
	var t int
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		case x86.AMOVL,
			x86.AMOVSS,
			x86.AMOVSD:
			if regtyp(&p.To) {
				if regtyp(&p.From) {
					if copyprop(g, r) {
						excise(r)
						t++
					} else if subprop(r) && copyprop(g, r) {
						excise(r)
						t++
					}
				}
			}

		case x86.AMOVBLZX,
			x86.AMOVWLZX,
			x86.AMOVBLSX,
			x86.AMOVWLSX:
			if regtyp(&p.To) {
				r1 = rnops(gc.Uniqs(r))
				if r1 != nil {
					p1 = r1.Prog
					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
						p1.As = x86.AMOVL
						t++
					}
				}
			}

		case x86.AADDL,
			x86.AADDW:
			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
				break
			}
			if p.From.Offset == -1 {
				if p.As == x86.AADDL {
					p.As = x86.ADECL
				} else {
					p.As = x86.ADECW
				}
				p.From = obj.Addr{}
				break
			}

			if p.From.Offset == 1 {
				if p.As == x86.AADDL {
					p.As = x86.AINCL
				} else {
					p.As = x86.AINCW
				}
				p.From = obj.Addr{}
				break
			}

		case x86.ASUBL,
			x86.ASUBW:
			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
				break
			}
			if p.From.Offset == -1 {
				if p.As == x86.ASUBL {
					p.As = x86.AINCL
				} else {
					p.As = x86.AINCW
				}
				p.From = obj.Addr{}
				break
			}

			if p.From.Offset == 1 {
				if p.As == x86.ASUBL {
					p.As = x86.ADECL
				} else {
					p.As = x86.ADECW
				}
				p.From = obj.Addr{}
				break
			}
		}
	}

	if t != 0 {
		goto loop1
	}

	// MOVSD removal.
	// We never use packed registers, so a MOVSD between registers
	// can be replaced by MOVAPD, which moves the pair of float64s
	// instead of just the lower one. We only use the lower one, but
	// the processor can do better if we do moves using both.
	for r := g.Start; r != nil; r = r.Link {
		p = r.Prog
		if p.As == x86.AMOVSD {
			if regtyp(&p.From) {
				if regtyp(&p.To) {
					p.As = x86.AMOVAPD
				}
			}
		}
	}

	gc.Flowend(g)
}
Example #7
0
func peep(firstp *obj.Prog) {
	g := gc.Flowstart(firstp, nil)
	if g == nil {
		return
	}
	gactive = 0

	var p *obj.Prog
	var r *gc.Flow
	var t int
loop1:
	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("loop1", g.Start, 0)
	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog

		// TODO(minux) Handle smaller moves. arm and amd64
		// distinguish between moves that *must* sign/zero
		// extend and moves that don't care so they
		// can eliminate moves that don't care without
		// breaking moves that do care. This might let us
		// simplify or remove the next peep loop, too.
		if p.As == arm64.AMOVD || p.As == arm64.AFMOVD {
			if regtyp(&p.To) {
				// Try to eliminate reg->reg moves
				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 != 0 {
		goto loop1
	}

	/*
	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
	 */
	var p1 *obj.Prog
	var r1 *gc.Flow
	for r := g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		default:
			continue

		case arm64.AMOVH,
			arm64.AMOVHU,
			arm64.AMOVB,
			arm64.AMOVBU,
			arm64.AMOVW,
			arm64.AMOVWU:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
		}

		r1 = r.Link
		if r1 == nil {
			continue
		}
		p1 = r1.Prog
		if p1.As != p.As {
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}
		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
			continue
		}
		excise(r1)
	}

	if gc.Debug['D'] > 1 {
		goto ret /* allow following code improvement to be suppressed */
	}

	// MOVD $c, R'; ADD R', R (R' unused) -> ADD $c, R
	for r := g.Start; r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		default:
			continue

		case arm64.AMOVD:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
			if p.From.Type != obj.TYPE_CONST {
				continue
			}
			if p.From.Offset < 0 || 4096 <= p.From.Offset {
				continue
			}
		}
		r1 = r.Link
		if r1 == nil {
			continue
		}
		p1 = r1.Prog
		if p1.As != arm64.AADD && p1.As != arm64.ASUB { // TODO(aram): also logical after we have bimm.
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}
		if p1.To.Type != obj.TYPE_REG {
			continue
		}
		if gc.Debug['P'] != 0 {
			fmt.Printf("encoding $%d directly into %v in:\n%v\n%v\n", p.From.Offset, obj.Aconv(p1.As), p, p1)
		}
		p1.From.Type = obj.TYPE_CONST
		p1.From = p.From
		excise(r)
	}

	/* TODO(minux):
	 * look for OP x,y,R; CMP R, $0 -> OP.S x,y,R
	 * when OP can set condition codes correctly
	 */

ret:
	gc.Flowend(g)
}
Example #8
0
File: peep.go Project: wycharry/go
func peep(firstp *obj.Prog) {
	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
	if g == nil {
		return
	}
	gactive = 0

	var p *obj.Prog

	if false {
		// constant propagation
		// find MOV $con,R followed by
		// another MOV $con,R without
		// setting R in the interim
		for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
			p = r.Prog
			switch p.As {
			case s390x.AMOVB,
				s390x.AMOVW,
				s390x.AMOVD:
				if regtyp(&p.To) {
					if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
						conprop(r)
					}
				}
			}
		}
	}

	var r *gc.Flow
	var t int
loop1:
	//	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
	//		gc.Dumpit("loop1", g.Start, 0)
	//	}

	t = 0
	for r = g.Start; r != nil; r = r.Link {
		p = r.Prog

		// TODO(austin) Handle smaller moves.  arm and amd64
		// distinguish between moves that moves that *must*
		// sign/zero extend and moves that don't care so they
		// can eliminate moves that don't care without
		// breaking moves that do care.  This might let us
		// simplify or remove the next peep loop, too.
		if p.As == s390x.AMOVD || p.As == s390x.AFMOVD {
			if regtyp(&p.To) {
				// Try to eliminate reg->reg moves
				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++
						}
					}
				}

				// Convert uses to $0 to uses of R0 and
				// propagate R0
				if regzer(&p.From) != 0 {
					if p.To.Type == obj.TYPE_REG {
						p.From.Type = obj.TYPE_REG
						p.From.Reg = s390x.REGZERO
						if copyprop(r) {
							excise(r)
							t++
						} else if subprop(r) && copyprop(r) {
							excise(r)
							t++
						}
					}
				}
			}
		}
	}

	if t != 0 {
		goto loop1
	}

	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
		gc.Dumpit("pass7 copyprop", g.Start, 0)
	}

	/*
	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
	 */
	var p1 *obj.Prog
	var r1 *gc.Flow
	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		p = r.Prog
		switch p.As {
		default:
			continue

		case s390x.AMOVH,
			s390x.AMOVHZ,
			s390x.AMOVB,
			s390x.AMOVBZ,
			s390x.AMOVW,
			s390x.AMOVWZ:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
		}

		r1 = r.Link
		if r1 == nil {
			continue
		}
		p1 = r1.Prog
		if p1.As != p.As {
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}
		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
			continue
		}
		excise(r1)
	}

	if gc.Debug['P'] > 1 {
		goto ret /* allow following code improvement to be suppressed */
	}

	if gc.Debug['p'] == 0 {
		// load pipelining
		// push any load from memory as early as possible
		// to give it time to complete before use.
		for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
			p = r.Prog
			switch p.As {
			case s390x.AMOVB,
				s390x.AMOVW,
				s390x.AMOVD:

				if regtyp(&p.To) && !regconsttyp(&p.From) {
					pushback(r)
				}
			}
		}
		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
			gc.Dumpit("pass8 push load as early as possible", g.Start, 0)
		}

	}

	/*
	 * look for OP a, b, c; MOV c, d; -> OP a, b, d;
	 */

	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {

		if (gc.Debugmergeopmv != -1) && (mergeopmv_cnt >= gc.Debugmergeopmv) {
			break
		}

		p = r.Prog

		switch p.As {
		case s390x.AADD,
			s390x.AADDC,
			s390x.AADDME,
			s390x.AADDE,
			s390x.AADDZE,
			s390x.AAND,
			s390x.AANDN,
			s390x.ADIVW,
			s390x.ADIVWU,
			s390x.ADIVD,
			s390x.ADIVDU,
			s390x.AMULLW,
			s390x.AMULHD,
			s390x.AMULHDU,
			s390x.AMULLD,
			s390x.ANAND,
			s390x.ANOR,
			s390x.AOR,
			s390x.AORN,
			s390x.AREM,
			s390x.AREMU,
			s390x.AREMD,
			s390x.AREMDU,
			s390x.ARLWMI,
			s390x.ARLWNM,
			s390x.ASLW,
			s390x.ASRAW,
			s390x.ASRW,
			s390x.ASLD,
			s390x.ASRAD,
			s390x.ASRD,
			s390x.ASUB,
			s390x.ASUBC,
			s390x.ASUBME,
			s390x.ASUBE,
			s390x.ASUBZE,
			s390x.AXOR:
			if p.To.Type != obj.TYPE_REG {
				continue
			}
			if p.Reg == 0 { // Only for 3 ops instruction
				continue
			}
		default:
			continue
		}

		r1 := r.Link
		for ; r1 != nil; r1 = r1.Link {
			if r1.Prog.As != obj.ANOP {
				break
			}
		}

		if r1 == nil {
			continue
		}

		p1 := r1.Prog
		switch p1.As {
		case s390x.AMOVD,
			s390x.AMOVW, s390x.AMOVWZ,
			s390x.AMOVH, s390x.AMOVHZ,
			s390x.AMOVB, s390x.AMOVBZ:
			if p1.To.Type != obj.TYPE_REG {
				continue
			}

		default:
			continue
		}
		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
			continue
		}

		if trymergeopmv(r1) {
			p.To = p1.To
			excise(r1)
			mergeopmv_cnt += 1
		}
	}

	if gc.Debug['v'] != 0 {
		gc.Dumpit("Merge operation and move", g.Start, 0)
	}

	/*
	 * look for CMP x, y; Branch -> Compare and branch
	 */

	if gc.Debugcnb == 0 {
		goto ret
	}

	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
		if (gc.Debugcnb != -1) && (cnb_cnt >= gc.Debugcnb) {
			break
		}
		p = r.Prog
		r1 = gc.Uniqs(r)
		if r1 == nil {
			continue
		}
		p1 = r1.Prog

		switch p.As {
		case s390x.ACMP:
			switch p1.As {
			case s390x.ABCL, s390x.ABC:
				continue
			case s390x.ABEQ:
				t = s390x.ACMPBEQ
			case s390x.ABGE:
				t = s390x.ACMPBGE
			case s390x.ABGT:
				t = s390x.ACMPBGT
			case s390x.ABLE:
				t = s390x.ACMPBLE
			case s390x.ABLT:
				t = s390x.ACMPBLT
			case s390x.ABNE:
				t = s390x.ACMPBNE
			default:
				continue
			}

		case s390x.ACMPU:
			switch p1.As {
			case s390x.ABCL, s390x.ABC:
				continue
			case s390x.ABEQ:
				t = s390x.ACMPUBEQ
			case s390x.ABGE:
				t = s390x.ACMPUBGE
			case s390x.ABGT:
				t = s390x.ACMPUBGT
			case s390x.ABLE:
				t = s390x.ACMPUBLE
			case s390x.ABLT:
				t = s390x.ACMPUBLT
			case s390x.ABNE:
				t = s390x.ACMPUBNE
			default:
				continue
			}

		case s390x.ACMPW, s390x.ACMPWU:
			continue

		default:
			continue
		}

		if gc.Debug['D'] != 0 {
			fmt.Printf("cnb %v; %v -> ", p, p1)
		}

		if p1.To.Sym != nil {
			continue
		}

		if p.To.Type == obj.TYPE_REG {
			p1.As = int16(t)
			p1.From = p.From
			p1.Reg = p.To.Reg
			p1.From3 = nil
		} else if p.To.Type == obj.TYPE_CONST {
			switch p.As {
			case s390x.ACMP, s390x.ACMPW:
				if (p.To.Offset < -(1 << 7)) || (p.To.Offset >= ((1 << 7) - 1)) {
					continue
				}
			case s390x.ACMPU, s390x.ACMPWU:
				if p.To.Offset >= (1 << 8) {
					continue
				}
			default:
			}
			p1.As = int16(t)
			p1.From = p.From
			p1.Reg = 0
			p1.From3 = new(obj.Addr)
			*(p1.From3) = p.To
		} else {
			continue
		}

		if gc.Debug['D'] != 0 {
			fmt.Printf("%v\n", p1)
		}
		cnb_cnt += 1
		excise(r)
	}

	if gc.Debug['v'] != 0 {
		gc.Dumpit("compare and branch", g.Start, 0)
	}

ret:
	gc.Flowend(g)
}