compiler,linker: support for DWARF inlined instances

Compiler and linker changes to support DWARF inlined instances,
see https://go.googlesource.com/proposal/+/HEAD/design/22080-dwarf-inlining.md
for design details.

This functionality is gated via the cmd/compile option -gendwarfinl=N,
where N={0,1,2}, where a value of 0 disables dwarf inline generation,
a value of 1 turns on dwarf generation without tracking of formal/local
vars from inlined routines, and a value of 2 enables inlines with
variable tracking.

Updates #22080

Change-Id: I69309b3b815d9fed04aebddc0b8d33d0dbbfad6e
Reviewed-on: https://go-review.googlesource.com/75550
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index e54bb97..0e8ef19 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -31,8 +31,11 @@
 
 import (
 	"cmd/compile/internal/types"
+	"cmd/internal/obj"
 	"cmd/internal/src"
 	"fmt"
+	"sort"
+	"strings"
 )
 
 // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
@@ -809,6 +812,9 @@
 	// Make temp names to use instead of the originals.
 	inlvars := make(map[*Node]*Node)
 
+	// record formals/locals for later post-processing
+	var inlfvars []*Node
+
 	// Find declarations corresponding to inlineable body.
 	var dcl []*Node
 	if fn.Name.Defn != nil {
@@ -867,13 +873,25 @@
 		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
 			ninit.Append(nod(ODCL, inlvars[ln], nil))
 		}
+		if genDwarfInline > 0 {
+			inlf := inlvars[ln]
+			if ln.Class() == PPARAM {
+				inlf.SetInlFormal(true)
+			} else {
+				inlf.SetInlLocal(true)
+			}
+			inlf.Pos = ln.Pos
+			inlfvars = append(inlfvars, inlf)
+		}
 	}
 
 	// temporaries for return values.
 	var retvars []*Node
 	for i, t := range fn.Type.Results().Fields().Slice() {
 		var m *Node
+		var mpos src.XPos
 		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
+			mpos = asNode(t.Nname).Pos
 			m = inlvar(asNode(t.Nname))
 			m = typecheck(m, Erv)
 			inlvars[asNode(t.Nname)] = m
@@ -882,6 +900,17 @@
 			m = retvar(t, i)
 		}
 
+		if genDwarfInline > 0 {
+			// Don't update the src.Pos on a return variable if it
+			// was manufactured by the inliner (e.g. "~r2"); such vars
+			// were not part of the original callee.
+			if !strings.HasPrefix(m.Sym.Name, "~r") {
+				m.SetInlFormal(true)
+				m.Pos = mpos
+				inlfvars = append(inlfvars, m)
+			}
+		}
+
 		ninit.Append(nod(ODCL, m, nil))
 		retvars = append(retvars, m)
 	}
@@ -976,8 +1005,16 @@
 	if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
 		parent = b.InliningIndex()
 	}
+	sort.Sort(byNodeName(dcl))
 	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
 
+	if genDwarfInline > 0 {
+		if !fn.Sym.Linksym().WasInlined() {
+			Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn)
+			fn.Sym.Linksym().Set(obj.AttrWasInlined, true)
+		}
+	}
+
 	subst := inlsubst{
 		retlabel:    retlabel,
 		retvars:     retvars,
@@ -993,6 +1030,12 @@
 
 	typecheckslice(body, Etop)
 
+	if genDwarfInline > 0 {
+		for _, v := range inlfvars {
+			v.Pos = subst.updatedPos(v.Pos)
+		}
+	}
+
 	//dumplist("ninit post", ninit);
 
 	call := nod(OINLCALL, nil, nil)
@@ -1192,3 +1235,28 @@
 	pos.SetBase(newbase)
 	return Ctxt.PosTable.XPos(pos)
 }
+
+func cmpNodeName(a, b *Node) bool {
+	// named before artificial
+	aart := 0
+	if strings.HasPrefix(a.Sym.Name, "~r") {
+		aart = 1
+	}
+	bart := 0
+	if strings.HasPrefix(b.Sym.Name, "~r") {
+		bart = 1
+	}
+	if aart != bart {
+		return aart < bart
+	}
+
+	// otherwise sort by name
+	return a.Sym.Name < b.Sym.Name
+}
+
+// byNodeName implements sort.Interface for []*Node using cmpNodeName.
+type byNodeName []*Node
+
+func (s byNodeName) Len() int           { return len(s) }
+func (s byNodeName) Less(i, j int) bool { return cmpNodeName(s[i], s[j]) }
+func (s byNodeName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }