1
0
mirror of https://github.com/golang/go synced 2024-11-26 14:46:47 -07:00

cmd/compile/internal/typecheck: refactor and simplify DeclFunc

This CL refactors typecheck.DeclFunc to require the caller to have
already constructed the ir.Func and signature type using ir.NewFunc
and types.NewSignature, and simplifies typecheck.DeclFunc to simply
return the slices of param and results ONAMEs.

typecheck.DeclFunc was the last reason that ir.Field still exists, so
this CL also gets rid of that.

Change-Id: Ib398420bac2fd135a235810b8af1635fa754965c
Reviewed-on: https://go-review.googlesource.com/c/go/+/520977
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2023-08-18 17:43:15 -07:00 committed by Gopher Robot
parent b581e44739
commit 009ca22fe2
7 changed files with 94 additions and 111 deletions

View File

@ -8,31 +8,10 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
)
// Calling TypeNode converts a *types.Type to a Node shell.
// A Field is a declared function parameter.
// It is not a Node.
type Field struct {
Pos src.XPos
Sym *types.Sym
Type *types.Type
IsDDD bool
}
func NewField(pos src.XPos, sym *types.Sym, typ *types.Type) *Field {
return &Field{Pos: pos, Sym: sym, Type: typ}
}
func (f *Field) String() string {
if f.Sym != nil {
return fmt.Sprintf("%v %v", f.Sym, f.Type)
}
return fmt.Sprint(f.Type)
}
// A typeNode is a Node wrapper for type t.
type typeNode struct {
miniNode

View File

@ -28,9 +28,13 @@ func MakeInit() {
}
// Make a function that contains all the initialization statements.
base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
initializers := typecheck.Lookup("init")
fn := typecheck.DeclFunc(initializers, nil, nil, nil)
pos := nf[0].Pos() // prolog/epilog gets line number of first init stmt
base.Pos = pos
sym := typecheck.Lookup("init")
fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
typecheck.DeclFunc(fn)
for _, dcl := range typecheck.InitTodoFunc.Dcl {
dcl.Curfn = fn
}
@ -113,9 +117,12 @@ func MakeTask() {
ni := len(InstrumentGlobalsMap)
if ni != 0 {
// Make an init._ function.
base.Pos = base.AutogeneratedPos
name := noder.Renameinit()
fnInit := typecheck.DeclFunc(name, nil, nil, nil)
pos := base.AutogeneratedPos
base.Pos = pos
sym := noder.Renameinit()
fnInit := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
typecheck.DeclFunc(fnInit)
// Get an array of instrumented global variables.
globals := instrumentGlobals(fnInit)

View File

@ -140,21 +140,25 @@ func hashFunc(t *types.Type) *ir.Func {
return sym.Def.(*ir.Name).Func
}
base.Pos = base.AutogeneratedPos // less confusing than end of input
pos := base.AutogeneratedPos // less confusing than end of input
base.Pos = pos
// func sym(p *T, h uintptr) uintptr
args := []*ir.Field{
ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)),
ir.NewField(base.Pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
}
results := []*ir.Field{ir.NewField(base.Pos, nil, types.Types[types.TUINTPTR])}
fn := typecheck.DeclFunc(sym, nil, args, results)
fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
[]*types.Field{
types.NewField(pos, typecheck.Lookup("p"), types.NewPtr(t)),
types.NewField(pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
},
[]*types.Field{
types.NewField(pos, nil, types.Types[types.TUINTPTR]),
},
))
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
np := fn.Type().Params().Field(0).Nname.(*ir.Name)
nh := fn.Type().Params().Field(1).Nname.(*ir.Name)
params, _ := typecheck.DeclFunc(fn)
np := params[0]
nh := params[1]
switch t.Kind() {
case types.TARRAY:
@ -365,19 +369,27 @@ func eqFunc(t *types.Type) *ir.Func {
if sym.Def != nil {
return sym.Def.(*ir.Name).Func
}
base.Pos = base.AutogeneratedPos // less confusing than end of input
pos := base.AutogeneratedPos // less confusing than end of input
base.Pos = pos
// func sym(p, q *T) bool
fn := typecheck.DeclFunc(sym, nil,
[]*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)), ir.NewField(base.Pos, typecheck.Lookup("q"), types.NewPtr(t))},
[]*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("r"), types.Types[types.TBOOL])},
)
fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
[]*types.Field{
types.NewField(pos, typecheck.Lookup("p"), types.NewPtr(t)),
types.NewField(pos, typecheck.Lookup("q"), types.NewPtr(t)),
},
[]*types.Field{
types.NewField(pos, typecheck.Lookup("r"), types.Types[types.TBOOL]),
},
))
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
np := fn.Type().Params().Field(0).Nname.(*ir.Name)
nq := fn.Type().Params().Field(1).Nname.(*ir.Name)
nr := fn.Type().Results().Field(0).Nname.(*ir.Name)
params, results := typecheck.DeclFunc(fn)
np := params[0]
nq := params[1]
nr := results[0]
// Label to jump to if an equality test fails.
neq := typecheck.AutoLabel(".neq")

View File

