Skip to content

Commit 672de52

Browse files
committed
go/ssa: simplify Alloc helpers
This change simplifies the helper functions for emitting Alloc instructions: - "add" -> "emit", since they all emit an Alloc instruction. - methods -> functions, since they are logically part of the builder rather than the Function built by it. (No need to enlarge Function's method table.) - there is now one place that creates an Alloc, one place that adds to Function.Locals, and one place that applies instantiations to Var.Type. - emitNew/Local accept a comment parameter. - docs are improved. Change-Id: I6b87ff5ba1f113551d79259de5a5c35ddb3ebc52 Reviewed-on: https://go-review.googlesource.com/c/tools/+/532755 Reviewed-by: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 931c74e commit 672de52

File tree

4 files changed

+79
-78
lines changed

4 files changed

+79
-78
lines changed

go/ssa/builder.go

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,8 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
323323
// treat make([]T, n, m) as new([m]T)[:n]
324324
cap := m.Int64()
325325
at := types.NewArray(ct.Elem(), cap)
326-
alloc := emitNew(fn, at, pos)
327-
alloc.Comment = "makeslice"
328326
v := &Slice{
329-
X: alloc,
327+
X: emitNew(fn, at, pos, "makeslice"),
330328
High: n,
331329
}
332330
v.setPos(pos)
@@ -363,9 +361,7 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
363361
}
364362

365363
case "new":
366-
alloc := emitNew(fn, mustDeref(typ), pos)
367-
alloc.Comment = "new"
368-
return alloc
364+
return emitNew(fn, mustDeref(typ), pos, "new")
369365

