]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: setup for new Node implementations
authorRuss Cox <rsc@golang.org>
Sat, 28 Nov 2020 05:14:38 +0000 (00:14 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 30 Nov 2020 18:33:50 +0000 (18:33 +0000)
Start a list of which ops are valid for the default
node struct implementation (currently all of them).

Add a Node implementation helper for a minimal node.

Passes buildall w/ toolstash -cmp.

Change-Id: I7ae45f2cf2be85013cb71ab00524be53f243e13d
Reviewed-on: https://go-review.googlesource.com/c/go/+/274088
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/ir/bitset.go
src/cmd/compile/internal/ir/mini.go [new file with mode: 0644]
src/cmd/compile/internal/ir/node.go

index ede3778184bbbb41b240511d678775a07fcbe2fc..9da464e1b67142b8fa6fcdc2eb7623dd576052d1 100644 (file)
@@ -1694,8 +1694,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
                        return n
                }
                op, why := convertop(n.Left().Op() == ir.OLITERAL, t, n.Type())
-               n.SetOp(op)
-               if n.Op() == ir.OXXX {
+               if op == ir.OXXX {
                        if !n.Diag() && !n.Type().Broke() && !n.Left().Diag() {
                                base.Errorf("cannot convert %L to type %v%s", n.Left(), n.Type(), why)
                                n.SetDiag(true)
@@ -1705,6 +1704,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
                        return n
                }
 
+               n.SetOp(op)
                switch n.Op() {
                case ir.OCONVNOP:
                        if t.Etype == n.Type().Etype {
index 29f136296fd1ebc7c81c89f3e389f0f84f8cfa50..0c7bd542f60bbcdf31949dd53a4fe88d6fd21e42 100644 (file)
@@ -14,6 +14,18 @@ func (f *bitset8) set(mask uint8, b bool) {
        }
 }
 
+func (f bitset8) get2(shift uint8) uint8 {
+       return uint8(f>>shift) & 3
+}
+
+// set2 sets two bits in f using the bottom two bits of b.
+func (f *bitset8) set2(shift uint8, b uint8) {
+       // Clear old bits.
+       *(*uint8)(f) &^= 3 << shift
+       // Set new bits.
+       *(*uint8)(f) |= uint8(b&3) << shift
+}
+
 type bitset16 uint16
 
 func (f *bitset16) set(mask uint16, b bool) {
diff --git a/src/cmd/compile/internal/ir/mini.go b/src/cmd/compile/internal/ir/mini.go
new file mode 100644 (file)
index 0000000..48dccf6
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright 2020 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 ir
+
+import (
+       "cmd/compile/internal/types"
+       "cmd/internal/src"
+       "fmt"
+       "go/constant"
+)
+
+// A miniNode is a minimal node implementation,
+// meant to be embedded as the first field in a larger node implementation,
+// at a cost of 8 bytes.
+//
+// A miniNode is NOT a valid Node by itself: the embedding struct
+// must at the least provide:
+//
+//     func (n *MyNode) String() string { return fmt.Sprint(n) }
+//     func (n *MyNode) RawCopy() Node { c := *n; return &c }
+//     func (n *MyNode) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+//
+// The embedding struct should also fill in n.op in its constructor,
+// for more useful panic messages when invalid methods are called,
+// instead of implementing Op itself.
+//
+type miniNode struct {
+       pos  src.XPos // uint32
+       op   Op       // uint8
+       bits bitset8
+       esc  uint16
+}
+
+// op can be read, but not written.
+// An embedding implementation can provide a SetOp if desired.
+// (The panicking SetOp is with the other panics below.)
+func (n *miniNode) Op() Op            { return n.op }
+func (n *miniNode) Pos() src.XPos     { return n.pos }
+func (n *miniNode) SetPos(x src.XPos) { n.pos = x }
+func (n *miniNode) Esc() uint16       { return n.esc }
+func (n *miniNode) SetEsc(x uint16)   { n.esc = x }
+
+const (
+       miniWalkdefShift   = 0
+       miniTypecheckShift = 2
+       miniInitorderShift = 4
+       miniDiag           = 1 << 6
+       miniHasCall        = 1 << 7 // for miniStmt
+)
+
+func (n *miniNode) Walkdef() uint8   { return n.bits.get2(miniWalkdefShift) }
+func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
+func (n *miniNode) Initorder() uint8 { return n.bits.get2(miniInitorderShift) }
+func (n *miniNode) SetWalkdef(x uint8) {
+       if x > 3 {
+               panic(fmt.Sprintf("cannot SetWalkdef %d", x))
+       }
+       n.bits.set2(miniWalkdefShift, x)
+}
+func (n *miniNode) SetTypecheck(x uint8) {
+       if x > 3 {
+               panic(fmt.Sprintf("cannot SetTypecheck %d", x))
+       }
+       n.bits.set2(miniTypecheckShift, x)
+}
+func (n *miniNode) SetInitorder(x uint8) {
+       if x > 3 {
+               panic(fmt.Sprintf("cannot SetInitorder %d", x))
+       }
+       n.bits.set2(miniInitorderShift, x)
+}
+
+func (n *miniNode) Diag() bool     { return n.bits&miniDiag != 0 }
+func (n *miniNode) SetDiag(x bool) { n.bits.set(miniDiag, x) }
+
+// Empty, immutable graph structure.
+
+func (n *miniNode) Left() Node       { return nil }
+func (n *miniNode) Right() Node      { return nil }
+func (n *miniNode) Init() Nodes      { return Nodes{} }
+func (n *miniNode) PtrInit() *Nodes  { return &immutableEmptyNodes }
+func (n *miniNode) Body() Nodes      { return Nodes{} }
+func (n *miniNode) PtrBody() *Nodes  { return &immutableEmptyNodes }
+func (n *miniNode) List() Nodes      { return Nodes{} }
+func (n *miniNode) PtrList() *Nodes  { return &immutableEmptyNodes }
+func (n *miniNode) Rlist() Nodes     { return Nodes{} }
+func (n *miniNode) PtrRlist() *Nodes { return &immutableEmptyNodes }
+func (n *miniNode) SetLeft(x Node) {
+       if x != nil {
+               panic(n.no("SetLeft"))
+       }
+}
+func (n *miniNode) SetRight(x Node) {
+       if x != nil {
+               panic(n.no("SetRight"))
+       }
+}
+func (n *miniNode) SetInit(x Nodes) {
+       if x != (Nodes{}) {
+               panic(n.no("SetInit"))
+       }
+}
+func (n *miniNode) SetBody(x Nodes) {
+       if x != (Nodes{}) {
+               panic(n.no("SetBody"))
+       }
+}
+func (n *miniNode) SetList(x Nodes) {
+       if x != (Nodes{}) {
+               panic(n.no("SetList"))
+       }
+}
+func (n *miniNode) SetRlist(x Nodes) {
+       if x != (Nodes{}) {
+               panic(n.no("SetRlist"))
+       }
+}
+
+// Additional functionality unavailable.
+
+func (n *miniNode) no(name string) string { return "cannot " + name + " on " + n.op.String() }
+
+func (n *miniNode) SetOp(Op)            { panic(n.no("SetOp")) }
+func (n *miniNode) SubOp() Op           { panic(n.no("SubOp")) }
+func (n *miniNode) SetSubOp(Op)         { panic(n.no("SetSubOp")) }
+func (n *miniNode) Type() *types.Type   { return nil }
+func (n *miniNode) SetType(*types.Type) { panic(n.no("SetType")) }
+func (n *miniNode) Func() *Func         { panic(n.no("Func")) }
+func (n *miniNode) SetFunc(*Func)       { panic(n.no("SetFunc")) }
+func (n *miniNode) Name() *Name         { return nil }
+func (n *miniNode) SetName(*Name)       { panic(n.no("SetName")) }
+func (n *miniNode) Sym() *types.Sym     { return nil }
+func (n *miniNode) SetSym(*types.Sym)   { panic(n.no("SetSym")) }
+func (n *miniNode) Offset() int64       { return types.BADWIDTH }
+func (n *miniNode) SetOffset(x int64)   { panic(n.no("SetOffset")) }
+func (n *miniNode) Class() Class        { return Pxxx }
+func (n *miniNode) SetClass(Class)      { panic(n.no("SetClass")) }
+func (n *miniNode) Likely() bool        { panic(n.no("Likely")) }
+func (n *miniNode) SetLikely(bool)      { panic(n.no("SetLikely")) }
+func (n *miniNode) SliceBounds() (low, high, max Node) {
+       panic(n.no("SliceBounds"))
+}
+func (n *miniNode) SetSliceBounds(low, high, max Node) {
+       panic(n.no("SetSliceBounds"))
+}
+func (n *miniNode) Iota() int64               { panic(n.no("Iota")) }
+func (n *miniNode) SetIota(int64)             { panic(n.no("SetIota")) }
+func (n *miniNode) Colas() bool               { return false }
+func (n *miniNode) SetColas(bool)             { panic(n.no("SetColas")) }
+func (n *miniNode) NoInline() bool            { panic(n.no("NoInline")) }
+func (n *miniNode) SetNoInline(bool)          { panic(n.no("SetNoInline")) }
+func (n *miniNode) Transient() bool           { panic(n.no("Transient")) }
+func (n *miniNode) SetTransient(bool)         { panic(n.no("SetTransient")) }
+func (n *miniNode) Implicit() bool            { return false }
+func (n *miniNode) SetImplicit(bool)          { panic(n.no("SetImplicit")) }
+func (n *miniNode) IsDDD() bool               { return false }
+func (n *miniNode) SetIsDDD(bool)             { panic(n.no("SetIsDDD")) }
+func (n *miniNode) Embedded() bool            { return false }
+func (n *miniNode) SetEmbedded(bool)          { panic(n.no("SetEmbedded")) }
+func (n *miniNode) IndexMapLValue() bool      { panic(n.no("IndexMapLValue")) }
+func (n *miniNode) SetIndexMapLValue(bool)    { panic(n.no("SetIndexMapLValue")) }
+func (n *miniNode) ResetAux()                 { panic(n.no("ResetAux")) }
+func (n *miniNode) HasBreak() bool            { panic(n.no("HasBreak")) }
+func (n *miniNode) SetHasBreak(bool)          { panic(n.no("SetHasBreak")) }
+func (n *miniNode) HasVal() bool              { return false }
+func (n *miniNode) Val() constant.Value       { panic(n.no("Val")) }
+func (n *miniNode) SetVal(v constant.Value)   { panic(n.no("SetVal")) }
+func (n *miniNode) Int64Val() int64           { panic(n.no("Int64Val")) }
+func (n *miniNode) Uint64Val() uint64         { panic(n.no("Uint64Val")) }
+func (n *miniNode) CanInt64() bool            { panic(n.no("CanInt64")) }
+func (n *miniNode) BoolVal() bool             { panic(n.no("BoolVal")) }
+func (n *miniNode) StringVal() string         { panic(n.no("StringVal")) }
+func (n *miniNode) HasCall() bool             { panic(n.no("HasCall")) }
+func (n *miniNode) SetHasCall(bool)           { panic(n.no("SetHasCall")) }
+func (n *miniNode) NonNil() bool              { return false }
+func (n *miniNode) MarkNonNil()               { panic(n.no("MarkNonNil")) }
+func (n *miniNode) Bounded() bool             { return false }
+func (n *miniNode) SetBounded(bool)           { panic(n.no("SetBounded")) }
+func (n *miniNode) Opt() interface{}          { return nil }
+func (n *miniNode) SetOpt(interface{})        { panic(n.no("SetOpt")) }
+func (n *miniNode) MarkReadonly()             { panic(n.no("MarkReadonly")) }
+func (n *miniNode) TChanDir() types.ChanDir   { panic(n.no("TChanDir")) }
+func (n *miniNode) SetTChanDir(types.ChanDir) { panic(n.no("SetTChanDir")) }
+
+// TODO: Delete when CanBeAnSSASym is removed from Node itself.
+func (*miniNode) CanBeAnSSASym() {}
index acfddd2dc7d768eaaad09c382177d5d27759492f..7a61355858fb1135ef3906cc5550d340c2c87f69 100644 (file)
@@ -199,7 +199,6 @@ func (n *node) SetOffset(x int64)     { n.offset = x }
 func (n *node) Esc() uint16           { return n.esc }
 func (n *node) SetEsc(x uint16)       { n.esc = x }
 func (n *node) Op() Op                { return n.op }
-func (n *node) SetOp(x Op)            { n.op = x }
 func (n *node) Init() Nodes           { return n.init }
 func (n *node) SetInit(x Nodes)       { n.init = x }
 func (n *node) PtrInit() *Nodes       { return &n.init }
@@ -213,6 +212,13 @@ func (n *node) Rlist() Nodes          { return n.rlist }
 func (n *node) SetRlist(x Nodes)      { n.rlist = x }
 func (n *node) PtrRlist() *Nodes      { return &n.rlist }
 
+func (n *node) SetOp(op Op) {
+       if !okForNod[op] {
+               panic("cannot node.SetOp " + op.String())
+       }
+       n.op = op
+}
+
 func (n *node) ResetAux() {
        n.aux = 0
 }
@@ -1109,6 +1115,10 @@ const (
 // a slice to save space.
 type Nodes struct{ slice *[]Node }
 
+// immutableEmptyNodes is an immutable, empty Nodes list.
+// The methods that would modify it panic instead.
+var immutableEmptyNodes = Nodes{}
+
 // asNodes returns a slice of *Node as a Nodes value.
 func AsNodes(s []Node) Nodes {
        return Nodes{&s}
@@ -1150,9 +1160,22 @@ func (n Nodes) Second() Node {
        return (*n.slice)[1]
 }
 
+func (n *Nodes) mutate() {
+       if n == &immutableEmptyNodes {
+               panic("immutable Nodes.Set")
+       }
+}
+
 // Set sets n to a slice.
 // This takes ownership of the slice.
 func (n *Nodes) Set(s []Node) {
+       if n == &immutableEmptyNodes {
+               if len(s) == 0 {
+                       // Allow immutableEmptyNodes.Set(nil) (a no-op).
+                       return
+               }
+               n.mutate()
+       }
        if len(s) == 0 {
                n.slice = nil
        } else {
@@ -1166,21 +1189,25 @@ func (n *Nodes) Set(s []Node) {
 
 // Set1 sets n to a slice containing a single node.
 func (n *Nodes) Set1(n1 Node) {
+       n.mutate()
        n.slice = &[]Node{n1}
 }
 
 // Set2 sets n to a slice containing two nodes.
 func (n *Nodes) Set2(n1, n2 Node) {
+       n.mutate()
        n.slice = &[]Node{n1, n2}
 }
 
 // Set3 sets n to a slice containing three nodes.
 func (n *Nodes) Set3(n1, n2, n3 Node) {
+       n.mutate()
        n.slice = &[]Node{n1, n2, n3}
 }
 
 // MoveNodes sets n to the contents of n2, then clears n2.
 func (n *Nodes) MoveNodes(n2 *Nodes) {
+       n.mutate()
        n.slice = n2.slice
        n2.slice = nil
 }
@@ -1214,6 +1241,7 @@ func (n *Nodes) Append(a ...Node) {
        if len(a) == 0 {
                return
        }
+       n.mutate()
        if n.slice == nil {
                s := make([]Node, len(a))
                copy(s, a)
@@ -1229,6 +1257,7 @@ func (n *Nodes) Prepend(a ...Node) {
        if len(a) == 0 {
                return
        }
+       n.mutate()
        if n.slice == nil {
                n.slice = &a
        } else {
@@ -1238,6 +1267,7 @@ func (n *Nodes) Prepend(a ...Node) {
 
 // AppendNodes appends the contents of *n2 to n, then clears n2.
 func (n *Nodes) AppendNodes(n2 *Nodes) {
+       n.mutate()
        switch {
        case n2.slice == nil:
        case n.slice == nil:
@@ -1341,43 +1371,7 @@ func (s NodeSet) Sorted(less func(Node, Node) bool) []Node {
        return res
 }
 
-func Nod(op Op, nleft, nright Node) Node {
-       return NodAt(base.Pos, op, nleft, nright)
-}
-
-func NodAt(pos src.XPos, op Op, nleft, nright Node) Node {
-       var n Node
-       switch op {
-       case ODCLFUNC:
-               var x struct {
-                       n node
-                       f Func
-               }
-               n = &x.n
-               n.SetFunc(&x.f)
-               n.Func().Decl = n
-       case ONAME:
-               base.Fatalf("use newname instead")
-       case OLABEL, OPACK:
-               var x struct {
-                       n node
-                       m Name
-               }
-               n = &x.n
-               n.SetName(&x.m)
-       default:
-               n = new(node)
-       }
-       n.SetOp(op)
-       n.SetLeft(nleft)
-       n.SetRight(nright)
-       n.SetPos(pos)
-       n.SetOffset(types.BADWIDTH)
-       n.SetOrig(n)
-       return n
-}
-
-// newnamel returns a new ONAME Node associated with symbol s at position pos.
+// NewNameAt returns a new ONAME Node associated with symbol s at position pos.
 // The caller is responsible for setting n.Name.Curfn.
 func NewNameAt(pos src.XPos, s *types.Sym) Node {
        if s == nil {
@@ -1664,3 +1658,193 @@ func IsBlank(n Node) bool {
 func IsMethod(n Node) bool {
        return n.Type().Recv() != nil
 }
+
+func Nod(op Op, nleft, nright Node) Node {
+       return NodAt(base.Pos, op, nleft, nright)
+}
+
+func NodAt(pos src.XPos, op Op, nleft, nright Node) Node {
+       var n Node
+       switch op {
+       case ODCLFUNC:
+               var x struct {
+                       n node
+                       f Func
+               }
+               n = &x.n
+               n.SetFunc(&x.f)
+               n.Func().Decl = n
+       case OLABEL, OPACK:
+               var x struct {
+                       n node
+                       m Name
+               }
+               n = &x.n
+               n.SetName(&x.m)
+       default:
+               n = new(node)
+       }
+       n.SetOp(op)
+       n.SetLeft(nleft)
+       n.SetRight(nright)
+       n.SetPos(pos)
+       n.SetOffset(types.BADWIDTH)
+       n.SetOrig(n)
+       return n
+}
+
+var okForNod = [OEND]bool{
+       OADD:           true,
+       OADDR:          true,
+       OADDSTR:        true,
+       OALIGNOF:       true,
+       OAND:           true,
+       OANDAND:        true,
+       OANDNOT:        true,
+       OAPPEND:        true,
+       OARRAYLIT:      true,
+       OAS:            true,
+       OAS2:           true,
+       OAS2DOTTYPE:    true,
+       OAS2FUNC:       true,
+       OAS2MAPR:       true,
+       OAS2RECV:       true,
+       OASOP:          true,
+       OBITNOT:        true,
+       OBLOCK:         true,
+       OBREAK:         true,
+       OBYTES2STR:     true,
+       OBYTES2STRTMP:  true,
+       OCALL:          true,
+       OCALLFUNC:      true,
+       OCALLINTER:     true,
+       OCALLMETH:      true,
+       OCALLPART:      true,
+       OCAP:           true,
+       OCASE:          true,
+       OCFUNC:         true,
+       OCHECKNIL:      true,
+       OCLOSE:         true,
+       OCLOSURE:       true,
+       OCLOSUREVAR:    true,
+       OCOMPLEX:       true,
+       OCOMPLIT:       true,
+       OCONTINUE:      true,
+       OCONV:          true,
+       OCONVIFACE:     true,
+       OCONVNOP:       true,
+       OCOPY:          true,
+       ODCL:           true,
+       ODCLCONST:      true,
+       ODCLFIELD:      true,
+       ODCLFUNC:       true,
+       ODCLTYPE:       true,
+       ODDD:           true,
+       ODEFER:         true,
+       ODELETE:        true,
+       ODEREF:         true,
+       ODIV:           true,
+       ODOT:           true,
+       ODOTINTER:      true,
+       ODOTMETH:       true,
+       ODOTPTR:        true,
+       ODOTTYPE:       true,
+       ODOTTYPE2:      true,
+       OEFACE:         true,
+       OEMPTY:         true,
+       OEQ:            true,
+       OFALL:          true,
+       OFOR:           true,
+       OFORUNTIL:      true,
+       OGE:            true,
+       OGETG:          true,
+       OGO:            true,
+       OGOTO:          true,
+       OGT:            true,
+       OIDATA:         true,
+       OIF:            true,
+       OIMAG:          true,
+       OINDEX:         true,
+       OINDEXMAP:      true,
+       OINLCALL:       true,
+       OINLMARK:       true,
+       OIOTA:          true,
+       OITAB:          true,
+       OKEY:           true,
+       OLABEL:         true,
+       OLE:            true,
+       OLEN:           true,
+       OLITERAL:       true,
+       OLSH:           true,
+       OLT:            true,
+       OMAKE:          true,
+       OMAKECHAN:      true,
+       OMAKEMAP:       true,
+       OMAKESLICE:     true,
+       OMAKESLICECOPY: true,
+       OMAPLIT:        true,
+       OMETHEXPR:      true,
+       OMOD:           true,
+       OMUL:           true,
+       ONAME:          true,
+       ONE:            true,
+       ONEG:           true,
+       ONEW:           true,
+       ONEWOBJ:        true,
+       ONIL:           true,
+       ONONAME:        true,
+       ONOT:           true,
+       OOFFSETOF:      true,
+       OOR:            true,
+       OOROR:          true,
+       OPACK:          true,
+       OPANIC:         true,
+       OPAREN:         true,
+       OPLUS:          true,
+       OPRINT:         true,
+       OPRINTN:        true,
+       OPTRLIT:        true,
+       ORANGE:         true,
+       OREAL:          true,
+       ORECOVER:       true,
+       ORECV:          true,
+       ORESULT:        true,
+       ORETJMP:        true,
+       ORETURN:        true,
+       ORSH:           true,
+       ORUNES2STR:     true,
+       ORUNESTR:       true,
+       OSELECT:        true,
+       OSELRECV:       true,
+       OSELRECV2:      true,
+       OSEND:          true,
+       OSIZEOF:        true,
+       OSLICE:         true,
+       OSLICE3:        true,
+       OSLICE3ARR:     true,
+       OSLICEARR:      true,
+       OSLICEHEADER:   true,
+       OSLICELIT:      true,
+       OSLICESTR:      true,
+       OSPTR:          true,
+       OSTR2BYTES:     true,
+       OSTR2BYTESTMP:  true,
+       OSTR2RUNES:     true,
+       OSTRUCTKEY:     true,
+       OSTRUCTLIT:     true,
+       OSUB:           true,
+       OSWITCH:        true,
+       OTARRAY:        true,
+       OTCHAN:         true,
+       OTFUNC:         true,
+       OTINTER:        true,
+       OTMAP:          true,
+       OTSTRUCT:       true,
+       OTYPE:          true,
+       OTYPESW:        true,
+       OVARDEF:        true,
+       OVARKILL:       true,
+       OVARLIVE:       true,
+       OXDOT:          true,
+       OXOR:           true,
+}