diff options
Diffstat (limited to 'src/cmd/gc/align.c')
-rw-r--r-- | src/cmd/gc/align.c | 653 |
1 files changed, 653 insertions, 0 deletions
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c new file mode 100644 index 000000000..14c1c4a8d --- /dev/null +++ b/src/cmd/gc/align.c @@ -0,0 +1,653 @@ +// Copyright 2009 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. + +#include "go.h" + +/* + * machine size and rounding + * alignment is dictated around + * the size of a pointer, set in betypeinit + * (see ../6g/galign.c). + */ + +static int defercalc; + +uint32 +rnd(uint32 o, uint32 r) +{ + if(r < 1 || r > 8 || (r&(r-1)) != 0) + fatal("rnd"); + return (o+r-1)&~(r-1); +} + +static void +offmod(Type *t) +{ + Type *f; + int32 o; + + o = 0; + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("offmod: not TFIELD: %lT", f); + f->width = o; + o += widthptr; + if(o >= MAXWIDTH) { + yyerror("interface too large"); + o = widthptr; + } + } +} + +static vlong +widstruct(Type *errtype, Type *t, vlong o, int flag) +{ + Type *f; + int32 w, maxalign; + + maxalign = flag; + if(maxalign < 1) + maxalign = 1; + for(f=t->type; f!=T; f=f->down) { + if(f->etype != TFIELD) + fatal("widstruct: not TFIELD: %lT", f); + dowidth(f->type); + if(f->type->align > maxalign) + maxalign = f->type->align; + if(f->type->width < 0) + fatal("invalid width %lld", f->type->width); + w = f->type->width; + if(f->type->align > 0) + o = rnd(o, f->type->align); + f->width = o; // really offset for TFIELD + if(f->nname != N) { + // this same stackparam logic is in addrescapes + // in typecheck.c. usually addrescapes runs after + // widstruct, in which case we could drop this, + // but function closure functions are the exception. + if(f->nname->stackparam) { + f->nname->stackparam->xoffset = o; + f->nname->xoffset = 0; + } else + f->nname->xoffset = o; + } + o += w; + if(o >= MAXWIDTH) { + yyerror("type %lT too large", errtype); + o = 8; // small but nonzero + } + } + // final width is rounded + if(flag) + o = rnd(o, maxalign); + t->align = maxalign; + + // type width only includes back to first field's offset + if(t->type == T) + t->width = 0; + else + t->width = o - t->type->width; + return o; +} + +void +dowidth(Type *t) +{ + int32 et; + int64 w; + int lno; + Type *t1; + + if(widthptr == 0) + fatal("dowidth without betypeinit"); + + if(t == T) + return; + + if(t->width > 0) + return; + + if(t->width == -2) { + lno = lineno; + lineno = t->lineno; + yyerror("invalid recursive type %T", t); + t->width = 0; + lineno = lno; + return; + } + + // defer checkwidth calls until after we're done + defercalc++; + + lno = lineno; + lineno = t->lineno; + t->width = -2; + t->align = 0; + + et = t->etype; + switch(et) { + case TFUNC: + case TCHAN: + case TMAP: + case TSTRING: + break; + + default: + /* simtype == 0 during bootstrap */ + if(simtype[t->etype] != 0) + et = simtype[t->etype]; + break; + } + + w = 0; + switch(et) { + default: + fatal("dowidth: unknown type: %T", t); + break; + + /* compiler-specific stuff */ + case TINT8: + case TUINT8: + case TBOOL: // bool is int8 + w = 1; + break; + case TINT16: + case TUINT16: + w = 2; + break; + case TINT32: + case TUINT32: + case TFLOAT32: + w = 4; + break; + case TINT64: + case TUINT64: + case TFLOAT64: + case TCOMPLEX64: + w = 8; + t->align = widthptr; + break; + case TCOMPLEX128: + w = 16; + t->align = widthptr; + break; + case TPTR32: + w = 4; + checkwidth(t->type); + break; + case TPTR64: + w = 8; + checkwidth(t->type); + break; + case TUNSAFEPTR: + w = widthptr; + break; + case TINTER: // implemented as 2 pointers + w = 2*widthptr; + t->align = widthptr; + offmod(t); + break; + case TCHAN: // implemented as pointer + w = widthptr; + checkwidth(t->type); + + // make fake type to check later to + // trigger channel argument check. + t1 = typ(TCHANARGS); + t1->type = t; + checkwidth(t1); + break; + case TCHANARGS: + t1 = t->type; + dowidth(t->type); // just in case + if(t1->type->width >= (1<<16)) + yyerror("channel element type too large (>64kB)"); + t->width = 1; + break; + case TMAP: // implemented as pointer + w = widthptr; + checkwidth(t->type); + checkwidth(t->down); + break; + case TFORW: // should have been filled in + yyerror("invalid recursive type %T", t); + w = 1; // anything will do + break; + case TANY: + // dummy type; should be replaced before use. + if(!debug['A']) + fatal("dowidth any"); + w = 1; // anything will do + break; + case TSTRING: + if(sizeof_String == 0) + fatal("early dowidth string"); + w = sizeof_String; + t->align = widthptr; + break; + case TARRAY: + if(t->type == T) + break; + if(t->bound >= 0) { + uint64 cap; + + dowidth(t->type); + if(t->type->width != 0) { + cap = (MAXWIDTH-1) / t->type->width; + if(t->bound > cap) + yyerror("type %lT larger than address space", t); + } + w = t->bound * t->type->width; + t->align = t->type->align; + } + else if(t->bound == -1) { + w = sizeof_Array; + checkwidth(t->type); + t->align = widthptr; + } + else if(t->bound == -100) + yyerror("use of [...] array outside of array literal"); + else + fatal("dowidth %T", t); // probably [...]T + break; + + case TSTRUCT: + if(t->funarg) + fatal("dowidth fn struct %T", t); + w = widstruct(t, t, 0, 1); + break; + + case TFUNC: + // make fake type to check later to + // trigger function argument computation. + t1 = typ(TFUNCARGS); + t1->type = t; + checkwidth(t1); + + // width of func type is pointer + w = widthptr; + break; + + case TFUNCARGS: + // function is 3 cated structures; + // compute their widths as side-effect. + t1 = t->type; + w = widstruct(t->type, *getthis(t1), 0, 0); + w = widstruct(t->type, *getinarg(t1), w, widthptr); + w = widstruct(t->type, *getoutarg(t1), w, widthptr); + t1->argwid = w; + if(w%widthptr) + warn("bad type %T %d\n", t1, w); + t->align = 1; + break; + } + + t->width = w; + if(t->align == 0) { + if(w > 8 || (w&(w-1)) != 0) + fatal("invalid alignment for %T", t); + t->align = w; + } + lineno = lno; + + if(defercalc == 1) + resumecheckwidth(); + else + --defercalc; +} + +/* + * when a type's width should be known, we call checkwidth + * to compute it. during a declaration like + * + * type T *struct { next T } + * + * it is necessary to defer the calculation of the struct width + * until after T has been initialized to be a pointer to that struct. + * similarly, during import processing structs may be used + * before their definition. in those situations, calling + * defercheckwidth() stops width calculations until + * resumecheckwidth() is called, at which point all the + * checkwidths that were deferred are executed. + * dowidth should only be called when the type's size + * is needed immediately. checkwidth makes sure the + * size is evaluated eventually. + */ +typedef struct TypeList TypeList; +struct TypeList { + Type *t; + TypeList *next; +}; + +static TypeList *tlfree; +static TypeList *tlq; + +void +checkwidth(Type *t) +{ + TypeList *l; + + if(t == T) + return; + + // function arg structs should not be checked + // outside of the enclosing function. + if(t->funarg) + fatal("checkwidth %T", t); + + if(!defercalc) { + dowidth(t); + return; + } + if(t->deferwidth) + return; + t->deferwidth = 1; + + l = tlfree; + if(l != nil) + tlfree = l->next; + else + l = mal(sizeof *l); + + l->t = t; + l->next = tlq; + tlq = l; +} + +void +defercheckwidth(void) +{ + // we get out of sync on syntax errors, so don't be pedantic. + if(defercalc && nerrors == 0) + fatal("defercheckwidth"); + defercalc = 1; +} + +void +resumecheckwidth(void) +{ + TypeList *l; + + if(!defercalc) + fatal("resumecheckwidth"); + for(l = tlq; l != nil; l = tlq) { + l->t->deferwidth = 0; + tlq = l->next; + dowidth(l->t); + l->next = tlfree; + tlfree = l; + } + defercalc = 0; +} + +void +typeinit(void) +{ + int i, etype, sameas; + Type *t; + Sym *s, *s1; + + if(widthptr == 0) + fatal("typeinit before betypeinit"); + + for(i=0; i<NTYPE; i++) + simtype[i] = i; + + types[TPTR32] = typ(TPTR32); + dowidth(types[TPTR32]); + + types[TPTR64] = typ(TPTR64); + dowidth(types[TPTR64]); + + t = typ(TUNSAFEPTR); + types[TUNSAFEPTR] = t; + t->sym = pkglookup("Pointer", unsafepkg); + t->sym->def = typenod(t); + + dowidth(types[TUNSAFEPTR]); + + tptr = TPTR32; + if(widthptr == 8) + tptr = TPTR64; + + for(i=TINT8; i<=TUINT64; i++) + isint[i] = 1; + isint[TINT] = 1; + isint[TUINT] = 1; + isint[TUINTPTR] = 1; + + isfloat[TFLOAT32] = 1; + isfloat[TFLOAT64] = 1; + + iscomplex[TCOMPLEX64] = 1; + iscomplex[TCOMPLEX128] = 1; + + isptr[TPTR32] = 1; + isptr[TPTR64] = 1; + + isforw[TFORW] = 1; + + issigned[TINT] = 1; + issigned[TINT8] = 1; + issigned[TINT16] = 1; + issigned[TINT32] = 1; + issigned[TINT64] = 1; + + /* + * initialize okfor + */ + for(i=0; i<NTYPE; i++) { + if(isint[i] || i == TIDEAL) { + okforeq[i] = 1; + okforcmp[i] = 1; + okforarith[i] = 1; + okforadd[i] = 1; + okforand[i] = 1; + okforconst[i] = 1; + issimple[i] = 1; + minintval[i] = mal(sizeof(*minintval[i])); + maxintval[i] = mal(sizeof(*maxintval[i])); + } + if(isfloat[i]) { + okforeq[i] = 1; + okforcmp[i] = 1; + okforadd[i] = 1; + okforarith[i] = 1; + okforconst[i] = 1; + issimple[i] = 1; + minfltval[i] = mal(sizeof(*minfltval[i])); + maxfltval[i] = mal(sizeof(*maxfltval[i])); + } + if(iscomplex[i]) { + okforeq[i] = 1; + okforadd[i] = 1; + okforarith[i] = 1; + okforconst[i] = 1; + issimple[i] = 1; + } + } + + issimple[TBOOL] = 1; + + okforadd[TSTRING] = 1; + + okforbool[TBOOL] = 1; + + okforcap[TARRAY] = 1; + okforcap[TCHAN] = 1; + + okforconst[TBOOL] = 1; + okforconst[TSTRING] = 1; + + okforlen[TARRAY] = 1; + okforlen[TCHAN] = 1; + okforlen[TMAP] = 1; + okforlen[TSTRING] = 1; + + okforeq[TPTR32] = 1; + okforeq[TPTR64] = 1; + okforeq[TUNSAFEPTR] = 1; + okforeq[TINTER] = 1; + okforeq[TMAP] = 1; + okforeq[TCHAN] = 1; + okforeq[TFUNC] = 1; + okforeq[TSTRING] = 1; + okforeq[TBOOL] = 1; + okforeq[TARRAY] = 1; // refined in typecheck + + okforcmp[TSTRING] = 1; + + for(i=0; i<nelem(okfor); i++) + okfor[i] = okfornone; + + // binary + okfor[OADD] = okforadd; + okfor[OAND] = okforand; + okfor[OANDAND] = okforbool; + okfor[OANDNOT] = okforand; + okfor[ODIV] = okforarith; + okfor[OEQ] = okforeq; + okfor[OGE] = okforcmp; + okfor[OGT] = okforcmp; + okfor[OLE] = okforcmp; + okfor[OLT] = okforcmp; + okfor[OMOD] = okforand; + okfor[OMUL] = okforarith; + okfor[ONE] = okforeq; + okfor[OOR] = okforand; + okfor[OOROR] = okforbool; + okfor[OSUB] = okforarith; + okfor[OXOR] = okforand; + okfor[OLSH] = okforand; + okfor[ORSH] = okforand; + + // unary + okfor[OCOM] = okforand; + okfor[OMINUS] = okforarith; + okfor[ONOT] = okforbool; + okfor[OPLUS] = okforarith; + + // special + okfor[OCAP] = okforcap; + okfor[OLEN] = okforlen; + + // comparison + iscmp[OLT] = 1; + iscmp[OGT] = 1; + iscmp[OGE] = 1; + iscmp[OLE] = 1; + iscmp[OEQ] = 1; + iscmp[ONE] = 1; + + mpatofix(maxintval[TINT8], "0x7f"); + mpatofix(minintval[TINT8], "-0x80"); + mpatofix(maxintval[TINT16], "0x7fff"); + mpatofix(minintval[TINT16], "-0x8000"); + mpatofix(maxintval[TINT32], "0x7fffffff"); + mpatofix(minintval[TINT32], "-0x80000000"); + mpatofix(maxintval[TINT64], "0x7fffffffffffffff"); + mpatofix(minintval[TINT64], "-0x8000000000000000"); + + mpatofix(maxintval[TUINT8], "0xff"); + mpatofix(maxintval[TUINT16], "0xffff"); + mpatofix(maxintval[TUINT32], "0xffffffff"); + mpatofix(maxintval[TUINT64], "0xffffffffffffffff"); + + /* f is valid float if min < f < max. (min and max are not themselves valid.) */ + mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/ + mpatoflt(minfltval[TFLOAT32], "-33554431p103"); + mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */ + mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970"); + + maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]; + minfltval[TCOMPLEX64] = minfltval[TFLOAT32]; + maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]; + minfltval[TCOMPLEX128] = minfltval[TFLOAT64]; + + /* for walk to use in error messages */ + types[TFUNC] = functype(N, nil, nil); + + /* types used in front end */ + // types[TNIL] got set early in lexinit + types[TIDEAL] = typ(TIDEAL); + types[TINTER] = typ(TINTER); + + /* simple aliases */ + simtype[TMAP] = tptr; + simtype[TCHAN] = tptr; + simtype[TFUNC] = tptr; + simtype[TUNSAFEPTR] = tptr; + + /* pick up the backend typedefs */ + for(i=0; typedefs[i].name; i++) { + s = lookup(typedefs[i].name); + s1 = pkglookup(typedefs[i].name, builtinpkg); + + etype = typedefs[i].etype; + if(etype < 0 || etype >= nelem(types)) + fatal("typeinit: %s bad etype", s->name); + sameas = typedefs[i].sameas; + if(sameas < 0 || sameas >= nelem(types)) + fatal("typeinit: %s bad sameas", s->name); + simtype[etype] = sameas; + minfltval[etype] = minfltval[sameas]; + maxfltval[etype] = maxfltval[sameas]; + minintval[etype] = minintval[sameas]; + maxintval[etype] = maxintval[sameas]; + + t = types[etype]; + if(t != T) + fatal("typeinit: %s already defined", s->name); + + t = typ(etype); + t->sym = s; + + dowidth(t); + types[etype] = t; + s1->def = typenod(t); + } + + Array_array = rnd(0, widthptr); + Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width); + Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width); + sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr); + + // string is same as slice wo the cap + sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr); + + dowidth(types[TSTRING]); + dowidth(idealstring); +} + +/* + * compute total size of f's in/out arguments. + */ +int +argsize(Type *t) +{ + Iter save; + Type *fp; + int w, x; + + w = 0; + + fp = structfirst(&save, getoutarg(t)); + while(fp != T) { + x = fp->width + fp->type->width; + if(x > w) + w = x; + fp = structnext(&save); + } + + fp = funcfirst(&save, t); + while(fp != T) { + x = fp->width + fp->type->width; + if(x > w) + w = x; + fp = funcnext(&save); + } + + w = (w+widthptr-1) & ~(widthptr-1); + return w; +} |