370366
case "len", "cap":
371367
// Special case: len or cap of an array or *array is
@@ -432,11 +428,10 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
432428
typ, _ := deref(fn.typeOf(e))
433429
var v *Alloc
434430
if escaping {
435-
v = emitNew(fn, typ, e.Lbrace)
431+
v = emitNew(fn, typ, e.Lbrace, "complit")
436432
} else {
437-
v = fn.addLocal(typ, e.Lbrace)
433+
v = emitLocal(fn, typ, e.Lbrace, "complit")
438434
}
439-
v.Comment = "complit"
440435
var sb storebuf
441436
b.compLit(fn, v, e, true, &sb)
442437
sb.emit(fn)
@@ -1091,9 +1086,8 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
10911086
} else {
10921087
// Replace a suffix of args with a slice containing it.
10931088
at := types.NewArray(vt, int64(len(varargs)))
1094-
a := emitNew(fn, at, token.NoPos)
1089+
a := emitNew(fn, at, token.NoPos, "varargs")
10951090
a.setPos(e.Rparen)
1096-
a.Comment = "varargs"
10971091
for i, arg := range varargs {
10981092
iaddr := &IndexAddr{
10991093
X: a,
@@ -1140,7 +1134,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
11401134
// 1:1 assignment
11411135
for i, id := range spec.Names {
11421136
if !isBlankIdent(id) {
1143-
fn.addLocalForIdent(id)
1137+
emitLocalVar(fn, identVar(fn, id))
11441138
}
11451139
lval := b.addr(fn, id, false) // non-escaping
11461140
b.assign(fn, lval, spec.Values[i], true, nil)
@@ -1151,7 +1145,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
11511145
// Locals are implicitly zero-initialized.
11521146
for _, id := range spec.Names {
11531147
if !isBlankIdent(id) {
1154-
lhs := fn.addLocalForIdent(id)
1148+
lhs := emitLocalVar(fn, identVar(fn, id))
11551149
if fn.debugInfo() {
11561150
emitDebugRef(fn, id, lhs, true)
11571151
}
@@ -1163,7 +1157,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
11631157
tuple := b.exprN(fn, spec.Values[0])
11641158
for i, id := range spec.Names {
11651159
if !isBlankIdent(id) {
1166-
fn.addLocalForIdent(id)
1160+
emitLocalVar(fn, identVar(fn, id))
11671161
lhs := b.addr(fn, id, false) // non-escaping
11681162
lhs.store(fn, emitExtract(fn, tuple, i))
11691163
}
@@ -1183,8 +1177,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
11831177
var lval lvalue = blank{}
11841178
if !isBlankIdent(lhs) {
11851179
if isDef {
1186-
if obj := fn.info.Defs[lhs.(*ast.Ident)]; obj != nil {
1187-
fn.addNamedLocal(obj)
1180+
if obj, ok := fn.info.Defs[lhs.(*ast.Ident)].(*types.Var); ok {
1181+
emitLocalVar(fn, obj)
11881182
isZero[i] = true
11891183
}
11901184
}
@@ -1293,9 +1287,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
12931287
switch t := t.(type) {
12941288
case *types.Slice:
12951289
at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts))
1296-
alloc := emitNew(fn, at, e.Lbrace)
1297-
alloc.Comment = "slicelit"
1298-
array = alloc
1290+
array = emitNew(fn, at, e.Lbrace, "slicelit")
12991291
case *types.Array:
13001292
at = t
13011293
array = addr
@@ -1583,13 +1575,13 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
15831575
}
15841576

15851577
func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) {
1586-
if obj := fn.info.Implicits[cc]; obj != nil {
1578+
if obj, ok := fn.info.Implicits[cc].(*types.Var); ok {
15871579
// In a switch y := x.(type), each case clause
15881580
// implicitly declares a distinct object y.
15891581
// In a single-type case, y has that type.
15901582
// In multi-type cases, 'case nil' and default,
15911583
// y has the same type as the interface operand.
1592-
emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos())
1584+
emitStore(fn, emitLocalVar(fn, obj), x, obj.Pos())
15931585
}
15941586
fn.targets = &targets{
15951587
tail: fn.targets,
@@ -1738,7 +1730,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
17381730

17391731
case *ast.AssignStmt: // x := <-states[state].Chan
17401732
if comm.Tok == token.DEFINE {
1741-
fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
1733+
emitLocalVar(fn, identVar(fn, comm.Lhs[0].(*ast.Ident)))
17421734
}
17431735
x := b.addr(fn, comm.Lhs[0], false) // non-escaping
17441736
v := emitExtract(fn, sel, r)
@@ -1749,7 +1741,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
17491741

17501742
if len(comm.Lhs) == 2 { // x, ok := ...
17511743
if comm.Tok == token.DEFINE {
1752-
fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
1744+
emitLocalVar(fn, identVar(fn, comm.Lhs[1].(*ast.Ident)))
17531745
}
17541746
ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
17551747
ok.store(fn, emitExtract(fn, sel, 1))
@@ -1874,7 +1866,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P
18741866
length = fn.emit(&c)
18751867
}
18761868

1877-
index := fn.addLocal(tInt, token.NoPos)
1869+
index := emitLocal(fn, tInt, token.NoPos, "rangeindex")
18781870
emitStore(fn, index, intConst(-1), pos)
18791871

18801872
loop = fn.newBasicBlock("rangeindex.loop")
@@ -2053,7 +2045,7 @@ func (b *builder) rangeInt(fn *Function, x Value, tk types.Type, pos token.Pos)
20532045
}
20542046

20552047
T := x.Type()
2056-
iter := fn.addLocal(T, token.NoPos)
2048+
iter := emitLocal(fn, T, token.NoPos, "rangeint.iter")
20572049
// x may be unsigned. Avoid initializing x to -1.
20582050

20592051
body := fn.newBasicBlock("rangeint.body")
@@ -2100,10 +2092,10 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
21002092
// using := never redeclares an existing variable; it
21012093
// always creates a new one.
21022094
if tk != nil {
2103-
fn.addLocalForIdent(s.Key.(*ast.Ident))
2095+
emitLocalVar(fn, identVar(fn, s.Key.(*ast.Ident)))
21042096
}
21052097
if tv != nil {
2106-
fn.addLocalForIdent(s.Value.(*ast.Ident))
2098+
emitLocalVar(fn, identVar(fn, s.Value.(*ast.Ident)))
21072099
}
21082100
}
21092101

go/ssa/emit.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,53 @@ import (
1313
"go/types"
1414
)
1515

16-
// emitNew emits to f a new (heap Alloc) instruction allocating an
17-
// object of type typ. pos is the optional source location.
18-
func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc {
19-
v := &Alloc{Heap: true}
16+
// emitAlloc emits to f a new Alloc instruction allocating a variable
17+
// of type typ.
18+
//
19+
// The caller must set Alloc.Heap=true (for an heap-allocated variable)
20+
// or add the Alloc to f.Locals (for a frame-allocated variable).
21+
//
22+
// During building, a variable in f.Locals may have its Heap flag
23+
// set when it is discovered that its address is taken.
24+
// These Allocs are removed from f.Locals at the end.
25+
//
26+
// The builder should generally call one of the emit{New,Local,LocalVar} wrappers instead.
27+
func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
28+
v := &Alloc{Comment: comment}
2029
v.setType(types.NewPointer(typ))
2130
v.setPos(pos)
2231
f.emit(v)
2332
return v
2433
}
2534

35+
// emitNew emits to f a new Alloc instruction heap-allocating a
36+
// variable of type typ. pos is the optional source location.
37+
func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
38+
alloc := emitAlloc(f, typ, pos, comment)
39+
alloc.Heap = true
40+
return alloc
41+
}
42+
43+
// emitLocal creates a local var for (t, pos, comment) and
44+
// emits an Alloc instruction for it.
45+
//
46+
// (Use this function or emitNew for synthetic variables;
47+
// for source-level variables, use emitLocalVar.)
48+
func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc {
49+
local := emitAlloc(f, t, pos, comment)
50+
f.Locals = append(f.Locals, local)
51+
return local
52+
}
53+
54+
// emitLocalVar creates a local var for v and emits an Alloc instruction for it.
55+
// Subsequent calls to f.lookup(v) return it.
56+
// It applies the appropriate generic instantiation to the type.
57+
func emitLocalVar(f *Function, v *types.Var) *Alloc {
58+
alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name())
59+
f.objects[v] = alloc
60+
return alloc
61+
}
62+
2663
// emitLoad emits to f an instruction to load the address addr into a
2764
// new temporary, and returns the value so defined.
2865
func emitLoad(f *Function, addr Value) *UnOp {
@@ -563,7 +600,7 @@ func emitSliceToArray(f *Function, val Value, typ types.Type) Value {
563600
emitIf(f, cond, nilb, nonnilb)
564601
f.currentBlock = nilb
565602

566-
zero := f.addLocal(typ, token.NoPos)
603+
zero := emitLocal(f, f.typ(typ), token.NoPos, "phizero")
567604
emitJump(f, done)
568605
f.currentBlock = nonnilb
569606

go/ssa/func.go

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (f *Function) addParam(name string, typ types.Type, pos token.Pos) *Paramet
133133
return v
134134
}
135135

136-
func (f *Function) addParamObj(obj types.Object) *Parameter {
136+
func (f *Function) addParamObj(obj *types.Var) *Parameter {
137137
name := obj.Name()
138138
if name == "" {
139139
name = fmt.Sprintf("arg%d", len(f.Params))
@@ -146,14 +146,9 @@ func (f *Function) addParamObj(obj types.Object) *Parameter {
146146
// addSpilledParam declares a parameter that is pre-spilled to the
147147
// stack; the function body will load/store the spilled location.
148148
// Subsequent lifting will eliminate spills where possible.
149-
func (f *Function) addSpilledParam(obj types.Object) {
149+
func (f *Function) addSpilledParam(obj *types.Var) {
150150
param := f.addParamObj(obj)
151-
spill := &Alloc{Comment: obj.Name()}
152-
spill.setType(types.NewPointer(param.Type()))
153-
spill.setPos(obj.Pos())
154-
f.objects[obj] = spill
155-
f.Locals = append(f.Locals, spill)
156-
f.emit(spill)
151+
spill := emitLocalVar(f, obj)
157152
f.emit(&Store{Addr: spill, Val: param})
158153
}
159154

@@ -177,7 +172,7 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
177172
if recv != nil {
178173
for _, field := range recv.List {
179174
for _, n := range field.Names {
180-
f.addSpilledParam(f.info.Defs[n])
175+
f.addSpilledParam(identVar(f, n))
181176
}
182177
// Anonymous receiver? No need to spill.
183178
if field.Names == nil {
@@ -191,7 +186,7 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
191186
n := len(f.Params) // 1 if has recv, 0 otherwise
192187
for _, field := range functype.Params.List {
193188
for _, n := range field.Names {
194-
f.addSpilledParam(f.info.Defs[n])
189+
f.addSpilledParam(identVar(f, n))
195190
}
196191
// Anonymous parameter? No need to spill.
197192
if field.Names == nil {
@@ -205,7 +200,8 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
205200
for _, field := range functype.Results.List {
206201
// Implicit "var" decl of locals for named results.
207202
for _, n := range field.Names {
208-
f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
203+
namedResult := emitLocalVar(f, identVar(f, n))
204+
f.namedResults = append(f.namedResults, namedResult)
209205
}
210206
}
211207
}
@@ -388,32 +384,6 @@ func (f *Function) debugInfo() bool {
388384
return p != nil && p.debug
389385
}
390386

391-
// addNamedLocal creates a local variable, adds it to function f and
392-
// returns it. Its name and type are taken from obj. Subsequent
393-
// calls to f.lookup(obj) will return the same local.
394-
func (f *Function) addNamedLocal(obj types.Object) *Alloc {
395-
l := f.addLocal(obj.Type(), obj.Pos())
396-
l.Comment = obj.Name()
397-
f.objects[obj] = l
398-
return l
399-
}
400-
401-
func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
402-
return f.addNamedLocal(f.info.Defs[id])
403-
}
404-
405-
// addLocal creates an anonymous local variable of type typ, adds it
406-
// to function f and returns it. pos is the optional source location.
407-
func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc {
408-
typ = f.typ(typ)
409-
v := &Alloc{}
410-
v.setType(types.NewPointer(typ))
411-
v.setPos(pos)
412-
f.Locals = append(f.Locals, v)
413-
f.emit(v)
414-
return v
415-
}
416-
417387
// lookup returns the address of the named variable identified by obj
418388
// that is local to function f or one of its enclosing functions.
419389
// If escaping, the reference comes from a potentially escaping pointer
@@ -704,3 +674,8 @@ func (n extentNode) End() token.Pos { return n[1] }
704674
// function. Otherwise, it is an opaque Node providing only position
705675
// information; this avoids pinning the AST in memory.
706676
func (f *Function) Syntax() ast.Node { return f.syntax }
677+
678+
// identVar returns the variable defined by id.
679+
func identVar(fn *Function, id *ast.Ident) *types.Var {
680+
return fn.info.Defs[id].(*types.Var)
681+
}

go/ssa/ssa.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ type Function struct {
318318
Prog *Program // enclosing program
319319
Params []*Parameter // function parameters; for methods, includes receiver
320320
FreeVars []*FreeVar // free variables whose values must be supplied by closure
321-
Locals []*Alloc // local variables of this function
321+
Locals []*Alloc // frame-allocated variables of this function
322322
Blocks []*BasicBlock // basic blocks of the function; nil => external
323323
Recover *BasicBlock // optional; control transfers here after recovered panic
324324
AnonFuncs []*Function // anonymous functions directly beneath this one
@@ -484,15 +484,12 @@ type Builtin struct {
484484
// type of the allocated variable is actually
485485
// Type().Underlying().(*types.Pointer).Elem().
486486
//
487-
// If Heap is false, Alloc allocates space in the function's
488-
// activation record (frame); we refer to an Alloc(Heap=false) as a
489-
// "local" alloc. Each local Alloc returns the same address each time
490-
// it is executed within the same activation; the space is
491-
// re-initialized to zero.
487+
// If Heap is false, Alloc zero-initializes the same local variable in
488+
// the call frame and returns its address; in this case the Alloc must
489+
// be present in Function.Locals. We call this a "local" alloc.
492490
//
493-
// If Heap is true, Alloc allocates space in the heap; we
494-
// refer to an Alloc(Heap=true) as a "new" alloc. Each new Alloc
495-
// returns a different address each time it is executed.
491+
// If Heap is true, Alloc allocates a new zero-initialized variable
492+
// each time the instruction is executed. We call this a "new" alloc.
496493
//
497494
// When Alloc is applied to a channel, map or slice type, it returns
498495
// the address of an uninitialized (nil) reference of that kind; store

0 commit comments

Comments
 (0)