aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-01-08 19:27:51 -0800
committerMatthew Dempsky <mdempsky@google.com>2021-01-11 19:59:28 +0000
commit2e8f29b79d4bce097ebe0c822b469d4714657395 (patch)
tree76ca4b0b9c7bd61b1dc700330284a50282ec09db
parent44d1a8523a50c30354e0b1ef70953567c26eed1a (diff)
downloadgo-2e8f29b79d4bce097ebe0c822b469d4714657395.tar.gz
go-2e8f29b79d4bce097ebe0c822b469d4714657395.zip
[dev.typeparams] cmd/compile: add types2.Sizes implementation
This CL adds an implementation of types2.Sizes that calculates sizes using the same sizing algorithm as cmd/compile. In particular, it matches how cmd/compile pads structures and includes padding in size calculations. Change-Id: I4dd8e51f95c90f9d7bd1e7463e40edcd3955a219 Reviewed-on: https://go-review.googlesource.com/c/go/+/282915 Trust: Matthew Dempsky <mdempsky@google.com> Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
-rw-r--r--src/cmd/compile/internal/noder/noder.go1
-rw-r--r--src/cmd/compile/internal/noder/sizes.go150
2 files changed, 151 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index 938ffe05ce..099e3a6956 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -133,6 +133,7 @@ func ParseFiles(filenames []string) (lines uint) {
return os.Open(file)
},
},
+ Sizes: &gcSizes{},
}
info := types2.Info{
Types: make(map[syntax.Expr]types2.TypeAndValue),
diff --git a/src/cmd/compile/internal/noder/sizes.go b/src/cmd/compile/internal/noder/sizes.go
new file mode 100644
index 0000000000..7cda6da9a6
--- /dev/null
+++ b/src/cmd/compile/internal/noder/sizes.go
@@ -0,0 +1,150 @@
+// Copyright 2021 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.
+
+package noder
+
+import (
+ "fmt"
+
+ "cmd/compile/internal/types"
+ "cmd/compile/internal/types2"
+)
+
+// Code below based on go/types.StdSizes.
+// Intentional differences are marked with "gc:".
+
+type gcSizes struct{}
+
+func (s *gcSizes) Alignof(T types2.Type) int64 {
+ // For arrays and structs, alignment is defined in terms
+ // of alignment of the elements and fields, respectively.
+ switch t := T.Underlying().(type) {
+ case *types2.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 s.Alignof(t.Elem())
+ case *types2.Struct:
+ // 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."
+ max := int64(1)
+ for i, nf := 0, t.NumFields(); i < nf; i++ {
+ if a := s.Alignof(t.Field(i).Type()); a > max {
+ max = a
+ }
+ }
+ return max
+ case *types2.Slice, *types2.Interface:
+ // Multiword data structures are effectively structs
+ // in which each element has size PtrSize.
+ return int64(types.PtrSize)
+ case *types2.Basic:
+ // Strings are like slices and interfaces.
+ if t.Info()&types2.IsString != 0 {
+ return int64(types.PtrSize)
+ }
+ }
+ a := s.Sizeof(T) // may be 0
+ // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+ if a < 1 {
+ return 1
+ }
+ // complex{64,128} are aligned like [2]float{32,64}.
+ if isComplex(T) {
+ a /= 2
+ }
+ if a > int64(types.RegSize) {
+ return int64(types.RegSize)
+ }
+ return a
+}
+
+func isComplex(T types2.Type) bool {
+ basic, ok := T.Underlying().(*types2.Basic)
+ return ok && basic.Info()&types2.IsComplex != 0
+}
+
+func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
+ offsets := make([]int64, len(fields))
+ var o int64
+ for i, f := range fields {
+ typ := f.Type()
+ a := s.Alignof(typ)
+ o = types.Rnd(o, a)
+ offsets[i] = o
+ o += s.Sizeof(typ)
+ }
+ return offsets
+}
+
+func (s *gcSizes) Sizeof(T types2.Type) int64 {
+ switch t := T.Underlying().(type) {
+ case *types2.Basic:
+ k := t.Kind()
+ if int(k) < len(basicSizes) {
+ if s := basicSizes[k]; s > 0 {
+ return int64(s)
+ }
+ }
+ switch k {
+ case types2.String:
+ return int64(types.PtrSize) * 2
+ case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer:
+ return int64(types.PtrSize)
+ }
+ panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k))
+ case *types2.Array:
+ n := t.Len()
+ if n <= 0 {
+ return 0
+ }
+ // n > 0
+ // gc: Size includes alignment padding.
+ return s.Sizeof(t.Elem()) * n
+ case *types2.Slice:
+ return int64(types.PtrSize) * 3
+ case *types2.Struct:
+ n := t.NumFields()
+ if n == 0 {
+ return 0
+ }
+ fields := make([]*types2.Var, n)
+ for i := range fields {
+ fields[i] = t.Field(i)
+ }
+ offsets := s.Offsetsof(fields)
+
+ // gc: The last field of a struct is not allowed to
+ // have size 0.
+ last := s.Sizeof(fields[n-1].Type())
+ if last == 0 {
+ last = 1
+ }
+
+ // gc: Size includes alignment padding.
+ return types.Rnd(offsets[n-1]+last, s.Alignof(t))
+ case *types2.Interface:
+ return int64(types.PtrSize) * 2
+ case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
+ return int64(types.PtrSize)
+ default:
+ panic(fmt.Sprintf("unimplemented type: %T", t))
+ }
+}
+
+var basicSizes = [...]byte{
+ types2.Bool: 1,
+ types2.Int8: 1,
+ types2.Int16: 2,
+ types2.Int32: 4,
+ types2.Int64: 8,
+ types2.Uint8: 1,
+ types2.Uint16: 2,
+ types2.Uint32: 4,
+ types2.Uint64: 8,
+ types2.Float32: 4,
+ types2.Float64: 8,
+ types2.Complex64: 8,
+ types2.Complex128: 16,
+}