From e7a0f6760377c6a4ad7f37ade8eabf2fdf150e0a Mon Sep 17 00:00:00 2001
From: Russ Cox <rsc@golang.org>
Date: Mon, 13 Dec 2010 11:57:41 -0500
Subject: [PATCH] gc: introduce explicit alignments

No semantic changes here, but working
toward being able to align structs based
on the maximum alignment of the fields
inside instead of having a fixed alignment
for all structs (issue 482).

R=ken2
CC=golang-dev
https://golang.org/cl/3617041
---
 src/cmd/5g/galign.c  |  1 -
 src/cmd/5g/ggen.c    |  4 +--
 src/cmd/6g/galign.c  |  1 -
 src/cmd/6g/ggen.c    |  4 +--
 src/cmd/8g/galign.c  |  1 -
 src/cmd/8g/ggen.c    |  4 +--
 src/cmd/gc/align.c   | 66 +++++++++++++++++++++++---------------------
 src/cmd/gc/gen.c     |  4 +--
 src/cmd/gc/go.h      |  2 +-
 src/cmd/gc/lex.c     |  2 +-
 src/cmd/gc/reflect.c | 11 ++------
 src/cmd/gc/subr.c    |  3 +-
 12 files changed, 49 insertions(+), 54 deletions(-)

diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 76affbf008..9c8760aea7 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -25,7 +25,6 @@ Typedef	typedefs[] =
 void
 betypeinit(void)
 {
-	maxround = 4;
 	widthptr = 4;
 
 	zprog.link = P;
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index db1837b110..42a89415d3 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -111,12 +111,12 @@ compile(Node *fn)
 	// fill in argument size
 	ptxt->to.type = D_CONST2;
 	ptxt->reg = 0; // flags
-	ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
 
 	// fill in final stack size
 	if(stksize > maxstksize)
 		maxstksize = stksize;
-	ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+	ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
 	maxstksize = 0;
 
 	if(debug['f'])
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 68647e21b4..bdfc9947e8 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -25,7 +25,6 @@ Typedef	typedefs[] =
 void
 betypeinit(void)
 {
-	maxround = 8;
 	widthptr = 8;
 
 	zprog.link = P;
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index ebee6f8103..d9fa1793c6 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -109,11 +109,11 @@ compile(Node *fn)
 	}
 
 	// fill in argument size
-	ptxt->to.offset = rnd(curfn->type->argwid, maxround);
+	ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
 
 	// fill in final stack size
 	ptxt->to.offset <<= 32;
-	ptxt->to.offset |= rnd(stksize+maxarg, maxround);
+	ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
 
 	if(debug['f'])
 		frame(0);
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 346647205a..1c14dfe471 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -25,7 +25,6 @@ Typedef	typedefs[] =
 void
 betypeinit(void)
 {
-	maxround = 4;
 	widthptr = 4;
 
 	zprog.link = P;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 0c3a8260c2..f1461adbeb 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -118,12 +118,12 @@ compile(Node *fn)
 		regopt(ptxt);
 	}
 	// fill in argument size
-	ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
 
 	// fill in final stack size
 	if(stksize > maxstksize)
 		maxstksize = stksize;
-	ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+	ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
 	maxstksize = 0;
 
 	if(debug['f'])
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 57dd3071be..4b6d92e786 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -16,15 +16,9 @@ static int defercalc;
 uint32
 rnd(uint32 o, uint32 r)
 {
-	if(maxround == 0)
+	if(r < 1 || r > 8 || (r&(r-1)) != 0)
 		fatal("rnd");
-
-	if(r > maxround)
-		r = maxround;
-	if(r != 0)
-		while(o%r != 0)
-			o++;
-	return o;
+	return (o+r-1)&~(r-1);
 }
 
 static void
@@ -42,30 +36,25 @@ offmod(Type *t)
 	}
 }
 
-static uint32
-arrayelemwidth(Type *t)
-{
-
-	while(t->etype == TARRAY && t->bound >= 0)
-		t = t->type;
-	return t->width;
-}
-
 static uint32
 widstruct(Type *t, uint32 o, int flag)
 {
 	Type *f;
-	int32 w, m;
-
+	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->align > maxalign)
+			maxalign = f->align;
 		if(f->type->width < 0)
 			fatal("invalid width %lld", f->type->width);
 		w = f->type->width;
-		m = arrayelemwidth(f->type);
-		o = rnd(o, m);
+		o = rnd(o, f->type->align);
 		f->width = o;	// really offset for TFIELD
 		if(f->nname != N) {
 			// this same stackparam logic is in addrescapes
@@ -82,7 +71,8 @@ widstruct(Type *t, uint32 o, int flag)
 	}
 	// final width is rounded
 	if(flag)
-		o = rnd(o, maxround);
+		o = rnd(o, maxalign);
+	t->align = maxalign;
 
 	// type width only includes back to first field's offset
 	if(t->type == T)
@@ -100,7 +90,7 @@ dowidth(Type *t)
 	int lno;
 	Type *t1;
 
-	if(maxround == 0 || widthptr == 0)
+	if(widthptr == 0)
 		fatal("dowidth without betypeinit");
 
 	if(t == T)
@@ -124,6 +114,7 @@ dowidth(Type *t)
 	lno = lineno;
 	lineno = t->lineno;
 	t->width = -2;
