LEFT | RIGHT |
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 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 importErrs: make(map[string]error), | 156 importErrs: make(map[string]error), |
157 nTo1Vars: make(map[*ast.ValueSpec]bool), | 157 nTo1Vars: make(map[*ast.ValueSpec]bool), |
158 packages: make(map[*types.Package]*Package), | 158 packages: make(map[*types.Package]*Package), |
159 types: make(map[ast.Expr]types.Type), | 159 types: make(map[ast.Expr]types.Type), |
160 } | 160 } |
161 | 161 |
162 // TODO(adonovan): opt: record the Expr/Ident calls into | 162 // TODO(adonovan): opt: record the Expr/Ident calls into |
163 // constants/idents/types maps associated with the containing | 163 // constants/idents/types maps associated with the containing |
164 // package so we can discard them once that package is built. | 164 // package so we can discard them once that package is built. |
165 b.typechecker = types.Context{ | 165 b.typechecker = types.Context{ |
166 » » // TODO(adonovan): permit the client to specify these | 166 » » Error: errh, |
167 » » // values. Perhaps expose the types.Context parameter | |
168 » » // directly (though of course we'll have to override | |
169 » » // the Expr/Ident/Import callbacks). | |
170 » » IntSize: 8, | |
171 » » PtrSize: 8, | |
172 » » Error: errh, | |
173 Expr: func(x ast.Expr, typ types.Type, val interface{}) { | 167 Expr: func(x ast.Expr, typ types.Type, val interface{}) { |
174 b.types[x] = typ | 168 b.types[x] = typ |
175 if val != nil { | 169 if val != nil { |
176 b.constants[x] = newLiteral(val, typ) | 170 b.constants[x] = newLiteral(val, typ) |
177 } | 171 } |
178 }, | 172 }, |
179 Ident: func(ident *ast.Ident, obj types.Object) { | 173 Ident: func(ident *ast.Ident, obj types.Object) { |
180 // Invariants: | 174 // Invariants: |
181 // - obj is non-nil. | 175 // - obj is non-nil. |
182 // - isBlankIdent(ident) <=> obj.GetType()==nil | 176 // - isBlankIdent(ident) <=> obj.GetType()==nil |
(...skipping 1157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1340 if !b.nTo1Vars[spec] { | 1334 if !b.nTo1Vars[spec] { |
1341 b.nTo1Vars[spec] = true | 1335 b.nTo1Vars[spec] = true |
1342 if b.mode&LogSource != 0 { | 1336 if b.mode&LogSource != 0 { |
1343 fmt.Fprintln(os.Stderr, "build globals", spec.Na
mes) // ugly... | 1337 fmt.Fprintln(os.Stderr, "build globals", spec.Na
mes) // ugly... |
1344 } | 1338 } |
1345 tuple := b.exprN(init, spec.Values[0]) | 1339 tuple := b.exprN(init, spec.Values[0]) |
1346 rtypes := tuple.Type().(*types.Result).Values | 1340 rtypes := tuple.Type().(*types.Result).Values |
1347 for i, id := range spec.Names { | 1341 for i, id := range spec.Names { |
1348 if !isBlankIdent(id) { | 1342 if !isBlankIdent(id) { |
1349 g := b.globals[b.obj(id)].(*Global) | 1343 g := b.globals[b.obj(id)].(*Global) |
1350 » » » » » g.spec = nil // just an optimisation | 1344 » » » » » g.spec = nil // just an optimization |
1351 emitStore(init, g, | 1345 emitStore(init, g, |
1352 emitExtract(init, tuple, i, rtyp
es[i].Type)) | 1346 emitExtract(init, tuple, i, rtyp
es[i].Type)) |
1353 } | 1347 } |
1354 } | 1348 } |
1355 } | 1349 } |
1356 } | 1350 } |
1357 } | 1351 } |
1358 | 1352 |
1359 // 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 |
1360 // function-local ValueSpec, spec. | 1354 // function-local ValueSpec, spec. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1419 } | 1413 } |
1420 } | 1414 } |
1421 lval = b.addr(fn, lhs, false) // non-escaping | 1415 lval = b.addr(fn, lhs, false) // non-escaping |
1422 } | 1416 } |
1423 lvals = append(lvals, lval) | 1417 lvals = append(lvals, lval) |
1424 } | 1418 } |
1425 if len(lhss) == len(rhss) { | 1419 if len(lhss) == len(rhss) { |
1426 // e.g. x, y = f(), g() | 1420 // e.g. x, y = f(), g() |
1427 if len(lhss) == 1 { | 1421 if len(lhss) == 1 { |
1428 // x = type{...} | 1422 // x = type{...} |
1429 » » » // Optimisation: in-place construction | 1423 » » » // Optimization: in-place construction |
1430 // of composite literals. | 1424 // of composite literals. |
1431 b.exprInPlace(fn, lvals[0], rhss[0]) | 1425 b.exprInPlace(fn, lvals[0], rhss[0]) |
1432 } else { | 1426 } else { |
1433 // Parallel assignment. All reads must occur | 1427 // Parallel assignment. All reads must occur |
1434 // before all updates, precluding exprInPlace. | 1428 // before all updates, precluding exprInPlace. |
1435 // TODO(adonovan): opt: is it sound to | 1429 // TODO(adonovan): opt: is it sound to |
1436 // perform exprInPlace if !isDef? | 1430 // perform exprInPlace if !isDef? |
1437 var rvals []Value | 1431 var rvals []Value |
1438 for _, rval := range rhss { | 1432 for _, rval := range rhss { |
1439 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... |
1764 emitJump(fn, done) | 1758 emitJump(fn, done) |
1765 fn.currentBlock = done | 1759 fn.currentBlock = done |
1766 } | 1760 } |
1767 | 1761 |
1768 // selectStmt emits to fn code for the select statement s, optionally | 1762 // selectStmt emits to fn code for the select statement s, optionally |
1769 // labelled by label. | 1763 // labelled by label. |
1770 // | 1764 // |
1771 func (b *Builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { | 1765 func (b *Builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { |
1772 // A blocking select of a single case degenerates to a | 1766 // A blocking select of a single case degenerates to a |
1773 // simple send or receive. | 1767 // simple send or receive. |
1774 » // TODO(adonovan): is this optimisation worth its weight? | 1768 » // TODO(adonovan): is this optimization worth its weight? |
1775 if len(s.Body.List) == 1 { | 1769 if len(s.Body.List) == 1 { |
1776 clause := s.Body.List[0].(*ast.CommClause) | 1770 clause := s.Body.List[0].(*ast.CommClause) |
1777 if clause.Comm != nil { | 1771 if clause.Comm != nil { |
1778 b.stmt(fn, clause.Comm) | 1772 b.stmt(fn, clause.Comm) |
1779 done := fn.newBasicBlock("select.done") | 1773 done := fn.newBasicBlock("select.done") |
1780 if label != nil { | 1774 if label != nil { |
1781 label._break = done | 1775 label._break = done |
1782 } | 1776 } |
1783 fn.targets = &targets{ | 1777 fn.targets = &targets{ |
1784 tail: fn.targets, | 1778 tail: fn.targets, |
(...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2784 } | 2778 } |
2785 } | 2779 } |
2786 p.files = nil | 2780 p.files = nil |
2787 | 2781 |
2788 // Finish up. | 2782 // Finish up. |
2789 emitJump(init, done) | 2783 emitJump(init, done) |
2790 init.currentBlock = done | 2784 init.currentBlock = done |
2791 init.emit(new(Ret)) | 2785 init.emit(new(Ret)) |
2792 init.finish() | 2786 init.finish() |
2793 } | 2787 } |
LEFT | RIGHT |