cmd/compile/internal/typecheck: merge SubstArgTypes into LookupRuntime

LookupRuntime is the only reason for using SubstArgTypes, and most
callers to LookupRuntime need to immediately call it anyway. So might
as well fuse them together.

Change-Id: Ie0724ed164b949040e898a2a77bea632801b64fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/521415
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Matthew Dempsky 2023-08-20 16:14:50 -07:00 committed by Gopher Robot
parent c6dd97e533
commit 08a08083c1
8 changed files with 48 additions and 82 deletions

View file

@ -294,8 +294,7 @@ func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
cmplen = tlen cmplen = tlen
} }
fn := typecheck.LookupRuntime("memequal") fn := typecheck.LookupRuntime("memequal", types.Types[types.TUINT8], types.Types[types.TUINT8])
fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
call := typecheck.Call(base.Pos, fn, []ir.Node{sptr, tptr, ir.Copy(cmplen)}, false).(*ir.CallExpr) call := typecheck.Call(base.Pos, fn, []ir.Node{sptr, tptr, ir.Copy(cmplen)}, false).(*ir.CallExpr)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen) cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen)
@ -373,14 +372,10 @@ func eqmem(p, q ir.Node, field int, size int64) ir.Node {
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) { func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
switch size { switch size {
default:
fn = typecheck.LookupRuntime("memequal")
needsize = true
case 1, 2, 4, 8, 16: case 1, 2, 4, 8, 16:
buf := fmt.Sprintf("memequal%d", int(size)*8) buf := fmt.Sprintf("memequal%d", int(size)*8)
fn = typecheck.LookupRuntime(buf) return typecheck.LookupRuntime(buf, t, t), false
} }
fn = typecheck.SubstArgTypes(fn, t, t) return typecheck.LookupRuntime("memequal", t, t), true
return fn, needsize
} }

View file

