// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
// Source: ../../cmd/compile/internal/types2/sizes.go

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements Sizes.

package types

// Sizes defines the sizing functions for package unsafe.
type Sizes interface {
	// Alignof returns the alignment of a variable of type T.
	// Alignof must implement the alignment guarantees required by the spec.
	// The result must be >= 1.
	Alignof(T Type) int64

	// Offsetsof returns the offsets of the given struct fields, in bytes.
	// Offsetsof must implement the offset guarantees required by the spec.
	// A negative entry in the result indicates that the struct is too large.
	Offsetsof(fields []*Var) []int64

	// Sizeof returns the size of a variable of type T.
	// Sizeof must implement the size guarantees required by the spec.
	// A negative result indicates that T is too large.
	Sizeof(T Type) int64
}

// StdSizes is a convenience type for creating commonly used Sizes.
// It makes the following simplifying assumptions:
//
//   - The size of explicitly sized basic types (int16, etc.) is the
//     specified size.
//   - The size of strings and interfaces is 2*WordSize.
//   - The size of slices is 3*WordSize.
//   - The size of an array of n elements corresponds to the size of
//     a struct of n consecutive fields of the array's element type.
//   - The size of a struct is the offset of the last field plus that
//     field's size. As with all element types, if the struct is used
//     in an array its size must first be aligned to a multiple of the
//     struct's alignment.
//   - All other types have size WordSize.
//   - Arrays and structs are aligned per spec definition; all other
//     types are naturally aligned with a maximum alignment MaxAlign.
//
// *StdSizes implements Sizes.
type StdSizes struct {
	WordSize int64 // word size in bytes - must be >= 4 (32bits)
	MaxAlign int64 // maximum alignment in bytes - must be >= 1
}

func ( *StdSizes) ( Type) ( int64) {
	defer func() {
		assert( >= 1)
	}()

	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := under().(type) {
	case *Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return .(.elem)
	case *Struct:
		if len(.fields) == 0 && _IsSyncAtomicAlign64() {
			// Special case: sync/atomic.align64 is an
			// empty struct we recognize as a signal that
			// the struct it contains must be
			// 64-bit-aligned.
			//
			// This logic is equivalent to the logic in
			// cmd/compile/internal/types/size.go:calcStructOffset
			return 8
		}

		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		 := int64(1)
		for ,  := range .fields {
			if  := .(.typ);  >  {
				 = 
			}
		}
		return 
	case *Slice, *Interface:
		// Multiword data structures are effectively structs
		// in which each element has size WordSize.
		// Type parameters lead to variable sizes/alignments;
		// StdSizes.Alignof won't be called for them.
		assert(!isTypeParam())
		return .WordSize
	case *Basic:
		// Strings are like slices and interfaces.
		if .Info()&IsString != 0 {
			return .WordSize
		}
	case *TypeParam, *Union:
		panic("unreachable")
	}
	 := .Sizeof() // may be 0 or negative
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if  < 1 {
		return 1
	}
	// complex{64,128} are aligned like [2]float{32,64}.
	if isComplex() {
		 /= 2
	}
	if  > .MaxAlign {
		return .MaxAlign
	}
	return 
}

func _IsSyncAtomicAlign64( Type) bool {
	 := asNamed()
	if  == nil {
		return false
	}
	 := .Obj()
	return .Name() == "align64" &&
		.Pkg() != nil &&
		(.Pkg().Path() == "sync/atomic" ||
			.Pkg().Path() == "internal/runtime/atomic")
}

func ( *StdSizes) ( []*Var) []int64 {
	 := make([]int64, len())
	var  int64
	for ,  := range  {
		if  < 0 {
			// all remaining offsets are too large
			[] = -1
			continue
		}
		// offs >= 0
		 := .Alignof(.typ)
		 = align(, ) // possibly < 0 if align overflows
		[] = 
		if  := .Sizeof(.typ);  >= 0 &&  >= 0 {
			 +=  // ok to overflow to < 0
		} else {
			 = -1 // f.typ or offs is too large
		}
	}
	return 
}

var basicSizes = [...]byte{
	Bool:       1,
	Int8:       1,
	Int16:      2,
	Int32:      4,
	Int64:      8,
	Uint8:      1,
	Uint16:     2,
	Uint32:     4,
	Uint64:     8,
	Float32:    4,
	Float64:    8,
	Complex64:  8,
	Complex128: 16,
}

