From 4f558e93026d8de1761b9adc74b4a8b9b0e695a8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 27 Aug 2014 11:32:17 -0400 Subject: cmd/cc, runtime: convert C compilers to use Go calling convention To date, the C compilers and Go compilers differed only in how values were returned from functions. This made it difficult to call Go from C or C from Go if return values were involved. It also made assembly called from Go and assembly called from C different. This CL changes the C compiler to use the Go conventions, passing results on the stack, after the arguments. [Exception: this does not apply to C ... functions, because you can't know where on the stack the arguments end.] By doing this, the CL makes it possible to rewrite C functions into Go one at a time, without worrying about which languages call that function or which languages it calls. This CL also updates all the assembly files in package runtime to use the new conventions. Argument references of the form 40(SP) have been rewritten to the form name+10(FP) instead, and there are now Go func prototypes for every assembly function called from C or Go. This means that 'go vet runtime' checks effectively every assembly function, and go vet's output was used to automate the bulk of the conversion. Some functions, like seek and nsec on Plan 9, needed to be rewritten. Many assembly routines called from C were reading arguments incorrectly, using MOVL instead of MOVQ or vice versa, especially on the less used systems like openbsd. These were found by go vet and have been corrected too. If we're lucky, this may reduce flakiness on those systems. Tested on: darwin/386 darwin/amd64 linux/arm linux/386 linux/amd64 If this breaks another system, the bug is almost certainly in the sys_$GOOS_$GOARCH.s file, since the rest of the CL is tested by the combination of the above systems. LGTM=dvyukov, iant R=golang-codereviews, 0intro, dave, alex.brainman, dvyukov, iant CC=golang-codereviews, josharian, r https://codereview.appspot.com/135830043 --- src/cmd/cc/cc.h | 2 +- src/cmd/cc/dcl.c | 3 ++- src/cmd/cc/pgen.c | 44 +++++++++++++++++++++++++++++++++----------- 3 files changed, 36 insertions(+), 13 deletions(-) (limited to 'src/cmd/cc') diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index c8aac1253..1dae5acd9 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -794,7 +794,7 @@ void xcom(Node*); int32 exreg(Type*); int32 align(int32, Type*, int, int32*); int32 maxround(int32, int32); -int hasdotdotdot(void); +int hasdotdotdot(Type*); void linkarchinit(void); extern schar ewidth[]; diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index 051a6c0a7..7cda9f924 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -697,7 +697,8 @@ argmark(Node *n, int pass) { Type *t; - autoffset = align(0, thisfn->link, Aarg0, nil); + if(hasdotdotdot(thisfn->link)) + autoffset = align(0, thisfn->link, Aarg0, nil); stkoff = 0; for(; n->left != Z; n = n->left) { if(n->op != OFUNC || n->left->op != ONAME) diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 0ee13787f..53410a11a 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -56,24 +56,24 @@ makefuncdatasym(char *namefmt, int64 funcdatakind) } int -hasdotdotdot(void) +hasdotdotdot(Type *t) { - Type *t; - - for(t=thisfn->down; t!=T; t=t->down) + for(t=t->down; t!=T; t=t->down) if(t->etype == TDOT) return 1; return 0; } vlong -argsize(void) +argsize(int doret) { Type *t; int32 s; //print("t=%T\n", thisfn); - s = align(0, thisfn->link, Aarg0, nil); + s = 0; + if(hasdotdotdot(thisfn)) + s = align(s, thisfn->link, Aarg0, nil); for(t=thisfn->down; t!=T; t=t->down) { switch(t->etype) { case TVOID: @@ -93,6 +93,14 @@ argsize(void) s = (s+7) & ~7; else s = (s+3) & ~3; + if(doret && thisfn->link->etype != TVOID) { + s = align(s, thisfn->link, Aarg1, nil); + s = align(s, thisfn->link, Aarg2, nil); + if(thechar == '6') + s = (s+7) & ~7; + else + s = (s+3) & ~3; + } return s; } @@ -129,7 +137,7 @@ codgen(Node *n, Node *nn) * generate funcdata symbol for this function. * data is filled in at the end of codgen(). */ - isvarargs = hasdotdotdot(); + isvarargs = hasdotdotdot(thisfn); gcargs = nil; if(!isvarargs) gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); @@ -212,7 +220,7 @@ supgen(Node *n) void gen(Node *n) { - Node *l, nod; + Node *l, nod, nod1; Prog *sp, *spc, *spb; Case *cn; long sbc, scc; @@ -273,14 +281,26 @@ loop: gbranch(ORETURN); break; } + if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) { + regret(&nod, n, thisfn, 2); + sugen(l, &nod, n->type->width); + noretval(3); + gbranch(ORETURN); + break; + } if(typecmplx[n->type->etype]) { sugen(l, nodret, n->type->width); noretval(3); gbranch(ORETURN); break; } - regret(&nod, n); + regret(&nod1, n, thisfn, 2); + nod = nod1; + if(nod.op != OREGISTER) + regalloc(&nod, n, Z); cgen(l, &nod); + if(nod1.op != OREGISTER) + gmove(&nod, &nod1); regfree(&nod); if(typefd[n->type->etype]) noretval(1); @@ -729,9 +749,11 @@ dumpgcargs(Type *fn, Sym *sym) symoffset = 0; gextern(sym, nodconst(1), symoffset, 4); symoffset += 4; - argbytes = (argsize() + ewidth[TIND] - 1); + argbytes = (argsize(1) + ewidth[TIND] - 1); bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); - argoffset = align(0, fn->link, Aarg0, nil); + argoffset = 0; + if(hasdotdotdot(thisfn)) + argoffset = align(0, fn->link, Aarg0, nil); if(argoffset > 0) { // The C calling convention returns structs by copying them to a // location pointed to by a hidden first argument. This first -- cgit v1.2.1