@ -239,7 +239,8 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
savepos := base.Pos
savedcurfn := ir.CurFunc
base.Pos = base.AutogeneratedPos
pos := base.AutogeneratedPos
base.Pos = pos
// At the moment we don't support wrapping a method, we'd need machinery
// below to handle the receiver. Panic if we see this scenario.
@ -250,10 +251,12 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
}
// Reuse f's types.Sym to create a new ODCLFUNC/function.
fn := typecheck.DeclFunc(f.Nname.Sym(), nil,
typecheck.NewFuncParams(ft.Params(), true),
typecheck.NewFuncParams(ft.Results(), false))
// TODO(mdempsky): Means we can't set sym.Def in Declfunc, ugh.
fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
typecheck.NewFuncParams(ft.Params().FieldSlice(), true),
typecheck.NewFuncParams(ft.Results().FieldSlice(), false)))
fn.ABI = wrapperABI
typecheck.DeclFunc(fn)
fn.SetABIWrapper(true)
fn.SetDupok(true)

View File

@ -1042,7 +1042,9 @@ func tryWrapGlobalMapInit(n ir.Node) (mapvar *ir.Name, genfn *ir.Func, call ir.N
//
minitsym := typecheck.LookupNum("map.init.", mapinitgen)
mapinitgen++
newfn := typecheck.DeclFunc(minitsym, nil, nil, nil)
newfn := ir.NewFunc(base.Pos, base.Pos, minitsym, types.NewSignature(nil, nil, nil))
typecheck.DeclFunc(newfn)
if base.Debug.WrapGlobalMapDbg > 0 {
fmt.Fprintf(os.Stderr, "=-= generated func is %v\n", newfn)
}

View File

@ -6,7 +6,6 @@ package typecheck
import (
"fmt"
"internal/types/errors"
"sync"
"cmd/compile/internal/base"
@ -17,32 +16,36 @@ import (
var funcStack []*ir.Func // stack of previous values of ir.CurFunc
func DeclFunc(sym *types.Sym, recv *ir.Field, params, results []*ir.Field) *ir.Func {
fn := ir.NewFunc(base.Pos, base.Pos, sym, nil)
// DeclFunc creates and returns ONAMEs for the parameters and results
// of the given function. It also sets ir.CurFunc, and adds fn to
// Target.Funcs.
//
// After the caller is done constructing fn, it must call
// FinishFuncBody.
func DeclFunc(fn *ir.Func) (params, results []*ir.Name) {
typ := fn.Type()
// 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().FieldSlice())
results = declareParams(fn, ir.PPARAMOUT, typ.Results().FieldSlice())
funcStack = append(funcStack, ir.CurFunc)
ir.CurFunc = fn
var recv1 *types.Field
if recv != nil {
recv1 = declareParam(fn, ir.PPARAM, -1, recv)
}
typ := types.NewSignature(recv1, declareParams(fn, ir.PPARAM, params), declareParams(fn, ir.PPARAMOUT, results))
checkdupfields("argument", typ.Recvs().FieldSlice(), typ.Params().FieldSlice(), typ.Results().FieldSlice())
fn.Nname.SetType(typ)
fn.Nname.SetTypecheck(1)
fn.Nname.Defn = fn
Target.Funcs = append(Target.Funcs, fn)
return fn
return
}
// finish the body.
// called in auto-declaration context.
// returns in extern-declaration context.
// FinishFuncBody restores ir.CurFunc to its state before the last
// call to DeclFunc.
func FinishFuncBody() {
funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
}
@ -53,36 +56,15 @@ func CheckFuncStack() {
}
}
// checkdupfields emits errors for duplicately named fields or methods in
// a list of struct or interface types.
func checkdupfields(what string, fss ...[]*types.Field) {
seen := make(map[*types.Sym]bool)
for _, fs := range fss {
for _, f := range fs {
if f.Sym == nil || f.Sym.IsBlank() {
continue
}
if seen[f.Sym] {
base.ErrorfAt(f.Pos, errors.DuplicateFieldAndMethod, "duplicate %s %s", what, f.Sym.Name)
continue
}
seen[f.Sym] = true
}
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 declareParams(fn *ir.Func, ctxt ir.Class, l []*ir.Field) []*types.Field {
fields := make([]*types.Field, len(l))
for i, n := range l {
fields[i] = declareParam(fn, ctxt, i, n)
}
return fields
}
func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *ir.Field) *types.Field {
f := types.NewField(param.Pos, param.Sym, param.Type)
f.SetIsDDD(param.IsDDD)
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 {
@ -99,11 +81,13 @@ func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *ir.Field) *types.Fie
}
}
if sym != nil {
f.Nname = fn.NewLocal(param.Pos, sym, ctxt, f.Type)
if sym == nil {
return nil
}
return f
name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
param.Nname = name
return name
}
// make a new Node off the books.

View File

@ -26,26 +26,22 @@ func LookupNum(prefix string, n int) *types.Sym {
}
// Given funarg struct list, return list of fn args.
func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
var args []*ir.Field
gen := 0
for _, t := range tl.Fields().Slice() {
s := t.Sym
func NewFuncParams(origs []*types.Field, mustname bool) []*types.Field {
res := make([]*types.Field, len(origs))
for i, orig := range origs {
s := orig.Sym
if mustname && (s == nil || s.Name == "_") {
// invent a name so that we can refer to it in the trampoline
s = LookupNum(".anon", gen)
gen++
s = LookupNum(".anon", i)
} else if s != nil && s.Pkg != types.LocalPkg {
// TODO(mdempsky): Preserve original position, name, and package.
s = Lookup(s.Name)
}
a := ir.NewField(base.Pos, s, t.Type)
a.Pos = t.Pos
a.IsDDD = t.IsDDD()
args = append(args, a)
p := types.NewField(orig.Pos, s, orig.Type)
p.SetIsDDD(orig.IsDDD())
res[i] = p
}
return args
return res
}
// NodAddr returns a node representing &n at base.Pos.