Commit 6b416650 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

[dev.ssa] cmd/compile: implement static data generation

The existing backend recognizes special
assignment statements as being implementable
with static data rather than code.
Unfortunately, it assumes that it is in the middle
of codegen; it emits data and modifies the AST.

This does not play well with SSA's two-phase
bootstrapping approach, in which we attempt to
compile code but fall back to the existing backend
if something goes wrong.

To work around this:

* Add the ability to inquire about static data
without side-effects.
* Save the static data required for a function.
* Emit that static data during SSA codegen.

Change-Id: I2e8a506c866ea3e27dffb597095833c87f62d87e
Reviewed-on: https://go-review.googlesource.com/12790Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent 2a5e6c47
...@@ -853,7 +853,7 @@ func gen(n *Node) { ...@@ -853,7 +853,7 @@ func gen(n *Node) {
cgen_dcl(n.Left) cgen_dcl(n.Left)
case OAS: case OAS:
if gen_as_init(n) { if gen_as_init(n, false) {
break break
} }
Cgen_as(n.Left, n.Right) Cgen_as(n.Left, n.Right)
......
...@@ -1236,6 +1236,7 @@ func getlit(lit *Node) int { ...@@ -1236,6 +1236,7 @@ func getlit(lit *Node) int {
return -1 return -1
} }
// stataddr sets nam to the static address of n and reports whether it succeeeded.
func stataddr(nam *Node, n *Node) bool { func stataddr(nam *Node, n *Node) bool {
if n == nil { if n == nil {
return false return false
...@@ -1408,7 +1409,9 @@ func entry(p *InitPlan) *InitEntry { ...@@ -1408,7 +1409,9 @@ func entry(p *InitPlan) *InitEntry {
return &p.E[len(p.E)-1] return &p.E[len(p.E)-1]
} }
func gen_as_init(n *Node) bool { // gen_as_init attempts to emit static data for n and reports whether it succeeded.
// If reportOnly is true, it does not emit static data and does not modify the AST.
func gen_as_init(n *Node, reportOnly bool) bool {
var nr *Node var nr *Node
var nl *Node var nl *Node
var nam Node var nam Node
...@@ -1457,7 +1460,9 @@ func gen_as_init(n *Node) bool { ...@@ -1457,7 +1460,9 @@ func gen_as_init(n *Node) bool {
case OSLICEARR: case OSLICEARR:
if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil { if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
nr = nr.Left nr = nr.Left
gused(nil) // in case the data is the dest of a goto if !reportOnly {
gused(nil) // in case the data is the dest of a goto
}
nl := nr nl := nr
if nr == nil || nr.Op != OADDR { if nr == nil || nr.Op != OADDR {
goto no goto no
...@@ -1472,16 +1477,18 @@ func gen_as_init(n *Node) bool { ...@@ -1472,16 +1477,18 @@ func gen_as_init(n *Node) bool {
goto no goto no
} }
nam.Xoffset += int64(Array_array) if !reportOnly {
gdata(&nam, nl, int(Types[Tptr].Width)) nam.Xoffset += int64(Array_array)
gdata(&nam, nl, int(Types[Tptr].Width))
nam.Xoffset += int64(Array_nel) - int64(Array_array) nam.Xoffset += int64(Array_nel) - int64(Array_array)
var nod1 Node var nod1 Node
Nodconst(&nod1, Types[TINT], nr.Type.Bound) Nodconst(&nod1, Types[TINT], nr.Type.Bound)
gdata(&nam, &nod1, Widthint) gdata(&nam, &nod1, Widthint)
nam.Xoffset += int64(Array_cap) - int64(Array_nel) nam.Xoffset += int64(Array_cap) - int64(Array_nel)
gdata(&nam, &nod1, Widthint) gdata(&nam, &nod1, Widthint)
}
return true return true
} }
...@@ -1512,13 +1519,19 @@ func gen_as_init(n *Node) bool { ...@@ -1512,13 +1519,19 @@ func gen_as_init(n *Node) bool {
TPTR64, TPTR64,
TFLOAT32, TFLOAT32,
TFLOAT64: TFLOAT64:
gdata(&nam, nr, int(nr.Type.Width)) if !reportOnly {
gdata(&nam, nr, int(nr.Type.Width))
}
case TCOMPLEX64, TCOMPLEX128: case TCOMPLEX64, TCOMPLEX128:
gdatacomplex(&nam, nr.Val().U.(*Mpcplx)) if !reportOnly {
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
}
case TSTRING: case TSTRING:
gdatastring(&nam, nr.Val().U.(string)) if !reportOnly {
gdatastring(&nam, nr.Val().U.(string))
}
} }
return true return true
......
...@@ -462,6 +462,17 @@ func (s *state) stmt(n *Node) { ...@@ -462,6 +462,17 @@ func (s *state) stmt(n *Node) {
addEdge(b, lab.target) addEdge(b, lab.target)
case OAS, OASWB: case OAS, OASWB:
// Check whether we can generate static data rather than code.
// If so, ignore n and defer data generation until codegen.
// Failure to do this causes writes to readonly symbols.
if gen_as_init(n, true) {
var data []*Node
if s.f.StaticData != nil {
data = s.f.StaticData.([]*Node)
}
s.f.StaticData = append(data, n)
return
}
s.assign(n.Op, n.Left, n.Right) s.assign(n.Op, n.Left, n.Right)
case OIF: case OIF:
...@@ -1484,6 +1495,15 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { ...@@ -1484,6 +1495,15 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Pc.As = obj.ARET // overwrite AEND Pc.As = obj.ARET // overwrite AEND
// Emit static data
if f.StaticData != nil {
for _, n := range f.StaticData.([]*Node) {
if !gen_as_init(n, false) {
Fatal("non-static data marked as static: %v\n\n", n, f)
}
}
}
// TODO: liveness // TODO: liveness
// TODO: gcargs // TODO: gcargs
// TODO: gclocals // TODO: gclocals
......
...@@ -9,13 +9,14 @@ import "sync" ...@@ -9,13 +9,14 @@ import "sync"
// A Func represents a Go func declaration (or function literal) and // A Func represents a Go func declaration (or function literal) and
// its body. This package compiles each Func independently. // its body. This package compiles each Func independently.
type Func struct { type Func struct {
Config *Config // architecture information Config *Config // architecture information
Name string // e.g. bytes·Compare Name string // e.g. bytes·Compare
Type Type // type signature of the function. Type Type // type signature of the function.
Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID) StaticData interface{} // associated static data, untouched by the ssa package
Entry *Block // the entry basic block Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID)
bid idAlloc // block ID allocator Entry *Block // the entry basic block
vid idAlloc // value ID allocator bid idAlloc // block ID allocator
vid idAlloc // value ID allocator
// when register allocation is done, maps value ids to locations // when register allocation is done, maps value ids to locations
RegAlloc []Location RegAlloc []Location
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment