github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/cmd/compile/internal/gc/align.go (about) 1 // Copyright 2009 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 // machine size and rounding alignment is dictated around 8 // the size of a pointer, set in betypeinit (see ../amd64/galign.go). 9 var defercalc int 10 11 func Rnd(o int64, r int64) int64 { 12 if r < 1 || r > 8 || r&(r-1) != 0 { 13 Fatalf("rnd %d", r) 14 } 15 return (o + r - 1) &^ (r - 1) 16 } 17 18 func offmod(t *Type) { 19 o := int32(0) 20 for _, f := range t.Fields().Slice() { 21 f.Offset = int64(o) 22 o += int32(Widthptr) 23 if int64(o) >= Thearch.MAXWIDTH { 24 yyerror("interface too large") 25 o = int32(Widthptr) 26 } 27 } 28 } 29 30 func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { 31 starto := o 32 maxalign := int32(flag) 33 if maxalign < 1 { 34 maxalign = 1 35 } 36 lastzero := int64(0) 37 var w int64 38 for _, f := range t.Fields().Slice() { 39 if f.Type == nil { 40 // broken field, just skip it so that other valid fields 41 // get a width. 42 continue 43 } 44 45 dowidth(f.Type) 46 if int32(f.Type.Align) > maxalign { 47 maxalign = int32(f.Type.Align) 48 } 49 if f.Type.Width < 0 { 50 Fatalf("invalid width %d", f.Type.Width) 51 } 52 w = f.Type.Width 53 if f.Type.Align > 0 { 54 o = Rnd(o, int64(f.Type.Align)) 55 } 56 f.Offset = o 57 if f.Nname != nil { 58 // addrescapes has similar code to update these offsets. 59 // Usually addrescapes runs after widstruct, 60 // in which case we could drop this, 61 // but function closure functions are the exception. 62 // NOTE(rsc): This comment may be stale. 63 // It's possible the ordering has changed and this is 64 // now the common case. I'm not sure. 65 if f.Nname.Name.Param.Stackcopy != nil { 66 f.Nname.Name.Param.Stackcopy.Xoffset = o 67 f.Nname.Xoffset = 0 68 } else { 69 f.Nname.Xoffset = o 70 } 71 } 72 73 if w == 0 { 74 lastzero = o 75 } 76 o += w 77 maxwidth := Thearch.MAXWIDTH 78 // On 32-bit systems, reflect tables impose an additional constraint 79 // that each field start offset must fit in 31 bits. 80 if maxwidth < 1<<32 { 81 maxwidth = 1<<31 - 1 82 } 83 if o >= maxwidth { 84 yyerror("type %L too large", errtype) 85 o = 8 // small but nonzero 86 } 87 } 88 89 // For nonzero-sized structs which end in a zero-sized thing, we add 90 // an extra byte of padding to the type. This padding ensures that 91 // taking the address of the zero-sized thing can't manufacture a 92 // pointer to the next object in the heap. See issue 9401. 93 if flag == 1 && o > starto && o == lastzero { 94 o++ 95 } 96 97 // final width is rounded 98 if flag != 0 { 99 o = Rnd(o, int64(maxalign)) 100 } 101 t.Align = uint8(maxalign) 102 103 // type width only includes back to first field's offset 104 t.Width = o - starto 105 106 return o 107 } 108 109 func dowidth(t *Type) { 110 if Widthptr == 0 { 111 Fatalf("dowidth without betypeinit") 112 } 113 114 if t == nil { 115 return 116 } 117 118 if t.Width > 0 { 119 if t.Align == 0 { 120 // See issue 11354 121 Fatalf("zero alignment with nonzero size %v", t) 122 } 123 return 124 } 125 126 if t.Width == -2 { 127 if !t.Broke { 128 t.Broke = true 129 yyerrorl(t.Pos, "invalid recursive type %v", t) 130 } 131 132 t.Width = 0 133 return 134 } 135 136 // break infinite recursion if the broken recursive type 137 // is referenced again 138 if t.Broke && t.Width == 0 { 139 return 140 } 141 142 // defer checkwidth calls until after we're done 143 defercalc++ 144 145 lno := lineno 146 lineno = t.Pos 147 t.Width = -2 148 t.Align = 0 149 150 et := t.Etype 151 switch et { 152 case TFUNC, TCHAN, TMAP, TSTRING: 153 break 154 155 // simtype == 0 during bootstrap 156 default: 157 if simtype[t.Etype] != 0 { 158 et = simtype[t.Etype] 159 } 160 } 161 162 w := int64(0) 163 switch et { 164 default: 165 Fatalf("dowidth: unknown type: %v", t) 166 167 // compiler-specific stuff 168 case TINT8, TUINT8, TBOOL: 169 // bool is int8 170 w = 1 171 172 case TINT16, TUINT16: 173 w = 2 174 175 case TINT32, TUINT32, TFLOAT32: 176 w = 4 177 178 case TINT64, TUINT64, TFLOAT64: 179 w = 8 180 t.Align = uint8(Widthreg) 181 182 case TCOMPLEX64: 183 w = 8 184 t.Align = 4 185 186 case TCOMPLEX128: 187 w = 16 188 t.Align = uint8(Widthreg) 189 190 case TPTR32: 191 w = 4 192 checkwidth(t.Elem()) 193 194 case TPTR64: 195 w = 8 196 checkwidth(t.Elem()) 197 198 case TUNSAFEPTR: 199 w = int64(Widthptr) 200 201 case TINTER: // implemented as 2 pointers 202 w = 2 * int64(Widthptr) 203 204 t.Align = uint8(Widthptr) 205 offmod(t) 206 207 case TCHAN: // implemented as pointer 208 w = int64(Widthptr) 209 210 checkwidth(t.Elem()) 211 212 // make fake type to check later to 213 // trigger channel argument check. 214 t1 := typChanArgs(t) 215 checkwidth(t1) 216 217 case TCHANARGS: 218 t1 := t.ChanArgs() 219 dowidth(t1) // just in case 220 if t1.Elem().Width >= 1<<16 { 221 yyerror("channel element type too large (>64kB)") 222 } 223 t.Width = 1 224 225 case TMAP: // implemented as pointer 226 w = int64(Widthptr) 227 checkwidth(t.Val()) 228 checkwidth(t.Key()) 229 230 case TFORW: // should have been filled in 231 if !t.Broke { 232 yyerror("invalid recursive type %v", t) 233 } 234 w = 1 // anything will do 235 236 case TANY: 237 // dummy type; should be replaced before use. 238 Fatalf("dowidth any") 239 240 case TSTRING: 241 if sizeof_String == 0 { 242 Fatalf("early dowidth string") 243 } 244 w = int64(sizeof_String) 245 t.Align = uint8(Widthptr) 246 247 case TARRAY: 248 if t.Elem() == nil { 249 break 250 } 251 if t.isDDDArray() { 252 if !t.Broke { 253 yyerror("use of [...] array outside of array literal") 254 t.Broke = true 255 } 256 break 257 } 258 259 dowidth(t.Elem()) 260 if t.Elem().Width != 0 { 261 cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width) 262 if uint64(t.NumElem()) > cap { 263 yyerror("type %L larger than address space", t) 264 } 265 } 266 w = t.NumElem() * t.Elem().Width 267 t.Align = t.Elem().Align 268 269 case TSLICE: 270 if t.Elem() == nil { 271 break 272 } 273 w = int64(sizeof_Array) 274 checkwidth(t.Elem()) 275 t.Align = uint8(Widthptr) 276 277 case TSTRUCT: 278 if t.IsFuncArgStruct() { 279 Fatalf("dowidth fn struct %v", t) 280 } 281 w = widstruct(t, t, 0, 1) 282 283 // make fake type to check later to 284 // trigger function argument computation. 285 case TFUNC: 286 t1 := typFuncArgs(t) 287 checkwidth(t1) 288 w = int64(Widthptr) // width of func type is pointer 289 290 // function is 3 cated structures; 291 // compute their widths as side-effect. 292 case TFUNCARGS: 293 t1 := t.FuncArgs() 294 w = widstruct(t1, t1.Recvs(), 0, 0) 295 w = widstruct(t1, t1.Params(), w, Widthreg) 296 w = widstruct(t1, t1.Results(), w, Widthreg) 297 t1.Extra.(*FuncType).Argwid = w 298 if w%int64(Widthreg) != 0 { 299 Warn("bad type %v %d\n", t1, w) 300 } 301 t.Align = 1 302 } 303 304 if Widthptr == 4 && w != int64(int32(w)) { 305 yyerror("type %v too large", t) 306 } 307 308 t.Width = w 309 if t.Align == 0 { 310 if w > 8 || w&(w-1) != 0 { 311 Fatalf("invalid alignment for %v", t) 312 } 313 t.Align = uint8(w) 314 } 315 316 lineno = lno 317 318 if defercalc == 1 { 319 resumecheckwidth() 320 } else { 321 defercalc-- 322 } 323 } 324 325 // when a type's width should be known, we call checkwidth 326 // to compute it. during a declaration like 327 // 328 // type T *struct { next T } 329 // 330 // it is necessary to defer the calculation of the struct width 331 // until after T has been initialized to be a pointer to that struct. 332 // similarly, during import processing structs may be used 333 // before their definition. in those situations, calling 334 // defercheckwidth() stops width calculations until 335 // resumecheckwidth() is called, at which point all the 336 // checkwidths that were deferred are executed. 337 // dowidth should only be called when the type's size 338 // is needed immediately. checkwidth makes sure the 339 // size is evaluated eventually. 340 341 var deferredTypeStack []*Type 342 343 func checkwidth(t *Type) { 344 if t == nil { 345 return 346 } 347 348 // function arg structs should not be checked 349 // outside of the enclosing function. 350 if t.IsFuncArgStruct() { 351 Fatalf("checkwidth %v", t) 352 } 353 354 if defercalc == 0 { 355 dowidth(t) 356 return 357 } 358 359 if t.Deferwidth { 360 return 361 } 362 t.Deferwidth = true 363 364 deferredTypeStack = append(deferredTypeStack, t) 365 } 366 367 func defercheckwidth() { 368 // we get out of sync on syntax errors, so don't be pedantic. 369 if defercalc != 0 && nerrors == 0 { 370 Fatalf("defercheckwidth") 371 } 372 defercalc = 1 373 } 374 375 func resumecheckwidth() { 376 if defercalc == 0 { 377 Fatalf("resumecheckwidth") 378 } 379 for len(deferredTypeStack) > 0 { 380 t := deferredTypeStack[len(deferredTypeStack)-1] 381 deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1] 382 t.Deferwidth = false 383 dowidth(t) 384 } 385 386 defercalc = 0 387 }