]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: implement static data generation
authorJosh Bleecher Snyder <josharian@gmail.com>
Tue, 28 Jul 2015 17:56:39 +0000 (10:56 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Tue, 28 Jul 2015 19:43:31 +0000 (19:43 +0000)
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>
src/cmd/compile/internal/gc/gen.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/func.go

index 6390818e1658c05692c6ec6bd70b5f681f2e2e3e..4ff4f7a2c8a680b1fd109937b80e56cd48fb265b 100644 (file)
@@ -853,7 +853,7 @@ func gen(n *Node) {
                cgen_dcl(n.Left)
 
        case OAS:
-               if gen_as_init(n) {
+               if gen_as_init(n, false) {
                        break
                }
                Cgen_as(n.Left, n.Right)
index 7875d1638053db026353b8d40fdca2d7d757a3e4..099c10a8bc897b412cba945f5b090879df70b4ba 100644 (file)
@@ -1236,6 +1236,7 @@ func getlit(lit *Node) int {
        return -1
 }
 
+// stataddr sets nam to the static address of n and reports whether it succeeeded.
 func stataddr(nam *Node, n *Node) bool {
        if n == nil {
                return false
@@ -1408,7 +1409,9 @@ func entry(p *InitPlan) *InitEntry {
        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 nl *Node
        var nam Node
@@ -1457,7 +1460,9 @@ func gen_as_init(n *Node) bool {
        case OSLICEARR:
                if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
                        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
                        if nr == nil || nr.Op != OADDR {
                                goto no
@@ -1472,16 +1477,18 @@ func gen_as_init(n *Node) bool {
                                goto no
                        }
 
-                       nam.Xoffset += int64(Array_array)
-                       gdata(&nam, nl, int(Types[Tptr].Width))
+                       if !reportOnly {
+                               nam.Xoffset += int64(Array_array)
+                               gdata(&nam, nl, int(Types[Tptr].Width))
 
-                       nam.Xoffset += int64(Array_nel) - int64(Array_array)
-                       var nod1 Node
-                       Nodconst(&nod1, Types[TINT], nr.Type.Bound)
-                       gdata(&nam, &nod1, Widthint)
+                               nam.Xoffset += int64(Array_nel) - int64(Array_array)
+                               var nod1 Node
+                               Nodconst(&nod1, Types[TINT], nr.Type.Bound)
+                               gdata(&nam, &nod1, Widthint)
 
-                       nam.Xoffset += int64(Array_cap) - int64(Array_nel)
-                       gdata(&nam, &nod1, Widthint)
+                               nam.Xoffset += int64(Array_cap) - int64(Array_nel)
+                               gdata(&nam, &nod1, Widthint)
+                       }
 
                        return true
                }
@@ -1512,13 +1519,19 @@ func gen_as_init(n *Node) bool {
                TPTR64,
                TFLOAT32,
                TFLOAT64:
-               gdata(&nam, nr, int(nr.Type.Width))
+               if !reportOnly {
+                       gdata(&nam, nr, int(nr.Type.Width))
+               }
 
        case TCOMPLEX64, TCOMPLEX128:
-               gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
+               if !reportOnly {
+                       gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
+               }
 
        case TSTRING:
-               gdatastring(&nam, nr.Val().U.(string))
+               if !reportOnly {
+                       gdatastring(&nam, nr.Val().U.(string))
+               }
        }
 
        return true
index b6b345f20517fa03f050f0a982c733a30050f938..29b6a141a51f95a2f45af90c93bd9de4dcc466b9 100644 (file)
@@ -462,6 +462,17 @@ func (s *state) stmt(n *Node) {
                addEdge(b, lab.target)
 
        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)
 
        case OIF:
@@ -1484,6 +1495,15 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
 
        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: gcargs
        // TODO: gclocals
index 34d27801046df396cdeaa8e843d3e924fa17f662..e0f7c9ff604f8aaf40ec06fdb10cfa27fce9a646 100644 (file)
@@ -9,13 +9,14 @@ import "sync"
 // A Func represents a Go func declaration (or function literal) and
 // its body.  This package compiles each Func independently.
 type Func struct {
-       Config *Config  // architecture information
-       Name   string   // e.g. bytes·Compare
-       Type   Type     // type signature of the function.
-       Blocks []*Block // unordered set of all basic blocks (note: not indexable by ID)
-       Entry  *Block   // the entry basic block
-       bid    idAlloc  // block ID allocator
-       vid    idAlloc  // value ID allocator
+       Config     *Config     // architecture information
+       Name       string      // e.g. bytes·Compare
+       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)
+       Entry      *Block      // the entry basic block
+       bid        idAlloc     // block ID allocator
+       vid        idAlloc     // value ID allocator
 
        // when register allocation is done, maps value ids to locations
        RegAlloc []Location