github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/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 gc
     6  
     7  import (
     8  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     9  	"github.com/gagliardetto/golang-go/cmd/internal/obj"
    10  	"fmt"
    11  )
    12  
    13  // AlgKind describes the kind of algorithms used for comparing and
    14  // hashing a Type.
    15  type AlgKind int
    16  
    17  const (
    18  	// These values are known by runtime.
    19  	ANOEQ AlgKind = iota
    20  	AMEM0
    21  	AMEM8
    22  	AMEM16
    23  	AMEM32
    24  	AMEM64
    25  	AMEM128
    26  	ASTRING
    27  	AINTER
    28  	ANILINTER
    29  	AFLOAT32
    30  	AFLOAT64
    31  	ACPLX64
    32  	ACPLX128
    33  
    34  	// Type can be compared/hashed as regular memory.
    35  	AMEM AlgKind = 100
    36  
    37  	// Type needs special comparison/hashing functions.
    38  	ASPECIAL AlgKind = -1
    39  )
    40  
    41  // IsComparable reports whether t is a comparable type.
    42  func IsComparable(t *types.Type) bool {
    43  	a, _ := algtype1(t)
    44  	return a != ANOEQ
    45  }
    46  
    47  // IsRegularMemory reports whether t can be compared/hashed as regular memory.
    48  func IsRegularMemory(t *types.Type) bool {
    49  	a, _ := algtype1(t)
    50  	return a == AMEM
    51  }
    52  
    53  // IncomparableField returns an incomparable Field of struct Type t, if any.
    54  func IncomparableField(t *types.Type) *types.Field {
    55  	for _, f := range t.FieldSlice() {
    56  		if !IsComparable(f.Type) {
    57  			return f
    58  		}
    59  	}
    60  	return nil
    61  }
    62  
    63  // algtype is like algtype1, except it returns the fixed-width AMEMxx variants
    64  // instead of the general AMEM kind when possible.
    65  func algtype(t *types.Type) AlgKind {
    66  	a, _ := algtype1(t)
    67  	if a == AMEM {
    68  		switch t.Width {
    69  		case 0:
    70  			return AMEM0
    71  		case 1:
    72  			return AMEM8
    73  		case 2:
    74  			return AMEM16
    75  		case 4:
    76  			return AMEM32
    77  		case 8:
    78  			return AMEM64
    79  		case 16:
    80  			return AMEM128
    81  		}
    82  	}
    83  
    84  	return a
    85  }
    86  
    87  // algtype1 returns the AlgKind used for comparing and hashing Type t.
    88  // If it returns ANOEQ, it also returns the component type of t that
    89  // makes it incomparable.
    90  func algtype1(t *types.Type) (AlgKind, *types.Type) {
    91  	if t.Broke() {
    92  		return AMEM, nil
    93  	}
    94  	if t.Noalg() {
    95  		return ANOEQ, t
    96  	}
    97  
    98  	switch t.Etype {
    99  	case TANY, TFORW:
   100  		// will be defined later.
   101  		return ANOEQ, t
   102  
   103  	case TINT8, TUINT8, TINT16, TUINT16,
   104  		TINT32, TUINT32, TINT64, TUINT64,
   105  		TINT, TUINT, TUINTPTR,
   106  		TBOOL, TPTR,
   107  		TCHAN, TUNSAFEPTR:
   108  		return AMEM, nil
   109  
   110  	case TFUNC, TMAP:
   111  		return ANOEQ, t
   112  
   113  	case TFLOAT32:
   114  		return AFLOAT32, nil
   115  
   116  	case TFLOAT64:
   117  		return AFLOAT64, nil
   118  
   119  	case TCOMPLEX64:
   120  		return ACPLX64, nil
   121  
   122  	case TCOMPLEX128:
   123  		return ACPLX128, nil
   124  
   125  	case TSTRING:
   126  		return ASTRING, nil
   127  
   128  	case TINTER:
   129  		if t.IsEmptyInterface() {
   130  			return ANILINTER, nil
   131  		}
   132  		return AINTER, nil
   133  
   134  	case TSLICE:
   135  		return ANOEQ, t
   136  
   137  	case TARRAY:
   138  		a, bad := algtype1(t.Elem())
   139  		switch a {
   140  		case AMEM:
   141  			return AMEM, nil
   142  		case ANOEQ:
   143  			return ANOEQ, bad
   144  		}
   145  
   146  		switch t.NumElem() {
   147  		case 0:
   148  			// We checked above that the element type is comparable.
   149  			return AMEM, nil
   150  		case 1:
   151  			// Single-element array is same as its lone element.
   152  			return a, nil
   153  		}
   154  
   155  		return ASPECIAL, nil
   156  
   157  	case TSTRUCT:
   158  		fields := t.FieldSlice()
   159  
   160  		// One-field struct is same as that one field alone.
   161  		if len(fields) == 1 && !fields[0].Sym.IsBlank() {
   162  			return algtype1(fields[0].Type)
   163  		}
   164  
   165  		ret := AMEM
   166  		for i, f := range fields {
   167  			// All fields must be comparable.
   168  			a, bad := algtype1(f.Type)
   169  			if a == ANOEQ {
   170  				return ANOEQ, bad
   171  			}
   172  
   173  			// Blank fields, padded fields, fields with non-memory
   174  			// equality need special compare.
   175  			if a != AMEM || f.Sym.IsBlank() || ispaddedfield(t, i) {
   176  				ret = ASPECIAL
   177  			}
   178  		}
   179  
   180  		return ret, nil
   181  	}
   182  
   183  	Fatalf("algtype1: unexpected type %v", t)
   184  	return 0, nil
   185  }
   186  
   187  // genhash returns a symbol which is the closure used to compute
   188  // the hash of a value of type t.
   189  // Note: the generated function must match runtime.typehash exactly.
   190  func genhash(t *types.Type) *obj.LSym {
   191  	switch algtype(t) {
   192  	default:
   193  		// genhash is only called for types that have equality
   194  		Fatalf("genhash %v", t)
   195  	case AMEM0:
   196  		return sysClosure("memhash0")
   197  	case AMEM8:
   198  		return sysClosure("memhash8")
   199  	case AMEM16:
   200  		return sysClosure("memhash16")
   201  	case AMEM32:
   202  		return sysClosure("memhash32")
   203  	case AMEM64:
   204  		return sysClosure("memhash64")
   205  	case AMEM128:
   206  		return sysClosure("memhash128")
   207  	case ASTRING:
   208  		return sysClosure("strhash")
   209  	case AINTER:
   210  		return sysClosure("interhash")
   211  	case ANILINTER:
   212  		return sysClosure("nilinterhash")
   213  	case AFLOAT32:
   214  		return sysClosure("f32hash")
   215  	case AFLOAT64:
   216  		return sysClosure("f64hash")
   217  	case ACPLX64:
   218  		return sysClosure("c64hash")
   219  	case ACPLX128:
   220  		return sysClosure("c128hash")
   221  	case AMEM:
   222  		// For other sizes of plain memory, we build a closure
   223  		// that calls memhash_varlen. The size of the memory is
   224  		// encoded in the first slot of the closure.
   225  		closure := typeLookup(fmt.Sprintf(".hashfunc%d", t.Width)).Linksym()
   226  		if len(closure.P) > 0 { // already generated
   227  			return closure
   228  		}
   229  		if memhashvarlen == nil {
   230  			memhashvarlen = sysfunc("memhash_varlen")
   231  		}
   232  		ot := 0
   233  		ot = dsymptr(closure, ot, memhashvarlen, 0)
   234  		ot = duintptr(closure, ot, uint64(t.Width)) // size encoded in closure
   235  		ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
   236  		return closure
   237  	case ASPECIAL:
   238  		break
   239  	}
   240  
   241  	closure := typesymprefix(".hashfunc", t).Linksym()
   242  	if len(closure.P) > 0 { // already generated
   243  		return closure
   244  	}
   245  
   246  	// Generate hash functions for subtypes.
   247  	// There are cases where we might not use these hashes,
   248  	// but in that case they will get dead-code eliminated.
   249  	// (And the closure generated by genhash will also get
   250  	// dead-code eliminated, as we call the subtype hashers
   251  	// directly.)
   252  	switch t.Etype {
   253  	case types.TARRAY:
   254  		genhash(t.Elem())
   255  	case types.TSTRUCT:
   256  		for _, f := range t.FieldSlice() {
   257  			genhash(f.Type)
   258  		}
   259  	}
   260  
   261  	sym := typesymprefix(".hash", t)
   262  	if Debug['r'] != 0 {
   263  		fmt.Printf("genhash %v %v %v\n", closure, sym, t)
   264  	}
   265  
   266  	lineno = autogeneratedPos // less confusing than end of input
   267  	dclcontext = PEXTERN
   268  
   269  	// func sym(p *T, h uintptr) uintptr
   270  	tfn := nod(OTFUNC, nil, nil)
   271  	tfn.List.Set2(
   272  		namedfield("p", types.NewPtr(t)),
   273  		namedfield("h", types.Types[TUINTPTR]),
   274  	)
   275  	tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
   276  
   277  	fn := dclfunc(sym, tfn)
   278  	np := asNode(tfn.Type.Params().Field(0).Nname)
   279  	nh := asNode(tfn.Type.Params().Field(1).Nname)
   280  
   281  	switch t.Etype {
   282  	case types.TARRAY:
   283  		// An array of pure memory would be handled by the
   284  		// standard algorithm, so the element type must not be
   285  		// pure memory.
   286  		hashel := hashfor(t.Elem())
   287  
   288  		n := nod(ORANGE, nil, nod(ODEREF, np, nil))
   289  		ni := newname(lookup("i"))
   290  		ni.Type = types.Types[TINT]
   291  		n.List.Set1(ni)
   292  		n.SetColas(true)
   293  		colasdefn(n.List.Slice(), n)
   294  		ni = n.List.First()
   295  
   296  		// h = hashel(&p[i], h)
   297  		call := nod(OCALL, hashel, nil)
   298  
   299  		nx := nod(OINDEX, np, ni)
   300  		nx.SetBounded(true)
   301  		na := nod(OADDR, nx, nil)
   302  		call.List.Append(na)
   303  		call.List.Append(nh)
   304  		n.Nbody.Append(nod(OAS, nh, call))
   305  
   306  		fn.Nbody.Append(n)
   307  
   308  	case types.TSTRUCT:
   309  		// Walk the struct using memhash for runs of AMEM
   310  		// and calling specific hash functions for the others.
   311  		for i, fields := 0, t.FieldSlice(); i < len(fields); {
   312  			f := fields[i]
   313  
   314  			// Skip blank fields.
   315  			if f.Sym.IsBlank() {
   316  				i++
   317  				continue
   318  			}
   319  
   320  			// Hash non-memory fields with appropriate hash function.
   321  			if !IsRegularMemory(f.Type) {
   322  				hashel := hashfor(f.Type)
   323  				call := nod(OCALL, hashel, nil)
   324  				nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
   325  				na := nod(OADDR, nx, nil)
   326  				call.List.Append(na)
   327  				call.List.Append(nh)
   328  				fn.Nbody.Append(nod(OAS, nh, call))
   329  				i++
   330  				continue
   331  			}
   332  
   333  			// Otherwise, hash a maximal length run of raw memory.
   334  			size, next := memrun(t, i)
   335  
   336  			// h = hashel(&p.first, size, h)
   337  			hashel := hashmem(f.Type)
   338  			call := nod(OCALL, hashel, nil)
   339  			nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
   340  			na := nod(OADDR, nx, nil)
   341  			call.List.Append(na)
   342  			call.List.Append(nh)
   343  			call.List.Append(nodintconst(size))
   344  			fn.Nbody.Append(nod(OAS, nh, call))
   345  
   346  			i = next
   347  		}
   348  	}
   349  
   350  	r := nod(ORETURN, nil, nil)
   351  	r.List.Append(nh)
   352  	fn.Nbody.Append(r)
   353  
   354  	if Debug['r'] != 0 {
   355  		dumplist("genhash body", fn.Nbody)
   356  	}
   357  
   358  	funcbody()
   359  
   360  	fn.Func.SetDupok(true)
   361  	fn = typecheck(fn, ctxStmt)
   362  
   363  	Curfn = fn
   364  	typecheckslice(fn.Nbody.Slice(), ctxStmt)
   365  	Curfn = nil
   366  
   367  	if debug_dclstack != 0 {
   368  		testdclstack()
   369  	}
   370  
   371  	fn.Func.SetNilCheckDisabled(true)
   372  	funccompile(fn)
   373  
   374  	// Build closure. It doesn't close over any variables, so
   375  	// it contains just the function pointer.
   376  	dsymptr(closure, 0, sym.Linksym(), 0)
   377  	ggloblsym(closure, int32(Widthptr), obj.DUPOK|obj.RODATA)
   378  
   379  	return closure
   380  }
   381  
   382  func hashfor(t *types.Type) *Node {
   383  	var sym *types.Sym
   384  
   385  	switch a, _ := algtype1(t); a {
   386  	case AMEM:
   387  		Fatalf("hashfor with AMEM type")
   388  	case AINTER:
   389  		sym = Runtimepkg.Lookup("interhash")
   390  	case ANILINTER:
   391  		sym = Runtimepkg.Lookup("nilinterhash")
   392  	case ASTRING:
   393  		sym = Runtimepkg.Lookup("strhash")
   394  	case AFLOAT32:
   395  		sym = Runtimepkg.Lookup("f32hash")
   396  	case AFLOAT64:
   397  		sym = Runtimepkg.Lookup("f64hash")
   398  	case ACPLX64:
   399  		sym = Runtimepkg.Lookup("c64hash")
   400  	case ACPLX128:
   401  		sym = Runtimepkg.Lookup("c128hash")
   402  	default:
   403  		// Note: the caller of hashfor ensured that this symbol
   404  		// exists and has a body by calling genhash for t.
   405  		sym = typesymprefix(".hash", t)
   406  	}
   407  
   408  	n := newname(sym)
   409  	n.SetClass(PFUNC)
   410  	n.Sym.SetFunc(true)
   411  	n.Type = functype(nil, []*Node{
   412  		anonfield(types.NewPtr(t)),
   413  		anonfield(types.Types[TUINTPTR]),
   414  	}, []*Node{
   415  		anonfield(types.Types[TUINTPTR]),
   416  	})
   417  	return n
   418  }
   419  
   420  // sysClosure returns a closure which will call the
   421  // given runtime function (with no closed-over variables).
   422  func sysClosure(name string) *obj.LSym {
   423  	s := sysvar(name + "·f")
   424  	if len(s.P) == 0 {
   425  		f := sysfunc(name)
   426  		dsymptr(s, 0, f, 0)
   427  		ggloblsym(s, int32(Widthptr), obj.DUPOK|obj.RODATA)
   428  	}
   429  	return s
   430  }
   431  
   432  // geneq returns a symbol which is the closure used to compute
   433  // equality for two objects of type t.
   434  func geneq(t *types.Type) *obj.LSym {
   435  	switch algtype(t) {
   436  	case ANOEQ:
   437  		// The runtime will panic if it tries to compare
   438  		// a type with a nil equality function.
   439  		return nil
   440  	case AMEM0:
   441  		return sysClosure("memequal0")
   442  	case AMEM8:
   443  		return sysClosure("memequal8")
   444  	case AMEM16:
   445  		return sysClosure("memequal16")
   446  	case AMEM32:
   447  		return sysClosure("memequal32")
   448  	case AMEM64:
   449  		return sysClosure("memequal64")
   450  	case AMEM128:
   451  		return sysClosure("memequal128")
   452  	case ASTRING:
   453  		return sysClosure("strequal")
   454  	case AINTER:
   455  		return sysClosure("interequal")
   456  	case ANILINTER:
   457  		return sysClosure("nilinterequal")
   458  	case AFLOAT32:
   459  		return sysClosure("f32equal")
   460  	case AFLOAT64:
   461  		return sysClosure("f64equal")
   462  	case ACPLX64:
   463  		return sysClosure("c64equal")
   464  	case ACPLX128:
   465  		return sysClosure("c128equal")
   466  	case AMEM:
   467  		// make equality closure. The size of the type
   468  		// is encoded in the closure.
   469  		closure := typeLookup(fmt.Sprintf(".eqfunc%d", t.Width)).Linksym()
   470  		if len(closure.P) != 0 {
   471  			return closure
   472  		}
   473  		if memequalvarlen == nil {
   474  			memequalvarlen = sysvar("memequal_varlen") // asm func
   475  		}
   476  		ot := 0
   477  		ot = dsymptr(closure, ot, memequalvarlen, 0)
   478  		ot = duintptr(closure, ot, uint64(t.Width))
   479  		ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
   480  		return closure
   481  	case ASPECIAL:
   482  		break
   483  	}
   484  
   485  	closure := typesymprefix(".eqfunc", t).Linksym()
   486  	if len(closure.P) > 0 { // already generated
   487  		return closure
   488  	}
   489  	sym := typesymprefix(".eq", t)
   490  	if Debug['r'] != 0 {
   491  		fmt.Printf("geneq %v\n", t)
   492  	}
   493  
   494  	// Autogenerate code for equality of structs and arrays.
   495  
   496  	lineno = autogeneratedPos // less confusing than end of input
   497  	dclcontext = PEXTERN
   498  
   499  	// func sym(p, q *T) bool
   500  	tfn := nod(OTFUNC, nil, nil)
   501  	tfn.List.Set2(
   502  		namedfield("p", types.NewPtr(t)),
   503  		namedfield("q", types.NewPtr(t)),
   504  	)
   505  	tfn.Rlist.Set1(anonfield(types.Types[TBOOL]))
   506  
   507  	fn := dclfunc(sym, tfn)
   508  	np := asNode(tfn.Type.Params().Field(0).Nname)
   509  	nq := asNode(tfn.Type.Params().Field(1).Nname)
   510  
   511  	// We reach here only for types that have equality but
   512  	// cannot be handled by the standard algorithms,
   513  	// so t must be either an array or a struct.
   514  	switch t.Etype {
   515  	default:
   516  		Fatalf("geneq %v", t)
   517  
   518  	case TARRAY:
   519  		// An array of pure memory would be handled by the
   520  		// standard memequal, so the element type must not be
   521  		// pure memory. Even if we unrolled the range loop,
   522  		// each iteration would be a function call, so don't bother
   523  		// unrolling.
   524  		nrange := nod(ORANGE, nil, nod(ODEREF, np, nil))
   525  
   526  		ni := newname(lookup("i"))
   527  		ni.Type = types.Types[TINT]
   528  		nrange.List.Set1(ni)
   529  		nrange.SetColas(true)
   530  		colasdefn(nrange.List.Slice(), nrange)
   531  		ni = nrange.List.First()
   532  
   533  		// if p[i] != q[i] { return false }
   534  		nx := nod(OINDEX, np, ni)
   535  
   536  		nx.SetBounded(true)
   537  		ny := nod(OINDEX, nq, ni)
   538  		ny.SetBounded(true)
   539  
   540  		nif := nod(OIF, nil, nil)
   541  		nif.Left = nod(ONE, nx, ny)
   542  		r := nod(ORETURN, nil, nil)
   543  		r.List.Append(nodbool(false))
   544  		nif.Nbody.Append(r)
   545  		nrange.Nbody.Append(nif)
   546  		fn.Nbody.Append(nrange)
   547  
   548  		// return true
   549  		ret := nod(ORETURN, nil, nil)
   550  		ret.List.Append(nodbool(true))
   551  		fn.Nbody.Append(ret)
   552  
   553  	case TSTRUCT:
   554  		var cond *Node
   555  		and := func(n *Node) {
   556  			if cond == nil {
   557  				cond = n
   558  				return
   559  			}
   560  			cond = nod(OANDAND, cond, n)
   561  		}
   562  
   563  		// Walk the struct using memequal for runs of AMEM
   564  		// and calling specific equality tests for the others.
   565  		for i, fields := 0, t.FieldSlice(); i < len(fields); {
   566  			f := fields[i]
   567  
   568  			// Skip blank-named fields.
   569  			if f.Sym.IsBlank() {
   570  				i++
   571  				continue
   572  			}
   573  
   574  			// Compare non-memory fields with field equality.
   575  			if !IsRegularMemory(f.Type) {
   576  				and(eqfield(np, nq, f.Sym))
   577  				i++
   578  				continue
   579  			}
   580  
   581  			// Find maximal length run of memory-only fields.
   582  			size, next := memrun(t, i)
   583  
   584  			// TODO(rsc): All the calls to newname are wrong for
   585  			// cross-package unexported fields.
   586  			if s := fields[i:next]; len(s) <= 2 {
   587  				// Two or fewer fields: use plain field equality.
   588  				for _, f := range s {
   589  					and(eqfield(np, nq, f.Sym))
   590  				}
   591  			} else {
   592  				// More than two fields: use memequal.
   593  				and(eqmem(np, nq, f.Sym, size))
   594  			}
   595  			i = next
   596  		}
   597  
   598  		if cond == nil {
   599  			cond = nodbool(true)
   600  		}
   601  
   602  		ret := nod(ORETURN, nil, nil)
   603  		ret.List.Append(cond)
   604  		fn.Nbody.Append(ret)
   605  	}
   606  
   607  	if Debug['r'] != 0 {
   608  		dumplist("geneq body", fn.Nbody)
   609  	}
   610  
   611  	funcbody()
   612  
   613  	fn.Func.SetDupok(true)
   614  	fn = typecheck(fn, ctxStmt)
   615  
   616  	Curfn = fn
   617  	typecheckslice(fn.Nbody.Slice(), ctxStmt)
   618  	Curfn = nil
   619  
   620  	if debug_dclstack != 0 {
   621  		testdclstack()
   622  	}
   623  
   624  	// Disable checknils while compiling this code.
   625  	// We are comparing a struct or an array,
   626  	// neither of which can be nil, and our comparisons
   627  	// are shallow.
   628  	fn.Func.SetNilCheckDisabled(true)
   629  	funccompile(fn)
   630  
   631  	// Generate a closure which points at the function we just generated.
   632  	dsymptr(closure, 0, sym.Linksym(), 0)
   633  	ggloblsym(closure, int32(Widthptr), obj.DUPOK|obj.RODATA)
   634  	return closure
   635  }
   636  
   637  // eqfield returns the node
   638  // 	p.field == q.field
   639  func eqfield(p *Node, q *Node, field *types.Sym) *Node {
   640  	nx := nodSym(OXDOT, p, field)
   641  	ny := nodSym(OXDOT, q, field)
   642  	ne := nod(OEQ, nx, ny)
   643  	return ne
   644  }
   645  
   646  // eqmem returns the node
   647  // 	memequal(&p.field, &q.field [, size])
   648  func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node {
   649  	nx := nod(OADDR, nodSym(OXDOT, p, field), nil)
   650  	ny := nod(OADDR, nodSym(OXDOT, q, field), nil)
   651  	nx = typecheck(nx, ctxExpr)
   652  	ny = typecheck(ny, ctxExpr)
   653  
   654  	fn, needsize := eqmemfunc(size, nx.Type.Elem())
   655  	call := nod(OCALL, fn, nil)
   656  	call.List.Append(nx)
   657  	call.List.Append(ny)
   658  	if needsize {
   659  		call.List.Append(nodintconst(size))
   660  	}
   661  
   662  	return call
   663  }
   664  
   665  func eqmemfunc(size int64, t *types.Type) (fn *Node, needsize bool) {
   666  	switch size {
   667  	default:
   668  		fn = syslook("memequal")
   669  		needsize = true
   670  	case 1, 2, 4, 8, 16:
   671  		buf := fmt.Sprintf("memequal%d", int(size)*8)
   672  		fn = syslook(buf)
   673  	}
   674  
   675  	fn = substArgTypes(fn, t, t)
   676  	return fn, needsize
   677  }
   678  
   679  // memrun finds runs of struct fields for which memory-only algs are appropriate.
   680  // t is the parent struct type, and start is the field index at which to start the run.
   681  // size is the length in bytes of the memory included in the run.
   682  // next is the index just after the end of the memory run.
   683  func memrun(t *types.Type, start int) (size int64, next int) {
   684  	next = start
   685  	for {
   686  		next++
   687  		if next == t.NumFields() {
   688  			break
   689  		}
   690  		// Stop run after a padded field.
   691  		if ispaddedfield(t, next-1) {
   692  			break
   693  		}
   694  		// Also, stop before a blank or non-memory field.
   695  		if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
   696  			break
   697  		}
   698  	}
   699  	return t.Field(next-1).End() - t.Field(start).Offset, next
   700  }
   701  
   702  // ispaddedfield reports whether the i'th field of struct type t is followed
   703  // by padding.
   704  func ispaddedfield(t *types.Type, i int) bool {
   705  	if !t.IsStruct() {
   706  		Fatalf("ispaddedfield called non-struct %v", t)
   707  	}
   708  	end := t.Width
   709  	if i+1 < t.NumFields() {
   710  		end = t.Field(i + 1).Offset
   711  	}
   712  	return t.Field(i).End() != end
   713  }