@ -249,9 +249,7 @@ func hashFunc(t *types.Type) *ir.Func {
} }
func runtimeHashFor(name string, t *types.Type) *ir.Name { func runtimeHashFor(name string, t *types.Type) *ir.Name {
n := typecheck.LookupRuntime(name) return typecheck.LookupRuntime(name, t)
n = typecheck.SubstArgTypes(n, t)
return n
} }
// hashfor returns the function to compute the hash of a value of type t. // hashfor returns the function to compute the hash of a value of type t.
@ -647,9 +645,7 @@ func eqFunc(t *types.Type) *ir.Func {
func EqFor(t *types.Type) (ir.Node, bool) { func EqFor(t *types.Type) (ir.Node, bool) {
switch a, _ := types.AlgType(t); a { switch a, _ := types.AlgType(t); a {
case types.AMEM: case types.AMEM:
n := typecheck.LookupRuntime("memequal") return typecheck.LookupRuntime("memequal", t, t), true
n = typecheck.SubstArgTypes(n, t, t)
return n, true
case types.ASPECIAL: case types.ASPECIAL:
fn := eqFunc(t) fn := eqFunc(t)
return fn.Nname, false return fn.Nname, false
@ -667,7 +663,5 @@ func anyCall(fn *ir.Func) bool {
} }
func hashmem(t *types.Type) ir.Node { func hashmem(t *types.Type) ir.Node {
n := typecheck.LookupRuntime("memhash") return typecheck.LookupRuntime("memhash", t)
n = typecheck.SubstArgTypes(n, t)
return n
} }

View file

@ -11,21 +11,25 @@ import (
"cmd/internal/obj" "cmd/internal/obj"
) )
func LookupRuntime(name string) *ir.Name { // LookupRuntime returns a function or variable declared in
// _builtin/runtime.go. If types_ is non-empty, successive occurrences
// of the "any" placeholder type will be substituted.
func LookupRuntime(name string, types_ ...*types.Type) *ir.Name {
s := ir.Pkgs.Runtime.Lookup(name) s := ir.Pkgs.Runtime.Lookup(name)
if s == nil || s.Def == nil { if s == nil || s.Def == nil {
base.Fatalf("LookupRuntime: can't find runtime.%s", name) base.Fatalf("LookupRuntime: can't find runtime.%s", name)
} }
return s.Def.(*ir.Name) n := s.Def.(*ir.Name)
if len(types_) != 0 {
n = substArgTypes(n, types_...)
}
return n
} }
// SubstArgTypes substitutes the given list of types for // SubstArgTypes substitutes the given list of types for
// successive occurrences of the "any" placeholder in the // successive occurrences of the "any" placeholder in the
// type syntax expression n.Type. // type syntax expression n.Type.
// The result of SubstArgTypes MUST be assigned back to old, e.g. func substArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
//
// n.Left = SubstArgTypes(n.Left, t1, t2)
func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
for _, t := range types_ { for _, t := range types_ {
types.CalcSize(t) types.CalcSize(t)
} }

View file

@ -514,8 +514,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, slice)} nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, slice)}
// func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) []T // func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) []T
fn := typecheck.LookupRuntime("growslice") fn := typecheck.LookupRuntime("growslice", elemtype, elemtype)
fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
// else { s = growslice(oldPtr, newLen, oldCap, num, T) } // else { s = growslice(oldPtr, newLen, oldCap, num, T) }
call := mkcall1(fn, s.Type(), nif.PtrInit(), oldPtr, newLen, oldCap, num, reflectdata.TypePtrAt(base.Pos, elemtype)) call := mkcall1(fn, s.Type(), nif.PtrInit(), oldPtr, newLen, oldCap, num, reflectdata.TypePtrAt(base.Pos, elemtype))
@ -541,8 +540,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
ir.CurFunc.SetWBPos(n.Pos()) ir.CurFunc.SetWBPos(n.Pos())
// instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int // instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
fn := typecheck.LookupRuntime("typedslicecopy") fn := typecheck.LookupRuntime("typedslicecopy", l1.Type().Elem(), l2.Type().Elem())
fn = typecheck.SubstArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes)) ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
ptr2, len2 := backingArrayPtrLen(l2) ptr2, len2 := backingArrayPtrLen(l2)
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, reflectdata.AppendElemRType(base.Pos, n), ptr1, len1, ptr2, len2) ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, reflectdata.AppendElemRType(base.Pos, n), ptr1, len1, ptr2, len2)
@ -557,8 +555,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes)) ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
ptr2, len2 := backingArrayPtrLen(l2) ptr2, len2 := backingArrayPtrLen(l2)
fn := typecheck.LookupRuntime("slicecopy") fn := typecheck.LookupRuntime("slicecopy", ptr1.Type().Elem(), ptr2.Type().Elem())
fn = typecheck.SubstArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(base.Pos, elemtype.Size())) ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(base.Pos, elemtype.Size()))
} else { } else {
// memmove(&s[idx], &l2[0], len(l2)*sizeof(T)) // memmove(&s[idx], &l2[0], len(l2)*sizeof(T))
@ -572,8 +569,7 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(base.Pos, elemtype.Size())) nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(base.Pos, elemtype.Size()))
// instantiate func memmove(to *any, frm *any, length uintptr) // instantiate func memmove(to *any, frm *any, length uintptr)
fn := typecheck.LookupRuntime("memmove") fn := typecheck.LookupRuntime("memmove", elemtype, elemtype)
fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid) ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid)
} }
ln := append(nodes, ncopy) ln := append(nodes, ncopy)
@ -696,8 +692,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, nt)} nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, nt)}
// instantiate growslice(oldPtr *any, newLen, oldCap, num int, typ *type) []any // instantiate growslice(oldPtr *any, newLen, oldCap, num int, typ *type) []any
fn := typecheck.LookupRuntime("growslice") fn := typecheck.LookupRuntime("growslice", elemtype, elemtype)
fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
// else { s = growslice(s.ptr, n, s.cap, l2, T) } // else { s = growslice(s.ptr, n, s.cap, l2, T) }
nif.Else = []ir.Node{ nif.Else = []ir.Node{

View file

@ -101,8 +101,8 @@ func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
ir.NewAssignStmt(base.Pos, s, slice), ir.NewAssignStmt(base.Pos, s, slice),
} }
fn := typecheck.LookupRuntime("growslice") // growslice(ptr *T, newLen, oldCap, num int, <type>) (ret []T) // growslice(ptr *T, newLen, oldCap, num int, <type>) (ret []T)
fn = typecheck.SubstArgTypes(fn, s.Type().Elem(), s.Type().Elem()) fn := typecheck.LookupRuntime("growslice", s.Type().Elem(), s.Type().Elem())
// else { s = growslice(s.ptr, n, s.cap, a, T) } // else { s = growslice(s.ptr, n, s.cap, a, T) }
nif.Else = []ir.Node{ nif.Else = []ir.Node{
@ -149,8 +149,7 @@ func walkClear(n *ir.UnaryExpr) ir.Node {
// walkClose walks an OCLOSE node. // walkClose walks an OCLOSE node.
func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node { func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
// cannot use chanfn - closechan takes any, not chan any // cannot use chanfn - closechan takes any, not chan any
fn := typecheck.LookupRuntime("closechan") fn := typecheck.LookupRuntime("closechan", n.X.Type())
fn = typecheck.SubstArgTypes(fn, n.X.Type())
return mkcall1(fn, nil, init, n.X) return mkcall1(fn, nil, init, n.X)
} }
@ -185,8 +184,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
n.Y = cheapExpr(n.Y, init) n.Y = cheapExpr(n.Y, init)
ptrR, lenR := backingArrayPtrLen(n.Y) ptrR, lenR := backingArrayPtrLen(n.Y)
fn := typecheck.LookupRuntime("slicecopy") fn := typecheck.LookupRuntime("slicecopy", ptrL.Type().Elem(), ptrR.Type().Elem())
fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(base.Pos, n.X.Type().Elem().Size())) return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(base.Pos, n.X.Type().Elem().Size()))
} }
@ -219,8 +217,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
ne.Likely = true ne.Likely = true
l = append(l, ne) l = append(l, ne)
fn := typecheck.LookupRuntime("memmove") fn := typecheck.LookupRuntime("memmove", nl.Type().Elem(), nl.Type().Elem())
fn = typecheck.SubstArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
nwid := ir.Node(typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR])) nwid := ir.Node(typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR]))
setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR])) setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
ne.Body.Append(setwid) ne.Body.Append(setwid)
@ -365,8 +362,7 @@ func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
} }
// Call runtime.makehmap to allocate an // Call runtime.makehmap to allocate an
// hmap on the heap and initialize hmap's hash0 field. // hmap on the heap and initialize hmap's hash0 field.
fn := typecheck.LookupRuntime("makemap_small") fn := typecheck.LookupRuntime("makemap_small", t.Key(), t.Elem())
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init) return mkcall1(fn, n.Type(), init)
} }
@ -392,8 +388,7 @@ func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
argtype = types.Types[types.TINT] argtype = types.Types[types.TINT]
} }
fn := typecheck.LookupRuntime(fnname) fn := typecheck.LookupRuntime(fnname, hmapType, t.Key(), t.Elem())
fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), h) return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), h)
} }
@ -503,8 +498,7 @@ func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
init.Append(r) init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr) // instantiate memmove(to *any, frm *any, size uintptr)
fn = typecheck.LookupRuntime("memmove") fn = typecheck.LookupRuntime("memmove", t.Elem(), t.Elem())
fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size) ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
init.Append(walkExpr(typecheck.Stmt(ncopy), init)) init.Append(walkExpr(typecheck.Stmt(ncopy), init))
@ -609,11 +603,10 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
switch n.Type().Kind() { switch n.Type().Kind() {
case types.TINTER: case types.TINTER:
if n.Type().IsEmptyInterface() { if n.Type().IsEmptyInterface() {
on = typecheck.LookupRuntime("printeface") on = typecheck.LookupRuntime("printeface", n.Type())
} else { } else {
on = typecheck.LookupRuntime("printiface") on = typecheck.LookupRuntime("printiface", n.Type())
} }
on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TPTR: case types.TPTR:
if n.Type().Elem().NotInHeap() { if n.Type().Elem().NotInHeap() {
on = typecheck.LookupRuntime("printuintptr") on = typecheck.LookupRuntime("printuintptr")
@ -625,11 +618,9 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
} }
fallthrough fallthrough
case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR: case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
on = typecheck.LookupRuntime("printpointer") on = typecheck.LookupRuntime("printpointer", n.Type())
on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TSLICE: case types.TSLICE:
on = typecheck.LookupRuntime("printslice") on = typecheck.LookupRuntime("printslice", n.Type())
on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR: case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
if types.RuntimeSymName(n.Type().Sym()) == "hex" { if types.RuntimeSymName(n.Type().Sym()) == "hex" {
on = typecheck.LookupRuntime("printhex") on = typecheck.LookupRuntime("printhex")
@ -863,9 +854,7 @@ func badtype(op ir.Op, tl, tr *types.Type) {
} }
func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node { func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
fn := typecheck.LookupRuntime(name) return typecheck.LookupRuntime(name, l, r)
fn = typecheck.SubstArgTypes(fn, l, r)
return fn
} }
// isRuneCount reports whether n is of the form len([]rune(string)). // isRuneCount reports whether n is of the form len([]rune(string)).

View file

@ -165,7 +165,7 @@ func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
// Time to do an allocation. We'll call into the runtime for that. // Time to do an allocation. We'll call into the runtime for that.
fnname, argType, needsaddr := dataWordFuncName(fromType) fnname, argType, needsaddr := dataWordFuncName(fromType)
fn := typecheck.LookupRuntime(fnname) var fn *ir.Name
var args []ir.Node var args []ir.Node
if needsaddr { if needsaddr {
@ -178,11 +178,12 @@ func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
if !ir.IsAddressable(n) { if !ir.IsAddressable(n) {
n = copyExpr(n, fromType, init) n = copyExpr(n, fromType, init)
} }
fn = typecheck.SubstArgTypes(fn, fromType) fn = typecheck.LookupRuntime(fnname, fromType)
args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)} args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
} else { } else {
// Use a specialized conversion routine that takes the type being // Use a specialized conversion routine that takes the type being
// converted by value, not by pointer. // converted by value, not by pointer.
fn = typecheck.LookupRuntime(fnname)
var arg ir.Node var arg ir.Node
switch { switch {
case fromType == argType: case fromType == argType:

View file

@ -231,14 +231,11 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
keysym := th.Field(0).Sym keysym := th.Field(0).Sym
elemsym := th.Field(1).Sym // ditto elemsym := th.Field(1).Sym // ditto
fn := typecheck.LookupRuntime("mapiterinit") fn := typecheck.LookupRuntime("mapiterinit", t.Key(), t.Elem(), th)
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), th)
init = append(init, mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), ha, typecheck.NodAddr(hit))) init = append(init, mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), ha, typecheck.NodAddr(hit)))
nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil()) nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
fn = typecheck.LookupRuntime("mapiternext") fn = typecheck.LookupRuntime("mapiternext", th)
fn = typecheck.SubstArgTypes(fn, th)
nfor.Post = mkcallstmt1(fn, typecheck.NodAddr(hit)) nfor.Post = mkcallstmt1(fn, typecheck.NodAddr(hit))
key := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), types.NewPtr(t.Key()))) key := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), types.NewPtr(t.Key())))
@ -454,8 +451,7 @@ func mapClear(m, rtyp ir.Node) ir.Node {
t := m.Type() t := m.Type()
// instantiate mapclear(typ *type, hmap map[any]any) // instantiate mapclear(typ *type, hmap map[any]any)
fn := typecheck.LookupRuntime("mapclear") fn := typecheck.LookupRuntime("mapclear", t.Key(), t.Elem())
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
n := mkcallstmt1(fn, rtyp, m) n := mkcallstmt1(fn, rtyp, m)
return walkStmt(typecheck.Stmt(n)) return walkStmt(typecheck.Stmt(n))
} }