func ( *StdSizes) ( Type) int64 {
	switch t := under().(type) {
	case *Basic:
		assert(isTyped())
		 := .kind
		if int() < len(basicSizes) {
			if  := basicSizes[];  > 0 {
				return int64()
			}
		}
		if  == String {
			return .WordSize * 2
		}
	case *Array:
		 := .len
		if  <= 0 {
			return 0
		}
		// n > 0
		 := .(.elem)
		if  < 0 {
			return -1 // element too large
		}
		if  == 0 {
			return 0 // 0-size element
		}
		// esize > 0
		 := .Alignof(.elem)
		 := align(, ) // possibly < 0 if align overflows
		if  < 0 {
			return -1
		}
		// ea >= 1
		 :=  - 1 // n1 >= 0
		// Final size is ea*n1 + esize; and size must be <= maxInt64.
		const  = 1<<63 - 1
		if  > 0 &&  > / {
			return -1 // ea*n1 overflows
		}
		return * +  // may still overflow to < 0 which is ok
	case *Slice:
		return .WordSize * 3
	case *Struct:
		 := .NumFields()
		if  == 0 {
			return 0
		}
		 := .Offsetsof(.fields)
		 := [-1]
		 := .(.fields[-1].typ)
		if  < 0 ||  < 0 {
			return -1 // type too large
		}
		return  +  // may overflow to < 0 which is ok
	case *Interface:
		// Type parameters lead to variable sizes/alignments;
		// StdSizes.Sizeof won't be called for them.
		assert(!isTypeParam())
		return .WordSize * 2
	case *TypeParam, *Union:
		panic("unreachable")
	}
	return .WordSize // catch-all
}

// common architecture word sizes and alignments
var gcArchSizes = map[string]*gcSizes{
	"386":      {4, 4},
	"amd64":    {8, 8},
	"amd64p32": {4, 8},
	"arm":      {4, 4},
	"arm64":    {8, 8},
	"loong64":  {8, 8},
	"mips":     {4, 4},
	"mipsle":   {4, 4},
	"mips64":   {8, 8},
	"mips64le": {8, 8},
	"ppc64":    {8, 8},
	"ppc64le":  {8, 8},
	"riscv64":  {8, 8},
	"s390x":    {8, 8},
	"sparc64":  {8, 8},
	"wasm":     {8, 8},
	// When adding more architectures here,
	// update the doc string of SizesFor below.
}

// SizesFor returns the Sizes used by a compiler for an architecture.
// The result is nil if a compiler/architecture pair is not known.
//
// Supported architectures for compiler "gc":
// "386", "amd64", "amd64p32", "arm", "arm64", "loong64", "mips", "mipsle",
// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
func (,  string) Sizes {
	switch  {
	case "gc":
		if  := gcSizesFor(, );  != nil {
			return Sizes()
		}
	case "gccgo":
		if ,  := gccgoArchSizes[];  {
			return Sizes()
		}
	}
	return nil
}

// stdSizes is used if Config.Sizes == nil.
var stdSizes = SizesFor("gc", "amd64")

func ( *Config) ( Type) int64 {
	 := stdSizes.Alignof
	if .Sizes != nil {
		 = .Sizes.Alignof
	}
	if  := ();  >= 1 {
		return 
	}
	panic("implementation of alignof returned an alignment < 1")
}

func ( *Config) ( *Struct) []int64 {
	var  []int64
	if .NumFields() > 0 {
		// compute offsets on demand
		 := stdSizes.Offsetsof
		if .Sizes != nil {
			 = .Sizes.Offsetsof
		}
		 = (.fields)
		// sanity checks
		if len() != .NumFields() {
			panic("implementation of offsetsof returned the wrong number of offsets")
		}
	}
	return 
}

// offsetof returns the offset of the field specified via
// the index sequence relative to T. All embedded fields
// must be structs (rather than pointers to structs).
// If the offset is too large (because T is too large),
// the result is negative.
func ( *Config) ( Type,  []int) int64 {
	var  int64
	for ,  := range  {
		 := under().(*Struct)
		 := .offsetsof()[]
		if  < 0 {
			return -1
		}
		 += 
		if  < 0 {
			return -1
		}
		 = .fields[].typ
	}
	return 
}

// sizeof returns the size of T.
// If T is too large, the result is negative.
func ( *Config) ( Type) int64 {
	 := stdSizes.Sizeof
	if .Sizes != nil {
		 = .Sizes.Sizeof
	}
	return ()
}

// align returns the smallest y >= x such that y % a == 0.
// a must be within 1 and 8 and it must be a power of 2.
// The result may be negative due to overflow.
func align(,  int64) int64 {
	assert( >= 0 && 1 <=  &&  <= 8 && &(-1) == 0)
	return ( +  - 1) &^ ( - 1)
}