LEFT | RIGHT |
(no file at all) | |
1 package ssa | 1 package ssa |
2 | 2 |
3 // This file defines the SSA builder. | 3 // This file defines the SSA builder. |
4 // | 4 // |
5 // The builder has two phases, CREATE and BUILD. In the CREATE | 5 // The builder has two phases, CREATE and BUILD. In the CREATE |
6 // phase, all packages are constructed and type-checked and | 6 // phase, all packages are constructed and type-checked and |
7 // definitions of all package members are created, method-sets are | 7 // definitions of all package members are created, method-sets are |
8 // computed, and bridge methods are synthesized. The create phase | 8 // computed, and bridge methods are synthesized. The create phase |
9 // proceeds in topological order over the import dependency graph, | 9 // proceeds in topological order over the import dependency graph, |
10 // initiated by client calls to CreatePackage. | 10 // initiated by client calls to CreatePackage. |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 | 115 |
116 // BuilderMode is a bitmask of options for diagnostics and checking. | 116 // BuilderMode is a bitmask of options for diagnostics and checking. |
117 type BuilderMode uint | 117 type BuilderMode uint |
118 | 118 |
119 const ( | 119 const ( |
120 LogPackages BuilderMode = 1 << iota // Dump package inventory t
o stderr | 120 LogPackages BuilderMode = 1 << iota // Dump package inventory t
o stderr |
121 LogFunctions // Dump function SSA code t
o stderr | 121 LogFunctions // Dump function SSA code t
o stderr |
122 LogSource // Show source locations as
SSA builder progresses | 122 LogSource // Show source locations as
SSA builder progresses |
123 SanityCheckFunctions // Perform sanity checking
of function bodies | 123 SanityCheckFunctions // Perform sanity checking
of function bodies |
124 UseGCImporter // Ignore SourceLoader; use
gc-compiled object code for all imports | 124 UseGCImporter // Ignore SourceLoader; use
gc-compiled object code for all imports |
| 125 NaiveForm // Build naïve SSA form: do
n't replace local loads/stores with registers |
125 ) | 126 ) |
126 | 127 |
127 // NewBuilder creates and returns a new SSA builder. | 128 // NewBuilder creates and returns a new SSA builder. |
128 // | 129 // |
129 // mode is a bitfield of options controlling verbosity, logging and | 130 // mode is a bitfield of options controlling verbosity, logging and |
130 // additional sanity checks. | 131 // additional sanity checks. |
131 // | 132 // |
132 // loader is a SourceLoader function that finds, loads and parses Go | 133 // loader is a SourceLoader function that finds, loads and parses Go |
133 // source files for a given import path. (It is ignored if the mode | 134 // source files for a given import path. (It is ignored if the mode |
134 // bits include UseGCImporter.) | 135 // bits include UseGCImporter.) |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 } | 374 } |
374 | 375 |
375 // The edge from e.Y to done carries the value of e.Y. | 376 // The edge from e.Y to done carries the value of e.Y. |
376 fn.currentBlock = rhs | 377 fn.currentBlock = rhs |
377 edges = append(edges, b.expr(fn, e.Y)) | 378 edges = append(edges, b.expr(fn, e.Y)) |
378 emitJump(fn, done) | 379 emitJump(fn, done) |
379 fn.currentBlock = done | 380 fn.currentBlock = done |
380 | 381 |
381 // TODO(adonovan): do we need emitConv on each edge? | 382 // TODO(adonovan): do we need emitConv on each edge? |
382 // Test with named boolean types. | 383 // Test with named boolean types. |
383 » phi := &Phi{Edges: edges} | 384 » phi := &Phi{Edges: edges, Comment: e.Op.String()} |
384 phi.Type_ = phi.Edges[0].Type() | 385 phi.Type_ = phi.Edges[0].Type() |
385 return done.emit(phi) | 386 return done.emit(phi) |
386 } | 387 } |
387 | 388 |
388 // exprN lowers a multi-result expression e to SSA form, emitting code | 389 // exprN lowers a multi-result expression e to SSA form, emitting code |
389 // to fn and returning a single Value whose type is a *types.Results | 390 // to fn and returning a single Value whose type is a *types.Results |
390 // (tuple). The caller must access the components via Extract. | 391 // (tuple). The caller must access the components via Extract. |
391 // | 392 // |
392 // Multi-result expressions include CallExprs in a multi-value | 393 // Multi-result expressions include CallExprs in a multi-value |
393 // assignment or return statement, and "value,ok" uses of | 394 // assignment or return statement, and "value,ok" uses of |
(...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1333 if !b.nTo1Vars[spec] { | 1334 if !b.nTo1Vars[spec] { |
1334 b.nTo1Vars[spec] = true | 1335 b.nTo1Vars[spec] = true |
1335 if b.mode&LogSource != 0 { | 1336 if b.mode&LogSource != 0 { |
1336 fmt.Fprintln(os.Stderr, "build globals", spec.Na
mes) // ugly... | 1337 fmt.Fprintln(os.Stderr, "build globals", spec.Na
mes) // ugly... |
1337 } | 1338 } |
1338 tuple := b.exprN(init, spec.Values[0]) | 1339 tuple := b.exprN(init, spec.Values[0]) |
1339 rtypes := tuple.Type().(*types.Result).Values | 1340 rtypes := tuple.Type().(*types.Result).Values |
1340 for i, id := range spec.Names { | 1341 for i, id := range spec.Names { |
1341 if !isBlankIdent(id) { | 1342 if !isBlankIdent(id) { |
1342 g := b.globals[b.obj(id)].(*Global) | 1343 g := b.globals[b.obj(id)].(*Global) |
1343 » » » » » g.spec = nil // just an optimisation | 1344 » » » » » g.spec = nil // just an optimization |
1344 emitStore(init, g, | 1345 emitStore(init, g, |
1345 emitExtract(init, tuple, i, rtyp
es[i].Type)) | 1346 emitExtract(init, tuple, i, rtyp
es[i].Type)) |
1346 } | 1347 } |
1347 } | 1348 } |
1348 } | 1349 } |
1349 } | 1350 } |
1350 } | 1351 } |
1351 | 1352 |
1352 // localValueSpec emits to fn code to define all of the vars in the | 1353 // localValueSpec emits to fn code to define all of the vars in the |
1353 // function-local ValueSpec, spec. | 1354 // function-local ValueSpec, spec. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1412 } | 1413 } |
1413 } | 1414 } |
1414 lval = b.addr(fn, lhs, false) // non-escaping | 1415 lval = b.addr(fn, lhs, false) // non-escaping |
1415 } | 1416 } |
1416 lvals = append(lvals, lval) | 1417 lvals = append(lvals, lval) |
1417 } | 1418 } |
1418 if len(lhss) == len(rhss) { | 1419 if len(lhss) == len(rhss) { |
1419 // e.g. x, y = f(), g() | 1420 // e.g. x, y = f(), g() |
1420 if len(lhss) == 1 { | 1421 if len(lhss) == 1 { |
1421 // x = type{...} | 1422 // x = type{...} |
1422 » » » // Optimisation: in-place construction | 1423 » » » // Optimization: in-place construction |
1423 // of composite literals. | 1424 // of composite literals. |
1424 b.exprInPlace(fn, lvals[0], rhss[0]) | 1425 b.exprInPlace(fn, lvals[0], rhss[0]) |
1425 } else { | 1426 } else { |
1426 // Parallel assignment. All reads must occur | 1427 // Parallel assignment. All reads must occur |
1427 // before all updates, precluding exprInPlace. | 1428 // before all updates, precluding exprInPlace. |
1428 // TODO(adonovan): opt: is it sound to | 1429 // TODO(adonovan): opt: is it sound to |
1429 // perform exprInPlace if !isDef? | 1430 // perform exprInPlace if !isDef? |
1430 var rvals []Value | 1431 var rvals []Value |
1431 for _, rval := range rhss { | 1432 for _, rval := range rhss { |
1432 rvals = append(rvals, b.expr(fn, rval)) | 1433 rvals = append(rvals, b.expr(fn, rval)) |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1757 emitJump(fn, done) | 1758 emitJump(fn, done) |
1758 fn.currentBlock = done | 1759 fn.currentBlock = done |
1759 } | 1760 } |
1760 | 1761 |
1761 // selectStmt emits to fn code for the select statement s, optionally | 1762 // selectStmt emits to fn code for the select statement s, optionally |
1762 // labelled by label. | 1763 // labelled by label. |
1763 // | 1764 // |
1764 func (b *Builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { | 1765 func (b *Builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { |
1765 // A blocking select of a single case degenerates to a | 1766 // A blocking select of a single case degenerates to a |
1766 // simple send or receive. | 1767 // simple send or receive. |
1767 » // TODO(adonovan): is this optimisation worth its weight? | 1768 » // TODO(adonovan): is this optimization worth its weight? |
1768 if len(s.Body.List) == 1 { | 1769 if len(s.Body.List) == 1 { |
1769 clause := s.Body.List[0].(*ast.CommClause) | 1770 clause := s.Body.List[0].(*ast.CommClause) |
1770 if clause.Comm != nil { | 1771 if clause.Comm != nil { |
1771 b.stmt(fn, clause.Comm) | 1772 b.stmt(fn, clause.Comm) |
1772 done := fn.newBasicBlock("select.done") | 1773 done := fn.newBasicBlock("select.done") |
1773 if label != nil { | 1774 if label != nil { |
1774 label._break = done | 1775 label._break = done |
1775 } | 1776 } |
1776 fn.targets = &targets{ | 1777 fn.targets = &targets{ |
1777 tail: fn.targets, | 1778 tail: fn.targets, |
(...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2777 } | 2778 } |
2778 } | 2779 } |
2779 p.files = nil | 2780 p.files = nil |
2780 | 2781 |
2781 // Finish up. | 2782 // Finish up. |
2782 emitJump(init, done) | 2783 emitJump(init, done) |
2783 init.currentBlock = done | 2784 init.currentBlock = done |
2784 init.emit(new(Ret)) | 2785 init.emit(new(Ret)) |
2785 init.finish() | 2786 init.finish() |
2786 } | 2787 } |
LEFT | RIGHT |