View file

@ -141,42 +141,34 @@ func chanfn(name string, n int, t *types.Type) ir.Node {
if !t.IsChan() { if !t.IsChan() {
base.Fatalf("chanfn %v", t) base.Fatalf("chanfn %v", t)
} }
fn := typecheck.LookupRuntime(name)
switch n { switch n {
default:
base.Fatalf("chanfn %d", n)
case 1: case 1:
fn = typecheck.SubstArgTypes(fn, t.Elem()) return typecheck.LookupRuntime(name, t.Elem())
case 2: case 2:
fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem()) return typecheck.LookupRuntime(name, t.Elem(), t.Elem())
} }
return fn base.Fatalf("chanfn %d", n)
return nil
} }
func mapfn(name string, t *types.Type, isfat bool) ir.Node { func mapfn(name string, t *types.Type, isfat bool) ir.Node {
if !t.IsMap() { if !t.IsMap() {
base.Fatalf("mapfn %v", t) base.Fatalf("mapfn %v", t)
} }
fn := typecheck.LookupRuntime(name)
if mapfast(t) == mapslow || isfat { if mapfast(t) == mapslow || isfat {
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem()) return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Key(), t.Elem())
} else {
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Elem())
} }
return fn return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Elem())
} }
func mapfndel(name string, t *types.Type) ir.Node { func mapfndel(name string, t *types.Type) ir.Node {
if !t.IsMap() { if !t.IsMap() {
base.Fatalf("mapfn %v", t) base.Fatalf("mapfn %v", t)
} }
fn := typecheck.LookupRuntime(name)
if mapfast(t) == mapslow { if mapfast(t) == mapslow {
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key()) return typecheck.LookupRuntime(name, t.Key(), t.Elem(), t.Key())
} else {
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
} }
return fn return typecheck.LookupRuntime(name, t.Key(), t.Elem())
} }
const ( const (