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

     1  // Copyright 2021 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 noder
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    11  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types2"
    12  )
    13  
    14  // Code below based on go/types.StdSizes.
    15  // Intentional differences are marked with "gc:".
    16  
    17  type gcSizes struct{}
    18  
    19  func (s *gcSizes) Alignof(T types2.Type) int64 {
    20  	// For arrays and structs, alignment is defined in terms
    21  	// of alignment of the elements and fields, respectively.
    22  	switch t := T.Underlying().(type) {
    23  	case *types2.Array:
    24  		// spec: "For a variable x of array type: unsafe.Alignof(x)
    25  		// is the same as unsafe.Alignof(x[0]), but at least 1."
    26  		return s.Alignof(t.Elem())
    27  	case *types2.Struct:
    28  		if t.NumFields() == 0 && types2.IsSyncAtomicAlign64(T) {
    29  			// Special case: sync/atomic.align64 is an
    30  			// empty struct we recognize as a signal that
    31  			// the struct it contains must be
    32  			// 64-bit-aligned.
    33  			//
    34  			// This logic is equivalent to the logic in
    35  			// cmd/compile/internal/types/size.go:calcStructOffset
    36  			return 8
    37  		}
    38  
    39  		// spec: "For a variable x of struct type: unsafe.Alignof(x)
    40  		// is the largest of the values unsafe.Alignof(x.f) for each
    41  		// field f of x, but at least 1."
    42  		max := int64(1)
    43  		for i, nf := 0, t.NumFields(); i < nf; i++ {
    44  			if a := s.Alignof(t.Field(i).Type()); a > max {
    45  				max = a
    46  			}
    47  		}
    48  		return max
    49  	case *types2.Slice, *types2.Interface:
    50  		// Multiword data structures are effectively structs
    51  		// in which each element has size PtrSize.
    52  		return int64(types.PtrSize)
    53  	case *types2.Basic:
    54  		// Strings are like slices and interfaces.
    55  		if t.Info()&types2.IsString != 0 {
    56  			return int64(types.PtrSize)
    57  		}
    58  	}
    59  	a := s.Sizeof(T) // may be 0
    60  	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
    61  	if a < 1 {
    62  		return 1
    63  	}
    64  	// complex{64,128} are aligned like [2]float{32,64}.
    65  	if isComplex(T) {
    66  		a /= 2
    67  	}
    68  	if a > int64(types.RegSize) {
    69  		return int64(types.RegSize)
    70  	}
    71  	return a
    72  }
    73  
    74  func isComplex(T types2.Type) bool {
    75  	basic, ok := T.Underlying().(*types2.Basic)
    76  	return ok && basic.Info()&types2.IsComplex != 0
    77  }
    78  
    79  func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
    80  	offsets := make([]int64, len(fields))
    81  	var o int64
    82  	for i, f := range fields {
    83  		typ := f.Type()
    84  		a := s.Alignof(typ)
    85  		o = types.RoundUp(o, a)
    86  		offsets[i] = o
    87  		o += s.Sizeof(typ)
    88  	}
    89  	return offsets
    90  }
    91  
    92  func (s *gcSizes) Sizeof(T types2.Type) int64 {
    93  	switch t := T.Underlying().(type) {
    94  	case *types2.Basic:
    95  		k := t.Kind()
    96  		if int(k) < len(basicSizes) {
    97  			if s := basicSizes[k]; s > 0 {
    98  				return int64(s)
    99  			}
   100  		}
   101  		switch k {
   102  		case types2.String:
   103  			return int64(types.PtrSize) * 2
   104  		case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer:
   105  			return int64(types.PtrSize)
   106  		}
   107  		panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k))
   108  	case *types2.Array:
   109  		n := t.Len()
   110  		if n <= 0 {
   111  			return 0
   112  		}
   113  		// n > 0
   114  		// gc: Size includes alignment padding.
   115  		return s.Sizeof(t.Elem()) * n
   116  	case *types2.Slice:
   117  		return int64(types.PtrSize) * 3
   118  	case *types2.Struct:
   119  		n := t.NumFields()
   120  		if n == 0 {
   121  			return 0
   122  		}
   123  		fields := make([]*types2.Var, n)
   124  		for i := range fields {
   125  			fields[i] = t.Field(i)
   126  		}
   127  		offsets := s.Offsetsof(fields)
   128  
   129  		// gc: The last field of a non-zero-sized struct is not allowed to
   130  		// have size 0.
   131  		last := s.Sizeof(fields[n-1].Type())
   132  		if last == 0 && offsets[n-1] > 0 {
   133  			last = 1
   134  		}
   135  
   136  		// gc: Size includes alignment padding.
   137  		return types.RoundUp(offsets[n-1]+last, s.Alignof(t))
   138  	case *types2.Interface:
   139  		return int64(types.PtrSize) * 2
   140  	case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
   141  		return int64(types.PtrSize)
   142  	default:
   143  		panic(fmt.Sprintf("unimplemented type: %T", t))
   144  	}
   145  }
   146  
   147  var basicSizes = [...]byte{
   148  	types2.Invalid:    1,
   149  	types2.Bool:       1,
   150  	types2.Int8:       1,
   151  	types2.Int16:      2,
   152  	types2.Int32:      4,
   153  	types2.Int64:      8,
   154  	types2.Uint8:      1,
   155  	types2.Uint16:     2,
   156  	types2.Uint32:     4,
   157  	types2.Uint64:     8,
   158  	types2.Float32:    4,
   159  	types2.Float64:    8,
   160  	types2.Complex64:  8,
   161  	types2.Complex128: 16,
   162  }