]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: split out package walk [generated]
authorRuss Cox <rsc@golang.org>
Wed, 23 Dec 2020 06:05:16 +0000 (01:05 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 23 Dec 2020 06:39:43 +0000 (06:39 +0000)
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# Late addition to package ir.
mv closuredebugruntimecheck ClosureDebugRuntimeCheck
mv hasemptycvars IsTrivialClosure
mv ClosureDebugRuntimeCheck IsTrivialClosure func.go
mv func.go cmd/compile/internal/ir

# Late addition to package reflectdata.
mv markTypeUsedInInterface MarkTypeUsedInInterface
mv markUsedIfaceMethod MarkUsedIfaceMethod
mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go
mv reflect.go cmd/compile/internal/reflectdata

# Late addition to package staticdata.
mv litsym InitConst
mv InitConst data.go
mv data.go cmd/compile/internal/staticdata

# Extract staticinit out of walk into its own package.
mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \
InitSchedule.tryStaticInit InitSchedule.staticcopy \
InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \
statuniqgen staticname stataddr anySideEffects getlit isvaluelit \
sched.go
mv InitSchedule.initplans InitSchedule.Plans
mv InitSchedule.inittemps InitSchedule.Temps
mv InitSchedule.out InitSchedule.Out
mv InitSchedule.staticInit InitSchedule.StaticInit
mv InitSchedule.staticassign InitSchedule.StaticAssign
mv InitSchedule Schedule
mv InitPlan Plan
mv InitEntry Entry
mv anySideEffects AnySideEffects
mv staticname StaticName
mv stataddr StaticLoc
mv sched.go cmd/compile/internal/staticinit

# Export API and unexport non-API.
mv transformclosure Closure
mv walk Walk

mv Order orderState

mv swt.go switch.go
mv racewalk.go race.go

mv closure.go order.go range.go select.go switch.go race.go \
sinit.go subr.go walk.go \
cmd/compile/internal/walk
'

: # Update format test.
cd ../../
go install cmd/compile/... cmd/internal/archive
go test -u || go test -u
rm -rf ../../../pkg/darwin_amd64/cmd

Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05
Reviewed-on: https://go-review.googlesource.com/c/go/+/279478
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
18 files changed:
src/cmd/compile/fmtmap_test.go
src/cmd/compile/internal/gc/compile.go
src/cmd/compile/internal/gc/initorder.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/ir/func.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/staticdata/data.go
src/cmd/compile/internal/staticinit/sched.go [new file with mode: 0644]
src/cmd/compile/internal/walk/closure.go [moved from src/cmd/compile/internal/gc/closure.go with 85% similarity]
src/cmd/compile/internal/walk/order.go [moved from src/cmd/compile/internal/gc/order.go with 95% similarity]
src/cmd/compile/internal/walk/race.go [moved from src/cmd/compile/internal/gc/racewalk.go with 99% similarity]
src/cmd/compile/internal/walk/range.go [moved from src/cmd/compile/internal/gc/range.go with 99% similarity]
src/cmd/compile/internal/walk/select.go [moved from src/cmd/compile/internal/gc/select.go with 99% similarity]
src/cmd/compile/internal/walk/sinit.go [moved from src/cmd/compile/internal/gc/sinit.go with 59% similarity]
src/cmd/compile/internal/walk/subr.go [moved from src/cmd/compile/internal/gc/subr.go with 99% similarity]
src/cmd/compile/internal/walk/switch.go [moved from src/cmd/compile/internal/gc/swt.go with 99% similarity]
src/cmd/compile/internal/walk/walk.go [moved from src/cmd/compile/internal/gc/walk.go with 97% similarity]

index 9bc059c2e44f9bd72eaf20ac2a6b09ff84a82299..a925ec05ace7f064c5346ed4cb73b1d4d088abf6 100644 (file)
@@ -37,7 +37,6 @@ var knownFormats = map[string]string{
        "[]cmd/compile/internal/syntax.token %s":       "",
        "cmd/compile/internal/arm.shift %d":            "",
        "cmd/compile/internal/gc.RegIndex %d":          "",
-       "cmd/compile/internal/gc.initKind %d":          "",
        "cmd/compile/internal/ir.Class %d":             "",
        "cmd/compile/internal/ir.Node %+v":             "",
        "cmd/compile/internal/ir.Node %L":              "",
@@ -68,6 +67,7 @@ var knownFormats = map[string]string{
        "cmd/compile/internal/syntax.token %s":         "",
        "cmd/compile/internal/types.Kind %d":           "",
        "cmd/compile/internal/types.Kind %s":           "",
+       "cmd/compile/internal/walk.initKind %d":        "",
        "go/constant.Value %#v":                        "",
        "math/big.Accuracy %s":                         "",
        "reflect.Type %s":                              "",
index c2a6a9e327719e35bbab9da61e655bbccb396133..926b2dee95245f92f717a2bfedde824d25232b92 100644 (file)
@@ -17,6 +17,7 @@ import (
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
+       "cmd/compile/internal/walk"
 )
 
 // "Portable" code generation.
@@ -61,7 +62,7 @@ func compile(fn *ir.Func) {
        ssagen.InitLSym(fn, true)
 
        errorsBefore := base.Errors()
-       walk(fn)
+       walk.Walk(fn)
        if base.Errors() > errorsBefore {
                return
        }
index 5caa2e769f134a12b436b4942a8cd8a3787e1832..4ac468fb4e5b3da50a96c11afb785c9bb756e793 100644 (file)
@@ -11,6 +11,7 @@ import (
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
+       "cmd/compile/internal/staticinit"
 )
 
 // Package initialization
@@ -77,9 +78,9 @@ type InitOrder struct {
 // corresponding list of statements to include in the init() function
 // body.
 func initOrder(l []ir.Node) []ir.Node {
-       s := InitSchedule{
-               initplans: make(map[ir.Node]*InitPlan),
-               inittemps: make(map[ir.Node]*ir.Name),
+       s := staticinit.Schedule{
+               Plans: make(map[ir.Node]*staticinit.Plan),
+               Temps: make(map[ir.Node]*ir.Name),
        }
        o := InitOrder{
                blocking: make(map[ir.Node][]ir.Node),
@@ -91,7 +92,7 @@ func initOrder(l []ir.Node) []ir.Node {
                switch n.Op() {
                case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
                        o.processAssign(n)
-                       o.flushReady(s.staticInit)
+                       o.flushReady(s.StaticInit)
                case ir.ODCLCONST, ir.ODCLFUNC, ir.ODCLTYPE:
                        // nop
                default:
@@ -124,7 +125,7 @@ func initOrder(l []ir.Node) []ir.Node {
                base.Fatalf("expected empty map: %v", o.blocking)
        }
 
-       return s.out
+       return s.Out
 }
 
 func (o *InitOrder) processAssign(n ir.Node) {
index 2a8012b462e53845e759f152f28f944ab0bf4293..aeb58a33104835cf2321033a42471d3ba2115cc2 100644 (file)
@@ -22,6 +22,7 @@ import (
        "cmd/compile/internal/staticdata"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
+       "cmd/compile/internal/walk"
        "cmd/internal/dwarf"
        "cmd/internal/obj"
        "cmd/internal/objabi"
@@ -268,7 +269,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
                        n := n.(*ir.Func)
                        if n.OClosure != nil {
                                ir.CurFunc = n
-                               transformclosure(n)
+                               walk.Closure(n)
                        }
                }
        }
index f159256da665e86c9cfc181747b9f1b2519a453a..0ab3a8dad43ae8cd178be6e524ea990d251502d7 100644 (file)
@@ -18,7 +18,6 @@ import (
        "cmd/internal/objabi"
        "encoding/json"
        "fmt"
-       "go/constant"
 )
 
 // These modes say which kind of object file to generate.
@@ -261,62 +260,6 @@ func addGCLocals() {
        }
 }
 
-// litsym writes the static literal c to n.
-// Neither n nor c is modified.
-func litsym(n *ir.Name, noff int64, c ir.Node, wid int) {
-       if n.Op() != ir.ONAME {
-               base.Fatalf("litsym n op %v", n.Op())
-       }
-       if n.Sym() == nil {
-               base.Fatalf("litsym nil n sym")
-       }
-       if c.Op() == ir.ONIL {
-               return
-       }
-       if c.Op() != ir.OLITERAL {
-               base.Fatalf("litsym c op %v", c.Op())
-       }
-       s := n.Sym().Linksym()
-       switch u := c.Val(); u.Kind() {
-       case constant.Bool:
-               i := int64(obj.Bool2int(constant.BoolVal(u)))
-               s.WriteInt(base.Ctxt, noff, wid, i)
-
-       case constant.Int:
-               s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u))
-
-       case constant.Float:
-               f, _ := constant.Float64Val(u)
-               switch c.Type().Kind() {
-               case types.TFLOAT32:
-                       s.WriteFloat32(base.Ctxt, noff, float32(f))
-               case types.TFLOAT64:
-                       s.WriteFloat64(base.Ctxt, noff, f)
-               }
-
-       case constant.Complex:
-               re, _ := constant.Float64Val(constant.Real(u))
-               im, _ := constant.Float64Val(constant.Imag(u))
-               switch c.Type().Kind() {
-               case types.TCOMPLEX64:
-                       s.WriteFloat32(base.Ctxt, noff, float32(re))
-                       s.WriteFloat32(base.Ctxt, noff+4, float32(im))
-               case types.TCOMPLEX128:
-                       s.WriteFloat64(base.Ctxt, noff, re)
-                       s.WriteFloat64(base.Ctxt, noff+8, im)
-               }
-
-       case constant.String:
-               i := constant.StringVal(u)
-               symdata := staticdata.StringSym(n.Pos(), i)
-               s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
-               s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
-
-       default:
-               base.Fatalf("litsym unhandled OLITERAL %v", c)
-       }
-}
-
 func ggloblnod(nam ir.Node) {
        s := nam.Sym().Linksym()
        s.Gotype = reflectdata.TypeSym(nam.Type()).Linksym()
index a93516d7162403f85b9207c4a254b31cde98247f..6bc8cd574c5791afb5ff00a4e4d5c31ec6a0c2c2 100644 (file)
@@ -288,3 +288,24 @@ func MarkFunc(n *Name) {
        n.Class_ = PFUNC
        n.Sym().SetFunc(true)
 }
+
+// ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
+// and compiling runtime
+func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
+       if base.Debug.Closure > 0 {
+               if clo.Esc() == EscHeap {
+                       base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
+               } else {
+                       base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
+               }
+       }
+       if base.Flag.CompilingRuntime && clo.Esc() == EscHeap {
+               base.ErrorfAt(clo.Pos(), "heap-allocated closure, not allowed in runtime")
+       }
+}
+
+// IsTrivialClosure reports whether closure clo has an
+// empty list of captured vars.
+func IsTrivialClosure(clo *ClosureExpr) bool {
+       return len(clo.Func.ClosureVars) == 0
+}
index a5e2fb407aaf38d96daccb9accc2b92ddfc7f8e5..ba3e0fa75ef9723381f6cfafe3f2cad940ad9a83 100644 (file)
@@ -1834,3 +1834,29 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
 }
 
 var ZeroSize int64
+
+// MarkTypeUsedInInterface marks that type t is converted to an interface.
+// This information is used in the linker in dead method elimination.
+func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
+       tsym := TypeSym(t).Linksym()
+       // Emit a marker relocation. The linker will know the type is converted
+       // to an interface if "from" is reachable.
+       r := obj.Addrel(from)
+       r.Sym = tsym
+       r.Type = objabi.R_USEIFACE
+}
+
+// MarkUsedIfaceMethod marks that an interface method is used in the current
+// function. n is OCALLINTER node.
+func MarkUsedIfaceMethod(n *ir.CallExpr) {
+       dot := n.X.(*ir.SelectorExpr)
+       ityp := dot.X.Type()
+       tsym := TypeSym(ityp).Linksym()
+       r := obj.Addrel(ir.CurFunc.LSym)
+       r.Sym = tsym
+       // dot.Xoffset is the method index * Widthptr (the offset of code pointer
+       // in itab).
+       midx := dot.Offset / int64(types.PtrSize)
+       r.Add = InterfaceMethodOffset(ityp, midx)
+       r.Type = objabi.R_USEIFACEMETHOD
+}
index 7627aaa11a115b86f1834b220d4fed7235e056e3..342a2e2bbc25fb46da6c599452d754ac465b1a10 100644 (file)
@@ -7,6 +7,7 @@ package staticdata
 import (
        "crypto/sha256"
        "fmt"
+       "go/constant"
        "io"
        "io/ioutil"
        "os"
@@ -294,3 +295,59 @@ func WriteFuncSyms() {
                objw.Global(sf, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
        }
 }
+
+// InitConst writes the static literal c to n.
+// Neither n nor c is modified.
+func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) {
+       if n.Op() != ir.ONAME {
+               base.Fatalf("litsym n op %v", n.Op())
+       }
+       if n.Sym() == nil {
+               base.Fatalf("litsym nil n sym")
+       }
+       if c.Op() == ir.ONIL {
+               return
+       }
+       if c.Op() != ir.OLITERAL {
+               base.Fatalf("litsym c op %v", c.Op())
+       }
+       s := n.Sym().Linksym()
+       switch u := c.Val(); u.Kind() {
+       case constant.Bool:
+               i := int64(obj.Bool2int(constant.BoolVal(u)))
+               s.WriteInt(base.Ctxt, noff, wid, i)
+
+       case constant.Int:
+               s.WriteInt(base.Ctxt, noff, wid, ir.IntVal(c.Type(), u))
+
+       case constant.Float:
+               f, _ := constant.Float64Val(u)
+               switch c.Type().Kind() {
+               case types.TFLOAT32:
+                       s.WriteFloat32(base.Ctxt, noff, float32(f))
+               case types.TFLOAT64:
+                       s.WriteFloat64(base.Ctxt, noff, f)
+               }
+
+       case constant.Complex:
+               re, _ := constant.Float64Val(constant.Real(u))
+               im, _ := constant.Float64Val(constant.Imag(u))
+               switch c.Type().Kind() {
+               case types.TCOMPLEX64:
+                       s.WriteFloat32(base.Ctxt, noff, float32(re))
+                       s.WriteFloat32(base.Ctxt, noff+4, float32(im))
+               case types.TCOMPLEX128:
+                       s.WriteFloat64(base.Ctxt, noff, re)
+                       s.WriteFloat64(base.Ctxt, noff+8, im)
+               }
+
+       case constant.String:
+               i := constant.StringVal(u)
+               symdata := StringSym(n.Pos(), i)
+               s.WriteAddr(base.Ctxt, noff, types.PtrSize, symdata, 0)
+               s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i)))
+
+       default:
+               base.Fatalf("litsym unhandled OLITERAL %v", c)
+       }
+}
diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go
new file mode 100644 (file)
index 0000000..2a499d6
--- /dev/null
@@ -0,0 +1,596 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package staticinit
+
+import (
+       "fmt"
+       "go/constant"
+
+       "cmd/compile/internal/base"
+       "cmd/compile/internal/ir"
+       "cmd/compile/internal/reflectdata"
+       "cmd/compile/internal/staticdata"
+       "cmd/compile/internal/typecheck"
+       "cmd/compile/internal/types"
+       "cmd/internal/obj"
+)
+
+type Entry struct {
+       Xoffset int64   // struct, array only
+       Expr    ir.Node // bytes of run-time computed expressions
+}
+
+type Plan struct {
+       E []Entry
+}
+
+// An Schedule is used to decompose assignment statements into
+// static and dynamic initialization parts. Static initializations are
+// handled by populating variables' linker symbol data, while dynamic
+// initializations are accumulated to be executed in order.
+type Schedule struct {
+       // Out is the ordered list of dynamic initialization
+       // statements.
+       Out []ir.Node
+
+       Plans map[ir.Node]*Plan
+       Temps map[ir.Node]*ir.Name
+}
+
+func (s *Schedule) append(n ir.Node) {
+       s.Out = append(s.Out, n)
+}
+
+// StaticInit adds an initialization statement n to the schedule.
+func (s *Schedule) StaticInit(n ir.Node) {
+       if !s.tryStaticInit(n) {
+               if base.Flag.Percent != 0 {
+                       ir.Dump("nonstatic", n)
+               }
+               s.append(n)
+       }
+}
+
+// tryStaticInit attempts to statically execute an initialization
+// statement and reports whether it succeeded.
+func (s *Schedule) tryStaticInit(nn ir.Node) bool {
+       // Only worry about simple "l = r" assignments. Multiple
+       // variable/expression OAS2 assignments have already been
+       // replaced by multiple simple OAS assignments, and the other
+       // OAS2* assignments mostly necessitate dynamic execution
+       // anyway.
+       if nn.Op() != ir.OAS {
+               return false
+       }
+       n := nn.(*ir.AssignStmt)
+       if ir.IsBlank(n.X) && !AnySideEffects(n.Y) {
+               // Discard.
+               return true
+       }
+       lno := ir.SetPos(n)
+       defer func() { base.Pos = lno }()
+       nam := n.X.(*ir.Name)
+       return s.StaticAssign(nam, 0, n.Y, nam.Type())
+}
+
+// like staticassign but we are copying an already
+// initialized value r.
+func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Type) bool {
+       if rn.Class_ == ir.PFUNC {
+               // TODO if roff != 0 { panic }
+               staticdata.InitFunc(l, loff, rn)
+               return true
+       }
+       if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
+               return false
+       }
+       if rn.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
+               return false
+       }
+       if rn.Defn.Op() != ir.OAS {
+               return false
+       }
+       if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
+               return false
+       }
+       orig := rn
+       r := rn.Defn.(*ir.AssignStmt).Y
+
+       for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
+               r = r.(*ir.ConvExpr).X
+       }
+
+       switch r.Op() {
+       case ir.OMETHEXPR:
+               r = r.(*ir.MethodExpr).FuncName()
+               fallthrough
+       case ir.ONAME:
+               r := r.(*ir.Name)
+               if s.staticcopy(l, loff, r, typ) {
+                       return true
+               }
+               // We may have skipped past one or more OCONVNOPs, so
+               // use conv to ensure r is assignable to l (#13263).
+               dst := ir.Node(l)
+               if loff != 0 || !types.Identical(typ, l.Type()) {
+                       dst = ir.NewNameOffsetExpr(base.Pos, l, loff, typ)
+               }
+               s.append(ir.NewAssignStmt(base.Pos, dst, typecheck.Conv(r, typ)))
+               return true
+
+       case ir.ONIL:
+               return true
+
+       case ir.OLITERAL:
+               if ir.IsZero(r) {
+                       return true
+               }
+               staticdata.InitConst(l, loff, r, int(typ.Width))
+               return true
+
+       case ir.OADDR:
+               r := r.(*ir.AddrExpr)
+               if a := r.X; a.Op() == ir.ONAME {
+                       a := a.(*ir.Name)
+                       staticdata.InitAddr(l, loff, a, 0)
+                       return true
+               }
+
+       case ir.OPTRLIT:
+               r := r.(*ir.AddrExpr)
+               switch r.X.Op() {
+               case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT:
+                       // copy pointer
+                       staticdata.InitAddr(l, loff, s.Temps[r], 0)
+                       return true
+               }
+
+       case ir.OSLICELIT:
+               r := r.(*ir.CompLitExpr)
+               // copy slice
+               staticdata.InitSlice(l, loff, s.Temps[r], r.Len)
+               return true
+
+       case ir.OARRAYLIT, ir.OSTRUCTLIT:
+               r := r.(*ir.CompLitExpr)
+               p := s.Plans[r]
+               for i := range p.E {
+                       e := &p.E[i]
+                       typ := e.Expr.Type()
+                       if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
+                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(typ.Width))
+                               continue
+                       }
+                       x := e.Expr
+                       if x.Op() == ir.OMETHEXPR {
+                               x = x.(*ir.MethodExpr).FuncName()
+                       }
+                       if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
+                               continue
+                       }
+                       // Requires computation, but we're
+                       // copying someone else's computation.
+                       ll := ir.NewNameOffsetExpr(base.Pos, l, loff+e.Xoffset, typ)
+                       rr := ir.NewNameOffsetExpr(base.Pos, orig, e.Xoffset, typ)
+                       ir.SetPos(rr)
+                       s.append(ir.NewAssignStmt(base.Pos, ll, rr))
+               }
+
+               return true
+       }
+
+       return false
+}
+
+func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Type) bool {
+       for r.Op() == ir.OCONVNOP {
+               r = r.(*ir.ConvExpr).X
+       }
+
+       switch r.Op() {
+       case ir.ONAME:
+               r := r.(*ir.Name)
+               return s.staticcopy(l, loff, r, typ)
+
+       case ir.OMETHEXPR:
+               r := r.(*ir.MethodExpr)
+               return s.staticcopy(l, loff, r.FuncName(), typ)
+
+       case ir.ONIL:
+               return true
+
+       case ir.OLITERAL:
+               if ir.IsZero(r) {
+                       return true
+               }
+               staticdata.InitConst(l, loff, r, int(typ.Width))
+               return true
+
+       case ir.OADDR:
+               r := r.(*ir.AddrExpr)
+               if name, offset, ok := StaticLoc(r.X); ok {
+                       staticdata.InitAddr(l, loff, name, offset)
+                       return true
+               }
+               fallthrough
+
+       case ir.OPTRLIT:
+               r := r.(*ir.AddrExpr)
+               switch r.X.Op() {
+               case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT:
+                       // Init pointer.
+                       a := StaticName(r.X.Type())
+
+                       s.Temps[r] = a
+                       staticdata.InitAddr(l, loff, a, 0)
+
+                       // Init underlying literal.
+                       if !s.StaticAssign(a, 0, r.X, a.Type()) {
+                               s.append(ir.NewAssignStmt(base.Pos, a, r.X))
+                       }
+                       return true
+               }
+               //dump("not static ptrlit", r);
+
+       case ir.OSTR2BYTES:
+               r := r.(*ir.ConvExpr)
+               if l.Class_ == ir.PEXTERN && r.X.Op() == ir.OLITERAL {
+                       sval := ir.StringVal(r.X)
+                       staticdata.InitSliceBytes(l, loff, sval)
+                       return true
+               }
+
+       case ir.OSLICELIT:
+               r := r.(*ir.CompLitExpr)
+               s.initplan(r)
+               // Init slice.
+               ta := types.NewArray(r.Type().Elem(), r.Len)
+               ta.SetNoalg(true)
+               a := StaticName(ta)
+               s.Temps[r] = a
+               staticdata.InitSlice(l, loff, a, r.Len)
+               // Fall through to init underlying array.
+               l = a
+               loff = 0
+               fallthrough
+
+       case ir.OARRAYLIT, ir.OSTRUCTLIT:
+               r := r.(*ir.CompLitExpr)
+               s.initplan(r)
+
+               p := s.Plans[r]
+               for i := range p.E {
+                       e := &p.E[i]
+                       if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
+                               staticdata.InitConst(l, loff+e.Xoffset, e.Expr, int(e.Expr.Type().Width))
+                               continue
+                       }
+                       ir.SetPos(e.Expr)
+                       if !s.StaticAssign(l, loff+e.Xoffset, e.Expr, e.Expr.Type()) {
+                               a := ir.NewNameOffsetExpr(base.Pos, l, loff+e.Xoffset, e.Expr.Type())
+                               s.append(ir.NewAssignStmt(base.Pos, a, e.Expr))
+                       }
+               }
+
+               return true
+
+       case ir.OMAPLIT:
+               break
+
+       case ir.OCLOSURE:
+               r := r.(*ir.ClosureExpr)
+               if ir.IsTrivialClosure(r) {
+                       if base.Debug.Closure > 0 {
+                               base.WarnfAt(r.Pos(), "closure converted to global")
+                       }
+                       // Closures with no captured variables are globals,
+                       // so the assignment can be done at link time.
+                       // TODO if roff != 0 { panic }
+                       staticdata.InitFunc(l, loff, r.Func.Nname)
+                       return true
+               }
+               ir.ClosureDebugRuntimeCheck(r)
+
+       case ir.OCONVIFACE:
+               // This logic is mirrored in isStaticCompositeLiteral.
+               // If you change something here, change it there, and vice versa.
+
+               // Determine the underlying concrete type and value we are converting from.
+               r := r.(*ir.ConvExpr)
+               val := ir.Node(r)
+               for val.Op() == ir.OCONVIFACE {
+                       val = val.(*ir.ConvExpr).X
+               }
+
+               if val.Type().IsInterface() {
+                       // val is an interface type.
+                       // If val is nil, we can statically initialize l;
+                       // both words are zero and so there no work to do, so report success.
+                       // If val is non-nil, we have no concrete type to record,
+                       // and we won't be able to statically initialize its value, so report failure.
+                       return val.Op() == ir.ONIL
+               }
+
+               reflectdata.MarkTypeUsedInInterface(val.Type(), l.Sym().Linksym())
+
+               var itab *ir.AddrExpr
+               if typ.IsEmptyInterface() {
+                       itab = reflectdata.TypePtr(val.Type())
+               } else {
+                       itab = reflectdata.ITabAddr(val.Type(), typ)
+               }
+
+               // Create a copy of l to modify while we emit data.
+
+               // Emit itab, advance offset.
+               staticdata.InitAddr(l, loff, itab.X.(*ir.Name), 0)
+
+               // Emit data.
+               if types.IsDirectIface(val.Type()) {
+                       if val.Op() == ir.ONIL {
+                               // Nil is zero, nothing to do.
+                               return true
+                       }
+                       // Copy val directly into n.
+                       ir.SetPos(val)
+                       if !s.StaticAssign(l, loff+int64(types.PtrSize), val, val.Type()) {
+                               a := ir.NewNameOffsetExpr(base.Pos, l, loff+int64(types.PtrSize), val.Type())
+                               s.append(ir.NewAssignStmt(base.Pos, a, val))
+                       }
+               } else {
+                       // Construct temp to hold val, write pointer to temp into n.
+                       a := StaticName(val.Type())
+                       s.Temps[val] = a
+                       if !s.StaticAssign(a, 0, val, val.Type()) {
+                               s.append(ir.NewAssignStmt(base.Pos, a, val))
+                       }
+                       staticdata.InitAddr(l, loff+int64(types.PtrSize), a, 0)
+               }
+
+               return true
+       }
+
+       //dump("not static", r);
+       return false
+}
+
+func (s *Schedule) initplan(n ir.Node) {
+       if s.Plans[n] != nil {
+               return
+       }
+       p := new(Plan)
+       s.Plans[n] = p
+       switch n.Op() {
+       default:
+               base.Fatalf("initplan")
+
+       case ir.OARRAYLIT, ir.OSLICELIT:
+               n := n.(*ir.CompLitExpr)
+               var k int64
+               for _, a := range n.List {
+                       if a.Op() == ir.OKEY {
+                               kv := a.(*ir.KeyExpr)
+                               k = typecheck.IndexConst(kv.Key)
+                               if k < 0 {
+                                       base.Fatalf("initplan arraylit: invalid index %v", kv.Key)
+                               }
+                               a = kv.Value
+                       }
+                       s.addvalue(p, k*n.Type().Elem().Width, a)
+                       k++
+               }
+
+       case ir.OSTRUCTLIT:
+               n := n.(*ir.CompLitExpr)
+               for _, a := range n.List {
+                       if a.Op() != ir.OSTRUCTKEY {
+                               base.Fatalf("initplan structlit")
+                       }
+                       a := a.(*ir.StructKeyExpr)
+                       if a.Field.IsBlank() {
+                               continue
+                       }
+                       s.addvalue(p, a.Offset, a.Value)
+               }
+
+       case ir.OMAPLIT:
+               n := n.(*ir.CompLitExpr)
+               for _, a := range n.List {
+                       if a.Op() != ir.OKEY {
+                               base.Fatalf("initplan maplit")
+                       }
+                       a := a.(*ir.KeyExpr)
+                       s.addvalue(p, -1, a.Value)
+               }
+       }
+}
+
+func (s *Schedule) addvalue(p *Plan, xoffset int64, n ir.Node) {
+       // special case: zero can be dropped entirely
+       if ir.IsZero(n) {
+               return
+       }
+
+       // special case: inline struct and array (not slice) literals
+       if isvaluelit(n) {
+               s.initplan(n)
+               q := s.Plans[n]
+               for _, qe := range q.E {
+                       // qe is a copy; we are not modifying entries in q.E
+                       qe.Xoffset += xoffset
+                       p.E = append(p.E, qe)
+               }
+               return
+       }
+
+       // add to plan
+       p.E = append(p.E, Entry{Xoffset: xoffset, Expr: n})
+}
+
+// from here down is the walk analysis
+// of composite literals.
+// most of the work is to generate
+// data statements for the constant
+// part of the composite literal.
+
+var statuniqgen int // name generator for static temps
+
+// StaticName returns a name backed by a (writable) static data symbol.
+// Use readonlystaticname for read-only node.
+func StaticName(t *types.Type) *ir.Name {
+       // Don't use lookupN; it interns the resulting string, but these are all unique.
+       n := typecheck.NewName(typecheck.Lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
+       statuniqgen++
+       typecheck.Declare(n, ir.PEXTERN)
+       n.SetType(t)
+       n.Sym().Linksym().Set(obj.AttrLocal, true)
+       return n
+}
+
+// StaticLoc returns the static address of n, if n has one, or else nil.
+func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
+       if n == nil {
+               return nil, 0, false
+       }
+
+       switch n.Op() {
+       case ir.ONAME:
+               n := n.(*ir.Name)
+               return n, 0, true
+
+       case ir.OMETHEXPR:
+               n := n.(*ir.MethodExpr)
+               return StaticLoc(n.FuncName())
+
+       case ir.ODOT:
+               n := n.(*ir.SelectorExpr)
+               if name, offset, ok = StaticLoc(n.X); !ok {
+                       break
+               }
+               offset += n.Offset
+               return name, offset, true
+
+       case ir.OINDEX:
+               n := n.(*ir.IndexExpr)
+               if n.X.Type().IsSlice() {
+                       break
+               }
+               if name, offset, ok = StaticLoc(n.X); !ok {
+                       break
+               }
+               l := getlit(n.Index)
+               if l < 0 {
+                       break
+               }
+
+               // Check for overflow.
+               if n.Type().Width != 0 && types.MaxWidth/n.Type().Width <= int64(l) {
+                       break
+               }
+               offset += int64(l) * n.Type().Width
+               return name, offset, true
+       }
+
+       return nil, 0, false
+}
+
+// AnySideEffects reports whether n contains any operations that could have observable side effects.
+func AnySideEffects(n ir.Node) bool {
+       return ir.Any(n, func(n ir.Node) bool {
+               switch n.Op() {
+               // Assume side effects unless we know otherwise.
+               default:
+                       return true
+
+               // No side effects here (arguments are checked separately).
+               case ir.ONAME,
+                       ir.ONONAME,
+                       ir.OTYPE,
+                       ir.OPACK,
+                       ir.OLITERAL,
+                       ir.ONIL,
+                       ir.OADD,
+                       ir.OSUB,
+                       ir.OOR,
+                       ir.OXOR,
+                       ir.OADDSTR,
+                       ir.OADDR,
+                       ir.OANDAND,
+                       ir.OBYTES2STR,
+                       ir.ORUNES2STR,
+                       ir.OSTR2BYTES,
+                       ir.OSTR2RUNES,
+                       ir.OCAP,
+                       ir.OCOMPLIT,
+                       ir.OMAPLIT,
+                       ir.OSTRUCTLIT,
+                       ir.OARRAYLIT,
+                       ir.OSLICELIT,
+                       ir.OPTRLIT,
+                       ir.OCONV,
+                       ir.OCONVIFACE,
+                       ir.OCONVNOP,
+                       ir.ODOT,
+                       ir.OEQ,
+                       ir.ONE,
+                       ir.OLT,
+                       ir.OLE,
+                       ir.OGT,
+                       ir.OGE,
+                       ir.OKEY,
+                       ir.OSTRUCTKEY,
+                       ir.OLEN,
+                       ir.OMUL,
+                       ir.OLSH,
+                       ir.ORSH,
+                       ir.OAND,
+                       ir.OANDNOT,
+                       ir.ONEW,
+                       ir.ONOT,
+                       ir.OBITNOT,
+                       ir.OPLUS,
+                       ir.ONEG,
+                       ir.OOROR,
+                       ir.OPAREN,
+                       ir.ORUNESTR,
+                       ir.OREAL,
+                       ir.OIMAG,
+                       ir.OCOMPLEX:
+                       return false
+
+               // Only possible side effect is division by zero.
+               case ir.ODIV, ir.OMOD:
+                       n := n.(*ir.BinaryExpr)
+                       if n.Y.Op() != ir.OLITERAL || constant.Sign(n.Y.Val()) == 0 {
+                               return true
+                       }
+
+               // Only possible side effect is panic on invalid size,
+               // but many makechan and makemap use size zero, which is definitely OK.
+               case ir.OMAKECHAN, ir.OMAKEMAP:
+                       n := n.(*ir.MakeExpr)
+                       if !ir.IsConst(n.Len, constant.Int) || constant.Sign(n.Len.Val()) != 0 {
+                               return true
+                       }
+
+               // Only possible side effect is panic on invalid size.
+               // TODO(rsc): Merge with previous case (probably breaks toolstash -cmp).
+               case ir.OMAKESLICE, ir.OMAKESLICECOPY:
+                       return true
+               }
+               return false
+       })
+}
+
+func getlit(lit ir.Node) int {
+       if ir.IsSmallIntConst(lit) {
+               return int(ir.Int64Val(lit))
+       }
+       return -1
+}
+
+func isvaluelit(n ir.Node) bool {
+       return n.Op() == ir.OARRAYLIT || n.Op() == ir.OSTRUCTLIT
+}
similarity index 85%
rename from src/cmd/compile/internal/gc/closure.go
rename to src/cmd/compile/internal/walk/closure.go
index 4679b6535bcd177a7a10dcb481e8025f7a295a83..545c762ac7b6d26578821f25df015afdc9c710d8 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
        "cmd/compile/internal/base"
