2011-06-02 10:48:17 -06:00
|
|
|
// Copyright 2011 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.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2011-06-09 16:08:57 -06:00
|
|
|
#include "gg.h"
|
|
|
|
#include "opt.h"
|
2011-06-09 16:02:34 -06:00
|
|
|
|
2011-09-06 08:24:21 -06:00
|
|
|
static void allocauto(Prog* p);
|
2011-06-02 10:48:17 -06:00
|
|
|
|
|
|
|
void
|
|
|
|
compile(Node *fn)
|
|
|
|
{
|
|
|
|
Plist *pl;
|
|
|
|
Node nod1, *n;
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
Prog *plocals, *ptxt, *p, *p1;
|
2011-06-02 10:48:17 -06:00
|
|
|
int32 lno;
|
|
|
|
Type *t;
|
|
|
|
Iter save;
|
2011-06-09 16:02:34 -06:00
|
|
|
vlong oldstksize;
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
NodeList *l;
|
2011-06-02 10:48:17 -06:00
|
|
|
|
|
|
|
if(newproc == N) {
|
|
|
|
newproc = sysfunc("newproc");
|
|
|
|
deferproc = sysfunc("deferproc");
|
|
|
|
deferreturn = sysfunc("deferreturn");
|
|
|
|
panicindex = sysfunc("panicindex");
|
|
|
|
panicslice = sysfunc("panicslice");
|
|
|
|
throwreturn = sysfunc("throwreturn");
|
|
|
|
}
|
|
|
|
|
2012-12-22 14:46:46 -07:00
|
|
|
lno = setlineno(fn);
|
|
|
|
|
|
|
|
if(fn->nbody == nil) {
|
|
|
|
if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0)
|
|
|
|
yyerror("missing function body", fn);
|
|
|
|
goto ret;
|
|
|
|
}
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
saveerrors();
|
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
// set up domain for labels
|
|
|
|
clearlabels();
|
|
|
|
|
|
|
|
curfn = fn;
|
|
|
|
dowidth(curfn->type);
|
|
|
|
|
|
|
|
if(curfn->type->outnamed) {
|
|
|
|
// add clearing of the output parameters
|
|
|
|
t = structfirst(&save, getoutarg(curfn->type));
|
|
|
|
while(t != T) {
|
|
|
|
if(t->nname != N) {
|
|
|
|
n = nod(OAS, t->nname, N);
|
|
|
|
typecheck(&n, Etop);
|
|
|
|
curfn->nbody = concat(list1(n), curfn->nbody);
|
|
|
|
}
|
|
|
|
t = structnext(&save);
|
|
|
|
}
|
|
|
|
}
|
2012-01-25 15:53:50 -07:00
|
|
|
|
|
|
|
order(curfn);
|
|
|
|
if(nerrors != 0)
|
|
|
|
goto ret;
|
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
hasdefer = 0;
|
|
|
|
walk(curfn);
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nerrors != 0)
|
2011-06-02 10:48:17 -06:00
|
|
|
goto ret;
|
2013-01-06 20:47:39 -07:00
|
|
|
if(flag_race)
|
2012-10-02 00:05:46 -06:00
|
|
|
racewalk(curfn);
|
|
|
|
if(nerrors != 0)
|
|
|
|
goto ret;
|
2011-06-02 10:48:17 -06:00
|
|
|
|
|
|
|
continpc = P;
|
|
|
|
breakpc = P;
|
|
|
|
|
|
|
|
pl = newplist();
|
|
|
|
pl->name = curfn->nname;
|
|
|
|
|
|
|
|
setlineno(curfn);
|
|
|
|
|
|
|
|
nodconst(&nod1, types[TINT32], 0);
|
2011-06-17 13:25:05 -06:00
|
|
|
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
|
2011-12-12 20:22:09 -07:00
|
|
|
if(fn->dupok)
|
|
|
|
ptxt->TEXTFLAG = DUPOK;
|
2013-02-21 15:01:13 -07:00
|
|
|
afunclit(&ptxt->from, curfn->nname);
|
2011-06-02 10:48:17 -06:00
|
|
|
|
|
|
|
ginit();
|
cmd/gc, cmd/ld: struct field tracking
This is an experiment in static analysis of Go programs
to understand which struct fields a program might use.
It is not part of the Go language specification, it must
be enabled explicitly when building the toolchain,
and it may be removed at any time.
After building the toolchain with GOEXPERIMENT=fieldtrack,
a specific field can be marked for tracking by including
`go:"track"` in the field tag:
package pkg
type T struct {
F int `go:"track"`
G int // untracked
}
To simplify usage, only named struct types can have
tracked fields, and only exported fields can be tracked.
The implementation works by making each function begin
with a sequence of no-op USEFIELD instructions declaring
which tracked fields are accessed by a specific function.
After the linker's dead code elimination removes unused
functions, the fields referred to by the remaining
USEFIELD instructions are the ones reported as used by
the binary.
The -k option to the linker specifies the fully qualified
symbol name (such as my/pkg.list) of a string variable that
should be initialized with the field tracking information
for the program. The field tracking string is a sequence
of lines, each terminated by a \n and describing a single
tracked field referred to by the program. Each line is made
up of one or more tab-separated fields. The first field is
the name of the tracked field, fully qualified, as in
"my/pkg.T.F". Subsequent fields give a shortest path of
reverse references from that field to a global variable or
function, corresponding to one way in which the program
might reach that field.
A common source of false positives in field tracking is
types with large method sets, because a reference to the
type descriptor carries with it references to all methods.
To address this problem, the CL also introduces a comment
annotation
//go:nointerface
that marks an upcoming method declaration as unavailable
for use in satisfying interfaces, both statically and
dynamically. Such a method is also invisible to package
reflect.
Again, all of this is disabled by default. It only turns on
if you have GOEXPERIMENT=fieldtrack set during make.bash.
R=iant, ken
CC=golang-dev
https://golang.org/cl/6749064
2012-11-01 22:17:21 -06:00
|
|
|
|
cmd/5g, cmd/5l, cmd/6l, cmd/8l, cmd/gc, cmd/ld, runtime: accurate args and locals information
Previously, the func structure contained an inaccurate value for
the args member and a 0 value for the locals member.
This change populates the func structure with args and locals
values computed by the compiler. The number of args was
already available in the ATEXT instruction. The number of
locals is now passed through in the new ALOCALS instruction.
This change also switches the unit of args and locals to be
bytes, just like the frame member, instead of 32-bit words.
R=golang-dev, bradfitz, cshapiro, dave, rsc
CC=golang-dev
https://golang.org/cl/7399045
2013-02-21 13:52:26 -07:00
|
|
|
plocals = gins(ALOCALS, N, N);
|
|
|
|
|
cmd/gc, cmd/ld: struct field tracking
This is an experiment in static analysis of Go programs
to understand which struct fields a program might use.
It is not part of the Go language specification, it must
be enabled explicitly when building the toolchain,
and it may be removed at any time.
After building the toolchain with GOEXPERIMENT=fieldtrack,
a specific field can be marked for tracking by including
`go:"track"` in the field tag:
package pkg
type T struct {
F int `go:"track"`
G int // untracked
}
To simplify usage, only named struct types can have
tracked fields, and only exported fields can be tracked.
The implementation works by making each function begin
with a sequence of no-op USEFIELD instructions declaring
which tracked fields are accessed by a specific function.
After the linker's dead code elimination removes unused
functions, the fields referred to by the remaining
USEFIELD instructions are the ones reported as used by
the binary.
The -k option to the linker specifies the fully qualified
symbol name (such as my/pkg.list) of a string variable that
should be initialized with the field tracking information
for the program. The field tracking string is a sequence
of lines, each terminated by a \n and describing a single
tracked field referred to by the program. Each line is made
up of one or more tab-separated fields. The first field is
the name of the tracked field, fully qualified, as in
"my/pkg.T.F". Subsequent fields give a shortest path of
reverse references from that field to a global variable or
function, corresponding to one way in which the program
might reach that field.
A common source of false positives in field tracking is
types with large method sets, because a reference to the
type descriptor carries with it references to all methods.
To address this problem, the CL also introduces a comment
annotation
//go:nointerface
that marks an upcoming method declaration as unavailable
for use in satisfying interfaces, both statically and
dynamically. Such a method is also invisible to package
reflect.
Again, all of this is disabled by default. It only turns on
if you have GOEXPERIMENT=fieldtrack set during make.bash.
R=iant, ken
CC=golang-dev
https://golang.org/cl/6749064
2012-11-01 22:17:21 -06:00
|
|
|
for(t=curfn->paramfld; t; t=t->down)
|
|
|
|
gtrack(tracksym(t->type));
|
|
|
|
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
for(l=fn->dcl; l; l=l->next) {
|
|
|
|
n = l->n;
|
|
|
|
if(n->op != ONAME) // might be OTYPE or OLITERAL
|
|
|
|
continue;
|
|
|
|
switch(n->class) {
|
|
|
|
case PAUTO:
|
|
|
|
case PPARAM:
|
|
|
|
case PPARAMOUT:
|
|
|
|
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
|
|
|
|
p = gins(ATYPE, l->n, &nod1);
|
|
|
|
p->from.gotype = ngotype(l->n);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
genlist(curfn->enter);
|
|
|
|
|
|
|
|
retpc = nil;
|
|
|
|
if(hasdefer || curfn->exit) {
|
|
|
|
p1 = gjmp(nil);
|
|
|
|
retpc = gjmp(nil);
|
|
|
|
patch(p1, pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
genlist(curfn->nbody);
|
|
|
|
gclean();
|
|
|
|
checklabels();
|
|
|
|
if(nerrors != 0)
|
|
|
|
goto ret;
|
|
|
|
if(curfn->endlineno)
|
|
|
|
lineno = curfn->endlineno;
|
|
|
|
|
|
|
|
if(curfn->type->outtuple != 0)
|
|
|
|
ginscall(throwreturn, 0);
|
|
|
|
|
|
|
|
if(retpc)
|
|
|
|
patch(retpc, pc);
|
|
|
|
ginit();
|
|
|
|
if(hasdefer)
|
|
|
|
ginscall(deferreturn, 0);
|
|
|
|
if(curfn->exit)
|
|
|
|
genlist(curfn->exit);
|
|
|
|
gclean();
|
|
|
|
if(nerrors != 0)
|
|
|
|
goto ret;
|
cmd/gc, cmd/ld: struct field tracking
This is an experiment in static analysis of Go programs
to understand which struct fields a program might use.
It is not part of the Go language specification, it must
be enabled explicitly when building the toolchain,
and it may be removed at any time.
After building the toolchain with GOEXPERIMENT=fieldtrack,
a specific field can be marked for tracking by including
`go:"track"` in the field tag:
package pkg
type T struct {
F int `go:"track"`
G int // untracked
}
To simplify usage, only named struct types can have
tracked fields, and only exported fields can be tracked.
The implementation works by making each function begin
with a sequence of no-op USEFIELD instructions declaring
which tracked fields are accessed by a specific function.
After the linker's dead code elimination removes unused
functions, the fields referred to by the remaining
USEFIELD instructions are the ones reported as used by
the binary.
The -k option to the linker specifies the fully qualified
symbol name (such as my/pkg.list) of a string variable that
should be initialized with the field tracking information
for the program. The field tracking string is a sequence
of lines, each terminated by a \n and describing a single
tracked field referred to by the program. Each line is made
up of one or more tab-separated fields. The first field is
the name of the tracked field, fully qualified, as in
"my/pkg.T.F". Subsequent fields give a shortest path of
reverse references from that field to a global variable or
function, corresponding to one way in which the program
might reach that field.
A common source of false positives in field tracking is
types with large method sets, because a reference to the
type descriptor carries with it references to all methods.
To address this problem, the CL also introduces a comment
annotation
//go:nointerface
that marks an upcoming method declaration as unavailable
for use in satisfying interfaces, both statically and
dynamically. Such a method is also invisible to package
reflect.
Again, all of this is disabled by default. It only turns on
if you have GOEXPERIMENT=fieldtrack set during make.bash.
R=iant, ken
CC=golang-dev
https://golang.org/cl/6749064
2012-11-01 22:17:21 -06:00
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
pc->as = ARET; // overwrite AEND
|
|
|
|
pc->lineno = lineno;
|
|
|
|
|
|
|
|
if(!debug['N'] || debug['R'] || debug['P']) {
|
|
|
|
regopt(ptxt);
|
|
|
|
}
|
|
|
|
|
2011-06-09 16:02:34 -06:00
|
|
|
oldstksize = stksize;
|
2011-09-06 08:24:21 -06:00
|
|
|
allocauto(ptxt);
|
cmd/5g, cmd/5l, cmd/6l, cmd/8l, cmd/gc, cmd/ld, runtime: accurate args and locals information
Previously, the func structure contained an inaccurate value for
the args member and a 0 value for the locals member.
This change populates the func structure with args and locals
values computed by the compiler. The number of args was
already available in the ATEXT instruction. The number of
locals is now passed through in the new ALOCALS instruction.
This change also switches the unit of args and locals to be
bytes, just like the frame member, instead of 32-bit words.
R=golang-dev, bradfitz, cshapiro, dave, rsc
CC=golang-dev
https://golang.org/cl/7399045
2013-02-21 13:52:26 -07:00
|
|
|
|
2013-02-22 16:32:54 -07:00
|
|
|
plocals->to.type = D_CONST;
|
cmd/5g, cmd/5l, cmd/6l, cmd/8l, cmd/gc, cmd/ld, runtime: accurate args and locals information
Previously, the func structure contained an inaccurate value for
the args member and a 0 value for the locals member.
This change populates the func structure with args and locals
values computed by the compiler. The number of args was
already available in the ATEXT instruction. The number of
locals is now passed through in the new ALOCALS instruction.
This change also switches the unit of args and locals to be
bytes, just like the frame member, instead of 32-bit words.
R=golang-dev, bradfitz, cshapiro, dave, rsc
CC=golang-dev
https://golang.org/cl/7399045
2013-02-21 13:52:26 -07:00
|
|
|
plocals->to.offset = stksize;
|
|
|
|
|
2011-06-09 16:02:34 -06:00
|
|
|
if(0)
|
2011-09-06 08:24:21 -06:00
|
|
|
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
|
2011-06-09 16:02:34 -06:00
|
|
|
|
2012-01-10 03:19:22 -07:00
|
|
|
setlineno(curfn);
|
2012-02-13 00:07:31 -07:00
|
|
|
if((int64)stksize+maxarg > (1ULL<<31))
|
2012-01-10 03:19:22 -07:00
|
|
|
yyerror("stack frame too large (>2GB)");
|
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
defframe(ptxt);
|
|
|
|
|
2011-06-09 16:02:34 -06:00
|
|
|
if(0)
|
2011-06-02 10:48:17 -06:00
|
|
|
frame(0);
|
|
|
|
|
|
|
|
ret:
|
|
|
|
lineno = lno;
|
|
|
|
}
|
2011-06-09 16:02:34 -06:00
|
|
|
|
|
|
|
|
|
|
|
// Sort the list of stack variables. autos after anything else,
|
|
|
|
// within autos, unused after used, and within used on reverse alignment.
|
|
|
|
// non-autos sort on offset.
|
|
|
|
static int
|
|
|
|
cmpstackvar(Node *a, Node *b)
|
|
|
|
{
|
|
|
|
if (a->class != b->class)
|
|
|
|
return (a->class == PAUTO) ? 1 : -1;
|
|
|
|
if (a->class != PAUTO)
|
|
|
|
return a->xoffset - b->xoffset;
|
|
|
|
if ((a->used == 0) != (b->used == 0))
|
|
|
|
return b->used - a->used;
|
|
|
|
return b->type->align - a->type->align;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-06-14 09:03:37 -06:00
|
|
|
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
|
2011-06-09 16:02:34 -06:00
|
|
|
static void
|
2011-09-06 08:24:21 -06:00
|
|
|
allocauto(Prog* ptxt)
|
2011-06-09 16:02:34 -06:00
|
|
|
{
|
|
|
|
NodeList *ll;
|
|
|
|
Node* n;
|
2011-07-18 05:09:28 -06:00
|
|
|
vlong w;
|
2011-06-09 16:02:34 -06:00
|
|
|
|
2011-09-06 08:24:21 -06:00
|
|
|
if(curfn->dcl == nil)
|
2011-06-09 16:02:34 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Mark the PAUTO's unused.
|
|
|
|
for(ll=curfn->dcl; ll != nil; ll=ll->next)
|
2011-06-14 09:03:37 -06:00
|
|
|
if (ll->n->class == PAUTO)
|
2011-06-09 16:02:34 -06:00
|
|
|
ll->n->used = 0;
|
|
|
|
|
2011-06-14 09:03:37 -06:00
|
|
|
markautoused(ptxt);
|
2011-06-09 16:02:34 -06:00
|
|
|
|
|
|
|
listsort(&curfn->dcl, cmpstackvar);
|
|
|
|
|
|
|
|
// Unused autos are at the end, chop 'em off.
|
|
|
|
ll = curfn->dcl;
|
|
|
|
n = ll->n;
|
|
|
|
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
2013-02-27 11:47:14 -07:00
|
|
|
// No locals used at all
|
2011-06-09 16:02:34 -06:00
|
|
|
curfn->dcl = nil;
|
|
|
|
stksize = 0;
|
2013-02-27 11:47:14 -07:00
|
|
|
fixautoused(ptxt);
|
2011-06-09 16:02:34 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
|
|
|
|
n = ll->next->n;
|
|
|
|
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
|
|
|
ll->next = nil;
|
|
|
|
curfn->dcl->end = ll;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reassign stack offsets of the locals that are still there.
|
|
|
|
stksize = 0;
|
|
|
|
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
|
|
|
|
n = ll->n;
|
|
|
|
if (n->class != PAUTO || n->op != ONAME)
|
|
|
|
continue;
|
|
|
|
|
2011-09-06 08:24:21 -06:00
|
|
|
dowidth(n->type);
|
2011-06-09 16:02:34 -06:00
|
|
|
w = n->type->width;
|
2011-07-27 16:55:30 -06:00
|
|
|
if(w >= MAXWIDTH || w < 0)
|
2011-06-09 16:02:34 -06:00
|
|
|
fatal("bad width");
|
|
|
|
stksize += w;
|
|
|
|
stksize = rnd(stksize, n->type->align);
|
|
|
|
if(thechar == '5')
|
|
|
|
stksize = rnd(stksize, widthptr);
|
|
|
|
n->stkdelta = -stksize - n->xoffset;
|
|
|
|
}
|
|
|
|
|
2011-06-14 09:03:37 -06:00
|
|
|
fixautoused(ptxt);
|
2011-06-09 16:02:34 -06:00
|
|
|
|
|
|
|
// The debug information needs accurate offsets on the symbols.
|
|
|
|
for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
|
|
|
|
if (ll->n->class != PAUTO || ll->n->op != ONAME)
|
|
|
|
continue;
|
|
|
|
ll->n->xoffset += ll->n->stkdelta;
|
|
|
|
ll->n->stkdelta = 0;
|
|
|
|
}
|
|
|
|
}
|