Пример #1
0
func outgcode(a int, g1 *obj.Addr, reg int, g2, g3 *obj.Addr) {
	var p *obj.Prog
	var pl *obj.Plist

	if asm.Pass == 1 {
		goto out
	}

	p = asm.Ctxt.NewProg()
	p.As = int16(a)
	p.Lineno = stmtline
	if nosched != 0 {
		p.Mark |= ppc64.NOSCHED
	}
	p.From = *g1
	p.Reg = int16(reg)
	p.From3 = *g2
	p.To = *g3
	p.Pc = int64(asm.PC)

	if lastpc == nil {
		pl = obj.Linknewplist(asm.Ctxt)
		pl.Firstpc = p
	} else {
		lastpc.Link = p
	}
	lastpc = p

out:
	if a != obj.AGLOBL && a != obj.ADATA {
		asm.PC++
	}
}
Пример #2
0
Файл: lex.go Проект: Ericean/go
func outcode(a int, g2 *Addr2) {
	var p *obj.Prog
	var pl *obj.Plist

	if asm.Pass == 1 {
		goto out
	}

	p = new(obj.Prog)
	*p = obj.Prog{}
	p.Ctxt = asm.Ctxt
	p.As = int16(a)
	p.Lineno = stmtline
	p.From = g2.from
	if g2.from3.Type != 0 {
		p.From3 = new(obj.Addr)
		*p.From3 = g2.from3
	}
	p.To = g2.to
	p.Pc = int64(asm.PC)

	if lastpc == nil {
		pl = obj.Linknewplist(asm.Ctxt)
		pl.Firstpc = p
	} else {

		lastpc.Link = p
	}
	lastpc = p

out:
	if a != obj.AGLOBL && a != obj.ADATA {
		asm.PC++
	}
}
Пример #3
0
func compile(fn *Node) {
	if Newproc == nil {
		Newproc = Sysfunc("newproc")
		Deferproc = Sysfunc("deferproc")
		Deferreturn = Sysfunc("deferreturn")
		Panicindex = Sysfunc("panicindex")
		panicslice = Sysfunc("panicslice")
		throwreturn = Sysfunc("throwreturn")
	}

	lno := setlineno(fn)

	Curfn = fn
	dowidth(Curfn.Type)

	var oldstksize int64
	var nod1 Node
	var ptxt *obj.Prog
	var pl *obj.Plist
	var p *obj.Prog
	var n *Node
	var nam *Node
	var gcargs *Sym
	var gclocals *Sym
	if fn.Nbody == nil {
		if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
			goto ret
		}

		if Debug['A'] != 0 {
			goto ret
		}
		emitptrargsmap()
		goto ret
	}

	saveerrors()

	// set up domain for labels
	clearlabels()

	if Curfn.Type.Outnamed {
		// add clearing of the output parameters
		var save Iter
		t := Structfirst(&save, Getoutarg(Curfn.Type))

		for t != nil {
			if t.Nname != nil {
				n = Nod(OAS, t.Nname, nil)
				typecheck(&n, Etop)
				Curfn.Nbody = concat(list1(n), Curfn.Nbody)
			}

			t = structnext(&save)
		}
	}

	order(Curfn)
	if nerrors != 0 {
		goto ret
	}

	hasdefer = false
	walk(Curfn)
	if nerrors != 0 {
		goto ret
	}
	if instrumenting {
		instrument(Curfn)
	}
	if nerrors != 0 {
		goto ret
	}

	continpc = nil
	breakpc = nil

	pl = newplist()
	pl.Name = Linksym(Curfn.Func.Nname.Sym)

	setlineno(Curfn)

	Nodconst(&nod1, Types[TINT32], 0)
	nam = Curfn.Func.Nname
	if isblank(nam) {
		nam = nil
	}
	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
	Afunclit(&ptxt.From, Curfn.Func.Nname)
	ptxt.From3 = new(obj.Addr)
	if fn.Func.Dupok {
		ptxt.From3.Offset |= obj.DUPOK
	}
	if fn.Func.Wrapper {
		ptxt.From3.Offset |= obj.WRAPPER
	}
	if fn.Func.Needctxt {
		ptxt.From3.Offset |= obj.NEEDCTXT
	}
	if fn.Func.Nosplit {
		ptxt.From3.Offset |= obj.NOSPLIT
	}
	if fn.Func.Systemstack {
		ptxt.From.Sym.Cfunc = 1
	}

	// Clumsy but important.
	// See test/recover.go for test cases and src/reflect/value.go
	// for the actual functions being considered.
	if myimportpath != "" && myimportpath == "reflect" {
		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
			ptxt.From3.Offset |= obj.WRAPPER
		}
	}

	ginit()

	gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
	gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)

	for _, t := range Curfn.Func.Fieldtrack {
		gtrack(tracksym(t))
	}

	for l := fn.Func.Dcl; l != nil; l = l.Next {
		n = l.N
		if n.Op != ONAME { // might be OTYPE or OLITERAL
			continue
		}
		switch n.Class {
		case PAUTO, PPARAM, PPARAMOUT:
			Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
			p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
			p.From.Gotype = Linksym(ngotype(l.N))
		}
	}

	Genlist(Curfn.Func.Enter)
	Genlist(Curfn.Nbody)
	gclean()
	checklabels()
	if nerrors != 0 {
		goto ret
	}
	if Curfn.Func.Endlineno != 0 {
		lineno = Curfn.Func.Endlineno
	}

	if Curfn.Type.Outtuple != 0 {
		Ginscall(throwreturn, 0)
	}

	ginit()

	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
	cgen_ret(nil)

	if hasdefer {
		// deferreturn pretends to have one uintptr argument.
		// Reserve space for it so stack scanner is happy.
		if Maxarg < int64(Widthptr) {
			Maxarg = int64(Widthptr)
		}
	}

	gclean()
	if nerrors != 0 {
		goto ret
	}

	Pc.As = obj.ARET // overwrite AEND
	Pc.Lineno = lineno

	fixjmp(ptxt)
	if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
		regopt(ptxt)
		nilopt(ptxt)
	}

	Thearch.Expandchecks(ptxt)

	oldstksize = Stksize
	allocauto(ptxt)

	if false {
		fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
	}

	setlineno(Curfn)
	if int64(Stksize)+Maxarg > 1<<31 {
		Yyerror("stack frame too large (>2GB)")
		goto ret
	}

	// Emit garbage collection symbols.
	liveness(Curfn, ptxt, gcargs, gclocals)

	gcsymdup(gcargs)
	gcsymdup(gclocals)

	Thearch.Defframe(ptxt)

	if Debug['f'] != 0 {
		frame(0)
	}

	// Remove leftover instrumentation from the instruction stream.
	removevardef(ptxt)

