github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/reflectdata/alg.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflectdata
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/bir3/gocompiler/src/cmd/compile/internal/base"
    11  	"github.com/bir3/gocompiler/src/cmd/compile/internal/compare"
    12  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ir"
    13  	"github.com/bir3/gocompiler/src/cmd/compile/internal/objw"
    14  	"github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck"
    15  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    16  	"github.com/bir3/gocompiler/src/cmd/internal/obj"
    17  )
    18  
    19  // AlgType returns the fixed-width AMEMxx variants instead of the general
    20  // AMEM kind when possible.
    21  func AlgType(t *types.Type) types.AlgKind {
    22  	a, _ := types.AlgType(t)
    23  	if a == types.AMEM {
    24  		if t.Alignment() < int64(base.Ctxt.Arch.Alignment) && t.Alignment() < t.Size() {
    25  			// For example, we can't treat [2]int16 as an int32 if int32s require
    26  			// 4-byte alignment. See issue 46283.
    27  			return a
    28  		}
    29  		switch t.Size() {
    30  		case 0:
    31  			return types.AMEM0
    32  		case 1:
    33  			return types.AMEM8
    34  		case 2:
    35  			return types.AMEM16
    36  		case 4:
    37  			return types.AMEM32
    38  		case 8:
    39  			return types.AMEM64
    40  		case 16:
    41  			return types.AMEM128
    42  		}
    43  	}
    44  
    45  	return a
    46  }
    47  
    48  // genhash returns a symbol which is the closure used to compute
    49  // the hash of a value of type t.
    50  // Note: the generated function must match runtime.typehash exactly.
    51  func genhash(t *types.Type) *obj.LSym {
    52  	switch AlgType(t) {
    53  	default:
    54  		// genhash is only called for types that have equality
    55  		base.Fatalf("genhash %v", t)
    56  	case types.AMEM0:
    57  		return sysClosure("memhash0")
    58  	case types.AMEM8:
    59  		return sysClosure("memhash8")
    60  	case types.AMEM16:
    61  		return sysClosure("memhash16")
    62  	case types.AMEM32:
    63  		return sysClosure("memhash32")
    64  	case types.AMEM64:
    65  		return sysClosure("memhash64")
    66  	case types.AMEM128:
    67  		return sysClosure("memhash128")
    68  	case types.ASTRING:
    69  		return sysClosure("strhash")
    70  	case types.AINTER:
    71  		return sysClosure("interhash")
    72  	case types.ANILINTER:
    73  		return sysClosure("nilinterhash")
    74  	case types.AFLOAT32:
    75  		return sysClosure("f32hash")
    76  	case types.AFLOAT64:
    77  		return sysClosure("f64hash")
    78  	case types.ACPLX64:
    79  		return sysClosure("c64hash")
    80  	case types.ACPLX128:
    81  		return sysClosure("c128hash")
    82  	case types.AMEM:
    83  		// For other sizes of plain memory, we build a closure
    84  		// that calls memhash_varlen. The size of the memory is
    85  		// encoded in the first slot of the closure.
    86  		closure := TypeLinksymLookup(fmt.Sprintf(".hashfunc%d", t.Size()))
    87  		if len(closure.P) > 0 { // already generated
    88  			return closure
    89  		}
    90  		if memhashvarlen == nil {
    91  			memhashvarlen = typecheck.LookupRuntimeFunc("memhash_varlen")
    92  		}
    93  		ot := 0
    94  		ot = objw.SymPtr(closure, ot, memhashvarlen, 0)
    95  		ot = objw.Uintptr(closure, ot, uint64(t.Size())) // size encoded in closure
    96  		objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
    97  		return closure
    98  	case types.ASPECIAL:
    99  		break
   100  	}
   101  
   102  	closure := TypeLinksymPrefix(".hashfunc", t)
   103  	if len(closure.P) > 0 { // already generated
   104  		return closure
   105  	}
   106  
   107  	// Generate hash functions for subtypes.
   108  	// There are cases where we might not use these hashes,
   109  	// but in that case they will get dead-code eliminated.
   110  	// (And the closure generated by genhash will also get
   111  	// dead-code eliminated, as we call the subtype hashers
   112  	// directly.)
   113  	switch t.Kind() {
   114  	case types.TARRAY:
   115  		genhash(t.Elem())
   116  	case types.TSTRUCT:
   117  		for _, f := range t.FieldSlice() {
   118  			genhash(f.Type)
   119  		}
   120  	}
   121  
   122  	sym := TypeSymPrefix(".hash", t)
   123  	if base.Flag.LowerR != 0 {
   124  		fmt.Printf("genhash %v %v %v\n", closure, sym, t)
   125  	}
   126  
   127  	base.Pos = base.AutogeneratedPos // less confusing than end of input
   128  	typecheck.DeclContext = ir.PEXTERN
   129  
   130  	// func sym(p *T, h uintptr) uintptr
   131  	args := []*ir.Field{
   132  		ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)),
   133  		ir.NewField(base.Pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
   134  	}
   135  	results := []*ir.Field{ir.NewField(base.Pos, nil, types.Types[types.TUINTPTR])}
   136  
   137  	fn := typecheck.DeclFunc(sym, nil, args, results)
   138  	np := ir.AsNode(fn.Type().Params().Field(0).Nname)
   139  	nh := ir.AsNode(fn.Type().Params().Field(1).Nname)
   140  
   141  	switch t.Kind() {
   142  	case types.TARRAY:
   143  		// An array of pure memory would be handled by the
   144  		// standard algorithm, so the element type must not be
   145  		// pure memory.
   146  		hashel := hashfor(t.Elem())
   147  
   148  		// for i := 0; i < nelem; i++
   149  		ni := typecheck.Temp(types.Types[types.TINT])
   150  		init := ir.NewAssignStmt(base.Pos, ni, ir.NewInt(0))
   151  		cond := ir.NewBinaryExpr(base.Pos, ir.OLT, ni, ir.NewInt(t.NumElem()))
   152  		post := ir.NewAssignStmt(base.Pos, ni, ir.NewBinaryExpr(base.Pos, ir.OADD, ni, ir.NewInt(1)))
   153  		loop := ir.NewForStmt(base.Pos, nil, cond, post, nil)
   154  		loop.PtrInit().Append(init)
   155  
   156  		// h = hashel(&p[i], h)
   157  		call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
   158  
   159  		nx := ir.NewIndexExpr(base.Pos, np, ni)
   160  		nx.SetBounded(true)
   161  		na := typecheck.NodAddr(nx)
   162  		call.Args.Append(na)
   163  		call.Args.Append(nh)
   164  		loop.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
   165  
   166  		fn.Body.Append(loop)
   167  
   168  	case types.TSTRUCT:
   169  		// Walk the struct using memhash for runs of AMEM
   170  		// and calling specific hash functions for the others.
   171  		for i, fields := 0, t.FieldSlice(); i < len(fields); {
   172  			f := fields[i]
   173  
   174  			// Skip blank fields.
   175  			if f.Sym.IsBlank() {
   176  				i++
   177  				continue
   178  			}
   179  
   180  			// Hash non-memory fields with appropriate hash function.
   181  			if !compare.IsRegularMemory(f.Type) {
   182  				hashel := hashfor(f.Type)
   183  				call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
   184  				nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
   185  				na := typecheck.NodAddr(nx)
   186  				call.Args.Append(na)
   187  				call.Args.Append(nh)
   188  				fn.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
   189  				i++
   190  				continue
   191  			}
   192  
   193  			// Otherwise, hash a maximal length run of raw memory.
   194  			size, next := compare.Memrun(t, i)
   195  
   196  			// h = hashel(&p.first, size, h)
   197  			hashel := hashmem(f.Type)
   198  			call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
   199  			nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
   200  			na := typecheck.NodAddr(nx)
   201  			call.Args.Append(na)
   202  			call.Args.Append(nh)
   203  			call.Args.Append(ir.NewInt(size))
   204  			fn.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
   205  
   206  			i = next
   207  		}
   208  	}
   209  
   210  	r := ir.NewReturnStmt(base.Pos, nil)
   211  	r.Results.Append(nh)
   212  	fn.Body.Append(r)
   213  
   214  	if base.Flag.LowerR != 0 {
   215  		ir.DumpList("genhash body", fn.Body)
   216  	}
   217  
   218  	typecheck.FinishFuncBody()
   219  
   220  	fn.SetDupok(true)
   221  	typecheck.Func(fn)
   222  
   223  	ir.CurFunc = fn
   224  	typecheck.Stmts(fn.Body)
   225  	ir.CurFunc = nil
   226  
   227  	if base.Debug.DclStack != 0 {
   228  		types.CheckDclstack()
   229  	}
   230  
   231  	fn.SetNilCheckDisabled(true)
   232  	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
   233  
   234  	// Build closure. It doesn't close over any variables, so
   235  	// it contains just the function pointer.
   236  	objw.SymPtr(closure, 0, fn.Linksym(), 0)
   237  	objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
   238  
   239  	return closure
   240  }
   241  
   242  func hashfor(t *types.Type) ir.Node {
   243  	var sym *types.Sym
   244  
   245  	switch a, _ := types.AlgType(t); a {
   246  	case types.AMEM:
   247  		base.Fatalf("hashfor with AMEM type")
   248  	case types.AINTER:
   249  		sym = ir.Pkgs.Runtime.Lookup("interhash")
   250  	case types.ANILINTER:
   251  		sym = ir.Pkgs.Runtime.Lookup("nilinterhash")
   252  	case types.ASTRING:
   253  		sym = ir.Pkgs.Runtime.Lookup("strhash")
   254  	case types.AFLOAT32:
   255  		sym = ir.Pkgs.Runtime.Lookup("f32hash")
   256  	case types.AFLOAT64:
   257  		sym = ir.Pkgs.Runtime.Lookup("f64hash")
   258  	case types.ACPLX64:
   259  		sym = ir.Pkgs.Runtime.Lookup("c64hash")
   260  	case types.ACPLX128:
   261  		sym = ir.Pkgs.Runtime.Lookup("c128hash")
   262  	default:
   263  		// Note: the caller of hashfor ensured that this symbol
   264  		// exists and has a body by calling genhash for t.
   265  		sym = TypeSymPrefix(".hash", t)
   266  	}
   267  
   268  	// TODO(austin): This creates an ir.Name with a nil Func.
   269  	n := typecheck.NewName(sym)
   270  	ir.MarkFunc(n)
   271  	n.SetType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{
   272  		types.NewField(base.Pos, nil, types.NewPtr(t)),
   273  		types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   274  	}, []*types.Field{
   275  		types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   276  	}))
   277  	return n
   278  }
   279  
   280  // sysClosure returns a closure which will call the
   281  // given runtime function (with no closed-over variables).
   282  func sysClosure(name string) *obj.LSym {
   283  	s := typecheck.LookupRuntimeVar(name + "·f")
   284  	if len(s.P) == 0 {
   285  		f := typecheck.LookupRuntimeFunc(name)
   286  		objw.SymPtr(s, 0, f, 0)
   287  		objw.Global(s, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
   288  	}
   289  	return s
   290  }
   291  
   292  // geneq returns a symbol which is the closure used to compute
   293  // equality for two objects of type t.
   294  func geneq(t *types.Type) *obj.LSym {
   295  	switch AlgType(t) {
   296  	case types.ANOEQ:
   297  		// The runtime will panic if it tries to compare
   298  		// a type with a nil equality function.
   299  		return nil
   300  	case types.AMEM0:
   301  		return sysClosure("memequal0")
   302  	case types.AMEM8:
   303  		return sysClosure("memequal8")
   304  	case types.AMEM16:
   305  		return sysClosure("memequal16")
   306  	case types.AMEM32:
   307  		return sysClosure("memequal32")
   308  	case types.AMEM64:
   309  		return sysClosure("memequal64")
   310  	case types.AMEM128:
   311  		return sysClosure("memequal128")
   312  	case types.ASTRING:
   313  		return sysClosure("strequal")
   314  	case types.AINTER:
   315  		return sysClosure("interequal")
   316  	case types.ANILINTER:
   317  		return sysClosure("nilinterequal")
   318  	case types.AFLOAT32:
   319  		return sysClosure("f32equal")
   320  	case types.AFLOAT64:
   321  		return sysClosure("f64equal")
   322  	case types.ACPLX64:
   323  		return sysClosure("c64equal")
   324  	case types.ACPLX128:
   325  		return sysClosure("c128equal")
   326  	case types.AMEM:
   327  		// make equality closure. The size of the type
   328  		// is encoded in the closure.
   329  		closure := TypeLinksymLookup(fmt.Sprintf(".eqfunc%d", t.Size()))
   330  		if len(closure.P) != 0 {
   331  			return closure
   332  		}
   333  		if memequalvarlen == nil {
   334  			memequalvarlen = typecheck.LookupRuntimeFunc("memequal_varlen")
   335  		}
   336  		ot := 0
   337  		ot = objw.SymPtr(closure, ot, memequalvarlen, 0)
   338  		ot = objw.Uintptr(closure, ot, uint64(t.Size()))
   339  		objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
   340  		return closure
   341  	case types.ASPECIAL:
   342  		break
   343  	}
   344  
   345  	closure := TypeLinksymPrefix(".eqfunc", t)
   346  	if len(closure.P) > 0 { // already generated
   347  		return closure
   348  	}
   349  	sym := TypeSymPrefix(".eq", t)
   350  	if base.Flag.LowerR != 0 {
   351  		fmt.Printf("geneq %v\n", t)
   352  	}
   353  
   354  	// Autogenerate code for equality of structs and arrays.
   355  
   356  	base.Pos = base.AutogeneratedPos // less confusing than end of input
   357  	typecheck.DeclContext = ir.PEXTERN
   358  
   359  	// func sym(p, q *T) bool
   360  	fn := typecheck.DeclFunc(sym, nil,
   361  		[]*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)), ir.NewField(base.Pos, typecheck.Lookup("q"), types.NewPtr(t))},
   362  		[]*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("r"), types.Types[types.TBOOL])},
   363  	)
   364  	np := ir.AsNode(fn.Type().Params().Field(0).Nname)
   365  	nq := ir.AsNode(fn.Type().Params().Field(1).Nname)
   366  	nr := ir.AsNode(fn.Type().Results().Field(0).Nname)
   367  
   368  	// Label to jump to if an equality test fails.
   369  	neq := typecheck.AutoLabel(".neq")
   370  
   371  	// We reach here only for types that have equality but
   372  	// cannot be handled by the standard algorithms,
   373  	// so t must be either an array or a struct.
   374  	switch t.Kind() {
   375  	default:
   376  		base.Fatalf("geneq %v", t)
   377  
   378  	case types.TARRAY:
   379  		nelem := t.NumElem()
   380  
   381  		// checkAll generates code to check the equality of all array elements.
   382  		// If unroll is greater than nelem, checkAll generates:
   383  		//
   384  		// if eq(p[0], q[0]) && eq(p[1], q[1]) && ... {
   385  		// } else {
   386  		//   goto neq
   387  		// }
   388  		//
   389  		// And so on.
   390  		//
   391  		// Otherwise it generates:
   392  		//
   393  		// iterateTo := nelem/unroll*unroll
   394  		// for i := 0; i < iterateTo; i += unroll {
   395  		//   if eq(p[i+0], q[i+0]) && eq(p[i+1], q[i+1]) && ... && eq(p[i+unroll-1], q[i+unroll-1]) {
   396  		//   } else {
   397  		//     goto neq
   398  		//   }
   399  		// }
   400  		// if eq(p[iterateTo+0], q[iterateTo+0]) && eq(p[iterateTo+1], q[iterateTo+1]) && ... {
   401  		// } else {
   402  		//    goto neq
   403  		// }
   404  		//
   405  		checkAll := func(unroll int64, last bool, eq func(pi, qi ir.Node) ir.Node) {
   406  			// checkIdx generates a node to check for equality at index i.
   407  			checkIdx := func(i ir.Node) ir.Node {
   408  				// pi := p[i]
   409  				pi := ir.NewIndexExpr(base.Pos, np, i)
   410  				pi.SetBounded(true)
   411  				pi.SetType(t.Elem())
   412  				// qi := q[i]
   413  				qi := ir.NewIndexExpr(base.Pos, nq, i)
   414  				qi.SetBounded(true)
   415  				qi.SetType(t.Elem())
   416  				return eq(pi, qi)
   417  			}
   418  
   419  			iterations := nelem / unroll
   420  			iterateTo := iterations * unroll
   421  			// If a loop is iterated only once, there shouldn't be any loop at all.
   422  			if iterations == 1 {
   423  				iterateTo = 0
   424  			}
   425  
   426  			if iterateTo > 0 {
   427  				// Generate an unrolled for loop.
   428  				// for i := 0; i < nelem/unroll*unroll; i += unroll
   429  				i := typecheck.Temp(types.Types[types.TINT])
   430  				init := ir.NewAssignStmt(base.Pos, i, ir.NewInt(0))
   431  				cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(iterateTo))
   432  				loop := ir.NewForStmt(base.Pos, nil, cond, nil, nil)
   433  				loop.PtrInit().Append(init)
   434  
   435  				// if eq(p[i+0], q[i+0]) && eq(p[i+1], q[i+1]) && ... && eq(p[i+unroll-1], q[i+unroll-1]) {
   436  				// } else {
   437  				//   goto neq
   438  				// }
   439  				for j := int64(0); j < unroll; j++ {
   440  					// if check {} else { goto neq }
   441  					nif := ir.NewIfStmt(base.Pos, checkIdx(i), nil, nil)
   442  					nif.Else.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, neq))
   443  					loop.Body.Append(nif)
   444  					post := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(1)))
   445  					loop.Body.Append(post)
   446  				}
   447  
   448  				fn.Body.Append(loop)
   449  
   450  				if nelem == iterateTo {
   451  					if last {
   452  						fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(true)))
   453  					}
   454  					return
   455  				}
   456  			}
   457  
   458  			// Generate remaining checks, if nelem is not a multiple of unroll.
   459  			if last {
   460  				// Do last comparison in a different manner.
   461  				nelem--
   462  			}
   463  			// if eq(p[iterateTo+0], q[iterateTo+0]) && eq(p[iterateTo+1], q[iterateTo+1]) && ... {
   464  			// } else {
   465  			//    goto neq
   466  			// }
   467  			for j := iterateTo; j < nelem; j++ {
   468  				// if check {} else { goto neq }
   469  				nif := ir.NewIfStmt(base.Pos, checkIdx(ir.NewInt(j)), nil, nil)
   470  				nif.Else.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, neq))
   471  				fn.Body.Append(nif)
   472  			}
   473  			if last {
   474  				fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, checkIdx(ir.NewInt(nelem))))
   475  			}
   476  		}
   477  
   478  		switch t.Elem().Kind() {
   479  		case types.TSTRING:
   480  			// Do two loops. First, check that all the lengths match (cheap).
   481  			// Second, check that all the contents match (expensive).
   482  			checkAll(3, false, func(pi, qi ir.Node) ir.Node {
   483  				// Compare lengths.
   484  				eqlen, _ := compare.EqString(pi, qi)
   485  				return eqlen
   486  			})
   487  			checkAll(1, true, func(pi, qi ir.Node) ir.Node {
   488  				// Compare contents.
   489  				_, eqmem := compare.EqString(pi, qi)
   490  				return eqmem
   491  			})
   492  		case types.TFLOAT32, types.TFLOAT64:
   493  			checkAll(2, true, func(pi, qi ir.Node) ir.Node {
   494  				// p[i] == q[i]
   495  				return ir.NewBinaryExpr(base.Pos, ir.OEQ, pi, qi)
   496  			})
   497  		// TODO: pick apart structs, do them piecemeal too
   498  		default:
   499  			checkAll(1, true, func(pi, qi ir.Node) ir.Node {
   500  				// p[i] == q[i]
   501  				return ir.NewBinaryExpr(base.Pos, ir.OEQ, pi, qi)
   502  			})
   503  		}
   504  
   505  	case types.TSTRUCT:
   506  		flatConds := compare.EqStruct(t, np, nq)
   507  		if len(flatConds) == 0 {
   508  			fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(true)))
   509  		} else {
   510  			for _, c := range flatConds[:len(flatConds)-1] {
   511  				// if cond {} else { goto neq }
   512  				n := ir.NewIfStmt(base.Pos, c, nil, nil)
   513  				n.Else.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, neq))
   514  				fn.Body.Append(n)
   515  			}
   516  			fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, flatConds[len(flatConds)-1]))
   517  		}
   518  	}
   519  
   520  	// ret:
   521  	//   return
   522  	ret := typecheck.AutoLabel(".ret")
   523  	fn.Body.Append(ir.NewLabelStmt(base.Pos, ret))
   524  	fn.Body.Append(ir.NewReturnStmt(base.Pos, nil))
   525  
   526  	// neq:
   527  	//   r = false
   528  	//   return (or goto ret)
   529  	fn.Body.Append(ir.NewLabelStmt(base.Pos, neq))
   530  	fn.Body.Append(ir.NewAssignStmt(base.Pos, nr, ir.NewBool(false)))
   531  	if compare.EqCanPanic(t) || anyCall(fn) {
   532  		// Epilogue is large, so share it with the equal case.
   533  		fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.OGOTO, ret))
   534  	} else {
   535  		// Epilogue is small, so don't bother sharing.
   536  		fn.Body.Append(ir.NewReturnStmt(base.Pos, nil))
   537  	}
   538  	// TODO(khr): the epilogue size detection condition above isn't perfect.
   539  	// We should really do a generic CL that shares epilogues across
   540  	// the board. See #24936.
   541  
   542  	if base.Flag.LowerR != 0 {
   543  		ir.DumpList("geneq body", fn.Body)
   544  	}
   545  
   546  	typecheck.FinishFuncBody()
   547  
   548  	fn.SetDupok(true)
   549  	typecheck.Func(fn)
   550  
   551  	ir.CurFunc = fn
   552  	typecheck.Stmts(fn.Body)
   553  	ir.CurFunc = nil
   554  
   555  	if base.Debug.DclStack != 0 {
   556  		types.CheckDclstack()
   557  	}
   558  
   559  	// Disable checknils while compiling this code.
   560  	// We are comparing a struct or an array,
   561  	// neither of which can be nil, and our comparisons
   562  	// are shallow.
   563  	fn.SetNilCheckDisabled(true)
   564  	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
   565  
   566  	// Generate a closure which points at the function we just generated.
   567  	objw.SymPtr(closure, 0, fn.Linksym(), 0)
   568  	objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
   569  	return closure
   570  }
   571  
   572  func anyCall(fn *ir.Func) bool {
   573  	return ir.Any(fn, func(n ir.Node) bool {
   574  		// TODO(rsc): No methods?
   575  		op := n.Op()
   576  		return op == ir.OCALL || op == ir.OCALLFUNC
   577  	})
   578  }
   579  
   580  func hashmem(t *types.Type) ir.Node {
   581  	sym := ir.Pkgs.Runtime.Lookup("memhash")
   582  
   583  	// TODO(austin): This creates an ir.Name with a nil Func.
   584  	n := typecheck.NewName(sym)
   585  	ir.MarkFunc(n)
   586  	n.SetType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{
   587  		types.NewField(base.Pos, nil, types.NewPtr(t)),
   588  		types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   589  		types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   590  	}, []*types.Field{
   591  		types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   592  	}))
   593  	return n
   594  }