@@ -12,9 +12,9 @@ import (
        "cmd/internal/src"
 )
 
-// transformclosure is called in a separate phase after escape analysis.
+// Closure is called in a separate phase after escape analysis.
 // It transform closure bodies to properly reference captured variables.
-func transformclosure(fn *ir.Func) {
+func Closure(fn *ir.Func) {
        lno := base.Pos
        base.Pos = fn.Pos()
 
@@ -115,38 +115,17 @@ func transformclosure(fn *ir.Func) {
        base.Pos = lno
 }
 
-// hasemptycvars reports whether closure clo has an
-// empty list of captured vars.
-func hasemptycvars(clo *ir.ClosureExpr) bool {
-       return len(clo.Func.ClosureVars) == 0
-}
-
-// closuredebugruntimecheck applies boilerplate checks for debug flags
-// and compiling runtime
-func closuredebugruntimecheck(clo *ir.ClosureExpr) {
-       if base.Debug.Closure > 0 {
-               if clo.Esc() == ir.EscHeap {
-                       base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
-               } else {
-                       base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
-               }
-       }
-       if base.Flag.CompilingRuntime && clo.Esc() == ir.EscHeap {
-               base.ErrorfAt(clo.Pos(), "heap-allocated closure, not allowed in runtime")
-       }
-}
-
 func walkclosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
        fn := clo.Func
 
        // If no closure vars, don't bother wrapping.
-       if hasemptycvars(clo) {
+       if ir.IsTrivialClosure(clo) {
                if base.Debug.Closure > 0 {
                        base.WarnfAt(clo.Pos(), "closure converted to global")
                }
                return fn.Nname
        }
-       closuredebugruntimecheck(clo)
+       ir.ClosureDebugRuntimeCheck(clo)
 
        typ := typecheck.ClosureType(clo)
 
similarity index 95%
rename from src/cmd/compile/internal/gc/order.go
rename to src/cmd/compile/internal/walk/order.go
index d1c5bb04a1b98c308c3c555cc0b068832cec0623..03310a50c639546e1c3f2d68605e1ddee38b8e4d 100644 (file)
@@ -2,17 +2,19 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
+       "fmt"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/escape"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/reflectdata"
+       "cmd/compile/internal/staticinit"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "fmt"
 )
 
 // Rewrite tree to use separate statements to enforce
@@ -45,8 +47,8 @@ import (
 // it can result in unnecessary zeroing of those variables in the function
 // prologue.
 
-// Order holds state during the ordering process.
-type Order struct {
+// orderState holds state during the ordering process.
+type orderState struct {
        out  []ir.Node             // list of generated statements
        temp []*ir.Name            // stack of temporary variables
        free map[string][]*ir.Name // free list of unused temporaries, by type.LongString().
@@ -65,14 +67,14 @@ func order(fn *ir.Func) {
 }
 
 // append typechecks stmt and appends it to out.
-func (o *Order) append(stmt ir.Node) {
+func (o *orderState) append(stmt ir.Node) {
        o.out = append(o.out, typecheck.Stmt(stmt))
 }
 
 // newTemp allocates a new temporary with the given type,
 // pushes it onto the temp stack, and returns it.
 // If clear is true, newTemp emits code to zero the temporary.
-func (o *Order) newTemp(t *types.Type, clear bool) *ir.Name {
+func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
        var v *ir.Name
        // Note: LongString is close to the type equality we want,
        // but not exactly. We still need to double-check with types.Identical.
@@ -100,7 +102,7 @@ func (o *Order) newTemp(t *types.Type, clear bool) *ir.Name {
 
 // copyExpr behaves like newTemp but also emits
 // code to initialize the temporary to the value n.
-func (o *Order) copyExpr(n ir.Node) ir.Node {
+func (o *orderState) copyExpr(n ir.Node) ir.Node {
        return o.copyExpr1(n, false)
 }
 
@@ -114,11 +116,11 @@ func (o *Order) copyExpr(n ir.Node) ir.Node {
 // (The other candidate would be map access, but map access
 // returns a pointer to the result data instead of taking a pointer
 // to be filled in.)
-func (o *Order) copyExprClear(n ir.Node) *ir.Name {
+func (o *orderState) copyExprClear(n ir.Node) *ir.Name {
        return o.copyExpr1(n, true)
 }
 
-func (o *Order) copyExpr1(n ir.Node, clear bool) *ir.Name {
+func (o *orderState) copyExpr1(n ir.Node, clear bool) *ir.Name {
        t := n.Type()
        v := o.newTemp(t, clear)
        o.append(ir.NewAssignStmt(base.Pos, v, n))
@@ -129,7 +131,7 @@ func (o *Order) copyExpr1(n ir.Node, clear bool) *ir.Name {
 // The definition of cheap is that n is a variable or constant.
 // If not, cheapExpr allocates a new tmp, emits tmp = n,
 // and then returns tmp.
-func (o *Order) cheapExpr(n ir.Node) ir.Node {
+func (o *orderState) cheapExpr(n ir.Node) ir.Node {
        if n == nil {
                return nil
        }
@@ -158,7 +160,7 @@ func (o *Order) cheapExpr(n ir.Node) ir.Node {
 // as assigning to the original n.
 //
 // The intended use is to apply to x when rewriting x += y into x = x + y.
-func (o *Order) safeExpr(n ir.Node) ir.Node {
+func (o *orderState) safeExpr(n ir.Node) ir.Node {
        switch n.Op() {
        case ir.ONAME, ir.OLITERAL, ir.ONIL:
                return n
@@ -241,15 +243,15 @@ func isaddrokay(n ir.Node) bool {
 // tmp = n, and then returns tmp.
 // The result of addrTemp MUST be assigned back to n, e.g.
 //     n.Left = o.addrTemp(n.Left)
-func (o *Order) addrTemp(n ir.Node) ir.Node {
+func (o *orderState) addrTemp(n ir.Node) ir.Node {
        if n.Op() == ir.OLITERAL || n.Op() == ir.ONIL {
                // TODO: expand this to all static composite literal nodes?
                n = typecheck.DefaultLit(n, nil)
                types.CalcSize(n.Type())
                vstat := readonlystaticname(n.Type())
-               var s InitSchedule
-               s.staticassign(vstat, 0, n, n.Type())
-               if s.out != nil {
+               var s staticinit.Schedule
+               s.StaticAssign(vstat, 0, n, n.Type())
+               if s.Out != nil {
                        base.Fatalf("staticassign of const generated code: %+v", n)
                }
                vstat = typecheck.Expr(vstat).(*ir.Name)
@@ -263,7 +265,7 @@ func (o *Order) addrTemp(n ir.Node) ir.Node {
 
 // mapKeyTemp prepares n to be a key in a map runtime call and returns n.
 // It should only be used for map runtime calls which have *_fast* versions.
-func (o *Order) mapKeyTemp(t *types.Type, n ir.Node) ir.Node {
+func (o *orderState) mapKeyTemp(t *types.Type, n ir.Node) ir.Node {
        // Most map calls need to take the address of the key.
        // Exception: map*_fast* calls. See golang.org/issue/19015.
        if mapfast(t) == mapslow {
@@ -318,13 +320,13 @@ func mapKeyReplaceStrConv(n ir.Node) bool {
 type ordermarker int
 
 // markTemp returns the top of the temporary variable stack.
-func (o *Order) markTemp() ordermarker {
+func (o *orderState) markTemp() ordermarker {
        return ordermarker(len(o.temp))
 }
 
 // popTemp pops temporaries off the stack until reaching the mark,
 // which must have been returned by markTemp.
-func (o *Order) popTemp(mark ordermarker) {
+func (o *orderState) popTemp(mark ordermarker) {
        for _, n := range o.temp[mark:] {
                key := n.Type().LongString()
                o.free[key] = append(o.free[key], n)
@@ -335,7 +337,7 @@ func (o *Order) popTemp(mark ordermarker) {
 // cleanTempNoPop emits VARKILL instructions to *out
 // for each temporary above the mark on the temporary stack.
 // It does not pop the temporaries from the stack.
-func (o *Order) cleanTempNoPop(mark ordermarker) []ir.Node {
+func (o *orderState) cleanTempNoPop(mark ordermarker) []ir.Node {
        var out []ir.Node
        for i := len(o.temp) - 1; i >= int(mark); i-- {
                n := o.temp[i]
@@ -346,13 +348,13 @@ func (o *Order) cleanTempNoPop(mark ordermarker) []ir.Node {
 
 // cleanTemp emits VARKILL instructions for each temporary above the
 // mark on the temporary stack and removes them from the stack.
-func (o *Order) cleanTemp(top ordermarker) {
+func (o *orderState) cleanTemp(top ordermarker) {
        o.out = append(o.out, o.cleanTempNoPop(top)...)
        o.popTemp(top)
 }
 
 // stmtList orders each of the statements in the list.
-func (o *Order) stmtList(l ir.Nodes) {
+func (o *orderState) stmtList(l ir.Nodes) {
        s := l
        for i := range s {
                orderMakeSliceCopy(s[i:])
@@ -396,14 +398,14 @@ func orderMakeSliceCopy(s []ir.Node) {
 }
 
 // edge inserts coverage instrumentation for libfuzzer.
-func (o *Order) edge() {
+func (o *orderState) edge() {
        if base.Debug.Libfuzzer == 0 {
                return
        }
 
        // Create a new uint8 counter to be allocated in section
        // __libfuzzer_extra_counters.
-       counter := staticname(types.Types[types.TUINT8])
+       counter := staticinit.StaticName(types.Types[types.TUINT8])
        counter.Name().SetLibfuzzerExtraCounter(true)
 
        // counter += 1
@@ -415,7 +417,7 @@ func (o *Order) edge() {
 // and then replaces the old slice in n with the new slice.
 // free is a map that can be used to obtain temporary variables by type.
 func orderBlock(n *ir.Nodes, free map[string][]*ir.Name) {
-       var order Order
+       var order orderState
        order.free = free
        mark := order.markTemp()
        order.edge()
@@ -428,8 +430,8 @@ func orderBlock(n *ir.Nodes, free map[string][]*ir.Name) {
 // leaves them as the init list of the final *np.
 // The result of exprInPlace MUST be assigned back to n, e.g.
 //     n.Left = o.exprInPlace(n.Left)
-func (o *Order) exprInPlace(n ir.Node) ir.Node {
-       var order Order
+func (o *orderState) exprInPlace(n ir.Node) ir.Node {
+       var order orderState
        order.free = o.free
        n = order.expr(n, nil)
        n = ir.InitExpr(order.out, n)
@@ -446,7 +448,7 @@ func (o *Order) exprInPlace(n ir.Node) ir.Node {
 //     n.Left = orderStmtInPlace(n.Left)
 // free is a map that can be used to obtain temporary variables by type.
 func orderStmtInPlace(n ir.Node, free map[string][]*ir.Name) ir.Node {
-       var order Order
+       var order orderState
        order.free = free
        mark := order.markTemp()
        order.stmt(n)
@@ -455,7 +457,7 @@ func orderStmtInPlace(n ir.Node, free map[string][]*ir.Name) ir.Node {
 }
 
 // init moves n's init list to o.out.
-func (o *Order) init(n ir.Node) {
+func (o *orderState) init(n ir.Node) {
        if ir.MayBeShared(n) {
                // For concurrency safety, don't mutate potentially shared nodes.
                // First, ensure that no work is required here.
@@ -470,7 +472,7 @@ func (o *Order) init(n ir.Node) {
 
 // call orders the call expression n.
 // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-func (o *Order) call(nn ir.Node) {
+func (o *orderState) call(nn ir.Node) {
        if len(nn.Init()) > 0 {
                // Caller should have already called o.init(nn).
                base.Fatalf("%v with unexpected ninit", nn.Op())
@@ -551,7 +553,7 @@ func (o *Order) call(nn ir.Node) {
 // cases they are also typically registerizable, so not much harm done.
 // And this only applies to the multiple-assignment form.
 // We could do a more precise analysis if needed, like in walk.go.
-func (o *Order) mapAssign(n ir.Node) {
+func (o *orderState) mapAssign(n ir.Node) {
        switch n.Op() {
        default:
                base.Fatalf("order.mapAssign %v", n.Op())
@@ -596,7 +598,7 @@ func (o *Order) mapAssign(n ir.Node) {
        }
 }
 
-func (o *Order) safeMapRHS(r ir.Node) ir.Node {
+func (o *orderState) safeMapRHS(r ir.Node) ir.Node {
        // Make sure we evaluate the RHS before starting the map insert.
        // We need to make sure the RHS won't panic.  See issue 22881.
        if r.Op() == ir.OAPPEND {
@@ -613,7 +615,7 @@ func (o *Order) safeMapRHS(r ir.Node) ir.Node {
 // stmt orders the statement n, appending to o.out.
 // Temporaries created during the statement are cleaned
 // up using VARKILL instructions as possible.
-func (o *Order) stmt(n ir.Node) {
+func (o *orderState) stmt(n ir.Node) {
        if n == nil {
                return
        }
@@ -1061,7 +1063,7 @@ func hasDefaultCase(n *ir.SwitchStmt) bool {
 }
 
 // exprList orders the expression list l into o.
-func (o *Order) exprList(l ir.Nodes) {
+func (o *orderState) exprList(l ir.Nodes) {
        s := l
        for i := range s {
                s[i] = o.expr(s[i], nil)
@@ -1070,14 +1072,14 @@ func (o *Order) exprList(l ir.Nodes) {
 
 // exprListInPlace orders the expression list l but saves
 // the side effects on the individual expression ninit lists.
-func (o *Order) exprListInPlace(l ir.Nodes) {
+func (o *orderState) exprListInPlace(l ir.Nodes) {
        s := l
        for i := range s {
                s[i] = o.exprInPlace(s[i])
        }
 }
 
-func (o *Order) exprNoLHS(n ir.Node) ir.Node {
+func (o *orderState) exprNoLHS(n ir.Node) ir.Node {
        return o.expr(n, nil)
 }
 
@@ -1088,7 +1090,7 @@ func (o *Order) exprNoLHS(n ir.Node) ir.Node {
 // to avoid copying the result of the expression to a temporary.)
 // The result of expr MUST be assigned back to n, e.g.
 //     n.Left = o.expr(n.Left, lhs)
-func (o *Order) expr(n, lhs ir.Node) ir.Node {
+func (o *orderState) expr(n, lhs ir.Node) ir.Node {
        if n == nil {
                return n
        }
@@ -1098,7 +1100,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
        return n
 }
 
-func (o *Order) expr1(n, lhs ir.Node) ir.Node {
+func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
        o.init(n)
 
        switch n.Op() {
@@ -1441,7 +1443,7 @@ func (o *Order) expr1(n, lhs ir.Node) ir.Node {
 //     tmp1, tmp2, tmp3 = ...
 //     a, b, a = tmp1, tmp2, tmp3
 // This is necessary to ensure left to right assignment order.
-func (o *Order) as2(n *ir.AssignListStmt) {
+func (o *orderState) as2(n *ir.AssignListStmt) {
        tmplist := []ir.Node{}
        left := []ir.Node{}
        for ni, l := range n.Lhs {
@@ -1463,7 +1465,7 @@ func (o *Order) as2(n *ir.AssignListStmt) {
 
 // okAs2 orders OAS2XXX with ok.
 // Just like as2, this also adds temporaries to ensure left-to-right assignment.
-func (o *Order) okAs2(n *ir.AssignListStmt) {
+func (o *orderState) okAs2(n *ir.AssignListStmt) {
        var tmp1, tmp2 ir.Node
        if !ir.IsBlank(n.Lhs[0]) {
                typ := n.Rhs[0].Type()
similarity index 99%
rename from src/cmd/compile/internal/gc/racewalk.go
rename to src/cmd/compile/internal/walk/race.go
index c52bf1479b1f00904bbe48047590e5be985a722e..1fe439a99a423bf79da1443f4e18ddb7ec2cd340 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
        "cmd/compile/internal/base"
similarity index 99%
rename from src/cmd/compile/internal/gc/range.go
rename to src/cmd/compile/internal/walk/range.go
index 2b2178a8bd2f0eed88a78583bfb8bdae8d6935c0..ea23761a398478da362c161a044394be49968317 100644 (file)
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
+       "unicode/utf8"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/reflectdata"
@@ -12,7 +14,6 @@ import (
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/sys"
-       "unicode/utf8"
 )
 
 func cheapComputableIndex(width int64) bool {
similarity index 99%
rename from src/cmd/compile/internal/gc/select.go
rename to src/cmd/compile/internal/walk/select.go
index 51bb1e5355ba6a9b604dbcbad058733ba7815a19..006833eb7ba6fad26d8f331686373e3d60e0dd52 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
        "cmd/compile/internal/base"
similarity index 59%
rename from src/cmd/compile/internal/gc/sinit.go
rename to src/cmd/compile/internal/walk/sinit.go
index 337b67af46222e33bfa14ab613f9d313c11699c5..dbb17dfe5015cb6933ce156ec376a52fcc9533a5 100644 (file)
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
-       "cmd/compile/internal/reflectdata"
        "cmd/compile/internal/staticdata"
+       "cmd/compile/internal/staticinit"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
-       "fmt"
 )
 
-type InitEntry struct {
-       Xoffset int64   // struct, array only
-       Expr    ir.Node // bytes of run-time computed expressions
-}
-
-type InitPlan struct {
-       E []InitEntry
-}
-
-// An InitSchedule is used to decompose assignment statements into
-// static and dynamic initialization parts. Static initializations are
-// handled by populating variables' linker symbol data, while dynamic
-// initializations are accumulated to be executed in order.
-type InitSchedule struct {
-       // out is the ordered list of dynamic initialization
-       // statements.
-       out []ir.Node
-
-       initplans map[ir.Node]*InitPlan
-       inittemps map[ir.Node]*ir.Name
-}
-
-func (s *InitSchedule) append(n ir.Node) {
-       s.out = append(s.out, n)
-}
-
-// staticInit adds an initialization statement n to the schedule.
-func (s *InitSchedule) staticInit(n ir.Node) {
-       if !s.tryStaticInit(n) {
-               if base.Flag.Percent != 0 {
-                       ir.Dump("nonstatic", n)
-               }
-               s.append(n)
-       }
-}
-
-// tryStaticInit attempts to statically execute an initialization
-// statement and reports whether it succeeded.
-func (s *InitSchedule) tryStaticInit(nn ir.Node) bool {
-       // Only worry about simple "l = r" assignments. Multiple
-       // variable/expression OAS2 assignments have already been
-       // replaced by multiple simple OAS assignments, and the other
-       // OAS2* assignments mostly necessitate dynamic execution
-       // anyway.
-       if nn.Op() != ir.OAS {
-               return false
-       }
-       n := nn.(*ir.AssignStmt)
-       if ir.IsBlank(n.X) && !anySideEffects(n.Y) {
-               // Discard.
-               return true
-       }
-       lno := ir.SetPos(n)
-       defer func() { base.Pos = lno }()
-       nam := n.X.(*ir.Name)
-       return s.staticassign(nam, 0, n.Y, nam.Type())
-}
-
-// like staticassign but we are copying an already
-// initialized value r.
-func (s *InitSchedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Type) bool {
-       if rn.Class_ == ir.PFUNC {
-               // TODO if roff != 0 { panic }
-               staticdata.InitFunc(l, loff, rn)
-               return true
-       }
-       if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
-               return false
-       }
-       if rn.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
-               return false
-       }
-       if rn.Defn.Op() != ir.OAS {
-               return false
-       }
-       if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
-               return false
-       }
-       orig := rn
-       r := rn.Defn.(*ir.AssignStmt).Y
-
-       for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
-               r = r.(*ir.ConvExpr).X
-       }
-
-       switch r.Op() {
-       case ir.OMETHEXPR:
-               r = r.(*ir.MethodExpr).FuncName()
-               fallthrough
-       case ir.ONAME:
-               r := r.(*ir.Name)
-               if s.staticcopy(l, loff, r, typ) {
-                       return true
-               }
-               // We may have skipped past one or more OCONVNOPs, so
-               // use conv to ensure r is assignable to l (#13263).
-               dst := ir.Node(l)
-               if loff != 0 || !types.Identical(typ, l.Type()) {
-                       dst = ir.NewNameOffsetExpr(base.Pos, l, loff, typ)
-               }
-               s.append(ir.NewAssignStmt(base.Pos, dst, typecheck.Conv(r, typ)))
-               return true
-
-       case ir.ONIL:
-               return true
-
-       case ir.OLITERAL:
-               if ir.IsZero(r) {
-                       return true
-               }
-               litsym(l, loff, r, int(typ.Width))
-               return true
-
-       case ir.OADDR:
-               r := r.(*ir.AddrExpr)
-               if a := r.X; a.Op() == ir.ONAME {
-                       a := a.(*ir.Name)
-                       staticdata.InitAddr(l, loff, a, 0)
-                       return true
-               }
-
-       case ir.OPTRLIT:
-               r := r.(*ir.AddrExpr)
-               switch r.X.Op() {
-               case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT, ir.OMAPLIT:
-                       // copy pointer
-                       staticdata.InitAddr(l, loff, s.inittemps[r], 0)
-                       return true
-               }
-
-       case ir.OSLICELIT:
-               r := r.(*ir.CompLitExpr)
-               // copy slice
-               staticdata.InitSlice(l, loff, s.inittemps[r], r.Len)
-               return true
-
-       case ir.OARRAYLIT, ir.OSTRUCTLIT:
-               r := r.(*ir.CompLitExpr)
-               p := s.initplans[r]
-               for i := range p.E {
-                       e := &p.E[i]
-                       typ := e.Expr.Type()
-                       if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
-                               litsym(l, loff+e.Xoffset, e.Expr, int(typ.Width))
-                               continue
-                       }
-                       x := e.Expr
-                       if x.Op() == ir.OMETHEXPR {
-                               x = x.(*ir.MethodExpr).FuncName()
-                       }
-                       if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
-                               continue
-                       }
-                       // Requires computation, but we're
-                       // copying someone else's computation.
-                       ll := ir.NewNameOffsetExpr(base.Pos, l, loff+e.Xoffset, typ)
-                       rr := ir.NewNameOffsetExpr(base.Pos, orig, e.Xoffset, typ)
-                       ir.SetPos(rr)
-                       s.append(ir.NewAssignStmt(base.Pos, ll, rr))
-               }
-
-               return true
-       }
-
-       return false
-}
-
-func (s *InitSchedule) staticassign(l *ir.Name, loff int64, r ir.Node, typ *types.Type) bool {
-       for r.Op() == ir.OCONVNOP {
-               r = r.(*ir.ConvExpr).X
-       }
-
-       switch r.Op() {
-       case ir.ONAME:
-               r := r.(*ir.Name)
-               return s.staticcopy(l, loff, r, typ)
-
-       case ir.OMETHEXPR:
-               r := r.(*ir.MethodExpr)
-               return s.staticcopy(l, loff, r.FuncName(), typ)
-
-       case ir.ONIL:
-               return true
-
-       case ir.OLITERAL:
-               if ir.IsZero(r) {
-                       return true
-               }
-               litsym(l, loff, r, int(typ.Width))
-               return true
-
-       case ir.OADDR:
-               r := r.(*ir.AddrExpr)
-               if name, offset, ok := stataddr(r.X); ok {
-                       staticdata.InitAddr(l, loff, name, offset)
-                       return true
-               }
-               fallthrough
-
-       case ir.OPTRLIT:
-               r := r.(*ir.AddrExpr)
-               switch r.X.Op() {
-               case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT:
-                       // Init pointer.
-                       a := staticname(r.X.Type())
-
-                       s.inittemps[r] = a
-                       staticdata.InitAddr(l, loff, a, 0)
-
-                       // Init underlying literal.
-                       if !s.staticassign(a, 0, r.X, a.Type()) {
-                               s.append(ir.NewAssignStmt(base.Pos, a, r.X))
-                       }
-                       return true
-               }
-               //dump("not static ptrlit", r);
-
-       case ir.OSTR2BYTES:
-               r := r.(*ir.ConvExpr)
-               if l.Class_ == ir.PEXTERN && r.X.Op() == ir.OLITERAL {
-                       sval := ir.StringVal(r.X)
-                       staticdata.InitSliceBytes(l, loff, sval)
-                       return true
-               }
-
-       case ir.OSLICELIT:
-               r := r.(*ir.CompLitExpr)
-               s.initplan(r)
-               // Init slice.
-               ta := types.NewArray(r.Type().Elem(), r.Len)
-               ta.SetNoalg(true)
-               a := staticname(ta)
-               s.inittemps[r] = a
-               staticdata.InitSlice(l, loff, a, r.Len)
-               // Fall through to init underlying array.
-               l = a
-               loff = 0
-               fallthrough
-
-       case ir.OARRAYLIT, ir.OSTRUCTLIT:
-               r := r.(*ir.CompLitExpr)
-               s.initplan(r)
-
-               p := s.initplans[r]
-               for i := range p.E {
-                       e := &p.E[i]
-                       if e.Expr.Op() == ir.OLITERAL || e.Expr.Op() == ir.ONIL {
-                               litsym(l, loff+e.Xoffset, e.Expr, int(e.Expr.Type().Width))
-                               continue
-                       }
-                       ir.SetPos(e.Expr)
-                       if !s.staticassign(l, loff+e.Xoffset, e.Expr, e.Expr.Type()) {
-                               a := ir.NewNameOffsetExpr(base.Pos, l, loff+e.Xoffset, e.Expr.Type())
-                               s.append(ir.NewAssignStmt(base.Pos, a, e.Expr))
-                       }
-               }
-
-               return true
-
-       case ir.OMAPLIT:
-               break
-
-       case ir.OCLOSURE:
-               r := r.(*ir.ClosureExpr)
-               if hasemptycvars(r) {
-                       if base.Debug.Closure > 0 {
-                               base.WarnfAt(r.Pos(), "closure converted to global")
-                       }
-                       // Closures with no captured variables are globals,
-                       // so the assignment can be done at link time.
-                       // TODO if roff != 0 { panic }
-                       staticdata.InitFunc(l, loff, r.Func.Nname)
-                       return true
-               }
-               closuredebugruntimecheck(r)
-
-       case ir.OCONVIFACE:
-               // This logic is mirrored in isStaticCompositeLiteral.
-               // If you change something here, change it there, and vice versa.
-
-               // Determine the underlying concrete type and value we are converting from.
-               r := r.(*ir.ConvExpr)
-               val := ir.Node(r)
-               for val.Op() == ir.OCONVIFACE {
-                       val = val.(*ir.ConvExpr).X
-               }
-
-               if val.Type().IsInterface() {
-                       // val is an interface type.
-                       // If val is nil, we can statically initialize l;
-                       // both words are zero and so there no work to do, so report success.
-                       // If val is non-nil, we have no concrete type to record,
-                       // and we won't be able to statically initialize its value, so report failure.
-                       return val.Op() == ir.ONIL
-               }
-
-               markTypeUsedInInterface(val.Type(), l.Sym().Linksym())
-
-               var itab *ir.AddrExpr
-               if typ.IsEmptyInterface() {
-                       itab = reflectdata.TypePtr(val.Type())
-               } else {
-                       itab = reflectdata.ITabAddr(val.Type(), typ)
-               }
-
-               // Create a copy of l to modify while we emit data.
-
-               // Emit itab, advance offset.
-               staticdata.InitAddr(l, loff, itab.X.(*ir.Name), 0)
-
-               // Emit data.
-               if types.IsDirectIface(val.Type()) {
-                       if val.Op() == ir.ONIL {
-                               // Nil is zero, nothing to do.
-                               return true
-                       }
-                       // Copy val directly into n.
-                       ir.SetPos(val)
-                       if !s.staticassign(l, loff+int64(types.PtrSize), val, val.Type()) {
-                               a := ir.NewNameOffsetExpr(base.Pos, l, loff+int64(types.PtrSize), val.Type())
-                               s.append(ir.NewAssignStmt(base.Pos, a, val))
-                       }
-               } else {
-                       // Construct temp to hold val, write pointer to temp into n.
-                       a := staticname(val.Type())
-                       s.inittemps[val] = a
-                       if !s.staticassign(a, 0, val, val.Type()) {
-                               s.append(ir.NewAssignStmt(base.Pos, a, val))
-                       }
-                       staticdata.InitAddr(l, loff+int64(types.PtrSize), a, 0)
-               }
-
-               return true
-       }
-
-       //dump("not static", r);
-       return false
-}
-
 // initContext is the context in which static data is populated.
 // It is either in an init function or in any other function.
 // Static data populated in an init function will be written either
@@ -378,29 +38,9 @@ func (c initContext) String() string {
        return "inNonInitFunction"
 }
 
-// from here down is the walk analysis
-// of composite literals.
-// most of the work is to generate
-// data statements for the constant
-// part of the composite literal.
-
-var statuniqgen int // name generator for static temps
-
-// staticname returns a name backed by a (writable) static data symbol.
-// Use readonlystaticname for read-only node.
-func staticname(t *types.Type) *ir.Name {
-       // Don't use lookupN; it interns the resulting string, but these are all unique.
-       n := typecheck.NewName(typecheck.Lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
-       statuniqgen++
-       typecheck.Declare(n, ir.PEXTERN)
-       n.SetType(t)
-       n.Sym().Linksym().Set(obj.AttrLocal, true)
-       return n
-}
-
 // readonlystaticname returns a name backed by a (writable) static data symbol.
 func readonlystaticname(t *types.Type) *ir.Name {
-       n := staticname(t)
+       n := staticinit.StaticName(t)
        n.MarkReadonly()
        n.Sym().Linksym().Set(obj.AttrContentAddressable, true)
        return n
@@ -572,7 +212,7 @@ func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node,
 
        for _, r := range n.List {
                a, value := splitnode(r)
-               if a == ir.BlankNode && !anySideEffects(value) {
+               if a == ir.BlankNode && !staticinit.AnySideEffects(value) {
                        // Discard.
                        continue
                }
@@ -629,14 +269,14 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes)
 
        if ctxt == inNonInitFunction {
                // put everything into static array
-               vstat := staticname(t)
+               vstat := staticinit.StaticName(t)
 
                fixedlit(ctxt, initKindStatic, n, vstat, init)
                fixedlit(ctxt, initKindDynamic, n, vstat, init)
 
                // copy static to slice
                var_ = typecheck.AssignExpr(var_)
-               name, offset, ok := stataddr(var_)
+               name, offset, ok := staticinit.StaticLoc(var_)
                if !ok || name.Class_ != ir.PEXTERN {
                        base.Fatalf("slicelit: %v", var_)
                }
@@ -672,7 +312,7 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes)
                if ctxt == inInitFunction {
                        vstat = readonlystaticname(t)
                } else {
-                       vstat = staticname(t)
+                       vstat = staticinit.StaticName(t)
                }
                fixedlit(ctxt, initKindStatic, n, vstat, init)
        }
@@ -993,150 +633,19 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
        return true
 }
 
-func getlit(lit ir.Node) int {
-       if ir.IsSmallIntConst(lit) {
-               return int(ir.Int64Val(lit))
-       }
-       return -1
-}
-
-// stataddr returns the static address of n, if n has one, or else nil.
-func stataddr(n ir.Node) (name *ir.Name, offset int64, ok bool) {
-       if n == nil {
-               return nil, 0, false
-       }
-
-       switch n.Op() {
-       case ir.ONAME:
-               n := n.(*ir.Name)
-               return n, 0, true
-
-       case ir.OMETHEXPR:
-               n := n.(*ir.MethodExpr)
-               return stataddr(n.FuncName())
-
-       case ir.ODOT:
-               n := n.(*ir.SelectorExpr)
-               if name, offset, ok = stataddr(n.X); !ok {
-                       break
-               }
-               offset += n.Offset
-               return name, offset, true
-
-       case ir.OINDEX:
-               n := n.(*ir.IndexExpr)
-               if n.X.Type().IsSlice() {
-                       break
-               }
-               if name, offset, ok = stataddr(n.X); !ok {
-                       break
-               }
-               l := getlit(n.Index)
-               if l < 0 {
-                       break
-               }
-
-               // Check for overflow.
-               if n.Type().Width != 0 && types.MaxWidth/n.Type().Width <= int64(l) {
-                       break
-               }
-               offset += int64(l) * n.Type().Width
-               return name, offset, true
-       }
-
-       return nil, 0, false
-}
-
-func (s *InitSchedule) initplan(n ir.Node) {
-       if s.initplans[n] != nil {
-               return
-       }
-       p := new(InitPlan)
-       s.initplans[n] = p
-       switch n.Op() {
-       default:
-               base.Fatalf("initplan")
-
-       case ir.OARRAYLIT, ir.OSLICELIT:
-               n := n.(*ir.CompLitExpr)
-               var k int64
-               for _, a := range n.List {
-                       if a.Op() == ir.OKEY {
-                               kv := a.(*ir.KeyExpr)
-                               k = typecheck.IndexConst(kv.Key)
-                               if k < 0 {
-                                       base.Fatalf("initplan arraylit: invalid index %v", kv.Key)
-                               }
-                               a = kv.Value
-                       }
-                       s.addvalue(p, k*n.Type().Elem().Width, a)
-                       k++
-               }
-
-       case ir.OSTRUCTLIT:
-               n := n.(*ir.CompLitExpr)
-               for _, a := range n.List {
-                       if a.Op() != ir.OSTRUCTKEY {
-                               base.Fatalf("initplan structlit")
-                       }
-                       a := a.(*ir.StructKeyExpr)
-                       if a.Field.IsBlank() {
-                               continue
-                       }
-                       s.addvalue(p, a.Offset, a.Value)
-               }
-
-       case ir.OMAPLIT:
-               n := n.(*ir.CompLitExpr)
-               for _, a := range n.List {
-                       if a.Op() != ir.OKEY {
-                               base.Fatalf("initplan maplit")
-                       }
-                       a := a.(*ir.KeyExpr)
-                       s.addvalue(p, -1, a.Value)
-               }
-       }
-}
-
-func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n ir.Node) {
-       // special case: zero can be dropped entirely
-       if ir.IsZero(n) {
-               return
-       }
-
-       // special case: inline struct and array (not slice) literals
-       if isvaluelit(n) {
-               s.initplan(n)
-               q := s.initplans[n]
-               for _, qe := range q.E {
-                       // qe is a copy; we are not modifying entries in q.E
-                       qe.Xoffset += xoffset
-                       p.E = append(p.E, qe)
-               }
-               return
-       }
-
-       // add to plan
-       p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
-}
-
-func isvaluelit(n ir.Node) bool {
-       return n.Op() == ir.OARRAYLIT || n.Op() == ir.OSTRUCTLIT
-}
-
 func genAsStatic(as *ir.AssignStmt) {
        if as.X.Type() == nil {
                base.Fatalf("genAsStatic as.Left not typechecked")
        }
 
-       name, offset, ok := stataddr(as.X)
+       name, offset, ok := staticinit.StaticLoc(as.X)
        if !ok || (name.Class_ != ir.PEXTERN && as.X != ir.BlankNode) {
                base.Fatalf("genAsStatic: lhs %v", as.X)
        }
 
        switch r := as.Y; r.Op() {
        case ir.OLITERAL:
-               litsym(name, offset, r, int(r.Type().Width))
+               staticdata.InitConst(name, offset, r, int(r.Type().Width))
                return
        case ir.OMETHEXPR:
                r := r.(*ir.MethodExpr)
similarity index 99%
rename from src/cmd/compile/internal/gc/subr.go
rename to src/cmd/compile/internal/walk/subr.go
index 17bbd1c3a2d2483c2b673e96efdeceab59bcd004..bc65432d4992af98ea50b5c5cd784bff407f9fbd 100644 (file)
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
+       "fmt"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "fmt"
 )
 
 // backingArrayPtrLen extracts the pointer and length from a slice or string.
similarity index 99%
rename from src/cmd/compile/internal/gc/swt.go
rename to src/cmd/compile/internal/walk/switch.go
index 9ffa8b67bb2772880da0bf8bf7c39807885898d0..9becd0e404ff5b553b9ce5d5e432ef2874a58513 100644 (file)
@@ -2,17 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
+       "go/constant"
+       "go/token"
+       "sort"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/src"
-       "go/constant"
-       "go/token"
-       "sort"
 )
 
 // walkswitch walks a switch statement.
similarity index 97%
rename from src/cmd/compile/internal/gc/walk.go
rename to src/cmd/compile/internal/walk/walk.go
index f86dbba2c9824bd72e6bbc48ed4c49d1be461ab6..cb3018a4ac4540e35ca764808d04561093215b9e 100644 (file)
@@ -2,9 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package gc
+package walk
 
 import (
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "go/constant"
+       "go/token"
+       "strings"
+
        "cmd/compile/internal/base"
        "cmd/compile/internal/escape"
        "cmd/compile/internal/ir"
@@ -17,19 +24,13 @@ import (
        "cmd/internal/objabi"
        "cmd/internal/src"
        "cmd/internal/sys"
-       "encoding/binary"
-       "errors"
-       "fmt"
-       "go/constant"
-       "go/token"
-       "strings"
 )
 
 // The constant is known to runtime.
 const tmpstringbufsize = 32
 const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
 
-func walk(fn *ir.Func) {
+func Walk(fn *ir.Func) {
        ir.CurFunc = fn
        errorsBefore := base.Errors()
        order(fn)
@@ -670,7 +671,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
                n := n.(*ir.CallExpr)
                if n.Op() == ir.OCALLINTER {
                        usemethod(n)
-                       markUsedIfaceMethod(n)
+                       reflectdata.MarkUsedIfaceMethod(n)
                }
 
                if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.OCLOSURE {
@@ -933,7 +934,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
                toType := n.Type()
 
                if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) { // skip unnamed functions (func _())
-                       markTypeUsedInInterface(fromType, ir.CurFunc.LSym)
+                       reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
                }
 
                // typeword generates the type word of the interface value.
@@ -1708,32 +1709,6 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
        // in the presence of type assertions.
 }
 
-// markTypeUsedInInterface marks that type t is converted to an interface.
-// This information is used in the linker in dead method elimination.
-func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
-       tsym := reflectdata.TypeSym(t).Linksym()
-       // Emit a marker relocation. The linker will know the type is converted
-       // to an interface if "from" is reachable.
-       r := obj.Addrel(from)
-       r.Sym = tsym
-       r.Type = objabi.R_USEIFACE
-}
-
-// markUsedIfaceMethod marks that an interface method is used in the current
-// function. n is OCALLINTER node.
-func markUsedIfaceMethod(n *ir.CallExpr) {
-       dot := n.X.(*ir.SelectorExpr)
-       ityp := dot.X.Type()
-       tsym := reflectdata.TypeSym(ityp).Linksym()
-       r := obj.Addrel(ir.CurFunc.LSym)
-       r.Sym = tsym
-       // dot.Xoffset is the method index * Widthptr (the offset of code pointer
-       // in itab).
-       midx := dot.Offset / int64(types.PtrSize)
-       r.Add = reflectdata.InterfaceMethodOffset(ityp, midx)
-       r.Type = objabi.R_USEIFACEMETHOD
-}
-
 // rtconvfn returns the parameter and result types that will be used by a
 // runtime function to convert from type src to type dst. The runtime function
 // name can be derived from the names of the returned types.
@@ -3737,94 +3712,6 @@ func usefield(n *ir.SelectorExpr) {
        ir.CurFunc.FieldTrack[sym] = struct{}{}
 }
 
-// anySideEffects reports whether n contains any operations that could have observable side effects.
-func anySideEffects(n ir.Node) bool {
-       return ir.Any(n, func(n ir.Node) bool {
-               switch n.Op() {
-               // Assume side effects unless we know otherwise.
-               default:
-                       return true
-
-               // No side effects here (arguments are checked separately).
-               case ir.ONAME,
-                       ir.ONONAME,
-                       ir.OTYPE,
-                       ir.OPACK,
-                       ir.OLITERAL,
-                       ir.ONIL,
-                       ir.OADD,
-                       ir.OSUB,
-                       ir.OOR,
-                       ir.OXOR,
-                       ir.OADDSTR,
-                       ir.OADDR,
-                       ir.OANDAND,
-                       ir.OBYTES2STR,
-                       ir.ORUNES2STR,
-                       ir.OSTR2BYTES,
-                       ir.OSTR2RUNES,
-                       ir.OCAP,
-                       ir.OCOMPLIT,
-                       ir.OMAPLIT,
-                       ir.OSTRUCTLIT,
-                       ir.OARRAYLIT,
-                       ir.OSLICELIT,
-                       ir.OPTRLIT,
-                       ir.OCONV,
-                       ir.OCONVIFACE,
-                       ir.OCONVNOP,
-                       ir.ODOT,
-                       ir.OEQ,
-                       ir.ONE,
-                       ir.OLT,
-                       ir.OLE,
-                       ir.OGT,
-                       ir.OGE,
-                       ir.OKEY,
-                       ir.OSTRUCTKEY,
-                       ir.OLEN,
-                       ir.OMUL,
-                       ir.OLSH,
-                       ir.ORSH,
-                       ir.OAND,
-                       ir.OANDNOT,
-                       ir.ONEW,
-                       ir.ONOT,
-                       ir.OBITNOT,
-                       ir.OPLUS,
-                       ir.ONEG,
-                       ir.OOROR,
-                       ir.OPAREN,
-                       ir.ORUNESTR,
-                       ir.OREAL,
-                       ir.OIMAG,
-                       ir.OCOMPLEX:
-                       return false
-
-               // Only possible side effect is division by zero.
-               case ir.ODIV, ir.OMOD:
-                       n := n.(*ir.BinaryExpr)
-                       if n.Y.Op() != ir.OLITERAL || constant.Sign(n.Y.Val()) == 0 {
-                               return true
-                       }
-
-               // Only possible side effect is panic on invalid size,
-               // but many makechan and makemap use size zero, which is definitely OK.
-               case ir.OMAKECHAN, ir.OMAKEMAP:
-                       n := n.(*ir.MakeExpr)
-                       if !ir.IsConst(n.Len, constant.Int) || constant.Sign(n.Len.Val()) != 0 {
-                               return true
-                       }
-
-               // Only possible side effect is panic on invalid size.
-               // TODO(rsc): Merge with previous case (probably breaks toolstash -cmp).
-               case ir.OMAKESLICE, ir.OMAKESLICECOPY:
-                       return true
-               }
-               return false
-       })
-}
-
 // Rewrite
 //     go builtin(x, y, z)
 // into