ret:
	lineno = lno
}
Пример #4
0
Файл: ggen.go Проект: 2thetop/go
// zerorange clears the stack in the given range.
func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
	cnt := hi - lo
	if cnt == 0 {
		return p
	}

	// Adjust the frame to account for LR.
	frame += gc.Ctxt.FixedFrameSize()
	offset := frame + lo
	reg := int16(s390x.REGSP)

	// If the offset cannot fit in a 12-bit unsigned displacement then we
	// need to create a copy of the stack pointer that we can adjust.
	// We also need to do this if we are going to loop.
	if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
		p.Reg = int16(s390x.REGSP)
		reg = s390x.REGRT1
		offset = 0
	}

	// Generate a loop of large clears.
	if cnt > clearLoopCutoff {
		n := cnt - (cnt % 256)
		end := int16(s390x.REGRT2)
		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
		p.Reg = reg
		p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
		p.From3 = new(obj.Addr)
		p.From3.Type = obj.TYPE_CONST
		p.From3.Offset = 256
		pl := p
		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
		p = appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
		p = appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
		gc.Patch(p, pl)

		cnt -= n
	}

	// Generate remaining clear instructions without a loop.
	for cnt > 0 {
		n := cnt

		// Can clear at most 256 bytes per instruction.
		if n > 256 {
			n = 256
		}

		switch n {
		// Handle very small clears with move instructions.
		case 8, 4, 2, 1:
			ins := s390x.AMOVB
			switch n {
			case 8:
				ins = s390x.AMOVD
			case 4:
				ins = s390x.AMOVW
			case 2:
				ins = s390x.AMOVH
			}
			p = appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)

		// Handle clears that would require multiple move instructions with XC.
		default:
			p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
			p.From3 = new(obj.Addr)
			p.From3.Type = obj.TYPE_CONST
			p.From3.Offset = n
		}

		cnt -= n
		offset += n
	}

	return p
}
Пример #5
0
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)
}