Example #1
0
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
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(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) {
					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 := 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 #3
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 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 #4
0
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 #5
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 #6
0
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,
			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 := 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, 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 := 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 #7
0
// UNUSED
func peep(firstp *obj.Prog) {
	g := gc.Flowstart(firstp, nil)
	if g == nil {
		return
	}
	gactive = 0

	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 := 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 := 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)
}