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