Example #1
0
func gclean() {
	for _, r := range Thearch.ReservedRegs {
		reg[r-Thearch.REGMIN]--
	}

	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
		n := reg[r-Thearch.REGMIN]
		if n != 0 {
			if Debug['v'] != 0 {
				Regdump()
			}
			Yyerror("reg %v left allocated", obj.Rconv(r))
		}
	}

	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
		n := reg[r-Thearch.REGMIN]
		if n != 0 {
			if Debug['v'] != 0 {
				Regdump()
			}
			Yyerror("reg %v left allocated", obj.Rconv(r))
		}
	}
}
Example #2
0
func Regdump() {
	if Debug['v'] == 0 {
		fmt.Printf("run compiler with -v for register allocation sites\n")
		return
	}

	dump := func(r int) {
		stk := regstk[r-Thearch.REGMIN]
		if len(stk) == 0 {
			return
		}
		fmt.Printf("reg %v allocated at:\n", obj.Rconv(r))
		fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1))
	}

	for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
		if reg[r-Thearch.REGMIN] != 0 {
			dump(r)
		}
	}
	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
		if reg[r-Thearch.REGMIN] == 0 {
			dump(r)
		}
	}
}
Example #3
0
// If s==nil, copyu returns the set/use of v in p; otherwise, it
// modifies p to replace reads of v with reads of s and returns 0 for
// success or non-zero for failure.
//
// If s==nil, copy returns one of the following values:
//	1 if v only used
//	2 if v is set and used in one address (read-alter-rewrite;
//	  can't substitute)
//	3 if v is only set
//	4 if v is set in one address and used in another (so addresses
//	  can be rewritten independently)
//	0 otherwise (not touched)
func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
	if p.From3Type() != obj.TYPE_NONE {
		// 7g never generates a from3
		fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
	}
	if p.RegTo2 != obj.REG_NONE {
		// 7g never generates a to2
		fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2)))
	}

	switch p.As {
	default:
		fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
		return 2

	case obj.ANOP, /* read p->from, write p->to */
		arm64.ANEG,
		arm64.AFNEGD,
		arm64.AFNEGS,
		arm64.AFSQRTD,
		arm64.AFCVTZSD,
		arm64.AFCVTZSS,
		arm64.AFCVTZSDW,
		arm64.AFCVTZSSW,
		arm64.AFCVTZUD,
		arm64.AFCVTZUS,
		arm64.AFCVTZUDW,
		arm64.AFCVTZUSW,
		arm64.AFCVTSD,
		arm64.AFCVTDS,
		arm64.ASCVTFD,
		arm64.ASCVTFS,
		arm64.ASCVTFWD,
		arm64.ASCVTFWS,
		arm64.AUCVTFD,
		arm64.AUCVTFS,
		arm64.AUCVTFWD,
		arm64.AUCVTFWS,
		arm64.AMOVB,
		arm64.AMOVBU,
		arm64.AMOVH,
		arm64.AMOVHU,
		arm64.AMOVW,
		arm64.AMOVWU,
		arm64.AMOVD,
		arm64.AFMOVS,
		arm64.AFMOVD:
		if p.Scond == 0 {
			if s != nil {
				if copysub(&p.From, v, s, true) {
					return 1
				}

				// Update only indirect uses of v in p->to
				if !copyas(&p.To, v) {
					if copysub(&p.To, v, s, true) {
						return 1
					}
				}
				return 0
			}

			if copyas(&p.To, v) {
				// Fix up implicit from
				if p.From.Type == obj.TYPE_NONE {
					p.From = p.To
				}
				if copyau(&p.From, v) {
					return 4
				}
				return 3
			}

			if copyau(&p.From, v) {
				return 1
			}
			if copyau(&p.To, v) {
				// p->to only indirectly uses v
				return 1
			}

			return 0
		}

		/* rar p->from, write p->to or read p->from, rar p->to */
		if p.From.Type == obj.TYPE_MEM {
			if copyas(&p.From, v) {
				// No s!=nil check; need to fail
				// anyway in that case
				return 2
			}

			if s != nil {
				if copysub(&p.To, v, s, true) {
					return 1
				}
				return 0
			}

			if copyas(&p.To, v) {
				return 3
			}
		} else if p.To.Type == obj.TYPE_MEM {
			if copyas(&p.To, v) {
				return 2
			}
			if s != nil {
				if copysub(&p.From, v, s, true) {
					return 1
				}
				return 0
			}

			if copyau(&p.From, v) {
				return 1
			}
		} else {
			fmt.Printf("copyu: bad %v\n", p)
		}

		return 0

	case arm64.AADD, /* read p->from, read p->reg, write p->to */
		arm64.AADDS,
		arm64.ASUB,
		arm64.AADC,
		arm64.AAND,
		arm64.AORR,
		arm64.AEOR,
		arm64.AROR,
		arm64.AMUL,
		arm64.ASMULL,
		arm64.AUMULL,
		arm64.ASMULH,
		arm64.AUMULH,
		arm64.ASDIV,
		arm64.AUDIV,
		arm64.ALSL,
		arm64.ALSR,
		arm64.AASR,
		arm64.AFADDD,
		arm64.AFADDS,
		arm64.AFSUBD,
		arm64.AFSUBS,
		arm64.AFMULD,
		arm64.AFMULS,
		arm64.AFDIVD,
		arm64.AFDIVS:
		if s != nil {
			if copysub(&p.From, v, s, true) {
				return 1
			}
			if copysub1(p, v, s, true) {
				return 1
			}

			// Update only indirect uses of v in p->to
			if !copyas(&p.To, v) {
				if copysub(&p.To, v, s, true) {
					return 1
				}
			}
			return 0
		}

		if copyas(&p.To, v) {
			if p.Reg == 0 {
				// Fix up implicit reg (e.g., ADD
				// R3,R4 -> ADD R3,R4,R4) so we can
				// update reg and to separately.
				p.Reg = p.To.Reg
			}

			if copyau(&p.From, v) {
				return 4
			}
			if copyau1(p, v) {
				return 4
			}
			return 3
		}

		if copyau(&p.From, v) {
			return 1
		}
		if copyau1(p, v) {
			return 1
		}
		if copyau(&p.To, v) {
			return 1
		}
		return 0

	case arm64.ABEQ,
		arm64.ABNE,
		arm64.ABGE,
		arm64.ABLT,
		arm64.ABGT,
		arm64.ABLE,
		arm64.ABLO,
		arm64.ABLS,
		arm64.ABHI,
		arm64.ABHS:
		return 0

	case obj.ACHECKNIL, /* read p->from */
		arm64.ACMP, /* read p->from, read p->reg */
		arm64.AFCMPD,
		arm64.AFCMPS:
		if s != nil {
			if copysub(&p.From, v, s, true) {
				return 1
			}
			if copysub1(p, v, s, true) {
				return 1
			}
			return 0
		}

		if copyau(&p.From, v) {
			return 1
		}
		if copyau1(p, v) {
			return 1
		}
		return 0

	case arm64.AB: /* read p->to */
		if s != nil {
			if copysub(&p.To, v, s, true) {
				return 1
			}
			return 0
		}

		if copyau(&p.To, v) {
			return 1
		}
		return 0

	case obj.ARET: /* funny */
		if s != nil {
			return 0
		}

		// All registers die at this point, so claim
		// everything is set (and not used).
		return 3

	case arm64.ABL: /* funny */
		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
			return 2
		}

		if s != nil {
			if copysub(&p.To, v, s, true) {
				return 1
			}
			return 0
		}

		if copyau(&p.To, v) {
			return 4
		}
		return 3

	// R31 is zero, used by DUFFZERO, cannot be substituted.
	// R16 is ptr to memory, used and set, cannot be substituted.
	case obj.ADUFFZERO:
		if v.Type == obj.TYPE_REG {
			if v.Reg == 31 {
				return 1
			}
			if v.Reg == 16 {
				return 2
			}
		}

		return 0

	// R16, R17 are ptr to src, dst, used and set, cannot be substituted.
	// R27 is scratch, set by DUFFCOPY, cannot be substituted.
	case obj.ADUFFCOPY:
		if v.Type == obj.TYPE_REG {
			if v.Reg == 16 || v.Reg == 17 {
				return 2
			}
			if v.Reg == 27 {
				return 3
			}
		}

		return 0

	case arm64.AHINT,
		obj.ATEXT,
		obj.APCDATA,
		obj.AFUNCDATA,
		obj.AVARDEF,
		obj.AVARKILL,
		obj.AVARLIVE,
		obj.AUSEFIELD:
		return 0
	}
}
Example #4
0
func regopt(firstp *obj.Prog) {
	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.
	var nreg int
	regnames := Thearch.Regnames(&nreg)

	nvar = nreg
	for i := 0; i < nreg; i++ {
		vars[i] = Var{}
	}
	for i := 0; i < nreg; i++ {
		if regnodes[i] == nil {
			regnodes[i] = newname(Lookup(regnames[i]))
		}
		vars[i].node = regnodes[i]
	}

	regbits = Thearch.Excludedregs()
	externs = zbits
	params = zbits
	consts = zbits
	addrs = zbits
	ivar = zbits
	ovar = zbits

	// pass 1
	// build aux data structure
	// allocate pcs
	// find use and set of variables
	g := Flowstart(firstp, func() interface{} { return new(Reg) })
	if g == nil {
		for i := 0; i < nvar; i++ {
			vars[i].node.SetOpt(nil)
		}
		return
	}

	firstf := g.Start

	for f := firstf; f != nil; f = f.Link {
		p := f.Prog
		// AVARLIVE must be considered a use, do not skip it.
		// Otherwise the variable will be optimized away,
		// and the whole point of AVARLIVE is to keep it on the stack.
		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
			continue
		}

		// Avoid making variables for direct-called functions.
		if p.As == obj.ACALL && p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_EXTERN {
			continue
		}

		// from vs to doesn't matter for registers.
		r := f.Data.(*Reg)
		r.use1.b[0] |= p.Info.Reguse | p.Info.Regindex
		r.set.b[0] |= p.Info.Regset

		bit := mkvar(f, &p.From)
		if bany(&bit) {
			if p.Info.Flags&LeftAddr != 0 {
				setaddrs(bit)
			}
			if p.Info.Flags&LeftRead != 0 {
				for z := 0; z < BITS; z++ {
					r.use1.b[z] |= bit.b[z]
				}
			}
			if p.Info.Flags&LeftWrite != 0 {
				for z := 0; z < BITS; z++ {
					r.set.b[z] |= bit.b[z]
				}
			}
		}

		// Compute used register for reg
		if p.Info.Flags&RegRead != 0 {
			r.use1.b[0] |= Thearch.RtoB(int(p.Reg))
		}

		// Currently we never generate three register forms.
		// If we do, this will need to change.
		if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
			Fatalf("regopt not implemented for from3")
		}

		bit = mkvar(f, &p.To)
		if bany(&bit) {
			if p.Info.Flags&RightAddr != 0 {
				setaddrs(bit)
			}
			if p.Info.Flags&RightRead != 0 {
				for z := 0; z < BITS; z++ {
					r.use2.b[z] |= bit.b[z]
				}
			}
			if p.Info.Flags&RightWrite != 0 {
				for z := 0; z < BITS; z++ {
					r.set.b[z] |= bit.b[z]
				}
			}
		}
	}

	for i := 0; i < nvar; i++ {
		v := &vars[i]
		if v.addr != 0 {
			bit := blsh(uint(i))
			for z := 0; z < BITS; z++ {
				addrs.b[z] |= bit.b[z]
			}
		}

		if Debug['R'] != 0 && Debug['v'] != 0 {
			fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, v.etype, v.width, v.node, v.offset)
		}
	}

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass1", firstf, 1)
	}

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

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass2", firstf, 1)
	}

	// pass 2.5
	// iterate propagating fat vardef covering forward
	// r->act records vars with a VARDEF since the last CALL.
	// (r->act will be reused in pass 5 for something else,
	// but we'll be done with it by then.)
	active := 0

	for f := firstf; f != nil; f = f.Link {
		f.Active = 0
		r := f.Data.(*Reg)
		r.act = zbits
	}

	for f := firstf; f != nil; f = f.Link {
		p := f.Prog
		if p.As == obj.AVARDEF && Isfat(((p.To.Node).(*Node)).Type) && ((p.To.Node).(*Node)).Opt() != nil {
			active++
			walkvardef(p.To.Node.(*Node), f, active)
		}
	}

	// pass 3
	// iterate propagating usage
	// 	back until flow graph is complete
	var f1 *Flow
	var i int
	var f *Flow
