mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: remove GOEXPERIMENT=nounified frontend
This CL removes most of the code specific to the nounified frontend. To simplify review, it's a strict remove-only CL. Updates #57410. Change-Id: Ic3196570aa4286618c1d5e7fd0d0e6601a18195b Reviewed-on: https://go-review.googlesource.com/c/go/+/458620 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
a7de684e1b
commit
da9761303c
23 changed files with 0 additions and 11575 deletions
|
|
@ -31,7 +31,6 @@ import (
|
|||
"go/constant"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
|
|
@ -40,7 +39,6 @@ import (
|
|||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
// Inlining budget parameters, gathered in one place
|
||||
|
|
@ -879,23 +877,6 @@ func inlCallee(fn ir.Node, profile *pgo.Profile) *ir.Func {
|
|||
return nil
|
||||
}
|
||||
|
||||
func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
|
||||
if t.Nname == nil {
|
||||
return ir.BlankNode
|
||||
}
|
||||
n := t.Nname.(*ir.Name)
|
||||
if ir.IsBlank(n) {
|
||||
return ir.BlankNode
|
||||
}
|
||||
inlvar := inlvars[n]
|
||||
if inlvar == nil {
|
||||
base.Fatalf("missing inlvar for %v", n)
|
||||
}
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
|
||||
inlvar.Name().Defn = as
|
||||
return inlvar
|
||||
}
|
||||
|
||||
var inlgen int
|
||||
|
||||
// SSADumpInline gives the SSA back end a chance to dump the function
|
||||
|
|
@ -1094,576 +1075,6 @@ func CalleeEffects(init *ir.Nodes, callee ir.Node) {
|
|||
}
|
||||
}
|
||||
|
||||
// oldInlineCall creates an InlinedCallExpr to replace the given call
|
||||
// expression. fn is the callee function to be inlined. inlIndex is
|
||||
// the inlining tree position index, for use with src.NewInliningBase
|
||||
// when rewriting positions.
|
||||
func oldInlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr {
|
||||
SSADumpInline(fn)
|
||||
|
||||
ninit := call.Init()
|
||||
|
||||
// For normal function calls, the function callee expression
|
||||
// may contain side effects. Make sure to preserve these,
|
||||
// if necessary (#42703).
|
||||
if call.Op() == ir.OCALLFUNC {
|
||||
CalleeEffects(&ninit, call.X)
|
||||
}
|
||||
|
||||
// Make temp names to use instead of the originals.
|
||||
inlvars := make(map[*ir.Name]*ir.Name)
|
||||
|
||||
// record formals/locals for later post-processing
|
||||
var inlfvars []*ir.Name
|
||||
|
||||
for _, ln := range fn.Inl.Dcl {
|
||||
if ln.Op() != ir.ONAME {
|
||||
continue
|
||||
}
|
||||
if ln.Class == ir.PPARAMOUT { // return values handled below.
|
||||
continue
|
||||
}
|
||||
inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
|
||||
inlvars[ln] = inlf
|
||||
if base.Flag.GenDwarfInl > 0 {
|
||||
if ln.Class == ir.PPARAM {
|
||||
inlf.Name().SetInlFormal(true)
|
||||
} else {
|
||||
inlf.Name().SetInlLocal(true)
|
||||
}
|
||||
inlf.SetPos(ln.Pos())
|
||||
inlfvars = append(inlfvars, inlf)
|
||||
}
|
||||
}
|
||||
|
||||
// We can delay declaring+initializing result parameters if:
|
||||
// temporaries for return values.
|
||||
var retvars []ir.Node
|
||||
for i, t := range fn.Type().Results().Fields().Slice() {
|
||||
var m *ir.Name
|
||||
if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
|
||||
n := nn.(*ir.Name)
|
||||
m = inlvar(n)
|
||||
m = typecheck.Expr(m).(*ir.Name)
|
||||
inlvars[n] = m
|
||||
} else {
|
||||
// anonymous return values, synthesize names for use in assignment that replaces return
|
||||
m = retvar(t, i)
|
||||
}
|
||||
|
||||
if base.Flag.GenDwarfInl > 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.Name().SetInlFormal(true)
|
||||
m.SetPos(t.Pos)
|
||||
inlfvars = append(inlfvars, m)
|
||||
}
|
||||
}
|
||||
|
||||
retvars = append(retvars, m)
|
||||
}
|
||||
|
||||
// Assign arguments to the parameters' temp names.
|
||||
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
||||
as.Def = true
|
||||
if call.Op() == ir.OCALLMETH {
|
||||
base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
|
||||
}
|
||||
as.Rhs.Append(call.Args...)
|
||||
|
||||
if recv := fn.Type().Recv(); recv != nil {
|
||||
as.Lhs.Append(inlParam(recv, as, inlvars))
|
||||
}
|
||||
for _, param := range fn.Type().Params().Fields().Slice() {
|
||||
as.Lhs.Append(inlParam(param, as, inlvars))
|
||||
}
|
||||
|
||||
if len(as.Rhs) != 0 {
|
||||
ninit.Append(typecheck.Stmt(as))
|
||||
}
|
||||
|
||||
if !fn.Inl.CanDelayResults {
|
||||
// Zero the return parameters.
|
||||
for _, n := range retvars {
|
||||
ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
|
||||
ras := ir.NewAssignStmt(base.Pos, n, nil)
|
||||
ninit.Append(typecheck.Stmt(ras))
|
||||
}
|
||||
}
|
||||
|
||||
retlabel := typecheck.AutoLabel(".i")
|
||||
|
||||
inlgen++
|
||||
|
||||
// Add an inline mark just before the inlined body.
|
||||
// This mark is inline in the code so that it's a reasonable spot
|
||||
// to put a breakpoint. Not sure if that's really necessary or not
|
||||
// (in which case it could go at the end of the function instead).
|
||||
// Note issue 28603.
|
||||
ninit.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(inlIndex)))
|
||||
|
||||
subst := inlsubst{
|
||||
retlabel: retlabel,
|
||||
retvars: retvars,
|
||||
inlvars: inlvars,
|
||||
defnMarker: ir.NilExpr{},
|
||||
bases: make(map[*src.PosBase]*src.PosBase),
|
||||
newInlIndex: inlIndex,
|
||||
fn: fn,
|
||||
}
|
||||
subst.edit = subst.node
|
||||
|
||||
body := subst.list(ir.Nodes(fn.Inl.Body))
|
||||
|
||||
lab := ir.NewLabelStmt(base.Pos, retlabel)
|
||||
body = append(body, lab)
|
||||
|
||||
if base.Flag.GenDwarfInl > 0 {
|
||||
for _, v := range inlfvars {
|
||||
v.SetPos(subst.updatedPos(v.Pos()))
|
||||
}
|
||||
}
|
||||
|
||||
//dumplist("ninit post", ninit);
|
||||
|
||||
res := ir.NewInlinedCallExpr(base.Pos, body, retvars)
|
||||
res.SetInit(ninit)
|
||||
res.SetType(call.Type())
|
||||
res.SetTypecheck(1)
|
||||
return res
|
||||
}
|
||||
|
||||
// Every time we expand a function we generate a new set of tmpnames,
|
||||
// PAUTO's in the calling functions, and link them off of the
|
||||
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
|
||||
func inlvar(var_ *ir.Name) *ir.Name {
|
||||
if base.Flag.LowerM > 3 {
|
||||
fmt.Printf("inlvar %+v\n", var_)
|
||||
}
|
||||
|
||||
n := typecheck.NewName(var_.Sym())
|
||||
n.SetType(var_.Type())
|
||||
n.SetTypecheck(1)
|
||||
n.Class = ir.PAUTO
|
||||
n.SetUsed(true)
|
||||
n.SetAutoTemp(var_.AutoTemp())
|
||||
n.Curfn = ir.CurFunc // the calling function, not the called one
|
||||
n.SetAddrtaken(var_.Addrtaken())
|
||||
|
||||
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
||||
return n
|
||||
}
|
||||
|
||||
// Synthesize a variable to store the inlined function's results in.
|
||||
func retvar(t *types.Field, i int) *ir.Name {
|
||||
n := typecheck.NewName(typecheck.LookupNum("~R", i))
|
||||
n.SetType(t.Type)
|
||||
n.SetTypecheck(1)
|
||||
n.Class = ir.PAUTO
|
||||
n.SetUsed(true)
|
||||
n.Curfn = ir.CurFunc // the calling function, not the called one
|
||||
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
||||
return n
|
||||
}
|
||||
|
||||
// The inlsubst type implements the actual inlining of a single
|
||||
// function call.
|
||||
type inlsubst struct {
|
||||
// Target of the goto substituted in place of a return.
|
||||
retlabel *types.Sym
|
||||
|
||||
// Temporary result variables.
|
||||
retvars []ir.Node
|
||||
|
||||
inlvars map[*ir.Name]*ir.Name
|
||||
// defnMarker is used to mark a Node for reassignment.
|
||||
// inlsubst.clovar set this during creating new ONAME.
|
||||
// inlsubst.node will set the correct Defn for inlvar.
|
||||
defnMarker ir.NilExpr
|
||||
|
||||
// bases maps from original PosBase to PosBase with an extra
|
||||
// inlined call frame.
|
||||
bases map[*src.PosBase]*src.PosBase
|
||||
|
||||
// newInlIndex is the index of the inlined call frame to
|
||||
// insert for inlined nodes.
|
||||
newInlIndex int
|
||||
|
||||
edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
|
||||
|
||||
// If non-nil, we are inside a closure inside the inlined function, and
|
||||
// newclofn is the Func of the new inlined closure.
|
||||
newclofn *ir.Func
|
||||
|
||||
fn *ir.Func // For debug -- the func that is being inlined
|
||||
|
||||
// If true, then don't update source positions during substitution
|
||||
// (retain old source positions).
|
||||
noPosUpdate bool
|
||||
}
|
||||
|
||||
// list inlines a list of nodes.
|
||||
func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
|
||||
s := make([]ir.Node, 0, len(ll))
|
||||
for _, n := range ll {
|
||||
s = append(s, subst.node(n))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// fields returns a list of the fields of a struct type representing receiver,
|
||||
// params, or results, after duplicating the field nodes and substituting the
|
||||
// Nname nodes inside the field nodes.
|
||||
func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
|
||||
oldfields := oldt.FieldSlice()
|
||||
newfields := make([]*types.Field, len(oldfields))
|
||||
for i := range oldfields {
|
||||
newfields[i] = oldfields[i].Copy()
|
||||
if oldfields[i].Nname != nil {
|
||||
newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
|
||||
}
|
||||
}
|
||||
return newfields
|
||||
}
|
||||
|
||||
// clovar creates a new ONAME node for a local variable or param of a closure
|
||||
// inside a function being inlined.
|
||||
func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
|
||||
m := ir.NewNameAt(n.Pos(), n.Sym())
|
||||
m.Class = n.Class
|
||||
m.SetType(n.Type())
|
||||
m.SetTypecheck(1)
|
||||
if n.IsClosureVar() {
|
||||
m.SetIsClosureVar(true)
|
||||
}
|
||||
if n.Addrtaken() {
|
||||
m.SetAddrtaken(true)
|
||||
}
|
||||
if n.Used() {
|
||||
m.SetUsed(true)
|
||||
}
|
||||
m.Defn = n.Defn
|
||||
|
||||
m.Curfn = subst.newclofn
|
||||
|
||||
switch defn := n.Defn.(type) {
|
||||
case nil:
|
||||
// ok
|
||||
case *ir.Name:
|
||||
if !n.IsClosureVar() {
|
||||
base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
|
||||
}
|
||||
if n.Sym().Pkg != types.LocalPkg {
|
||||
// If the closure came from inlining a function from
|
||||
// another package, must change package of captured
|
||||
// variable to localpkg, so that the fields of the closure
|
||||
// struct are local package and can be accessed even if
|
||||
// name is not exported. If you disable this code, you can
|
||||
// reproduce the problem by running 'go test
|
||||
// go/internal/srcimporter'. TODO(mdempsky) - maybe change
|
||||
// how we create closure structs?
|
||||
m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
|
||||
}
|
||||
// Make sure any inlvar which is the Defn
|
||||
// of an ONAME closure var is rewritten
|
||||
// during inlining. Don't substitute
|
||||
// if Defn node is outside inlined function.
|
||||
if subst.inlvars[n.Defn.(*ir.Name)] != nil {
|
||||
m.Defn = subst.node(n.Defn)
|
||||
}
|
||||
case *ir.AssignStmt, *ir.AssignListStmt:
|
||||
// Mark node for reassignment at the end of inlsubst.node.
|
||||
m.Defn = &subst.defnMarker
|
||||
case *ir.TypeSwitchGuard:
|
||||
// TODO(mdempsky): Set m.Defn properly. See discussion on #45743.
|
||||
case *ir.RangeStmt:
|
||||
// TODO: Set m.Defn properly if we support inlining range statement in the future.
|
||||
default:
|
||||
base.FatalfAt(n.Pos(), "unexpected Defn: %+v", defn)
|
||||
}
|
||||
|
||||
if n.Outer != nil {
|
||||
// Either the outer variable is defined in function being inlined,
|
||||
// and we will replace it with the substituted variable, or it is
|
||||
// defined outside the function being inlined, and we should just
|
||||
// skip the outer variable (the closure variable of the function
|
||||
// being inlined).
|
||||
s := subst.node(n.Outer).(*ir.Name)
|
||||
if s == n.Outer {
|
||||
s = n.Outer.Outer
|
||||
}
|
||||
m.Outer = s
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// closure does the necessary substitutions for a ClosureExpr n and returns the new
|
||||
// closure node.
|
||||
func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
|
||||
// Prior to the subst edit, set a flag in the inlsubst to indicate
|
||||
// that we don't want to update the source positions in the new
|
||||
// closure function. If we do this, it will appear that the
|
||||
// closure itself has things inlined into it, which is not the
|
||||
// case. See issue #46234 for more details. At the same time, we
|
||||
// do want to update the position in the new ClosureExpr (which is
|
||||
// part of the function we're working on). See #49171 for an
|
||||
// example of what happens if we miss that update.
|
||||
newClosurePos := subst.updatedPos(n.Pos())
|
||||
defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate)
|
||||
subst.noPosUpdate = true
|
||||
|
||||
//fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
|
||||
|
||||
oldfn := n.Func
|
||||
newfn := ir.NewClosureFunc(oldfn.Pos(), true)
|
||||
|
||||
if subst.newclofn != nil {
|
||||
//fmt.Printf("Inlining a closure with a nested closure\n")
|
||||
}
|
||||
prevxfunc := subst.newclofn
|
||||
|
||||
// Mark that we are now substituting within a closure (within the
|
||||
// inlined function), and create new nodes for all the local
|
||||
// vars/params inside this closure.
|
||||
subst.newclofn = newfn
|
||||
newfn.Dcl = nil
|
||||
newfn.ClosureVars = nil
|
||||
for _, oldv := range oldfn.Dcl {
|
||||
newv := subst.clovar(oldv)
|
||||
subst.inlvars[oldv] = newv
|
||||
newfn.Dcl = append(newfn.Dcl, newv)
|
||||
}
|
||||
for _, oldv := range oldfn.ClosureVars {
|
||||
newv := subst.clovar(oldv)
|
||||
subst.inlvars[oldv] = newv
|
||||
newfn.ClosureVars = append(newfn.ClosureVars, newv)
|
||||
}
|
||||
|
||||
// Need to replace ONAME nodes in
|
||||
// newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
|
||||
oldt := oldfn.Type()
|
||||
newrecvs := subst.fields(oldt.Recvs())
|
||||
var newrecv *types.Field
|
||||
if len(newrecvs) > 0 {
|
||||
newrecv = newrecvs[0]
|
||||
}
|
||||
newt := types.NewSignature(oldt.Pkg(), newrecv,
|
||||
nil, subst.fields(oldt.Params()), subst.fields(oldt.Results()))
|
||||
|
||||
newfn.Nname.SetType(newt)
|
||||
newfn.Body = subst.list(oldfn.Body)
|
||||
|
||||
// Remove the nodes for the current closure from subst.inlvars
|
||||
for _, oldv := range oldfn.Dcl {
|
||||
delete(subst.inlvars, oldv)
|
||||
}
|
||||
for _, oldv := range oldfn.ClosureVars {
|
||||
delete(subst.inlvars, oldv)
|
||||
}
|
||||
// Go back to previous closure func
|
||||
subst.newclofn = prevxfunc
|
||||
|
||||
// Actually create the named function for the closure, now that
|
||||
// the closure is inlined in a specific function.
|
||||
newclo := newfn.OClosure
|
||||
newclo.SetPos(newClosurePos)
|
||||
newclo.SetInit(subst.list(n.Init()))
|
||||
return typecheck.Expr(newclo)
|
||||
}
|
||||
|
||||
// node recursively copies a node from the saved pristine body of the
|
||||
// inlined function, substituting references to input/output
|
||||
// parameters with ones to the tmpnames, and substituting returns with
|
||||
// assignments to the output.
|
||||
func (subst *inlsubst) node(n ir.Node) ir.Node {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
case ir.ONAME:
|
||||
n := n.(*ir.Name)
|
||||
|
||||
// Handle captured variables when inlining closures.
|
||||
if n.IsClosureVar() && subst.newclofn == nil {
|
||||
o := n.Outer
|
||||
|
||||
// Deal with case where sequence of closures are inlined.
|
||||
// TODO(danscales) - write test case to see if we need to
|
||||
// go up multiple levels.
|
||||
if o.Curfn != ir.CurFunc {
|
||||
o = o.Outer
|
||||
}
|
||||
|
||||
// make sure the outer param matches the inlining location
|
||||
if o == nil || o.Curfn != ir.CurFunc {
|
||||
base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
|
||||
}
|
||||
|
||||
if base.Flag.LowerM > 2 {
|
||||
fmt.Printf("substituting captured name %+v -> %+v\n", n, o)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
|
||||
if base.Flag.LowerM > 2 {
|
||||
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
||||
}
|
||||
return inlvar
|
||||
}
|
||||
|
||||
if base.Flag.LowerM > 2 {
|
||||
fmt.Printf("not substituting name %+v\n", n)
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OMETHEXPR:
|
||||
n := n.(*ir.SelectorExpr)
|
||||
return n
|
||||
|
||||
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
|
||||
// If n is a named constant or type, we can continue
|
||||
// using it in the inline copy. Otherwise, make a copy
|
||||
// so we can update the line number.
|
||||
if n.Sym() != nil {
|
||||
return n
|
||||
}
|
||||
|
||||
case ir.ORETURN:
|
||||
if subst.newclofn != nil {
|
||||
// Don't do special substitutions if inside a closure
|
||||
break
|
||||
}
|
||||
// Because of the above test for subst.newclofn,
|
||||
// this return is guaranteed to belong to the current inlined function.
|
||||
n := n.(*ir.ReturnStmt)
|
||||
init := subst.list(n.Init())
|
||||
if len(subst.retvars) != 0 && len(n.Results) != 0 {
|
||||
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
||||
|
||||
// Make a shallow copy of retvars.
|
||||
// Otherwise OINLCALL.Rlist will be the same list,
|
||||
// and later walk and typecheck may clobber it.
|
||||
for _, n := range subst.retvars {
|
||||
as.Lhs.Append(n)
|
||||
}
|
||||
as.Rhs = subst.list(n.Results)
|
||||
|
||||
if subst.fn.Inl.CanDelayResults {
|
||||
for _, n := range as.Lhs {
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
|
||||
n.Name().Defn = as
|
||||
}
|
||||
}
|
||||
|
||||
init = append(init, typecheck.Stmt(as))
|
||||
}
|
||||
init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
|
||||
typecheck.Stmts(init)
|
||||
return ir.NewBlockStmt(base.Pos, init)
|
||||
|
||||
case ir.OGOTO, ir.OBREAK, ir.OCONTINUE:
|
||||
if subst.newclofn != nil {
|
||||
// Don't do special substitutions if inside a closure
|
||||
break
|
||||
}
|
||||
n := n.(*ir.BranchStmt)
|
||||
m := ir.Copy(n).(*ir.BranchStmt)
|
||||
m.SetPos(subst.updatedPos(m.Pos()))
|
||||
m.SetInit(nil)
|
||||
m.Label = translateLabel(n.Label)
|
||||
return m
|
||||
|
||||
case ir.OLABEL:
|
||||
if subst.newclofn != nil {
|
||||
// Don't do special substitutions if inside a closure
|
||||
break
|
||||
}
|
||||
n := n.(*ir.LabelStmt)
|
||||
m := ir.Copy(n).(*ir.LabelStmt)
|
||||
m.SetPos(subst.updatedPos(m.Pos()))
|
||||
m.SetInit(nil)
|
||||
m.Label = translateLabel(n.Label)
|
||||
return m
|
||||
|
||||
case ir.OCLOSURE:
|
||||
return subst.closure(n.(*ir.ClosureExpr))
|
||||
|
||||
}
|
||||
|
||||
m := ir.Copy(n)
|
||||
m.SetPos(subst.updatedPos(m.Pos()))
|
||||
ir.EditChildren(m, subst.edit)
|
||||
|
||||
if subst.newclofn == nil {
|
||||
// Translate any label on FOR, RANGE loops, SWITCH or SELECT
|
||||
switch m.Op() {
|
||||
case ir.OFOR:
|
||||
m := m.(*ir.ForStmt)
|
||||
m.Label = translateLabel(m.Label)
|
||||
return m
|
||||
|
||||
case ir.ORANGE:
|
||||
m := m.(*ir.RangeStmt)
|
||||
m.Label = translateLabel(m.Label)
|
||||
return m
|
||||
|
||||
case ir.OSWITCH:
|
||||
m := m.(*ir.SwitchStmt)
|
||||
m.Label = translateLabel(m.Label)
|
||||
return m
|
||||
|
||||
case ir.OSELECT:
|
||||
m := m.(*ir.SelectStmt)
|
||||
m.Label = translateLabel(m.Label)
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *ir.AssignStmt:
|
||||
if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
|
||||
lhs.Defn = m
|
||||
}
|
||||
case *ir.AssignListStmt:
|
||||
for _, lhs := range m.Lhs {
|
||||
if lhs, ok := lhs.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
|
||||
lhs.Defn = m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// translateLabel makes a label from an inlined function (if non-nil) be unique by
|
||||
// adding "·inlgen".
|
||||
func translateLabel(l *types.Sym) *types.Sym {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
p := fmt.Sprintf("%s·%d", l.Name, inlgen)
|
||||
return typecheck.Lookup(p)
|
||||
}
|
||||
|
||||
func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
|
||||
if subst.noPosUpdate {
|
||||
return xpos
|
||||
}
|
||||
pos := base.Ctxt.PosTable.Pos(xpos)
|
||||
oldbase := pos.Base() // can be nil
|
||||
newbase := subst.bases[oldbase]
|
||||
if newbase == nil {
|
||||
newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
|
||||
subst.bases[oldbase] = newbase
|
||||
}
|
||||
pos.SetBase(newbase)
|
||||
return base.Ctxt.PosTable.XPos(pos)
|
||||
}
|
||||
|
||||
func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
|
||||
s := make([]*ir.Name, 0, len(ll))
|
||||
for _, n := range ll {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue