mirror of
https://github.com/golang/go
synced 2024-10-05 20:41:22 -06:00
[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/12790 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
2a5e6c47bc
commit
6b41665039
@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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
|
||||||
|
if !reportOnly {
|
||||||
gused(nil) // in case the data is the dest of a goto
|
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,6 +1477,7 @@ func gen_as_init(n *Node) bool {
|
|||||||
goto no
|
goto no
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reportOnly {
|
||||||
nam.Xoffset += int64(Array_array)
|
nam.Xoffset += int64(Array_array)
|
||||||
gdata(&nam, nl, int(Types[Tptr].Width))
|
gdata(&nam, nl, int(Types[Tptr].Width))
|
||||||
|
|
||||||
@ -1482,6 +1488,7 @@ func gen_as_init(n *Node) bool {
|
|||||||
|
|
||||||
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,14 +1519,20 @@ func gen_as_init(n *Node) bool {
|
|||||||
TPTR64,
|
TPTR64,
|
||||||
TFLOAT32,
|
TFLOAT32,
|
||||||
TFLOAT64:
|
TFLOAT64:
|
||||||
|
if !reportOnly {
|
||||||
gdata(&nam, nr, int(nr.Type.Width))
|
gdata(&nam, nr, int(nr.Type.Width))
|
||||||
|
}
|
||||||
|
|
||||||
case TCOMPLEX64, TCOMPLEX128:
|
case TCOMPLEX64, TCOMPLEX128:
|
||||||
|
if !reportOnly {
|
||||||
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
|
gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
|
||||||
|
}
|
||||||
|
|
||||||
case TSTRING:
|
case TSTRING:
|
||||||
|
if !reportOnly {
|
||||||
gdatastring(&nam, nr.Val().U.(string))
|
gdatastring(&nam, nr.Val().U.(string))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -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) {
|
|||||||
|
|
||||||
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
|
||||||
|
@ -12,6 +12,7 @@ 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.
|
||||||
|
StaticData interface{} // associated static data, untouched by the ssa package
|
||||||
Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID)
|
Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID)
|
||||||
Entry *Block // the entry basic block
|
Entry *Block // the entry basic block
|
||||||
bid idAlloc // block ID allocator
|
bid idAlloc // block ID allocator
|
||||||
|
Loading…
Reference in New Issue
Block a user