loop1:
	change = 0

	for f = firstf; f != nil; f = f.Link {
		f.Active = 0
	}
	for f = firstf; f != nil; f = f.Link {
		if f.Prog.As == obj.ARET {
			prop(f, zbits, zbits)
		}
	}

	// pick up unreachable code
loop11:
	i = 0

	for f = firstf; f != nil; f = f1 {
		f1 = f.Link
		if f1 != nil && f1.Active != 0 && f.Active == 0 {
			prop(f, zbits, zbits)
			i = 1
		}
	}

	if i != 0 {
		goto loop11
	}
	if change != 0 {
		goto loop1
	}

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass3", firstf, 1)
	}

	// pass 4
	// iterate propagating register/variable synchrony
	// 	forward until graph is complete
loop2:
	change = 0

	for f = firstf; f != nil; f = f.Link {
		f.Active = 0
	}
	synch(firstf, zbits)
	if change != 0 {
		goto loop2
	}

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass4", firstf, 1)
	}

	// pass 4.5
	// move register pseudo-variables into regu.
	mask := uint64((1 << uint(nreg)) - 1)
	for f := firstf; f != nil; f = f.Link {
		r := f.Data.(*Reg)
		r.regu = (r.refbehind.b[0] | r.set.b[0]) & mask
		r.set.b[0] &^= mask
		r.use1.b[0] &^= mask
		r.use2.b[0] &^= mask
		r.refbehind.b[0] &^= mask
		r.refahead.b[0] &^= mask
		r.calbehind.b[0] &^= mask
		r.calahead.b[0] &^= mask
		r.regdiff.b[0] &^= mask
		r.act.b[0] &^= mask
	}

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass4.5", firstf, 1)
	}

	// pass 5
	// isolate regions
	// calculate costs (paint1)
	var bit Bits
	if f := firstf; f != nil {
		r := f.Data.(*Reg)
		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) && !f.Refset {
			// should never happen - all variables are preset
			if Debug['w'] != 0 {
				fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), &bit)
			}
			f.Refset = true
		}
	}

	for f := firstf; f != nil; f = f.Link {
		(f.Data.(*Reg)).act = zbits
	}
	nregion = 0
	region = region[:0]
	for f := firstf; f != nil; f = f.Link {
		r := f.Data.(*Reg)
		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) && !f.Refset {
			if Debug['w'] != 0 {
				fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), &bit)
			}
			f.Refset = true
			Thearch.Excise(f)
		}

		for z := 0; z < BITS; z++ {
			bit.b[z] = LOAD(r, z) &^ (r.act.b[z] | addrs.b[z])
		}
		for bany(&bit) {
			i = bnum(&bit)
			change = 0
			paint1(f, i)
			biclr(&bit, uint(i))
			if change <= 0 {
				continue
			}
			if nregion >= MaxRgn {
				nregion++
				continue
			}

			region = append(region, Rgn{
				enter: f,
				cost:  int16(change),
				varno: int16(i),
			})
			nregion++
		}
	}

	if false && Debug['v'] != 0 && strings.Contains(Curfn.Func.Nname.Sym.Name, "Parse") {
		Warn("regions: %d\n", nregion)
	}
	if nregion >= MaxRgn {
		if Debug['v'] != 0 {
			Warn("too many regions: %d\n", nregion)
		}
		nregion = MaxRgn
	}

	sort.Sort(rcmp(region[:nregion]))

	if Debug['R'] != 0 && Debug['v'] != 0 {
		Dumpit("pass5", firstf, 1)
	}

	// pass 6
	// determine used registers (paint2)
	// replace code (paint3)
	if Debug['R'] != 0 && Debug['v'] != 0 {
		fmt.Printf("\nregisterizing\n")
	}
	for i := 0; i < nregion; i++ {
		rgp := &region[i]
		if Debug['R'] != 0 && Debug['v'] != 0 {
			fmt.Printf("region %d: cost %d varno %d enter %d\n", i, rgp.cost, rgp.varno, rgp.enter.Prog.Pc)
		}
		bit = blsh(uint(rgp.varno))
		usedreg := paint2(rgp.enter, int(rgp.varno), 0)
		vreg := allreg(usedreg, rgp)
		if rgp.regno != 0 {
			if Debug['R'] != 0 && Debug['v'] != 0 {
				v := &vars[rgp.varno]
				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, v.etype, obj.Rconv(int(rgp.regno)), usedreg, vreg)
			}

			paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
		}
	}

	// free aux structures. peep allocates new ones.
	for i := 0; i < nvar; i++ {
		vars[i].node.SetOpt(nil)
	}
	Flowend(g)
	firstf = nil

	if Debug['R'] != 0 && Debug['v'] != 0 {
		// Rebuild flow graph, since we inserted instructions
		g := Flowstart(firstp, nil)
		firstf = g.Start
		Dumpit("pass6", firstf, 0)
		Flowend(g)
		firstf = nil
	}

	// pass 7
	// peep-hole on basic block
	if Debug['R'] == 0 || Debug['P'] != 0 {
		Thearch.Peep(firstp)
	}

	// eliminate nops
	for p := firstp; p != nil; p = p.Link {
		for p.Link != nil && p.Link.As == obj.ANOP {
			p.Link = p.Link.Link
		}
		if p.To.Type == obj.TYPE_BRANCH {
			for p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.ANOP {
				p.To.Val = p.To.Val.(*obj.Prog).Link
			}
		}
	}

	if Debug['R'] != 0 {
		if Ostats.Ncvtreg != 0 || Ostats.Nspill != 0 || Ostats.Nreload != 0 || Ostats.Ndelmov != 0 || Ostats.Nvar != 0 || Ostats.Naddr != 0 || false {
			fmt.Printf("\nstats\n")
		}

		if Ostats.Ncvtreg != 0 {
			fmt.Printf("\t%4d cvtreg\n", Ostats.Ncvtreg)
		}
		if Ostats.Nspill != 0 {
			fmt.Printf("\t%4d spill\n", Ostats.Nspill)
		}
		if Ostats.Nreload != 0 {
			fmt.Printf("\t%4d reload\n", Ostats.Nreload)
		}
		if Ostats.Ndelmov != 0 {
			fmt.Printf("\t%4d delmov\n", Ostats.Ndelmov)
		}
		if Ostats.Nvar != 0 {
			fmt.Printf("\t%4d var\n", Ostats.Nvar)
		}
		if Ostats.Naddr != 0 {
			fmt.Printf("\t%4d addr\n", Ostats.Naddr)
		}

		Ostats = OptStats{}
	}
}
Example #5
0
func clearfat(nl *gc.Node) {
	/* clear a fat object */
	if gc.Debug['g'] != 0 {
		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
	}

	w := uint64(nl.Type.Width)

	// Avoid taking the address for simple enough types.
	if gc.Componentgen(nil, nl) {
		return
	}

	c := w % 8 // bytes
	q := w / 8 // dwords

	if gc.Reginuse(mips.REGRT1) {
		gc.Fatalf("%v in use during clearfat", obj.Rconv(mips.REGRT1))
	}

	var r0 gc.Node
	gc.Nodreg(&r0, gc.Types[gc.TUINT64], mips.REGZERO)
	var dst gc.Node
	gc.Nodreg(&dst, gc.Types[gc.Tptr], mips.REGRT1)
	gc.Regrealloc(&dst)
	gc.Agen(nl, &dst)

	var boff uint64
	if q > 128 {
		p := gins(mips.ASUBV, nil, &dst)
		p.From.Type = obj.TYPE_CONST
		p.From.Offset = 8

		var end gc.Node
		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
		p = gins(mips.AMOVV, &dst, &end)
		p.From.Type = obj.TYPE_ADDR
		p.From.Offset = int64(q * 8)

		p = gins(mips.AMOVV, &r0, &dst)
		p.To.Type = obj.TYPE_MEM
		p.To.Offset = 8
		pl := p

		p = gins(mips.AADDV, nil, &dst)
		p.From.Type = obj.TYPE_CONST
		p.From.Offset = 8

		gc.Patch(ginsbranch(mips.ABNE, nil, &dst, &end, 0), pl)

		gc.Regfree(&end)

		// The loop leaves R1 on the last zeroed dword
		boff = 8
		// TODO(dfc): https://golang.org/issue/12108
		// If DUFFZERO is used inside a tail call (see genwrapper) it will
		// overwrite the link register.
	} else if false && q >= 4 {
		p := gins(mips.ASUBV, nil, &dst)
		p.From.Type = obj.TYPE_CONST
		p.From.Offset = 8
		f := gc.Sysfunc("duffzero")
		p = gins(obj.ADUFFZERO, nil, f)
		gc.Afunclit(&p.To, f)

		// 8 and 128 = magic constants: see ../../runtime/asm_mips64x.s
		p.To.Offset = int64(8 * (128 - q))

		// duffzero leaves R1 on the last zeroed dword
		boff = 8
	} else {
		var p *obj.Prog
		for t := uint64(0); t < q; t++ {
			p = gins(mips.AMOVV, &r0, &dst)
			p.To.Type = obj.TYPE_MEM
			p.To.Offset = int64(8 * t)
		}

		boff = 8 * q
	}

	var p *obj.Prog
	for t := uint64(0); t < c; t++ {
		p = gins(mips.AMOVB, &r0, &dst)
		p.To.Type = obj.TYPE_MEM
		p.To.Offset = int64(t + boff)
	}

	gc.Regfree(&dst)
}
Example #6
0
func clearfat(nl *gc.Node) {
	/* clear a fat object */
	if gc.Debug['g'] != 0 {
		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
	}

	w := uint64(nl.Type.Width)

	// Avoid taking the address for simple enough types.
	if gc.Componentgen(nil, nl) {
		return
	}

	c := w % 8 // bytes
	q := w / 8 // dwords

	if gc.Reginuse(ppc64.REGRT1) {
		gc.Fatalf("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
	}

	var r0 gc.Node
	gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
	var dst gc.Node
	gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
	gc.Regrealloc(&dst)
	gc.Agen(nl, &dst)

	var boff uint64
	if q > 128 {
		p := gins(ppc64.ASUB, nil, &dst)
		p.From.Type = obj.TYPE_CONST
		p.From.Offset = 8

		var end gc.Node
		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
		p = gins(ppc64.AMOVD, &dst, &end)
		p.From.Type = obj.TYPE_ADDR
		p.From.Offset = int64(q * 8)

		p = gins(ppc64.AMOVDU, &r0, &dst)
		p.To.Type = obj.TYPE_MEM
		p.To.Offset = 8
		pl := p

		p = gins(ppc64.ACMP, &dst, &end)
		gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)

		gc.Regfree(&end)

		// The loop leaves R3 on the last zeroed dword
		boff = 8
	} else if q >= 4 {
		p := gins(ppc64.ASUB, nil, &dst)
		p.From.Type = obj.TYPE_CONST
		p.From.Offset = 8
		f := gc.Sysfunc("duffzero")
		p = gins(obj.ADUFFZERO, nil, f)
		gc.Afunclit(&p.To, f)

		// 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
		p.To.Offset = int64(4 * (128 - q))

		// duffzero leaves R3 on the last zeroed dword
		boff = 8
	} else {
		var p *obj.Prog
		for t := uint64(0); t < q; t++ {
			p = gins(ppc64.AMOVD, &r0, &dst)
			p.To.Type = obj.TYPE_MEM
			p.To.Offset = int64(8 * t)
		}

		boff = 8 * q
	}

	var p *obj.Prog
	for t := uint64(0); t < c; t++ {
		p = gins(ppc64.AMOVB, &r0, &dst)
		p.To.Type = obj.TYPE_MEM
		p.To.Offset = int64(t + boff)
	}

	gc.Regfree(&dst)
}
Example #7
0
func nodedump(n *Node, flag FmtFlag) string {
	if n == nil {
		return ""
	}

	recur := flag&FmtShort == 0

	var buf bytes.Buffer
	if recur {
		indent(&buf)
		if dumpdepth > 10 {
			buf.WriteString("...")
			return buf.String()
		}

		if n.Ninit.Len() != 0 {
			fmt.Fprintf(&buf, "%v-init%v", n.Op, n.Ninit)
			indent(&buf)
		}
	}

	switch n.Op {
	default:
		fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0))

	case OREGISTER, OINDREG:
		fmt.Fprintf(&buf, "%v-%v%v", n.Op, obj.Rconv(int(n.Reg)), jconv(n, 0))

	case OLITERAL:
		fmt.Fprintf(&buf, "%v-%v%v", n.Op, vconv(n.Val(), 0), jconv(n, 0))

	case ONAME, ONONAME:
		if n.Sym != nil {
			fmt.Fprintf(&buf, "%v-%v%v", n.Op, n.Sym, jconv(n, 0))
		} else {
			fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0))
		}
		if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
			indent(&buf)
			fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
		}

	case OASOP:
		fmt.Fprintf(&buf, "%v-%v%v", n.Op, Op(n.Etype), jconv(n, 0))

	case OTYPE:
		fmt.Fprintf(&buf, "%v %v%v type=%v", n.Op, n.Sym, jconv(n, 0), n.Type)
		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
			indent(&buf)
			fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
		}
	}

	if n.Sym != nil && n.Op != ONAME {
		fmt.Fprintf(&buf, " %v", n.Sym)
	}

	if n.Type != nil {
		fmt.Fprintf(&buf, " %v", n.Type)
	}

	if recur {
		if n.Left != nil {
			buf.WriteString(Nconv(n.Left, 0))
		}
		if n.Right != nil {
			buf.WriteString(Nconv(n.Right, 0))
		}
		if n.List.Len() != 0 {
			indent(&buf)
			fmt.Fprintf(&buf, "%v-list%v", n.Op, n.List)
		}

		if n.Rlist.Len() != 0 {
			indent(&buf)
			fmt.Fprintf(&buf, "%v-rlist%v", n.Op, n.Rlist)
		}

		if n.Nbody.Len() != 0 {
			indent(&buf)
			fmt.Fprintf(&buf, "%v-body%v", n.Op, n.Nbody)
		}
	}

	return buf.String()
}
Example #8
0
func exprfmt(n *Node, prec int) string {
	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
		n = n.Left
	}

	if n == nil {
		return "<N>"
	}

	nprec := opprec[n.Op]
	if n.Op == OTYPE && n.Sym != nil {
		nprec = 8
	}

	if prec > nprec {
		return fmt.Sprintf("(%v)", n)
	}

	switch n.Op {
	case OPAREN:
		return fmt.Sprintf("(%v)", n.Left)

	case ODDDARG:
		return "... argument"

	case OREGISTER:
		return obj.Rconv(int(n.Reg))

	case OLITERAL: // this is a bit of a mess
		if fmtmode == FErr {
			if n.Orig != nil && n.Orig != n {
				return exprfmt(n.Orig, prec)
			}
			if n.Sym != nil {
				return sconv(n.Sym, 0)
			}
		}
		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
			return exprfmt(n.Orig, prec)
		}
		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
			// Need parens when type begins with what might
			// be misinterpreted as a unary operator: * or <-.
			if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) {
				return fmt.Sprintf("(%v)(%v)", n.Type, vconv(n.Val(), 0))
			} else {
				return fmt.Sprintf("%v(%v)", n.Type, vconv(n.Val(), 0))
			}
		}

		return vconv(n.Val(), 0)

	// Special case: name used as local variable in export.
	// _ becomes ~b%d internally; print as _ for export
	case ONAME:
		if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
			return "_"
		}
		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
			return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen)
		}

		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
		// but for export, this should be rendered as (*pkg.T).meth.
		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
		if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
			if n.Left.Type.IsPtr() {
				return fmt.Sprintf("(%v).%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
			} else {
				return fmt.Sprintf("%v.%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
			}
		}
		fallthrough

	case OPACK, ONONAME:
		return sconv(n.Sym, 0)

	case OTYPE:
		if n.Type == nil && n.Sym != nil {
			return sconv(n.Sym, 0)
		}
		return Tconv(n.Type, 0)

	case OTARRAY:
		if n.Left != nil {
			return fmt.Sprintf("[]%v", n.Left)
		}
		return fmt.Sprintf("[]%v", n.Right) // happens before typecheck

	case OTMAP:
		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)

	case OTCHAN:
		switch ChanDir(n.Etype) {
		case Crecv:
			return fmt.Sprintf("<-chan %v", n.Left)

		case Csend:
			return fmt.Sprintf("chan<- %v", n.Left)

		default:
			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
				return fmt.Sprintf("chan (%v)", n.Left)
			} else {
				return fmt.Sprintf("chan %v", n.Left)
			}
		}

	case OTSTRUCT:
		return "<struct>"

	case OTINTER:
		return "<inter>"

	case OTFUNC:
		return "<func>"

	case OCLOSURE:
		if fmtmode == FErr {
			return "func literal"
		}
		if n.Nbody.Len() != 0 {
			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
		}
		return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody)

	case OCOMPLIT:
		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
		if fmtmode == FErr {
			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
				if ptrlit {
					return fmt.Sprintf("&%v literal", n.Right.Type.Elem())
				} else {
					return fmt.Sprintf("%v literal", n.Right.Type)
				}
			}

			return "composite literal"
		}

		if fmtmode == FExp && ptrlit {
			// typecheck has overwritten OIND by OTYPE with pointer type.
			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Elem(), hconv(n.List, FmtComma))
		}

		return fmt.Sprintf("(%v{ %v })", n.Right, hconv(n.List, FmtComma))

	case OPTRLIT:
		if fmtmode == FExp && n.Left.Implicit {
			return Nconv(n.Left, 0)
		}
		return fmt.Sprintf("&%v", n.Left)

	case OSTRUCTLIT:
		if fmtmode == FExp { // requires special handling of field names
			var f string
			if n.Implicit {
				f += "{"
			} else {
				f += fmt.Sprintf("(%v{", n.Type)
			}
			for i1, n1 := range n.List.Slice() {
				f += fmt.Sprintf(" %v:%v", sconv(n1.Left.Sym, FmtShort|FmtByte), n1.Right)

				if i1+1 < n.List.Len() {
					f += ","
				} else {
					f += " "
				}
			}

			if !n.Implicit {
				f += "})"
				return f
			}
			f += "}"
			return f
		}
		fallthrough

	case OARRAYLIT, OMAPLIT:
		if fmtmode == FErr {
			return fmt.Sprintf("%v literal", n.Type)
		}
		if fmtmode == FExp && n.Implicit {
			return fmt.Sprintf("{ %v }", hconv(n.List, FmtComma))
		}
		return fmt.Sprintf("(%v{ %v })", n.Type, hconv(n.List, FmtComma))

	case OKEY:
		if n.Left != nil && n.Right != nil {
			if fmtmode == FExp && n.Left.Type == structkey {
				// requires special handling of field names
				return fmt.Sprintf("%v:%v", sconv(n.Left.Sym, FmtShort|FmtByte), n.Right)
			} else {
				return fmt.Sprintf("%v:%v", n.Left, n.Right)
			}
		}

		if n.Left == nil && n.Right != nil {
			return fmt.Sprintf(":%v", n.Right)
		}
		if n.Left != nil && n.Right == nil {
			return fmt.Sprintf("%v:", n.Left)
		}
		return ":"

	case OCALLPART:
		var f string
		f += exprfmt(n.Left, nprec)
		if n.Right == nil || n.Right.Sym == nil {
			f += ".<nil>"
			return f
		}
		f += fmt.Sprintf(".%v", sconv(n.Right.Sym, FmtShort|FmtByte))
		return f

	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
		var f string
		f += exprfmt(n.Left, nprec)
		if n.Sym == nil {
			f += ".<nil>"
			return f
		}
		f += fmt.Sprintf(".%v", sconv(n.Sym, FmtShort|FmtByte))
		return f

	case ODOTTYPE, ODOTTYPE2:
		var f string
		f += exprfmt(n.Left, nprec)
		if n.Right != nil {
			f += fmt.Sprintf(".(%v)", n.Right)
			return f
		}
		f += fmt.Sprintf(".(%v)", n.Type)
		return f

	case OINDEX, OINDEXMAP:
		return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)

	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
		var buf bytes.Buffer
		buf.WriteString(exprfmt(n.Left, nprec))
		buf.WriteString("[")
		low, high, max := n.SliceBounds()
		if low != nil {
			buf.WriteString(low.String())
		}
		buf.WriteString(":")
		if high != nil {
			buf.WriteString(high.String())
		}
		if n.Op.IsSlice3() {
			buf.WriteString(":")
			if max != nil {
				buf.WriteString(max.String())
			}
		}
		buf.WriteString("]")
		return buf.String()

	case OCOPY, OCOMPLEX:
		return fmt.Sprintf("%#v(%v, %v)", n.Op, n.Left, n.Right)

	case OCONV,
		OCONVIFACE,
		OCONVNOP,
		OARRAYBYTESTR,
		OARRAYRUNESTR,
		OSTRARRAYBYTE,
		OSTRARRAYRUNE,
		ORUNESTR:
		if n.Type == nil || n.Type.Sym == nil {
			return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
		}
		if n.Left != nil {
			return fmt.Sprintf("%v(%v)", n.Type, n.Left)
		}
		return fmt.Sprintf("%v(%v)", n.Type, hconv(n.List, FmtComma))

	case OREAL,
		OIMAG,
		OAPPEND,
		OCAP,
		OCLOSE,
		ODELETE,
		OLEN,
		OMAKE,
		ONEW,
		OPANIC,
		ORECOVER,
		OPRINT,
		OPRINTN:
		if n.Left != nil {
			return fmt.Sprintf("%#v(%v)", n.Op, n.Left)
		}
		if n.Isddd {
			return fmt.Sprintf("%#v(%v...)", n.Op, hconv(n.List, FmtComma))
		}
		return fmt.Sprintf("%#v(%v)", n.Op, hconv(n.List, FmtComma))

	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
		var f string
		f += exprfmt(n.Left, nprec)
		if n.Isddd {
			f += fmt.Sprintf("(%v...)", hconv(n.List, FmtComma))
			return f
		}
		f += fmt.Sprintf("(%v)", hconv(n.List, FmtComma))
		return f

	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
		if n.List.Len() != 0 { // pre-typecheck
			return fmt.Sprintf("make(%v, %v)", n.Type, hconv(n.List, FmtComma))
		}
		if n.Right != nil {
			return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
		}
		if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
		}
		return fmt.Sprintf("make(%v)", n.Type)

		// Unary
	case OPLUS,
		OMINUS,
		OADDR,
		OCOM,
		OIND,
		ONOT,
		ORECV:
		f := n.Op.GoString() // %#v
		if n.Left.Op == n.Op {
			f += " "
		}
		f += exprfmt(n.Left, nprec+1)
		return f

		// Binary
	case OADD,
		OAND,
		OANDAND,
		OANDNOT,
		ODIV,
		OEQ,
		OGE,
		OGT,
		OLE,
		OLT,
		OLSH,
		OMOD,
		OMUL,
		ONE,
		OOR,
		OOROR,
		ORSH,
		OSEND,
		OSUB,
		OXOR:
		var f string
		f += exprfmt(n.Left, nprec)

		f += fmt.Sprintf(" %#v ", n.Op)
		f += exprfmt(n.Right, nprec+1)
		return f

	case OADDSTR:
		var f string
		i := 0
		for _, n1 := range n.List.Slice() {
			if i != 0 {
				f += " + "
			}
			f += exprfmt(n1, nprec)
			i++
		}

		return f

	case OCMPSTR, OCMPIFACE:
		var f string
		f += exprfmt(n.Left, nprec)
		// TODO(marvin): Fix Node.EType type union.
		f += fmt.Sprintf(" %#v ", Op(n.Etype))
		f += exprfmt(n.Right, nprec+1)
		return f

	case ODCLCONST:
		// if exporting, DCLCONST should just be removed as its usage
		// has already been replaced with literals
		if fmtbody {
			return ""
		}
	}

	return fmt.Sprintf("<node %v>", n.Op)
}