mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/ir: add Func.DeclareParams
There's several copies of this function. We only need one. While here, normalize so that we always declare parameters, and always use the names ~pNN for params and ~rNN for results. Change-Id: I49e90d3fd1820f3c07936227ed5cfefd75d49a1c Reviewed-on: https://go-review.googlesource.com/c/go/+/528415 Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Auto-Submit: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
de4ead8102
commit
d18e9407b0
15 changed files with 179 additions and 361 deletions
|
|
@ -21,42 +21,12 @@ type paramsAnalyzer struct {
|
||||||
*condLevelTracker
|
*condLevelTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
// dclParams returns a slice containing the non-blank, named params
|
|
||||||
// for the specific function (plus rcvr as well if applicable) in
|
|
||||||
// declaration order.
|
|
||||||
func dclParams(fn *ir.Func) []*ir.Name {
|
|
||||||
params := []*ir.Name{}
|
|
||||||
for _, n := range fn.Dcl {
|
|
||||||
if n.Op() != ir.ONAME {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if n.Class != ir.PPARAM {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
params = append(params, n)
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
// getParams returns an *ir.Name slice containing all params for the
|
// getParams returns an *ir.Name slice containing all params for the
|
||||||
// function (plus rcvr as well if applicable). Note that this slice
|
// function (plus rcvr as well if applicable).
|
||||||
// includes entries for blanks; entries in the returned slice corresponding
|
|
||||||
// to blanks or unnamed params will be nil.
|
|
||||||
func getParams(fn *ir.Func) []*ir.Name {
|
func getParams(fn *ir.Func) []*ir.Name {
|
||||||
dclparms := dclParams(fn)
|
sig := fn.Type()
|
||||||
dclidx := 0
|
numParams := sig.NumRecvs() + sig.NumParams()
|
||||||
recvrParms := fn.Type().RecvParams()
|
return fn.Dcl[:numParams]
|
||||||
params := make([]*ir.Name, len(recvrParms))
|
|
||||||
for i := range recvrParms {
|
|
||||||
var v *ir.Name
|
|
||||||
if recvrParms[i].Sym != nil &&
|
|
||||||
!recvrParms[i].Sym.IsBlank() {
|
|
||||||
v = dclparms[dclidx]
|
|
||||||
dclidx++
|
|
||||||
}
|
|
||||||
params[i] = v
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeParamsAnalyzer(fn *ir.Func) *paramsAnalyzer {
|
func makeParamsAnalyzer(fn *ir.Func) *paramsAnalyzer {
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,7 @@ type Func struct {
|
||||||
// include closurevars until transforming closures during walk.
|
// include closurevars until transforming closures during walk.
|
||||||
// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
|
// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
|
||||||
// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
|
// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
|
||||||
// However, as anonymous or blank PPARAMs are not actually declared,
|
// Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
|
||||||
// they are omitted from Dcl.
|
|
||||||
// Anonymous and blank PPARAMOUTs are declared as ~rNN and ~bNN Names, respectively.
|
|
||||||
Dcl []*Name
|
Dcl []*Name
|
||||||
|
|
||||||
// ClosureVars lists the free variables that are used within a
|
// ClosureVars lists the free variables that are used within a
|
||||||
|
|
@ -455,3 +453,40 @@ func IsFuncPCIntrinsic(n *CallExpr) bool {
|
||||||
return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
|
return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
|
||||||
fn.Pkg.Path == "internal/abi"
|
fn.Pkg.Path == "internal/abi"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeclareParams creates Names for all of the parameters in fn's
|
||||||
|
// signature and adds them to fn.Dcl.
|
||||||
|
//
|
||||||
|
// If setNname is true, then it also sets types.Field.Nname for each
|
||||||
|
// parameter.
|
||||||
|
func (fn *Func) DeclareParams(setNname bool) {
|
||||||
|
if fn.Dcl != nil {
|
||||||
|
base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
|
||||||
|
for i, param := range params {
|
||||||
|
sym := param.Sym
|
||||||
|
if sym == nil || sym.IsBlank() {
|
||||||
|
sym = fn.Sym().Pkg.LookupNum(prefix, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := NewNameAt(param.Pos, sym, param.Type)
|
||||||
|
name.Class = ctxt
|
||||||
|
name.Curfn = fn
|
||||||
|
fn.Dcl[offset+i] = name
|
||||||
|
|
||||||
|
if setNname {
|
||||||
|
param.Nname = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := fn.Type()
|
||||||
|
params := sig.RecvParams()
|
||||||
|
results := sig.Results()
|
||||||
|
|
||||||
|
fn.Dcl = make([]*Name, len(params)+len(results))
|
||||||
|
declareParams(params, PPARAM, "~p", 0)
|
||||||
|
declareParams(results, PPARAMOUT, "~r", len(params))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,16 +102,13 @@ func NewBuiltin(sym *types.Sym, op Op) *Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLocal returns a new function-local variable with the given name and type.
|
// NewLocal returns a new function-local variable with the given name and type.
|
||||||
func (fn *Func) NewLocal(pos src.XPos, sym *types.Sym, class Class, typ *types.Type) *Name {
|
func (fn *Func) NewLocal(pos src.XPos, sym *types.Sym, typ *types.Type) *Name {
|
||||||
switch class {
|
if fn.Dcl == nil {
|
||||||
case PPARAM, PPARAMOUT, PAUTO:
|
base.FatalfAt(pos, "must call DeclParams on %v first", fn)
|
||||||
// ok
|
|
||||||
default:
|
|
||||||
base.FatalfAt(pos, "NewLocal: unexpected class for %v: %v", sym, class)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n := NewNameAt(pos, sym, typ)
|
n := NewNameAt(pos, sym, typ)
|
||||||
n.Class = class
|
n.Class = PAUTO
|
||||||
n.Curfn = fn
|
n.Curfn = fn
|
||||||
fn.Dcl = append(fn.Dcl, n)
|
fn.Dcl = append(fn.Dcl, n)
|
||||||
return n
|
return n
|
||||||
|
|
|
||||||
|
|
@ -318,11 +318,18 @@ func (op Op) IsCmp() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nodes is a pointer to a slice of *Node.
|
// Nodes is a slice of Node.
|
||||||
// For fields that are not used in most nodes, this is used instead of
|
|
||||||
// a slice to save space.
|
|
||||||
type Nodes []Node
|
type Nodes []Node
|
||||||
|
|
||||||
|
// ToNodes returns s as a slice of Nodes.
|
||||||
|
func ToNodes[T Node](s []T) Nodes {
|
||||||
|
res := make(Nodes, len(s))
|
||||||
|
for i, n := range s {
|
||||||
|
res[i] = n
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// Append appends entries to Nodes.
|
// Append appends entries to Nodes.
|
||||||
func (n *Nodes) Append(a ...Node) {
|
func (n *Nodes) Append(a ...Node) {
|
||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -205,15 +205,15 @@ func s15a8(x *[15]int64) [15]int64 {
|
||||||
`"relatedInformation":[`+
|
`"relatedInformation":[`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~R0 = y:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r0 = y:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u0026y.b (assign-pair)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r0 = \u0026y.b (assign-pair)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~R0:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~r0:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~R0 (return)"}]}`)
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~r0 (return)"}]}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,11 @@ type reader struct {
|
||||||
locals []*ir.Name
|
locals []*ir.Name
|
||||||
closureVars []*ir.Name
|
closureVars []*ir.Name
|
||||||
|
|
||||||
|
// funarghack is used during inlining to suppress setting
|
||||||
|
// Field.Nname to the inlined copies of the parameters. This is
|
||||||
|
// necessary because we reuse the same types.Type as the original
|
||||||
|
// function, and most of the compiler still relies on field.Nname to
|
||||||
|
// find parameters/results.
|
||||||
funarghack bool
|
funarghack bool
|
||||||
|
|
||||||
// methodSym is the name of method's name, if reading a method.
|
// methodSym is the name of method's name, if reading a method.
|
||||||
|
|
@ -145,14 +150,6 @@ type reader struct {
|
||||||
|
|
||||||
// Label to return to.
|
// Label to return to.
|
||||||
retlabel *types.Sym
|
retlabel *types.Sym
|
||||||
|
|
||||||
// inlvars is the list of variables that the inlinee's arguments are
|
|
||||||
// assigned to, one for each receiver and normal parameter, in order.
|
|
||||||
inlvars ir.Nodes
|
|
||||||
|
|
||||||
// retvars is the list of variables that the inlinee's results are
|
|
||||||
// assigned to, one for each result parameter, in order.
|
|
||||||
retvars ir.Nodes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A readerDict represents an instantiated "compile-time dictionary,"
|
// A readerDict represents an instantiated "compile-time dictionary,"
|
||||||
|
|
@ -1237,7 +1234,7 @@ func (r *reader) funcBody(fn *ir.Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ir.WithFunc(fn, func() {
|
ir.WithFunc(fn, func() {
|
||||||
r.funcargs(fn)
|
r.declareParams()
|
||||||
|
|
||||||
if r.syntheticBody(fn.Pos()) {
|
if r.syntheticBody(fn.Pos()) {
|
||||||
return
|
return
|
||||||
|
|
@ -1294,7 +1291,7 @@ func (r *reader) callShaped(pos src.XPos) {
|
||||||
shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym)
|
shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym)
|
||||||
}
|
}
|
||||||
|
|
||||||
recvs, params := r.syntheticArgs(pos)
|
params := r.syntheticArgs()
|
||||||
|
|
||||||
// Construct the arguments list: receiver (if any), then runtime
|
// Construct the arguments list: receiver (if any), then runtime
|
||||||
// dictionary, and finally normal parameters.
|
// dictionary, and finally normal parameters.
|
||||||
|
|
@ -1306,7 +1303,10 @@ func (r *reader) callShaped(pos src.XPos) {
|
||||||
// putting the dictionary parameter after that is the least invasive
|
// putting the dictionary parameter after that is the least invasive
|
||||||
// solution at the moment.
|
// solution at the moment.
|
||||||
var args ir.Nodes
|
var args ir.Nodes
|
||||||
args.Append(recvs...)
|
if r.methodSym != nil {
|
||||||
|
args.Append(params[0])
|
||||||
|
params = params[1:]
|
||||||
|
}
|
||||||
args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict))))
|
args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict))))
|
||||||
args.Append(params...)
|
args.Append(params...)
|
||||||
|
|
||||||
|
|
@ -1315,44 +1315,9 @@ func (r *reader) callShaped(pos src.XPos) {
|
||||||
|
|
||||||
// syntheticArgs returns the recvs and params arguments passed to the
|
// syntheticArgs returns the recvs and params arguments passed to the
|
||||||
// current function.
|
// current function.
|
||||||
func (r *reader) syntheticArgs(pos src.XPos) (recvs, params ir.Nodes) {
|
func (r *reader) syntheticArgs() ir.Nodes {
|
||||||
sig := r.curfn.Nname.Type()
|
sig := r.curfn.Nname.Type()
|
||||||
|
return ir.ToNodes(r.curfn.Dcl[:sig.NumRecvs()+sig.NumParams()])
|
||||||
inlVarIdx := 0
|
|
||||||
addParams := func(out *ir.Nodes, params []*types.Field) {
|
|
||||||
for _, param := range params {
|
|
||||||
var arg ir.Node
|
|
||||||
if param.Nname != nil {
|
|
||||||
name := param.Nname.(*ir.Name)
|
|
||||||
if !ir.IsBlank(name) {
|
|
||||||
if r.inlCall != nil {
|
|
||||||
// During inlining, we want the respective inlvar where we
|
|
||||||
// assigned the callee's arguments.
|
|
||||||
arg = r.inlvars[inlVarIdx]
|
|
||||||
} else {
|
|
||||||
// Otherwise, we can use the parameter itself directly.
|
|
||||||
base.AssertfAt(name.Curfn == r.curfn, name.Pos(), "%v has curfn %v, but want %v", name, name.Curfn, r.curfn)
|
|
||||||
arg = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For anonymous and blank parameters, we don't have an *ir.Name
|
|
||||||
// to use as the argument. However, since we know the shaped
|
|
||||||
// function won't use the value either, we can just pass the
|
|
||||||
// zero value.
|
|
||||||
if arg == nil {
|
|
||||||
arg = ir.NewZero(pos, param.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
out.Append(arg)
|
|
||||||
inlVarIdx++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addParams(&recvs, sig.Recvs())
|
|
||||||
addParams(¶ms, sig.Params())
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// syntheticTailCall emits a tail call to fn, passing the given
|
// syntheticTailCall emits a tail call to fn, passing the given
|
||||||
|
|
@ -1489,105 +1454,32 @@ func (dict *readerDict) varType() *types.Type {
|
||||||
return types.NewArray(types.Types[types.TUINTPTR], dict.numWords())
|
return types.NewArray(types.Types[types.TUINTPTR], dict.numWords())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) funcargs(fn *ir.Func) {
|
func (r *reader) declareParams() {
|
||||||
sig := fn.Nname.Type()
|
r.curfn.DeclareParams(!r.funarghack)
|
||||||
|
|
||||||
if recv := sig.Recv(); recv != nil {
|
for _, name := range r.curfn.Dcl {
|
||||||
r.funcarg(recv, recv.Sym, ir.PPARAM)
|
if name.Sym().Name == dictParamName {
|
||||||
}
|
r.dictParam = name
|
||||||
for _, param := range sig.Params() {
|
continue
|
||||||
r.funcarg(param, param.Sym, ir.PPARAM)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, param := range sig.Results() {
|
|
||||||
sym := param.Sym
|
|
||||||
|
|
||||||
if sym == nil || sym.IsBlank() {
|
|
||||||
prefix := "~r"
|
|
||||||
if r.inlCall != nil {
|
|
||||||
prefix = "~R"
|
|
||||||
} else if sym != nil {
|
|
||||||
prefix = "~b"
|
|
||||||
}
|
|
||||||
sym = typecheck.LookupNum(prefix, i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.funcarg(param, sym, ir.PPARAMOUT)
|
r.addLocal(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) {
|
func (r *reader) addLocal(name *ir.Name) {
|
||||||
if sym == nil {
|
if r.synthetic == nil {
|
||||||
assert(ctxt == ir.PPARAM)
|
r.Sync(pkgbits.SyncAddLocal)
|
||||||
if r.inlCall != nil {
|
if r.p.SyncMarkers() {
|
||||||
r.inlvars.Append(ir.BlankNode)
|
want := r.Int()
|
||||||
}
|
if have := len(r.locals); have != want {
|
||||||
return
|
base.FatalfAt(name.Pos(), "locals table has desynced")
|
||||||
}
|
|
||||||
|
|
||||||
name := r.addLocal(r.inlPos(param.Pos), sym, ctxt, param.Type)
|
|
||||||
|
|
||||||
if r.inlCall == nil {
|
|
||||||
if !r.funarghack {
|
|
||||||
param.Nname = name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ctxt == ir.PPARAMOUT {
|
|
||||||
r.retvars.Append(name)
|
|
||||||
} else {
|
|
||||||
r.inlvars.Append(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *reader) addLocal(pos src.XPos, sym *types.Sym, ctxt ir.Class, typ *types.Type) *ir.Name {
|
|
||||||
assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT)
|
|
||||||
|
|
||||||
name := ir.NewNameAt(pos, sym, typ)
|
|
||||||
|
|
||||||
if name.Sym().Name == dictParamName {
|
|
||||||
r.dictParam = name
|
|
||||||
} else {
|
|
||||||
if r.synthetic == nil {
|
|
||||||
r.Sync(pkgbits.SyncAddLocal)
|
|
||||||
if r.p.SyncMarkers() {
|
|
||||||
want := r.Int()
|
|
||||||
if have := len(r.locals); have != want {
|
|
||||||
base.FatalfAt(name.Pos(), "locals table has desynced")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
r.varDictIndex(name)
|
|
||||||
}
|
}
|
||||||
|
r.varDictIndex(name)
|
||||||
r.locals = append(r.locals, name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name.SetUsed(true)
|
r.locals = append(r.locals, name)
|
||||||
|
|
||||||
// TODO(mdempsky): Move earlier.
|
|
||||||
if ir.IsBlank(name) {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.inlCall != nil {
|
|
||||||
if ctxt == ir.PAUTO {
|
|
||||||
name.SetInlLocal(true)
|
|
||||||
} else {
|
|
||||||
name.SetInlFormal(true)
|
|
||||||
ctxt = ir.PAUTO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
name.Class = ctxt
|
|
||||||
name.Curfn = r.curfn
|
|
||||||
|
|
||||||
r.curfn.Dcl = append(r.curfn.Dcl, name)
|
|
||||||
|
|
||||||
if ctxt == ir.PAUTO {
|
|
||||||
name.SetFrameOffset(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) useLocal() *ir.Name {
|
func (r *reader) useLocal() *ir.Name {
|
||||||
|
|
@ -1836,7 +1728,8 @@ func (r *reader) assign() (ir.Node, bool) {
|
||||||
_, sym := r.localIdent()
|
_, sym := r.localIdent()
|
||||||
typ := r.typ()
|
typ := r.typ()
|
||||||
|
|
||||||
name := r.addLocal(pos, sym, ir.PAUTO, typ)
|
name := r.curfn.NewLocal(pos, sym, typ)
|
||||||
|
r.addLocal(name)
|
||||||
return name, true
|
return name, true
|
||||||
|
|
||||||
case assignExpr:
|
case assignExpr:
|
||||||
|
|
@ -2076,10 +1969,8 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
|
||||||
clause.RTypes = rtypes
|
clause.RTypes = rtypes
|
||||||
|
|
||||||
if ident != nil {
|
if ident != nil {
|
||||||
pos := r.pos()
|
name := r.curfn.NewLocal(r.pos(), ident.Sym(), r.typ())
|
||||||
typ := r.typ()
|
r.addLocal(name)
|
||||||
|
|
||||||
name := r.addLocal(pos, ident.Sym(), ir.PAUTO, typ)
|
|
||||||
clause.Var = name
|
clause.Var = name
|
||||||
name.Defn = tag
|
name.Defn = tag
|
||||||
}
|
}
|
||||||
|
|
@ -2651,14 +2542,11 @@ func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1
|
||||||
typ := types.NewSignature(nil, params, results)
|
typ := types.NewSignature(nil, params, results)
|
||||||
|
|
||||||
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
|
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
|
||||||
recvs, params := r.syntheticArgs(pos)
|
|
||||||
assert(len(recvs) == 0)
|
|
||||||
|
|
||||||
fun := captured[0]
|
fun := captured[0]
|
||||||
|
|
||||||
var args ir.Nodes
|
var args ir.Nodes
|
||||||
args.Append(captured[1:]...)
|
args.Append(captured[1:]...)
|
||||||
args.Append(params...)
|
args.Append(r.syntheticArgs()...)
|
||||||
|
|
||||||
r.syntheticTailCall(pos, fun, args)
|
r.syntheticTailCall(pos, fun, args)
|
||||||
}
|
}
|
||||||
|
|
@ -2689,10 +2577,8 @@ func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []
|
||||||
typ := types.NewSignature(nil, params, results)
|
typ := types.NewSignature(nil, params, results)
|
||||||
|
|
||||||
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
|
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
|
||||||
recvs, args := r.syntheticArgs(pos)
|
|
||||||
assert(len(recvs) == 0)
|
|
||||||
|
|
||||||
fn := captured[0]
|
fn := captured[0]
|
||||||
|
args := r.syntheticArgs()
|
||||||
|
|
||||||
// Rewrite first argument based on implicits/deref/addr.
|
// Rewrite first argument based on implicits/deref/addr.
|
||||||
{
|
{
|
||||||
|
|
@ -2805,17 +2691,13 @@ func syntheticSig(sig *types.Type) (params, results []*types.Field) {
|
||||||
clone := func(params []*types.Field) []*types.Field {
|
clone := func(params []*types.Field) []*types.Field {
|
||||||
res := make([]*types.Field, len(params))
|
res := make([]*types.Field, len(params))
|
||||||
for i, param := range params {
|
for i, param := range params {
|
||||||
sym := param.Sym
|
|
||||||
if sym == nil || sym.Name == "_" {
|
|
||||||
sym = typecheck.LookupNum(".anon", i)
|
|
||||||
}
|
|
||||||
// TODO(mdempsky): It would be nice to preserve the original
|
// TODO(mdempsky): It would be nice to preserve the original
|
||||||
// parameter positions here instead, but at least
|
// parameter positions here instead, but at least
|
||||||
// typecheck.NewMethodType replaces them with base.Pos, making
|
// typecheck.NewMethodType replaces them with base.Pos, making
|
||||||
// them useless. Worse, the positions copied from base.Pos may
|
// them useless. Worse, the positions copied from base.Pos may
|
||||||
// have inlining contexts, which we definitely don't want here
|
// have inlining contexts, which we definitely don't want here
|
||||||
// (e.g., #54625).
|
// (e.g., #54625).
|
||||||
res[i] = types.NewField(base.AutogeneratedPos, sym, param.Type)
|
res[i] = types.NewField(base.AutogeneratedPos, param.Sym, param.Type)
|
||||||
res[i].SetIsDDD(param.IsDDD())
|
res[i].SetIsDDD(param.IsDDD())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
|
@ -3492,6 +3374,7 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
r.inlFunc = fn
|
r.inlFunc = fn
|
||||||
r.inlTreeIndex = inlIndex
|
r.inlTreeIndex = inlIndex
|
||||||
r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
|
r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
|
||||||
|
r.funarghack = true
|
||||||
|
|
||||||
r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
|
r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
|
||||||
for i, cv := range r.inlFunc.ClosureVars {
|
for i, cv := range r.inlFunc.ClosureVars {
|
||||||
|
|
@ -3506,7 +3389,17 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
|
r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
|
||||||
}
|
}
|
||||||
|
|
||||||
r.funcargs(fn)
|
r.declareParams()
|
||||||
|
|
||||||
|
var inlvars, retvars []*ir.Name
|
||||||
|
{
|
||||||
|
sig := r.curfn.Type()
|
||||||
|
endParams := sig.NumRecvs() + sig.NumParams()
|
||||||
|
endResults := endParams + sig.NumResults()
|
||||||
|
|
||||||
|
inlvars = r.curfn.Dcl[:endParams]
|
||||||
|
retvars = r.curfn.Dcl[endParams:endResults]
|
||||||
|
}
|
||||||
|
|
||||||
r.delayResults = fn.Inl.CanDelayResults
|
r.delayResults = fn.Inl.CanDelayResults
|
||||||
|
|
||||||
|
|
@ -3529,15 +3422,14 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
args.Append(call.Args...)
|
args.Append(call.Args...)
|
||||||
|
|
||||||
// Create assignment to declare and initialize inlvars.
|
// Create assignment to declare and initialize inlvars.
|
||||||
as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, r.inlvars, args)
|
as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, ir.ToNodes(inlvars), args)
|
||||||
as2.Def = true
|
as2.Def = true
|
||||||
var as2init ir.Nodes
|
var as2init ir.Nodes
|
||||||
for _, name := range r.inlvars {
|
for _, name := range inlvars {
|
||||||
if ir.IsBlank(name) {
|
if ir.IsBlank(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
||||||
name := name.(*ir.Name)
|
|
||||||
as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
|
as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
|
||||||
name.Defn = as2
|
name.Defn = as2
|
||||||
}
|
}
|
||||||
|
|
@ -3547,9 +3439,8 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
if !r.delayResults {
|
if !r.delayResults {
|
||||||
// If not delaying retvars, declare and zero initialize the
|
// If not delaying retvars, declare and zero initialize the
|
||||||
// result variables now.
|
// result variables now.
|
||||||
for _, name := range r.retvars {
|
for _, name := range retvars {
|
||||||
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
||||||
name := name.(*ir.Name)
|
|
||||||
init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
|
init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
|
||||||
ras := ir.NewAssignStmt(call.Pos(), name, nil)
|
ras := ir.NewAssignStmt(call.Pos(), name, nil)
|
||||||
init.Append(typecheck.Stmt(ras))
|
init.Append(typecheck.Stmt(ras))
|
||||||
|
|
@ -3582,7 +3473,7 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
var edit func(ir.Node) ir.Node
|
var edit func(ir.Node) ir.Node
|
||||||
edit = func(n ir.Node) ir.Node {
|
edit = func(n ir.Node) ir.Node {
|
||||||
if ret, ok := n.(*ir.ReturnStmt); ok {
|
if ret, ok := n.(*ir.ReturnStmt); ok {
|
||||||
n = typecheck.Stmt(r.inlReturn(ret))
|
n = typecheck.Stmt(r.inlReturn(ret, retvars))
|
||||||
}
|
}
|
||||||
ir.EditChildren(n, edit)
|
ir.EditChildren(n, edit)
|
||||||
return n
|
return n
|
||||||
|
|
@ -3595,17 +3486,20 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
// Reparent any declarations into the caller function.
|
// Reparent any declarations into the caller function.
|
||||||
for _, name := range r.curfn.Dcl {
|
for _, name := range r.curfn.Dcl {
|
||||||
name.Curfn = callerfn
|
name.Curfn = callerfn
|
||||||
callerfn.Dcl = append(callerfn.Dcl, name)
|
|
||||||
|
|
||||||
if name.AutoTemp() {
|
if name.Class != ir.PAUTO {
|
||||||
name.SetEsc(ir.EscUnknown)
|
name.SetPos(r.inlPos(name.Pos()))
|
||||||
|
name.SetInlFormal(true)
|
||||||
|
name.Class = ir.PAUTO
|
||||||
|
} else {
|
||||||
name.SetInlLocal(true)
|
name.SetInlLocal(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
callerfn.Dcl = append(callerfn.Dcl, r.curfn.Dcl...)
|
||||||
|
|
||||||
body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel))
|
body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel))
|
||||||
|
|
||||||
res := ir.NewInlinedCallExpr(call.Pos(), body, append([]ir.Node(nil), r.retvars...))
|
res := ir.NewInlinedCallExpr(call.Pos(), body, ir.ToNodes(retvars))
|
||||||
res.SetInit(init)
|
res.SetInit(init)
|
||||||
res.SetType(call.Type())
|
res.SetType(call.Type())
|
||||||
res.SetTypecheck(1)
|
res.SetTypecheck(1)
|
||||||
|
|
@ -3618,20 +3512,19 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
|
||||||
|
|
||||||
// inlReturn returns a statement that can substitute for the given
|
// inlReturn returns a statement that can substitute for the given
|
||||||
// return statement when inlining.
|
// return statement when inlining.
|
||||||
func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt {
|
func (r *reader) inlReturn(ret *ir.ReturnStmt, retvars []*ir.Name) *ir.BlockStmt {
|
||||||
pos := r.inlCall.Pos()
|
pos := r.inlCall.Pos()
|
||||||
|
|
||||||
block := ir.TakeInit(ret)
|
block := ir.TakeInit(ret)
|
||||||
|
|
||||||
if results := ret.Results; len(results) != 0 {
|
if results := ret.Results; len(results) != 0 {
|
||||||
assert(len(r.retvars) == len(results))
|
assert(len(retvars) == len(results))
|
||||||
|
|
||||||
as2 := ir.NewAssignListStmt(pos, ir.OAS2, append([]ir.Node(nil), r.retvars...), ret.Results)
|
as2 := ir.NewAssignListStmt(pos, ir.OAS2, ir.ToNodes(retvars), ret.Results)
|
||||||
|
|
||||||
if r.delayResults {
|
if r.delayResults {
|
||||||
for _, name := range r.retvars {
|
for _, name := range retvars {
|
||||||
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
// TODO(mdempsky): Use inlined position of name.Pos() instead?
|
||||||
name := name.(*ir.Name)
|
|
||||||
block.Append(ir.NewDecl(pos, ir.ODCL, name))
|
block.Append(ir.NewDecl(pos, ir.ODCL, name))
|
||||||
name.Defn = as2
|
name.Defn = as2
|
||||||
}
|
}
|
||||||
|
|
@ -3667,18 +3560,11 @@ func expandInline(fn *ir.Func, pri pkgReaderIndex) {
|
||||||
r.funcBody(tmpfn)
|
r.funcBody(tmpfn)
|
||||||
}
|
}
|
||||||
|
|
||||||
used := usedLocals(tmpfn.Body)
|
// Move tmpfn's params to fn.Inl.Dcl, and reparent under fn.
|
||||||
|
|
||||||
for _, name := range tmpfn.Dcl {
|
for _, name := range tmpfn.Dcl {
|
||||||
if name.Class != ir.PAUTO || used.Has(name) {
|
name.Curfn = fn
|
||||||
name.Curfn = fn
|
|
||||||
fn.Inl.Dcl = append(fn.Inl.Dcl, name)
|
|
||||||
} else {
|
|
||||||
// TODO(mdempsky): Simplify code after confident that this never
|
|
||||||
// happens anymore.
|
|
||||||
base.FatalfAt(name.Pos(), "unused auto: %v", name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn.Inl.Dcl = tmpfn.Dcl
|
||||||
fn.Inl.HaveDcl = true
|
fn.Inl.HaveDcl = true
|
||||||
|
|
||||||
// Double check that we didn't change fn.Dcl by accident.
|
// Double check that we didn't change fn.Dcl by accident.
|
||||||
|
|
@ -3895,19 +3781,9 @@ func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *t
|
||||||
sig := newWrapperType(wrapper, method)
|
sig := newWrapperType(wrapper, method)
|
||||||
|
|
||||||
fn := ir.NewFunc(pos, pos, sym, sig)
|
fn := ir.NewFunc(pos, pos, sym, sig)
|
||||||
|
fn.DeclareParams(true)
|
||||||
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
|
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
|
||||||
|
|
||||||
// TODO(mdempsky): De-duplicate with similar logic in funcargs.
|
|
||||||
defParams := func(class ir.Class, params []*types.Field) {
|
|
||||||
for _, param := range params {
|
|
||||||
param.Nname = fn.NewLocal(param.Pos, param.Sym, class, param.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defParams(ir.PPARAM, sig.Recvs())
|
|
||||||
defParams(ir.PPARAM, sig.Params())
|
|
||||||
defParams(ir.PPARAMOUT, sig.Results())
|
|
||||||
|
|
||||||
return fn
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3946,11 +3822,7 @@ func newWrapperType(recvType *types.Type, method *types.Field) *types.Type {
|
||||||
clone := func(params []*types.Field) []*types.Field {
|
clone := func(params []*types.Field) []*types.Field {
|
||||||
res := make([]*types.Field, len(params))
|
res := make([]*types.Field, len(params))
|
||||||
for i, param := range params {
|
for i, param := range params {
|
||||||
sym := param.Sym
|
res[i] = types.NewField(param.Pos, param.Sym, param.Type)
|
||||||
if sym == nil || sym.Name == "_" {
|
|
||||||
sym = typecheck.LookupNum(".anon", i)
|
|
||||||
}
|
|
||||||
res[i] = types.NewField(param.Pos, sym, param.Type)
|
|
||||||
res[i].SetIsDDD(param.IsDDD())
|
res[i].SetIsDDD(param.IsDDD())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
|
|
@ -3960,7 +3832,7 @@ func newWrapperType(recvType *types.Type, method *types.Field) *types.Type {
|
||||||
|
|
||||||
var recv *types.Field
|
var recv *types.Field
|
||||||
if recvType != nil {
|
if recvType != nil {
|
||||||
recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType)
|
recv = types.NewField(sig.Recv().Pos, sig.Recv().Sym, recvType)
|
||||||
}
|
}
|
||||||
params := clone(sig.Params())
|
params := clone(sig.Params())
|
||||||
results := clone(sig.Results())
|
results := clone(sig.Results())
|
||||||
|
|
|
||||||
|
|
@ -1114,7 +1114,7 @@ func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dic
|
||||||
w.sig = sig
|
w.sig = sig
|
||||||
w.dict = dict
|
w.dict = dict
|
||||||
|
|
||||||
w.funcargs(sig)
|
w.declareParams(sig)
|
||||||
if w.Bool(block != nil) {
|
if w.Bool(block != nil) {
|
||||||
w.stmts(block.List)
|
w.stmts(block.List)
|
||||||
w.pos(block.Rbrace)
|
w.pos(block.Rbrace)
|
||||||
|
|
@ -1123,24 +1123,18 @@ func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dic
|
||||||
return w.Flush(), w.closureVars
|
return w.Flush(), w.closureVars
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writer) funcargs(sig *types2.Signature) {
|
func (w *writer) declareParams(sig *types2.Signature) {
|
||||||
do := func(params *types2.Tuple, result bool) {
|
addLocals := func(params *types2.Tuple) {
|
||||||
for i := 0; i < params.Len(); i++ {
|
for i := 0; i < params.Len(); i++ {
|
||||||
w.funcarg(params.At(i), result)
|
w.addLocal(params.At(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if recv := sig.Recv(); recv != nil {
|
if recv := sig.Recv(); recv != nil {
|
||||||
w.funcarg(recv, false)
|
w.addLocal(recv)
|
||||||
}
|
|
||||||
do(sig.Params(), false)
|
|
||||||
do(sig.Results(), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *writer) funcarg(param *types2.Var, result bool) {
|
|
||||||
if param.Name() != "" || result {
|
|
||||||
w.addLocal(param)
|
|
||||||
}
|
}
|
||||||
|
addLocals(sig.Params())
|
||||||
|
addLocals(sig.Results())
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLocal records the declaration of a new local variable.
|
// addLocal records the declaration of a new local variable.
|
||||||
|
|
|
||||||
|
|
@ -156,9 +156,9 @@ func hashFunc(t *types.Type) *ir.Func {
|
||||||
sym.Def = fn.Nname
|
sym.Def = fn.Nname
|
||||||
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
|
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
|
||||||
|
|
||||||
params, _ := typecheck.DeclFunc(fn)
|
typecheck.DeclFunc(fn)
|
||||||
np := params[0]
|
np := fn.Dcl[0]
|
||||||
nh := params[1]
|
nh := fn.Dcl[1]
|
||||||
|
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case types.TARRAY:
|
case types.TARRAY:
|
||||||
|
|
@ -382,10 +382,10 @@ func eqFunc(t *types.Type) *ir.Func {
|
||||||
sym.Def = fn.Nname
|
sym.Def = fn.Nname
|
||||||
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
|
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
|
||||||
|
|
||||||
params, results := typecheck.DeclFunc(fn)
|
typecheck.DeclFunc(fn)
|
||||||
np := params[0]
|
np := fn.Dcl[0]
|
||||||
nq := params[1]
|
nq := fn.Dcl[1]
|
||||||
nr := results[0]
|
nr := fn.Dcl[2]
|
||||||
|
|
||||||
// Label to jump to if an equality test fails.
|
// Label to jump to if an equality test fails.
|
||||||
neq := typecheck.AutoLabel(".neq")
|
neq := typecheck.AutoLabel(".neq")
|
||||||
|
|
|
||||||
|
|
@ -55,16 +55,15 @@ type Conf struct {
|
||||||
|
|
||||||
func (c *Conf) Frontend() Frontend {
|
func (c *Conf) Frontend() Frontend {
|
||||||
if c.fe == nil {
|
if c.fe == nil {
|
||||||
f := ir.NewFunc(src.NoXPos, src.NoXPos, &types.Sym{
|
pkg := types.NewPkg("my/import/path", "path")
|
||||||
Pkg: types.NewPkg("my/import/path", "path"),
|
fn := ir.NewFunc(src.NoXPos, src.NoXPos, pkg.Lookup("function"), types.NewSignature(nil, nil, nil))
|
||||||
Name: "function",
|
fn.DeclareParams(true)
|
||||||
}, nil)
|
fn.LSym = &obj.LSym{Name: "my/import/path.function"}
|
||||||
f.LSym = &obj.LSym{Name: "my/import/path.function"}
|
|
||||||
|
|
||||||
c.fe = TestFrontend{
|
c.fe = TestFrontend{
|
||||||
t: c.tb,
|
t: c.tb,
|
||||||
ctxt: c.config.ctxt,
|
ctxt: c.config.ctxt,
|
||||||
f: f,
|
f: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.fe
|
return c.fe
|
||||||
|
|
|
||||||
|
|
@ -249,8 +249,8 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
|
||||||
// Reuse f's types.Sym to create a new ODCLFUNC/function.
|
// Reuse f's types.Sym to create a new ODCLFUNC/function.
|
||||||
// TODO(mdempsky): Means we can't set sym.Def in Declfunc, ugh.
|
// TODO(mdempsky): Means we can't set sym.Def in Declfunc, ugh.
|
||||||
fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
|
fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
|
||||||
typecheck.NewFuncParams(ft.Params(), true),
|
typecheck.NewFuncParams(ft.Params()),
|
||||||
typecheck.NewFuncParams(ft.Results(), false)))
|
typecheck.NewFuncParams(ft.Results())))
|
||||||
fn.ABI = wrapperABI
|
fn.ABI = wrapperABI
|
||||||
typecheck.DeclFunc(fn)
|
typecheck.DeclFunc(fn)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -673,7 +673,7 @@ func (s *state) setHeapaddr(pos src.XPos, n *ir.Name, ptr *ssa.Value) {
|
||||||
|
|
||||||
// Declare variable to hold address.
|
// Declare variable to hold address.
|
||||||
sym := &types.Sym{Name: "&" + n.Sym().Name, Pkg: types.LocalPkg}
|
sym := &types.Sym{Name: "&" + n.Sym().Name, Pkg: types.LocalPkg}
|
||||||
addr := s.curfn.NewLocal(pos, sym, ir.PAUTO, types.NewPtr(n.Type()))
|
addr := s.curfn.NewLocal(pos, sym, types.NewPtr(n.Type()))
|
||||||
addr.SetUsed(true)
|
addr.SetUsed(true)
|
||||||
types.CalcSize(addr.Type())
|
types.CalcSize(addr.Type())
|
||||||
|
|
||||||
|
|
@ -7928,7 +7928,7 @@ func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t
|
||||||
}
|
}
|
||||||
|
|
||||||
sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
|
sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
|
||||||
n := e.curfn.NewLocal(parent.N.Pos(), sym, ir.PAUTO, t)
|
n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
|
||||||
n.SetUsed(true)
|
n.SetUsed(true)
|
||||||
n.SetEsc(ir.EscNever)
|
n.SetEsc(ir.EscNever)
|
||||||
types.CalcSize(t)
|
types.CalcSize(t)
|
||||||
|
|
|
||||||
|
|
@ -16,32 +16,18 @@ import (
|
||||||
|
|
||||||
var funcStack []*ir.Func // stack of previous values of ir.CurFunc
|
var funcStack []*ir.Func // stack of previous values of ir.CurFunc
|
||||||
|
|
||||||
// DeclFunc creates and returns ONAMEs for the parameters and results
|
// DeclFunc declares the parameters for fn and adds it to
|
||||||
// of the given function. It also sets ir.CurFunc, and adds fn to
|
|
||||||
// Target.Funcs.
|
// Target.Funcs.
|
||||||
//
|
//
|
||||||
// After the caller is done constructing fn, it must call
|
// Before returning, it sets CurFunc to fn. When the caller is done
|
||||||
// FinishFuncBody.
|
// constructing fn, it must call FinishFuncBody to restore CurFunc.
|
||||||
func DeclFunc(fn *ir.Func) (params, results []*ir.Name) {
|
func DeclFunc(fn *ir.Func) {
|
||||||
typ := fn.Type()
|
fn.DeclareParams(true)
|
||||||
|
|
||||||
// Currently, DeclFunc is only used to create normal functions, not
|
|
||||||
// methods. If a use case for creating methods shows up, we can
|
|
||||||
// extend it to support those too.
|
|
||||||
if typ.Recv() != nil {
|
|
||||||
base.FatalfAt(fn.Pos(), "unexpected receiver parameter")
|
|
||||||
}
|
|
||||||
|
|
||||||
params = declareParams(fn, ir.PPARAM, typ.Params())
|
|
||||||
results = declareParams(fn, ir.PPARAMOUT, typ.Results())
|
|
||||||
|
|
||||||
funcStack = append(funcStack, ir.CurFunc)
|
|
||||||
ir.CurFunc = fn
|
|
||||||
|
|
||||||
fn.Nname.Defn = fn
|
fn.Nname.Defn = fn
|
||||||
Target.Funcs = append(Target.Funcs, fn)
|
Target.Funcs = append(Target.Funcs, fn)
|
||||||
|
|
||||||
return
|
funcStack = append(funcStack, ir.CurFunc)
|
||||||
|
ir.CurFunc = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// FinishFuncBody restores ir.CurFunc to its state before the last
|
// FinishFuncBody restores ir.CurFunc to its state before the last
|
||||||
|
|
@ -56,65 +42,29 @@ func CheckFuncStack() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func declareParams(fn *ir.Func, ctxt ir.Class, params []*types.Field) []*ir.Name {
|
|
||||||
names := make([]*ir.Name, len(params))
|
|
||||||
for i, param := range params {
|
|
||||||
names[i] = declareParam(fn, ctxt, i, param)
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *types.Field) *ir.Name {
|
|
||||||
sym := param.Sym
|
|
||||||
if ctxt == ir.PPARAMOUT {
|
|
||||||
if sym == nil {
|
|
||||||
// Name so that escape analysis can track it. ~r stands for 'result'.
|
|
||||||
sym = LookupNum("~r", i)
|
|
||||||
} else if sym.IsBlank() {
|
|
||||||
// Give it a name so we can assign to it during return. ~b stands for 'blank'.
|
|
||||||
// The name must be different from ~r above because if you have
|
|
||||||
// func f() (_ int)
|
|
||||||
// func g() int
|
|
||||||
// f is allowed to use a plain 'return' with no arguments, while g is not.
|
|
||||||
// So the two cases must be distinguished.
|
|
||||||
sym = LookupNum("~b", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sym == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
|
|
||||||
param.Nname = name
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// make a new Node off the books.
|
// make a new Node off the books.
|
||||||
func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
|
func TempAt(pos src.XPos, curfn *ir.Func, typ *types.Type) *ir.Name {
|
||||||
if curfn == nil {
|
if curfn == nil {
|
||||||
base.Fatalf("no curfn for TempAt")
|
base.FatalfAt(pos, "no curfn for TempAt")
|
||||||
}
|
}
|
||||||
if t == nil {
|
if typ == nil {
|
||||||
base.Fatalf("TempAt called with nil type")
|
base.FatalfAt(pos, "TempAt called with nil type")
|
||||||
}
|
}
|
||||||
if t.Kind() == types.TFUNC && t.Recv() != nil {
|
if typ.Kind() == types.TFUNC && typ.Recv() != nil {
|
||||||
base.Fatalf("misuse of method type: %v", t)
|
base.FatalfAt(pos, "misuse of method type: %v", typ)
|
||||||
}
|
}
|
||||||
|
types.CalcSize(typ)
|
||||||
|
|
||||||
s := &types.Sym{
|
sym := &types.Sym{
|
||||||
Name: autotmpname(len(curfn.Dcl)),
|
Name: autotmpname(len(curfn.Dcl)),
|
||||||
Pkg: types.LocalPkg,
|
Pkg: types.LocalPkg,
|
||||||
}
|
}
|
||||||
n := curfn.NewLocal(pos, s, ir.PAUTO, t)
|
name := curfn.NewLocal(pos, sym, typ)
|
||||||
s.Def = n // TODO(mdempsky): Should be unnecessary.
|
name.SetEsc(ir.EscNever)
|
||||||
n.SetEsc(ir.EscNever)
|
name.SetUsed(true)
|
||||||
n.SetUsed(true)
|
name.SetAutoTemp(true)
|
||||||
n.SetAutoTemp(true)
|
|
||||||
|
|
||||||
types.CalcSize(t)
|
return name
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ func tcGoDefer(n *ir.GoDeferStmt) {
|
||||||
|
|
||||||
// Create a new wrapper function without parameters or results.
|
// Create a new wrapper function without parameters or results.
|
||||||
wrapperFn := ir.NewClosureFunc(n.Pos(), n.Pos(), n.Op(), types.NewSignature(nil, nil, nil), ir.CurFunc, Target)
|
wrapperFn := ir.NewClosureFunc(n.Pos(), n.Pos(), n.Op(), types.NewSignature(nil, nil, nil), ir.CurFunc, Target)
|
||||||
|
wrapperFn.DeclareParams(true)
|
||||||
wrapperFn.SetWrapper(true)
|
wrapperFn.SetWrapper(true)
|
||||||
|
|
||||||
// argps collects the list of operands within the call expression
|
// argps collects the list of operands within the call expression
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,10 @@ func LookupNum(prefix string, n int) *types.Sym {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given funarg struct list, return list of fn args.
|
// Given funarg struct list, return list of fn args.
|
||||||
func NewFuncParams(origs []*types.Field, mustname bool) []*types.Field {
|
func NewFuncParams(origs []*types.Field) []*types.Field {
|
||||||
res := make([]*types.Field, len(origs))
|
res := make([]*types.Field, len(origs))
|
||||||
for i, orig := range origs {
|
for i, orig := range origs {
|
||||||
s := orig.Sym
|
p := types.NewField(orig.Pos, orig.Sym, orig.Type)
|
||||||
if mustname && (s == nil || s.Name == "_") {
|
|
||||||
// invent a name so that we can refer to it in the trampoline
|
|
||||||
s = LookupNum(".anon", i)
|
|
||||||
} else if s != nil && s.Pkg != types.LocalPkg {
|
|
||||||
// TODO(mdempsky): Preserve original position, name, and package.
|
|
||||||
s = Lookup(s.Name)
|
|
||||||
}
|
|
||||||
p := types.NewField(orig.Pos, s, orig.Type)
|
|
||||||
p.SetIsDDD(orig.IsDDD())
|
p.SetIsDDD(orig.IsDDD())
|
||||||
res[i] = p
|
res[i] = p
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// errorcheck -0 -m -live -std
|
// errorcheck -0 -m -live -std
|
||||||
|
|
||||||
|
//go:build !windows && !js && !wasip1
|
||||||
// +build !windows,!js,!wasip1
|
// +build !windows,!js,!wasip1
|
||||||
|
|
||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
|
@ -22,7 +23,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func implicit(uintptr) // ERROR "assuming arg#1 is unsafe uintptr"
|
func implicit(uintptr) // ERROR "assuming ~p0 is unsafe uintptr"
|
||||||
|
|
||||||
//go:uintptrkeepalive
|
//go:uintptrkeepalive
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
@ -47,13 +48,13 @@ func autotmpSyscall() { // ERROR "can inline autotmpSyscall"
|
||||||
func localImplicit() { // ERROR "can inline localImplicit"
|
func localImplicit() { // ERROR "can inline localImplicit"
|
||||||
var t int
|
var t int
|
||||||
p := unsafe.Pointer(&t)
|
p := unsafe.Pointer(&t)
|
||||||
implicit(uintptr(p)) // ERROR "live at call to implicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
implicit(uintptr(p)) // ERROR "live at call to implicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||||
}
|
}
|
||||||
|
|
||||||
func localExplicit() { // ERROR "can inline localExplicit"
|
func localExplicit() { // ERROR "can inline localExplicit"
|
||||||
var t int
|
var t int
|
||||||
p := unsafe.Pointer(&t)
|
p := unsafe.Pointer(&t)
|
||||||
explicit(uintptr(p)) // ERROR "live at call to explicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
explicit(uintptr(p)) // ERROR "live at call to explicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||||
}
|
}
|
||||||
|
|
||||||
func localSyscall() { // ERROR "can inline localSyscall"
|
func localSyscall() { // ERROR "can inline localSyscall"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue