pgen.go 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gc

import (
	"cmd/internal/obj"
	"fmt"
	"strings"
)

// "Portable" code generation.
// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
// Must code to the intersection of the three back ends.

//#include	"opt.h"

var makefuncdatasym_nsym int32

func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
	var nod Node

	namebuf = fmt.Sprintf(namefmt, makefuncdatasym_nsym)
	makefuncdatasym_nsym++
26 27
	sym := Lookup(namebuf)
	pnod := newname(sym)
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	pnod.Class = PEXTERN
	Nodconst(&nod, Types[TINT32], funcdatakind)
	Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
	return sym
}

// gvardef inserts a VARDEF for n into the instruction stream.
// VARDEF is an annotation for the liveness analysis, marking a place
// where a complete initialization (definition) of a variable begins.
// Since the liveness analysis can see initialization of single-word
// variables quite easy, gvardef is usually only called for multi-word
// or 'fat' variables, those satisfying isfat(n->type).
// However, gvardef is also called when a non-fat variable is initialized
// via a block move; the only time this happens is when you have
//	return f()
// for a function with multiple return values exactly matching the return
// types of the current function.
//
// A 'VARDEF x' annotation in the instruction stream tells the liveness
// analysis to behave as though the variable x is being initialized at that
// point in the instruction stream. The VARDEF must appear before the
// actual (multi-instruction) initialization, and it must also appear after
// any uses of the previous value, if any. For example, if compiling:
//
//	x = x[1:]
//
// it is important to generate code like:
//
//	base, len, cap = pieces of x[1:]
//	VARDEF x
//	x = {base, len, cap}
//
// If instead the generated code looked like:
//
//	VARDEF x
//	base, len, cap = pieces of x[1:]
//	x = {base, len, cap}
//
// then the liveness analysis would decide the previous value of x was
// unnecessary even though it is about to be used by the x[1:] computation.
// Similarly, if the generated code looked like:
//
//	base, len, cap = pieces of x[1:]
//	x = {base, len, cap}
//	VARDEF x
//
// then the liveness analysis will not preserve the new value of x, because
// the VARDEF appears to have "overwritten" it.
//
// VARDEF is a bit of a kludge to work around the fact that the instruction
// stream is working on single-word values but the liveness analysis
// wants to work on individual variables, which might be multi-word
// aggregates. It might make sense at some point to look into letting
// the liveness analysis work on single-word values as well, although
// there are complications around interface values, slices, and strings,
// all of which cannot be treated as individual words.
//
// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
// even if its address has been taken. That is, a VARKILL annotation asserts
// that its argument is certainly dead, for use when the liveness analysis
// would not otherwise be able to deduce that fact.

func gvardefx(n *Node, as int) {
	if n == nil {
		Fatal("gvardef nil")
	}
	if n.Op != ONAME {
		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n, 0))
		return
	}

	switch n.Class {
	case PAUTO,
		PPARAM,
		PPARAMOUT:
		Thearch.Gins(as, nil, n)
	}
}

func Gvardef(n *Node) {
	gvardefx(n, obj.AVARDEF)
}

func gvarkill(n *Node) {
	gvardefx(n, obj.AVARKILL)
}

func removevardef(firstp *obj.Prog) {
116
	for p := firstp; p != nil; p = p.Link {
117 118 119 120 121 122 123 124 125 126 127 128
		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
			p.Link = p.Link.Link
		}
		if p.To.Type == obj.TYPE_BRANCH {
			for p.To.U.Branch != nil && (p.To.U.Branch.As == obj.AVARDEF || p.To.U.Branch.As == obj.AVARKILL) {
				p.To.U.Branch = p.To.U.Branch.Link
			}
		}
	}
}

func gcsymdup(s *Sym) {
129
	ls := Linksym(s)
130 131 132 133 134 135
	if len(ls.R) > 0 {
		Fatal("cannot rosymdup %s with relocations", ls.Name)
	}
	var d MD5
	md5reset(&d)
	md5write(&d, ls.P, len(ls.P))
136 137
	var hi uint64
	lo := md5sum(&d, &hi)
138 139 140 141 142
	ls.Name = fmt.Sprintf("gclocals·%016x%016x", lo, hi)
	ls.Dupok = 1
}

func emitptrargsmap() {
143
	sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Nname.Sym.Name))
144

145 146 147
	nptr := int(Curfn.Type.Argwid / int64(Widthptr))
	bv := bvalloc(int32(nptr) * 2)
	nbitmap := 1
148 149 150
	if Curfn.Type.Outtuple > 0 {
		nbitmap = 2
	}
151
	off := duint32(sym, 0, uint32(nbitmap))
152
	off = duint32(sym, off, uint32(bv.n))
153
	var xoffset int64
154 155 156 157 158 159 160 161 162 163
	if Curfn.Type.Thistuple > 0 {
		xoffset = 0
		twobitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
	}

	if Curfn.Type.Intuple > 0 {
		xoffset = 0
		twobitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
	}

164
	for j := 0; int32(j) < bv.n; j += 32 {
165 166 167 168 169
		off = duint32(sym, off, bv.b[j/32])
	}
	if Curfn.Type.Outtuple > 0 {
		xoffset = 0
		twobitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
170
		for j := 0; int32(j) < bv.n; j += 32 {
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
			off = duint32(sym, off, bv.b[j/32])
		}
	}

	ggloblsym(sym, int32(off), obj.RODATA)
}

// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.
// Because autos are laid out in decreasing addresses
// on the stack, pointers first, zeroed things first and decreasing size
// really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size.
// Non-autos sort on offset.
func cmpstackvar(a *Node, b *Node) int {
	if a.Class != b.Class {
		if a.Class == PAUTO {
			return +1
		}
		return -1
	}

	if a.Class != PAUTO {
		if a.Xoffset < b.Xoffset {
			return -1
		}
		if a.Xoffset > b.Xoffset {
			return +1
		}
		return 0
	}

	if (a.Used == 0) != (b.Used == 0) {
		return int(b.Used) - int(a.Used)
	}

208 209
	ap := bool2int(haspointers(a.Type))
	bp := bool2int(haspointers(b.Type))
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
	if ap != bp {
		return bp - ap
	}

	ap = int(a.Needzero)
	bp = int(b.Needzero)
	if ap != bp {
		return bp - ap
	}

	if a.Type.Width < b.Type.Width {
		return +1
	}
	if a.Type.Width > b.Type.Width {
		return -1
	}

	return stringsCompare(a.Sym.Name, b.Sym.Name)
}

// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
func allocauto(ptxt *obj.Prog) {
	Stksize = 0
	stkptrsize = 0

	if Curfn.Dcl == nil {
		return
	}

	// Mark the PAUTO's unused.
240
	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
241 242 243 244 245 246 247 248 249 250
		if ll.N.Class == PAUTO {
			ll.N.Used = 0
		}
	}

	markautoused(ptxt)

	listsort(&Curfn.Dcl, cmpstackvar)

	// Unused autos are at the end, chop 'em off.
251
	ll := Curfn.Dcl
252

253
	n := ll.N
254
	if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
255 256 257 258 259 260 261
		// No locals used at all
		Curfn.Dcl = nil

		fixautoused(ptxt)
		return
	}

262
	for ll := Curfn.Dcl; ll.Next != nil; ll = ll.Next {
263
		n = ll.Next.N
264
		if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
265 266 267 268 269 270 271
			ll.Next = nil
			Curfn.Dcl.End = ll
			break
		}
	}

	// Reassign stack offsets of the locals that are still there.
272 273
	var w int64
	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
		n = ll.N
		if n.Class != PAUTO || n.Op != ONAME {
			continue
		}

		dowidth(n.Type)
		w = n.Type.Width
		if w >= Thearch.MAXWIDTH || w < 0 {
			Fatal("bad width")
		}
		Stksize += w
		Stksize = Rnd(Stksize, int64(n.Type.Align))
		if haspointers(n.Type) {
			stkptrsize = Stksize
		}
		if Thearch.Thechar == '5' || Thearch.Thechar == '9' {
			Stksize = Rnd(Stksize, int64(Widthptr))
		}
		if Stksize >= 1<<31 {
			setlineno(Curfn)
			Yyerror("stack frame too large (>2GB)")
		}

		n.Stkdelta = -Stksize - n.Xoffset
	}

	Stksize = Rnd(Stksize, int64(Widthreg))
	stkptrsize = Rnd(stkptrsize, int64(Widthreg))

	fixautoused(ptxt)

	// The debug information needs accurate offsets on the symbols.
