From 864b54e2c3b7b2e6634cb22cd70fe1a8ec723ae9 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 28 Sep 2022 12:30:46 +0700 Subject: [PATCH] cmd/compile: generate type equal func during walk So we don't generate ONAME node with nil Func. Do not pass toolstash-check because the CL changes the order of compiling functions. Change-Id: Ib967328f36b8c59a5525445667103c0c80ccdc82 Reviewed-on: https://go-review.googlesource.com/c/go/+/436436 Reviewed-by: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-by: Michael Knyszek Run-TryBot: Cuong Manh Le --- src/cmd/compile/internal/reflectdata/alg.go | 29 +++++++++++++++++---- src/cmd/compile/internal/walk/compare.go | 8 ++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index 1a8b76851c..4577e9cfc4 100644 --- a/src/cmd/compile/internal/reflectdata/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -357,16 +357,19 @@ func geneq(t *types.Type) *obj.LSym { func eqFunc(t *types.Type) *ir.Func { // Autogenerate code for equality of structs and arrays. - + sym := TypeSymPrefix(".eq", t) + if sym.Def != nil { + return sym.Def.(*ir.Name).Func + } base.Pos = base.AutogeneratedPos // less confusing than end of input typecheck.DeclContext = ir.PEXTERN // func sym(p, q *T) bool - sym := TypeSymPrefix(".eq", t) 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])}, ) + sym.Def = fn.Nname np := ir.AsNode(fn.Type().Params().Field(0).Nname) nq := ir.AsNode(fn.Type().Params().Field(1).Nname) nr := ir.AsNode(fn.Type().Results().Field(0).Nname) @@ -554,9 +557,9 @@ func eqFunc(t *types.Type) *ir.Func { fn.SetDupok(true) typecheck.Func(fn) - ir.CurFunc = fn - typecheck.Stmts(fn.Body) - ir.CurFunc = nil + ir.WithFunc(fn, func() { + typecheck.Stmts(fn.Body) + }) // Disable checknils while compiling this code. // We are comparing a struct or an array, @@ -567,6 +570,22 @@ func eqFunc(t *types.Type) *ir.Func { return fn } +// EqFor returns ONAME node represents type t's equal function, and a boolean +// to indicates whether a length needs to be passed when calling the function. +func EqFor(t *types.Type) (ir.Node, bool) { + switch a, _ := types.AlgType(t); a { + case types.AMEM: + n := typecheck.LookupRuntime("memequal") + n = typecheck.SubstArgTypes(n, t, t) + return n, true + case types.ASPECIAL: + fn := eqFunc(t) + return fn.Nname, false + } + base.Fatalf("EqFor %v", t) + return nil, false +} + func anyCall(fn *ir.Func) bool { return ir.Any(fn, func(n ir.Node) bool { // TODO(rsc): No methods? diff --git a/src/cmd/compile/internal/walk/compare.go b/src/cmd/compile/internal/walk/compare.go index 0382894f38..87987b09a6 100644 --- a/src/cmd/compile/internal/walk/compare.go +++ b/src/cmd/compile/internal/walk/compare.go @@ -186,11 +186,15 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { base.Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr) } - fn, needsize := eqFor(t) + // Should only arrive here with large memory or + // a struct/array containing a non-memory field/element. + // Small memory is handled inline, and single non-memory + // is handled by walkCompare. + fn, needsLength := reflectdata.EqFor(t) call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil) call.Args.Append(typecheck.NodAddr(cmpl)) call.Args.Append(typecheck.NodAddr(cmpr)) - if needsize { + if needsLength { call.Args.Append(ir.NewInt(t.Size())) } res := ir.Node(call)