github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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 import "cmd/internal/obj" 8 9 /* 10 * machine size and rounding 11 * alignment is dictated around 12 * the size of a pointer, set in betypeinit 13 * (see ../6g/galign.c). 14 */ 15 var defercalc int 16 17 func Rnd(o int64, r int64) int64 { 18 if r < 1 || r > 8 || r&(r-1) != 0 { 19 Fatal("rnd %d", r) 20 } 21 return (o + r - 1) &^ (r - 1) 22 } 23 24 func offmod(t *Type) { 25 o := int32(0) 26 for f := t.Type; f != nil; f = f.Down { 27 if f.Etype != TFIELD { 28 Fatal("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong)) 29 } 30 f.Width = int64(o) 31 o += int32(Widthptr) 32 if int64(o) >= Thearch.MAXWIDTH { 33 Yyerror("interface too large") 34 o = int32(Widthptr) 35 } 36 } 37 } 38 39 func widstruct(errtype *Type, t *Type, o int64, flag int) int64 { 40 starto := o 41 maxalign := int32(flag) 42 if maxalign < 1 { 43 maxalign = 1 44 } 45 lastzero := int64(0) 46 var w int64 47 for f := t.Type; f != nil; f = f.Down { 48 if f.Etype != TFIELD { 49 Fatal("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong)) 50 } 51 if f.Type == nil { 52 // broken field, just skip it so that other valid fields 53 // get a width. 54 continue 55 } 56 57 dowidth(f.Type) 58 if int32(f.Type.Align) > maxalign { 59 maxalign = int32(f.Type.Align) 60 } 61 if f.Type.Width < 0 { 62 Fatal("invalid width %d", f.Type.Width) 63 } 64 w = f.Type.Width 65 if f.Type.Align > 0 { 66 o = Rnd(o, int64(f.Type.Align)) 67 } 68 f.Width = o // really offset for TFIELD 69 if f.Nname != nil { 70 // this same stackparam logic is in addrescapes 71 // in typecheck.c. usually addrescapes runs after 72 // widstruct, in which case we could drop this, 73 // but function closure functions are the exception. 74 if f.Nname.Stackparam != nil { 75 f.Nname.Stackparam.Xoffset = o 76 f.Nname.Xoffset = 0 77 } else { 78 f.Nname.Xoffset = o 79 } 80 } 81 82 if w == 0 { 83 lastzero = o 84 } 85 o += w 86 if o >= Thearch.MAXWIDTH { 87 Yyerror("type %v too large", Tconv(errtype, obj.FmtLong)) 88 o = 8 // small but nonzero 89 } 90 } 91 92 // For nonzero-sized structs which end in a zero-sized thing, we add 93 // an extra byte of padding to the type. This padding ensures that 94 // taking the address of the zero-sized thing can't manufacture a 95 // pointer to the next object in the heap. See issue 9401. 96 if flag == 1 && o > starto && o == lastzero { 97 o++ 98 } 99 100 // final width is rounded 101 if flag != 0 { 102 o = Rnd(o, int64(maxalign)) 103 } 104 t.Align = uint8(maxalign) 105 106 // type width only includes back to first field's offset 107 t.Width = o - starto 108 109 return o 110 } 111 112 func dowidth(t *Type) { 113 if Widthptr == 0 { 114 Fatal("dowidth without betypeinit") 115 } 116 117 if t == nil { 118 return 119 } 120 121 if t.Width > 0 { 122 return 123 } 124 125 if t.Width == -2 { 126 lno := int(lineno) 127 lineno = int32(t.Lineno) 128 if t.Broke == 0 { 129 t.Broke = 1 130 Yyerror("invalid recursive type %v", Tconv(t, 0)) 131 } 132 133 t.Width = 0 134 lineno = int32(lno) 135 return 136 } 137 138 // break infinite recursion if the broken recursive type 139 // is referenced again 140 if t.Broke != 0 && t.Width == 0 { 141 return 142 } 143 144 // defer checkwidth calls until after we're done 145 defercalc++ 146 147 lno := int(lineno) 148 lineno = int32(t.Lineno) 149 t.Width = -2 150 t.Align = 0 151 152 et := int32(t.Etype) 153 switch et { 154 case TFUNC, TCHAN, TMAP, TSTRING: 155 break 156 157 /* simtype == 0 during bootstrap */ 158 default: 159 if Simtype[t.Etype] != 0 { 160 et = int32(Simtype[t.Etype]) 161 } 162 } 163 164 w := int64(0) 165 switch et { 166 default: 167 Fatal("dowidth: unknown type: %v", Tconv(t, 0)) 168 169 /* compiler-specific stuff */ 170 case TINT8, TUINT8, TBOOL: 171 // bool is int8 172 w = 1 173 174 case TINT16, TUINT16: 175 w = 2 176 177 case TINT32, TUINT32, TFLOAT32: 178 w = 4 179 180 case TINT64, TUINT64, TFLOAT64, TCOMPLEX64: 181 w = 8 182 t.Align = uint8(Widthreg) 183 184 case TCOMPLEX128: 185 w = 16 186 t.Align = uint8(Widthreg) 187 188 case TPTR32: 189 w = 4 190 checkwidth(t.Type) 191 192 case TPTR64: 193 w = 8 194 checkwidth(t.Type) 195 196 case TUNSAFEPTR: 197 w = int64(Widthptr) 198 199 case TINTER: // implemented as 2 pointers 200 w = 2 * int64(Widthptr) 201 202 t.Align = uint8(Widthptr) 203 offmod(t) 204 205 case TCHAN: // implemented as pointer 206 w = int64(Widthptr) 207 208 checkwidth(t.Type) 209 210 // make fake type to check later to 211 // trigger channel argument check. 212 t1 := typ(TCHANARGS) 213 214 t1.Type = t 215 checkwidth(t1) 216 217 case TCHANARGS: 218 t1 := t.Type 219 dowidth(t.Type) // just in case 220 if t1.Type.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 228 checkwidth(t.Type) 229 checkwidth(t.Down) 230 231 case TFORW: // should have been filled in 232 if t.Broke == 0 { 233 Yyerror("invalid recursive type %v", Tconv(t, 0)) 234 } 235 w = 1 // anything will do 236 237 // dummy type; should be replaced before use. 238 case TANY: 239 if Debug['A'] == 0 { 240 Fatal("dowidth any") 241 } 242 w = 1 // anything will do 243 244 case TSTRING: 245 if sizeof_String == 0 { 246 Fatal("early dowidth string") 247 } 248 w = int64(sizeof_String) 249 t.Align = uint8(Widthptr) 250 251 case TARRAY: 252 if t.Type == nil { 253 break 254 } 255 if t.Bound >= 0 { 256 dowidth(t.Type) 257 if t.Type.Width != 0 { 258 cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width) 259 if uint64(t.Bound) > cap { 260 Yyerror("type %v larger than address space", Tconv(t, obj.FmtLong)) 261 } 262 } 263 264 w = t.Bound * t.Type.Width 265 t.Align = t.Type.Align 266 } else if t.Bound == -1 { 267 w = int64(sizeof_Array) 268 checkwidth(t.Type) 269 t.Align = uint8(Widthptr) 270 } else if t.Bound == -100 { 271 if t.Broke == 0 { 272 Yyerror("use of [...] array outside of array literal") 273 t.Broke = 1 274 } 275 } else { 276 Fatal("dowidth %v", Tconv(t, 0)) // probably [...]T 277 } 278 279 case TSTRUCT: 280 if t.Funarg != 0 { 281 Fatal("dowidth fn struct %v", Tconv(t, 0)) 282 } 283 w = widstruct(t, t, 0, 1) 284 285 // make fake type to check later to 286 // trigger function argument computation. 287 case TFUNC: 288 t1 := typ(TFUNCARGS) 289 290 t1.Type = t 291 checkwidth(t1) 292 293 // width of func type is pointer 294 w = int64(Widthptr) 295 296 // function is 3 cated structures; 297 // compute their widths as side-effect. 298 case TFUNCARGS: 299 t1 := t.Type 300 301 w = widstruct(t.Type, *getthis(t1), 0, 0) 302 w = widstruct(t.Type, *getinarg(t1), w, Widthreg) 303 w = widstruct(t.Type, *Getoutarg(t1), w, Widthreg) 304 t1.Argwid = w 305 if w%int64(Widthreg) != 0 { 306 Warn("bad type %v %d\n", Tconv(t1, 0), w) 307 } 308 t.Align = 1 309 } 310 311 if Widthptr == 4 && w != int64(int32(w)) { 312 Yyerror("type %v too large", Tconv(t, 0)) 313 } 314 315 t.Width = w 316 if t.Align == 0 { 317 if w > 8 || w&(w-1) != 0 { 318 Fatal("invalid alignment for %v", Tconv(t, 0)) 319 } 320 t.Align = uint8(w) 321 } 322 323 lineno = int32(lno) 324 325 if defercalc == 1 { 326 resumecheckwidth() 327 } else { 328 defercalc-- 329 } 330 } 331 332 /* 333 * when a type's width should be known, we call checkwidth 334 * to compute it. during a declaration like 335 * 336 * type T *struct { next T } 337 * 338 * it is necessary to defer the calculation of the struct width 339 * until after T has been initialized to be a pointer to that struct. 340 * similarly, during import processing structs may be used 341 * before their definition. in those situations, calling 342 * defercheckwidth() stops width calculations until 343 * resumecheckwidth() is called, at which point all the 344 * checkwidths that were deferred are executed. 345 * dowidth should only be called when the type's size 346 * is needed immediately. checkwidth makes sure the 347 * size is evaluated eventually. 348 */ 349 type TypeList struct { 350 t *Type 351 next *TypeList 352 } 353 354 var tlfree *TypeList 355 356 var tlq *TypeList 357 358 func checkwidth(t *Type) { 359 if t == nil { 360 return 361 } 362 363 // function arg structs should not be checked 364 // outside of the enclosing function. 365 if t.Funarg != 0 { 366 Fatal("checkwidth %v", Tconv(t, 0)) 367 } 368 369 if defercalc == 0 { 370 dowidth(t) 371 return 372 } 373 374 if t.Deferwidth != 0 { 375 return 376 } 377 t.Deferwidth = 1 378 379 l := tlfree 380 if l != nil { 381 tlfree = l.next 382 } else { 383 l = new(TypeList) 384 } 385 386 l.t = t 387 l.next = tlq 388 tlq = l 389 } 390 391 func defercheckwidth() { 392 // we get out of sync on syntax errors, so don't be pedantic. 393 if defercalc != 0 && nerrors == 0 { 394 Fatal("defercheckwidth") 395 } 396 defercalc = 1 397 } 398 399 func resumecheckwidth() { 400 if defercalc == 0 { 401 Fatal("resumecheckwidth") 402 } 403 for l := tlq; l != nil; l = tlq { 404 l.t.Deferwidth = 0 405 tlq = l.next 406 dowidth(l.t) 407 l.next = tlfree 408 tlfree = l 409 } 410 411 defercalc = 0 412 } 413 414 func typeinit() { 415 if Widthptr == 0 { 416 Fatal("typeinit before betypeinit") 417 } 418 419 for i := 0; i < NTYPE; i++ { 420 Simtype[i] = uint8(i) 421 } 422 423 Types[TPTR32] = typ(TPTR32) 424 dowidth(Types[TPTR32]) 425 426 Types[TPTR64] = typ(TPTR64) 427 dowidth(Types[TPTR64]) 428 429 t := typ(TUNSAFEPTR) 430 Types[TUNSAFEPTR] = t 431 t.Sym = Pkglookup("Pointer", unsafepkg) 432 t.Sym.Def = typenod(t) 433 434 dowidth(Types[TUNSAFEPTR]) 435 436 Tptr = TPTR32 437 if Widthptr == 8 { 438 Tptr = TPTR64 439 } 440 441 for i := TINT8; i <= TUINT64; i++ { 442 Isint[i] = true 443 } 444 Isint[TINT] = true 445 Isint[TUINT] = true 446 Isint[TUINTPTR] = true 447 448 Isfloat[TFLOAT32] = true 449 Isfloat[TFLOAT64] = true 450 451 Iscomplex[TCOMPLEX64] = true 452 Iscomplex[TCOMPLEX128] = true 453 454 Isptr[TPTR32] = true 455 Isptr[TPTR64] = true 456 457 isforw[TFORW] = true 458 459 Issigned[TINT] = true 460 Issigned[TINT8] = true 461 Issigned[TINT16] = true 462 Issigned[TINT32] = true 463 Issigned[TINT64] = true 464 465 /* 466 * initialize okfor 467 */ 468 for i := 0; i < NTYPE; i++ { 469 if Isint[i] || i == TIDEAL { 470 okforeq[i] = true 471 okforcmp[i] = true 472 okforarith[i] = true 473 okforadd[i] = true 474 okforand[i] = true 475 okforconst[i] = true 476 issimple[i] = true 477 Minintval[i] = new(Mpint) 478 Maxintval[i] = new(Mpint) 479 } 480 481 if Isfloat[i] { 482 okforeq[i] = true 483 okforcmp[i] = true 484 okforadd[i] = true 485 okforarith[i] = true 486 okforconst[i] = true 487 issimple[i] = true 488 minfltval[i] = newMpflt() 489 maxfltval[i] = newMpflt() 490 } 491 492 if Iscomplex[i] { 493 okforeq[i] = true 494 okforadd[i] = true 495 okforarith[i] = true 496 okforconst[i] = true 497 issimple[i] = true 498 } 499 } 500 501 issimple[TBOOL] = true 502 503 okforadd[TSTRING] = true 504 505 okforbool[TBOOL] = true 506 507 okforcap[TARRAY] = true 508 okforcap[TCHAN] = true 509 510 okforconst[TBOOL] = true 511 okforconst[TSTRING] = true 512 513 okforlen[TARRAY] = true 514 okforlen[TCHAN] = true 515 okforlen[TMAP] = true 516 okforlen[TSTRING] = true 517 518 okforeq[TPTR32] = true 519 okforeq[TPTR64] = true 520 okforeq[TUNSAFEPTR] = true 521 okforeq[TINTER] = true 522 okforeq[TCHAN] = true 523 okforeq[TSTRING] = true 524 okforeq[TBOOL] = true 525 okforeq[TMAP] = true // nil only; refined in typecheck 526 okforeq[TFUNC] = true // nil only; refined in typecheck 527 okforeq[TARRAY] = true // nil slice only; refined in typecheck 528 okforeq[TSTRUCT] = true // it's complicated; refined in typecheck 529 530 okforcmp[TSTRING] = true 531 532 var i int 533 for i = 0; i < len(okfor); i++ { 534 okfor[i] = okfornone[:] 535 } 536 537 // binary 538 okfor[OADD] = okforadd[:] 539 540 okfor[OAND] = okforand[:] 541 okfor[OANDAND] = okforbool[:] 542 okfor[OANDNOT] = okforand[:] 543 okfor[ODIV] = okforarith[:] 544 okfor[OEQ] = okforeq[:] 545 okfor[OGE] = okforcmp[:] 546 okfor[OGT] = okforcmp[:] 547 okfor[OLE] = okforcmp[:] 548 okfor[OLT] = okforcmp[:] 549 okfor[OMOD] = okforand[:] 550 okfor[OMUL] = okforarith[:] 551 okfor[ONE] = okforeq[:] 552 okfor[OOR] = okforand[:] 553 okfor[OOROR] = okforbool[:] 554 okfor[OSUB] = okforarith[:] 555 okfor[OXOR] = okforand[:] 556 okfor[OLSH] = okforand[:] 557 okfor[ORSH] = okforand[:] 558 559 // unary 560 okfor[OCOM] = okforand[:] 561 562 okfor[OMINUS] = okforarith[:] 563 okfor[ONOT] = okforbool[:] 564 okfor[OPLUS] = okforarith[:] 565 566 // special 567 okfor[OCAP] = okforcap[:] 568 569 okfor[OLEN] = okforlen[:] 570 571 // comparison 572 iscmp[OLT] = true 573 574 iscmp[OGT] = true 575 iscmp[OGE] = true 576 iscmp[OLE] = true 577 iscmp[OEQ] = true 578 iscmp[ONE] = true 579 580 mpatofix(Maxintval[TINT8], "0x7f") 581 mpatofix(Minintval[TINT8], "-0x80") 582 mpatofix(Maxintval[TINT16], "0x7fff") 583 mpatofix(Minintval[TINT16], "-0x8000") 584 mpatofix(Maxintval[TINT32], "0x7fffffff") 585 mpatofix(Minintval[TINT32], "-0x80000000") 586 mpatofix(Maxintval[TINT64], "0x7fffffffffffffff") 587 mpatofix(Minintval[TINT64], "-0x8000000000000000") 588 589 mpatofix(Maxintval[TUINT8], "0xff") 590 mpatofix(Maxintval[TUINT16], "0xffff") 591 mpatofix(Maxintval[TUINT32], "0xffffffff") 592 mpatofix(Maxintval[TUINT64], "0xffffffffffffffff") 593 594 /* f is valid float if min < f < max. (min and max are not themselves valid.) */ 595 mpatoflt(maxfltval[TFLOAT32], "33554431p103") /* 2^24-1 p (127-23) + 1/2 ulp*/ 596 mpatoflt(minfltval[TFLOAT32], "-33554431p103") 597 mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970") /* 2^53-1 p (1023-52) + 1/2 ulp */ 598 mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970") 599 600 maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32] 601 minfltval[TCOMPLEX64] = minfltval[TFLOAT32] 602 maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64] 603 minfltval[TCOMPLEX128] = minfltval[TFLOAT64] 604 605 /* for walk to use in error messages */ 606 Types[TFUNC] = functype(nil, nil, nil) 607 608 /* types used in front end */ 609 // types[TNIL] got set early in lexinit 610 Types[TIDEAL] = typ(TIDEAL) 611 612 Types[TINTER] = typ(TINTER) 613 614 /* simple aliases */ 615 Simtype[TMAP] = uint8(Tptr) 616 617 Simtype[TCHAN] = uint8(Tptr) 618 Simtype[TFUNC] = uint8(Tptr) 619 Simtype[TUNSAFEPTR] = uint8(Tptr) 620 621 /* pick up the backend thearch.typedefs */ 622 var s1 *Sym 623 var etype int 624 var sameas int 625 var s *Sym 626 for i = range Thearch.Typedefs { 627 s = Lookup(Thearch.Typedefs[i].Name) 628 s1 = Pkglookup(Thearch.Typedefs[i].Name, builtinpkg) 629 630 etype = Thearch.Typedefs[i].Etype 631 if etype < 0 || etype >= len(Types) { 632 Fatal("typeinit: %s bad etype", s.Name) 633 } 634 sameas = Thearch.Typedefs[i].Sameas 635 if sameas < 0 || sameas >= len(Types) { 636 Fatal("typeinit: %s bad sameas", s.Name) 637 } 638 Simtype[etype] = uint8(sameas) 639 minfltval[etype] = minfltval[sameas] 640 maxfltval[etype] = maxfltval[sameas] 641 Minintval[etype] = Minintval[sameas] 642 Maxintval[etype] = Maxintval[sameas] 643 644 t = Types[etype] 645 if t != nil { 646 Fatal("typeinit: %s already defined", s.Name) 647 } 648 649 t = typ(etype) 650 t.Sym = s1 651 652 dowidth(t) 653 Types[etype] = t 654 s1.Def = typenod(t) 655 } 656 657 Array_array = int(Rnd(0, int64(Widthptr))) 658 Array_nel = int(Rnd(int64(Array_array)+int64(Widthptr), int64(Widthint))) 659 Array_cap = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthint))) 660 sizeof_Array = int(Rnd(int64(Array_cap)+int64(Widthint), int64(Widthptr))) 661 662 // string is same as slice wo the cap 663 sizeof_String = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthptr))) 664 665 dowidth(Types[TSTRING]) 666 dowidth(idealstring) 667 } 668 669 /* 670 * compute total size of f's in/out arguments. 671 */ 672 func Argsize(t *Type) int { 673 var save Iter 674 var x int64 675 676 w := int64(0) 677 678 fp := Structfirst(&save, Getoutarg(t)) 679 for fp != nil { 680 x = fp.Width + fp.Type.Width 681 if x > w { 682 w = x 683 } 684 fp = structnext(&save) 685 } 686 687 fp = funcfirst(&save, t) 688 for fp != nil { 689 x = fp.Width + fp.Type.Width 690 if x > w { 691 w = x 692 } 693 fp = funcnext(&save) 694 } 695 696 w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1) 697 if int64(int(w)) != w { 698 Fatal("argsize too big") 699 } 700 return int(w) 701 }