306
	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
		if ll.N.Class != PAUTO || ll.N.Op != ONAME {
			continue
		}
		ll.N.Xoffset += ll.N.Stkdelta
		ll.N.Stkdelta = 0
	}
}

func movelarge(l *NodeList) {
	for ; l != nil; l = l.Next {
		if l.N.Op == ODCLFUNC {
			movelargefn(l.N)
		}
	}
}

func movelargefn(fn *Node) {
	var n *Node

326
	for l := fn.Dcl; l != nil; l = l.Next {
327 328 329 330 331 332 333 334 335 336 337 338 339
		n = l.N
		if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize {
			addrescapes(n)
		}
	}
}

func Cgen_checknil(n *Node) {
	if Disable_checknil != 0 {
		return
	}

	// Ideally we wouldn't see any integer types here, but we do.
340
	if n.Type == nil || (Isptr[n.Type.Etype] == 0 && Isint[n.Type.Etype] == 0 && n.Type.Etype != TUNSAFEPTR) {
341 342 343 344
		Dump("checknil", n)
		Fatal("bad checknil")
	}

345
	if ((Thearch.Thechar == '5' || Thearch.Thechar == '9') && n.Op != OREGISTER) || n.Addable == 0 || n.Op == OLITERAL {
346
		var reg Node
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
		Thearch.Regalloc(&reg, Types[Tptr], n)
		Thearch.Cgen(n, &reg)
		Thearch.Gins(obj.ACHECKNIL, &reg, nil)
		Thearch.Regfree(&reg)
		return
	}

	Thearch.Gins(obj.ACHECKNIL, n, nil)
}

/*
 * ggen.c
 */
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")
	}

370
	lno := setlineno(fn)
371 372 373 374

	Curfn = fn
	dowidth(Curfn.Type)

375 376 377 378 379 380 381 382 383
	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
384
	if fn.Nbody == nil {
385
		if pure_go != 0 || strings.HasPrefix(fn.Nname.Sym.Name, "init.") {
386
			Yyerror("missing function body for %q", fn.Nname.Sym.Name)
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
			goto ret
		}

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

	saveerrors()

	// set up domain for labels
	clearlabels()

	if Curfn.Type.Outnamed != 0 {
		// add clearing of the output parameters
404 405
		var save Iter
		t := Structfirst(&save, Getoutarg(Curfn.Type))
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454

		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 = 0
	walk(Curfn)
	if nerrors != 0 {
		goto ret
	}
	if flag_race != 0 {
		racewalk(Curfn)
	}
	if nerrors != 0 {
		goto ret
	}

	continpc = nil
	breakpc = nil

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

	setlineno(Curfn)

	Nodconst(&nod1, Types[TINT32], 0)
	nam = Curfn.Nname
	if isblank(nam) {
		nam = nil
	}
	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
	if fn.Dupok != 0 {
		ptxt.From3.Offset |= obj.DUPOK
	}
	if fn.Wrapper != 0 {
		ptxt.From3.Offset |= obj.WRAPPER
	}
455
	if fn.Needctxt {
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
		ptxt.From3.Offset |= obj.NEEDCTXT
	}
	if fn.Nosplit {
		ptxt.From3.Offset |= obj.NOSPLIT
	}

	// 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.Nname.Sym.Name == "callReflect" || Curfn.Nname.Sym.Name == "callMethod" {
			ptxt.From3.Offset |= obj.WRAPPER
		}
	}

	Afunclit(&ptxt.From, Curfn.Nname)

	Thearch.Ginit()

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

478
	for t := Curfn.Paramfld; t != nil; t = t.Down {
479 480 481
		gtrack(tracksym(t.Type))
	}

482
	for l := fn.Dcl; l != nil; l = l.Next {
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
		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.Enter)
	Genlist(Curfn.Nbody)
	Thearch.Gclean()
	checklabels()
	if nerrors != 0 {
		goto ret
	}
	if Curfn.Endlineno != 0 {
		lineno = Curfn.Endlineno
	}

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

	Thearch.Ginit()

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

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

	Thearch.Gclean()
	if nerrors != 0 {
		goto ret
	}

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

	fixjmp(ptxt)
534
	if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
		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
}