+	t->align = 0;
 
 	et = t->etype;
 	switch(et) {
@@ -166,9 +157,11 @@ dowidth(Type *t)
 	case TFLOAT64:
 	case TCOMPLEX64:
 		w = 8;
+		t->align = widthptr;
 		break;
 	case TCOMPLEX128:
 		w = 16;
+		t->align = widthptr;
 		break;
 	case TPTR32:
 		w = 4;
@@ -180,6 +173,7 @@ dowidth(Type *t)
 		break;
 	case TINTER:		// implemented as 2 pointers
 		w = 2*widthptr;
+		t->align = widthptr;
 		offmod(t);
 		break;
 	case TCHAN:		// implemented as pointer
@@ -197,6 +191,7 @@ dowidth(Type *t)
 		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;
@@ -217,6 +212,7 @@ dowidth(Type *t)
 		if(sizeof_String == 0)
 			fatal("early dowidth string");
 		w = sizeof_String;
+		t->align = widthptr;
 		break;
 	case TARRAY:
 		if(t->type == T)
@@ -235,11 +231,13 @@ dowidth(Type *t)
 				yyerror("type %lT larger than address space", t);
 			w = t->bound * t->type->width;
 			if(w == 0)
-				w = maxround;
+				w = 1;
+			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");
@@ -250,9 +248,9 @@ dowidth(Type *t)
 	case TSTRUCT:
 		if(t->funarg)
 			fatal("dowidth fn struct %T", t);
-		w = widstruct(t, 0, 1);
+		w = widstruct(t, 0, widthptr);
 		if(w == 0)
-			w = maxround;
+			w = 1;
 		break;
 
 	case TFUNC:
@@ -271,16 +269,22 @@ dowidth(Type *t)
 		// compute their widths as side-effect.
 		t1 = t->type;
 		w = widstruct(*getthis(t1), 0, 0);
-		w = widstruct(*getinarg(t1), w, 1);
-		w = widstruct(*getoutarg(t1), w, 1);
+		w = widstruct(*getinarg(t1), w, widthptr);
+		w = widstruct(*getoutarg(t1), w, widthptr);
 		t1->argwid = w;
+		t->align = 1;
 		break;
 	}
 
 	// catch all for error cases; avoid divide by zero later
 	if(w == 0)
-		w = maxround;
+		w = 1;
 	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)
@@ -596,10 +600,10 @@ typeinit(void)
 	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, maxround);
+	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, maxround);
+	sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
 
 	dowidth(types[TSTRING]);
 	dowidth(idealstring);
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 65861c7635..8144fabaa8 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -58,7 +58,7 @@ allocparams(void)
 		if(w >= MAXWIDTH)
 			fatal("bad width");
 		stksize += w;
-		stksize = rnd(stksize, w);
+		stksize = rnd(stksize, n->type->align);
 		n->xoffset = -stksize;
 	}
 	lineno = lno;
@@ -664,7 +664,7 @@ tempname(Node *n, Type *t)
 	dowidth(t);
 	w = t->width;
 	stksize += w;
-	stksize = rnd(stksize, w);
+	stksize = rnd(stksize, t->align);
 	n->xoffset = -stksize;
 	n->pun = anyregalloc();
 }
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 5b7e316fe0..4b48ad55ea 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -154,6 +154,7 @@ struct	Type
 	uchar	deferwidth;
 	uchar	broke;
 	uchar	isddd;	// TFIELD is ... argument
+	uchar	align;
 
 	Node*	nod;		// canonical OTYPE node
 	Type*	orig;		// original type (type literal or predefined type)
@@ -751,7 +752,6 @@ EXTERN	int	hasdefer;		// flag that curfn has defer statetment
 
 EXTERN	Node*	curfn;
 
-EXTERN	int	maxround;
 EXTERN	int	widthptr;
 
 EXTERN	Node*	typesw;
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 9dded356d4..0f1acd2fcd 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -194,7 +194,7 @@ main(int argc, char *argv[])
 	fmtinstall('F', Fconv);		// big float numbers
 
 	betypeinit();
-	if(maxround == 0 || widthptr == 0)
+	if(widthptr == 0)
 		fatal("betypeinit failed");
 
 	lexinit();
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 04ff3f0ec8..b31eb51549 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -577,7 +577,6 @@ dcommontype(Sym *s, int ot, Type *t)
 {
 	int i;
 	Sym *s1;
-	Type *elem;
 	char *p;
 
 	dowidth(t);
@@ -605,14 +604,8 @@ dcommontype(Sym *s, int ot, Type *t)
 	ot = duintptr(s, ot, t->width);
 	ot = duint32(s, ot, typehash(t));
 	ot = duint8(s, ot, algtype(t));
-	elem = t;
-	while(elem->etype == TARRAY && elem->bound >= 0)
-		elem = elem->type;
-	i = elem->width;
-	if(i > maxround)
-		i = maxround;
-	ot = duint8(s, ot, i);	// align
-	ot = duint8(s, ot, i);	// fieldAlign
+	ot = duint8(s, ot, t->align);	// align
+	ot = duint8(s, ot, t->align);	// fieldAlign
 	i = kinds[t->etype];
 	if(t->etype == TARRAY && t->bound < 0)
 		i = KindSlice;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 8acf1cdfec..9b6c79d866 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -2309,7 +2309,8 @@ ptrto(Type *t)
 		fatal("ptrto: nil");
 	t1 = typ(tptr);
 	t1->type = t;
-	t1->width = types[tptr]->width;
+	t1->width = widthptr;
+	t1->align = widthptr;
 	return t1;
 }
 
-- 
2.30.9