]> gcc.gnu.org Git - gcc.git/blame - libgo/go/go/types/sizes.go
libgo: add riscv and js/wasm as known targets
[gcc.git] / libgo / go / go / types / sizes.go
CommitLineData
af146490
ILT
1// Copyright 2013 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// This file implements Sizes.
6
7package types
8
9// Sizes defines the sizing functions for package unsafe.
10type Sizes interface {
11 // Alignof returns the alignment of a variable of type T.
12 // Alignof must implement the alignment guarantees required by the spec.
13 Alignof(T Type) int64
14
15 // Offsetsof returns the offsets of the given struct fields, in bytes.
16 // Offsetsof must implement the offset guarantees required by the spec.
17 Offsetsof(fields []*Var) []int64
18
19 // Sizeof returns the size of a variable of type T.
20 // Sizeof must implement the size guarantees required by the spec.
21 Sizeof(T Type) int64
22}
23
24// StdSizes is a convenience type for creating commonly used Sizes.
25// It makes the following simplifying assumptions:
26//
27// - The size of explicitly sized basic types (int16, etc.) is the
28// specified size.
29// - The size of strings and interfaces is 2*WordSize.
30// - The size of slices is 3*WordSize.
31// - The size of an array of n elements corresponds to the size of
32// a struct of n consecutive fields of the array's element type.
33// - The size of a struct is the offset of the last field plus that
34// field's size. As with all element types, if the struct is used
35// in an array its size must first be aligned to a multiple of the
36// struct's alignment.
37// - All other types have size WordSize.
38// - Arrays and structs are aligned per spec definition; all other
39// types are naturally aligned with a maximum alignment MaxAlign.
40//
41// *StdSizes implements Sizes.
42//
43type StdSizes struct {
44 WordSize int64 // word size in bytes - must be >= 4 (32bits)
45 MaxAlign int64 // maximum alignment in bytes - must be >= 1
46}
47
48func (s *StdSizes) Alignof(T Type) int64 {
49 // For arrays and structs, alignment is defined in terms
50 // of alignment of the elements and fields, respectively.
51 switch t := T.Underlying().(type) {
52 case *Array:
53 // spec: "For a variable x of array type: unsafe.Alignof(x)
54 // is the same as unsafe.Alignof(x[0]), but at least 1."
55 return s.Alignof(t.elem)
56 case *Struct:
57 // spec: "For a variable x of struct type: unsafe.Alignof(x)
58 // is the largest of the values unsafe.Alignof(x.f) for each
59 // field f of x, but at least 1."
60 max := int64(1)
61 for _, f := range t.fields {
62 if a := s.Alignof(f.typ); a > max {
63 max = a
64 }
65 }
66 return max
c2047754
ILT
67 case *Slice, *Interface:
68 // Multiword data structures are effectively structs
69 // in which each element has size WordSize.
70 return s.WordSize
71 case *Basic:
72 // Strings are like slices and interfaces.
73 if t.Info()&IsString != 0 {
74 return s.WordSize
75 }
af146490
ILT
76 }
77 a := s.Sizeof(T) // may be 0
78 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
79 if a < 1 {
80 return 1
81 }
c2047754
ILT
82 // complex{64,128} are aligned like [2]float{32,64}.
83 if isComplex(T) {
84 a /= 2
85 }
af146490
ILT
86 if a > s.MaxAlign {
87 return s.MaxAlign
88 }
89 return a
90}
91
92func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
93 offsets := make([]int64, len(fields))
94 var o int64
95 for i, f := range fields {
96 a := s.Alignof(f.typ)
97 o = align(o, a)
98 offsets[i] = o
99 o += s.Sizeof(f.typ)
100 }
101 return offsets
102}
103
104var basicSizes = [...]byte{
105 Bool: 1,
106 Int8: 1,
107 Int16: 2,
108 Int32: 4,
109 Int64: 8,
110 Uint8: 1,
111 Uint16: 2,
112 Uint32: 4,
113 Uint64: 8,
114 Float32: 4,
115 Float64: 8,
116 Complex64: 8,
117 Complex128: 16,
118}
119
120func (s *StdSizes) Sizeof(T Type) int64 {
121 switch t := T.Underlying().(type) {
122 case *Basic:
123 assert(isTyped(T))
124 k := t.kind
125 if int(k) < len(basicSizes) {
126 if s := basicSizes[k]; s > 0 {
127 return int64(s)
128 }
129 }
130 if k == String {
131 return s.WordSize * 2
132 }
133 case *Array:
134 n := t.len
135 if n == 0 {
136 return 0
137 }
138 a := s.Alignof(t.elem)
139 z := s.Sizeof(t.elem)
140 return align(z, a)*(n-1) + z
141 case *Slice:
142 return s.WordSize * 3
143 case *Struct:
144 n := t.NumFields()
145 if n == 0 {
146 return 0
147 }
c2047754
ILT
148 offsets := s.Offsetsof(t.fields)
149 return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
af146490
ILT
150 case *Interface:
151 return s.WordSize * 2
152 }
153 return s.WordSize // catch-all
154}
155
bc998d03
ILT
156// common architecture word sizes and alignments
157var gcArchSizes = map[string]*StdSizes{
158 "386": {4, 4},
159 "arm": {4, 4},
160 "arm64": {8, 8},
161 "amd64": {8, 8},
162 "amd64p32": {4, 8},
163 "mips": {4, 4},
164 "mipsle": {4, 4},
165 "mips64": {8, 8},
166 "mips64le": {8, 8},
167 "ppc64": {8, 8},
168 "ppc64le": {8, 8},
169 "s390x": {8, 8},
87cbbc45 170 "wasm": {8, 8},
bc998d03
ILT
171 // When adding more architectures here,
172 // update the doc string of SizesFor below.
173}
174
175// SizesFor returns the Sizes used by a compiler for an architecture.
176// The result is nil if a compiler/architecture pair is not known.
177//
178// Supported architectures for compiler "gc":
179// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
87cbbc45 180// "mips64", "mips64le", "ppc64", "ppc64le", "s390x", "wasm".
bc998d03 181func SizesFor(compiler, arch string) Sizes {
ffad1c54
ILT
182 var m map[string]*StdSizes
183 switch compiler {
184 case "gc":
185 m = gcArchSizes
186 case "gccgo":
187 m = gccgoArchSizes
188 default:
bc998d03
ILT
189 return nil
190 }
ffad1c54 191 s, ok := m[arch]
bc998d03
ILT
192 if !ok {
193 return nil
194 }
195 return s
196}
197
af146490 198// stdSizes is used if Config.Sizes == nil.
bc998d03 199var stdSizes = SizesFor("gc", "amd64")
af146490
ILT
200
201func (conf *Config) alignof(T Type) int64 {
202 if s := conf.Sizes; s != nil {
203 if a := s.Alignof(T); a >= 1 {
204 return a
205 }
206 panic("Config.Sizes.Alignof returned an alignment < 1")
207 }
208 return stdSizes.Alignof(T)
209}
210
211func (conf *Config) offsetsof(T *Struct) []int64 {
f98dd1a3
ILT
212 var offsets []int64
213 if T.NumFields() > 0 {
af146490
ILT
214 // compute offsets on demand
215 if s := conf.Sizes; s != nil {
c2047754
ILT
216 offsets = s.Offsetsof(T.fields)
217 // sanity checks
218 if len(offsets) != T.NumFields() {
219 panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
220 }
221 for _, o := range offsets {
222 if o < 0 {
223 panic("Config.Sizes.Offsetsof returned an offset < 0")
af146490
ILT
224 }
225 }
226 } else {
c2047754 227 offsets = stdSizes.Offsetsof(T.fields)
af146490 228 }
af146490
ILT
229 }
230 return offsets
231}
232
233// offsetof returns the offset of the field specified via
234// the index sequence relative to typ. All embedded fields
235// must be structs (rather than pointer to structs).
236func (conf *Config) offsetof(typ Type, index []int) int64 {
237 var o int64
238 for _, i := range index {
239 s := typ.Underlying().(*Struct)
240 o += conf.offsetsof(s)[i]
241 typ = s.fields[i].typ
242 }
243 return o
244}
245
246func (conf *Config) sizeof(T Type) int64 {
247 if s := conf.Sizes; s != nil {
248 if z := s.Sizeof(T); z >= 0 {
249 return z
250 }
251 panic("Config.Sizes.Sizeof returned a size < 0")
252 }
253 return stdSizes.Sizeof(T)
254}
255
256// align returns the smallest y >= x such that y % a == 0.
257func align(x, a int64) int64 {
258 y := x + a - 1
259 return y - y%a
260}
This page took 0.262211 seconds and 5 git commands to generate.