aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/order.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/order.go')
-rw-r--r--src/cmd/compile/internal/gc/order.go928
1 files changed, 465 insertions, 463 deletions
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 863de5b6c7..b7d713439b 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -5,6 +5,8 @@
package gc
import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
@@ -42,33 +44,33 @@ import (
// Order holds state during the ordering process.
type Order struct {
- out []*Node // list of generated statements
- temp []*Node // stack of temporary variables
- free map[string][]*Node // free list of unused temporaries, by type.LongString().
+ out []ir.Node // list of generated statements
+ temp []ir.Node // stack of temporary variables
+ free map[string][]ir.Node // free list of unused temporaries, by type.LongString().
}
// Order rewrites fn.Nbody to apply the ordering constraints
// described in the comment at the top of the file.
-func order(fn *Node) {
- if Debug.W > 1 {
- s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
- dumplist(s, fn.Nbody)
+func order(fn ir.Node) {
+ if base.Flag.W > 1 {
+ s := fmt.Sprintf("\nbefore order %v", fn.Func().Nname.Sym())
+ ir.DumpList(s, fn.Body())
}
- orderBlock(&fn.Nbody, map[string][]*Node{})
+ orderBlock(fn.PtrBody(), map[string][]ir.Node{})
}
// 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) *Node {
- var v *Node
+func (o *Order) newTemp(t *types.Type, clear bool) ir.Node {
+ var v ir.Node
// Note: LongString is close to the type equality we want,
// but not exactly. We still need to double-check with types.Identical.
key := t.LongString()
a := o.free[key]
for i, n := range a {
- if types.Identical(t, n.Type) {
+ if types.Identical(t, n.Type()) {
v = a[i]
a[i] = a[len(a)-1]
a = a[:len(a)-1]
@@ -80,7 +82,7 @@ func (o *Order) newTemp(t *types.Type, clear bool) *Node {
v = temp(t)
}
if clear {
- a := nod(OAS, v, nil)
+ a := ir.Nod(ir.OAS, v, nil)
a = typecheck(a, ctxStmt)
o.out = append(o.out, a)
}
@@ -101,9 +103,9 @@ func (o *Order) newTemp(t *types.Type, clear bool) *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) copyExpr(n *Node, t *types.Type, clear bool) *Node {
+func (o *Order) copyExpr(n ir.Node, t *types.Type, clear bool) ir.Node {
v := o.newTemp(t, clear)
- a := nod(OAS, v, n)
+ a := ir.Nod(ir.OAS, v, n)
a = typecheck(a, ctxStmt)
o.out = append(o.out, a)
return v
@@ -113,25 +115,25 @@ func (o *Order) copyExpr(n *Node, t *types.Type, clear bool) *Node {
// 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 *Node) *Node {
+func (o *Order) cheapExpr(n ir.Node) ir.Node {
if n == nil {
return nil
}
- switch n.Op {
- case ONAME, OLITERAL:
+ switch n.Op() {
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
- case OLEN, OCAP:
- l := o.cheapExpr(n.Left)
- if l == n.Left {
+ case ir.OLEN, ir.OCAP:
+ l := o.cheapExpr(n.Left())
+ if l == n.Left() {
return n
}
- a := n.sepcopy()
- a.Left = l
+ a := ir.SepCopy(n)
+ a.SetLeft(l)
return typecheck(a, ctxExpr)
}
- return o.copyExpr(n, n.Type, false)
+ return o.copyExpr(n, n.Type(), false)
}
// safeExpr returns a safe version of n.
@@ -141,47 +143,47 @@ func (o *Order) cheapExpr(n *Node) *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 *Node) *Node {
- switch n.Op {
- case ONAME, OLITERAL:
+func (o *Order) safeExpr(n ir.Node) ir.Node {
+ switch n.Op() {
+ case ir.ONAME, ir.OLITERAL, ir.ONIL:
return n
- case ODOT, OLEN, OCAP:
- l := o.safeExpr(n.Left)
- if l == n.Left {
+ case ir.ODOT, ir.OLEN, ir.OCAP:
+ l := o.safeExpr(n.Left())
+ if l == n.Left() {
return n
}
- a := n.sepcopy()
- a.Left = l
+ a := ir.SepCopy(n)
+ a.SetLeft(l)
return typecheck(a, ctxExpr)
- case ODOTPTR, ODEREF:
- l := o.cheapExpr(n.Left)
- if l == n.Left {
+ case ir.ODOTPTR, ir.ODEREF:
+ l := o.cheapExpr(n.Left())
+ if l == n.Left() {
return n
}
- a := n.sepcopy()
- a.Left = l
+ a := ir.SepCopy(n)
+ a.SetLeft(l)
return typecheck(a, ctxExpr)
- case OINDEX, OINDEXMAP:
- var l *Node
- if n.Left.Type.IsArray() {
- l = o.safeExpr(n.Left)
+ case ir.OINDEX, ir.OINDEXMAP:
+ var l ir.Node
+ if n.Left().Type().IsArray() {
+ l = o.safeExpr(n.Left())
} else {
- l = o.cheapExpr(n.Left)
+ l = o.cheapExpr(n.Left())
}
- r := o.cheapExpr(n.Right)
- if l == n.Left && r == n.Right {
+ r := o.cheapExpr(n.Right())
+ if l == n.Left() && r == n.Right() {
return n
}
- a := n.sepcopy()
- a.Left = l
- a.Right = r
+ a := ir.SepCopy(n)
+ a.SetLeft(l)
+ a.SetRight(r)
return typecheck(a, ctxExpr)
default:
- Fatalf("order.safeExpr %v", n.Op)
+ base.Fatalf("order.safeExpr %v", n.Op())
return nil // not reached
}
}
@@ -192,8 +194,8 @@ func (o *Order) safeExpr(n *Node) *Node {
// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
// because we emit explicit VARKILL instructions marking the end of those
// temporaries' lifetimes.
-func isaddrokay(n *Node) bool {
- return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp())
+func isaddrokay(n ir.Node) bool {
+ return islvalue(n) && (n.Op() != ir.ONAME || n.Class() == ir.PEXTERN || ir.IsAutoTmp(n))
}
// addrTemp ensures that n is okay to pass by address to runtime routines.
@@ -201,16 +203,16 @@ func isaddrokay(n *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 *Node) *Node {
- if consttype(n) != CTxxx {
+func (o *Order) 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 = defaultlit(n, nil)
- dowidth(n.Type)
- vstat := readonlystaticname(n.Type)
+ dowidth(n.Type())
+ vstat := readonlystaticname(n.Type())
var s InitSchedule
s.staticassign(vstat, n)
if s.out != nil {
- Fatalf("staticassign of const generated code: %+v", n)
+ base.Fatalf("staticassign of const generated code: %+v", n)
}
vstat = typecheck(vstat, ctxExpr)
return vstat
@@ -218,12 +220,12 @@ func (o *Order) addrTemp(n *Node) *Node {
if isaddrokay(n) {
return n
}
- return o.copyExpr(n, n.Type, false)
+ return o.copyExpr(n, n.Type(), false)
}
// 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 *Node) *Node {
+func (o *Order) 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 {
@@ -246,22 +248,22 @@ func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node {
// It would be nice to handle these generally, but because
// []byte keys are not allowed in maps, the use of string(k)
// comes up in important cases in practice. See issue 3512.
-func mapKeyReplaceStrConv(n *Node) bool {
+func mapKeyReplaceStrConv(n ir.Node) bool {
var replaced bool
- switch n.Op {
- case OBYTES2STR:
- n.Op = OBYTES2STRTMP
+ switch n.Op() {
+ case ir.OBYTES2STR:
+ n.SetOp(ir.OBYTES2STRTMP)
replaced = true
- case OSTRUCTLIT:
- for _, elem := range n.List.Slice() {
- if mapKeyReplaceStrConv(elem.Left) {
+ case ir.OSTRUCTLIT:
+ for _, elem := range n.List().Slice() {
+ if mapKeyReplaceStrConv(elem.Left()) {
replaced = true
}
}
- case OARRAYLIT:
- for _, elem := range n.List.Slice() {
- if elem.Op == OKEY {
- elem = elem.Right
+ case ir.OARRAYLIT:
+ for _, elem := range n.List().Slice() {
+ if elem.Op() == ir.OKEY {
+ elem = elem.Right()
}
if mapKeyReplaceStrConv(elem) {
replaced = true
@@ -282,7 +284,7 @@ func (o *Order) markTemp() ordermarker {
// which must have been returned by markTemp.
func (o *Order) popTemp(mark ordermarker) {
for _, n := range o.temp[mark:] {
- key := n.Type.LongString()
+ key := n.Type().LongString()
o.free[key] = append(o.free[key], n)
}
o.temp = o.temp[:mark]
@@ -291,11 +293,11 @@ 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) []*Node {
- var out []*Node
+func (o *Order) cleanTempNoPop(mark ordermarker) []ir.Node {
+ var out []ir.Node
for i := len(o.temp) - 1; i >= int(mark); i-- {
n := o.temp[i]
- kill := nod(OVARKILL, n, nil)
+ kill := ir.Nod(ir.OVARKILL, n, nil)
kill = typecheck(kill, ctxStmt)
out = append(out, kill)
}
@@ -310,7 +312,7 @@ func (o *Order) cleanTemp(top ordermarker) {
}
// stmtList orders each of the statements in the list.
-func (o *Order) stmtList(l Nodes) {
+func (o *Order) stmtList(l ir.Nodes) {
s := l.Slice()
for i := range s {
orderMakeSliceCopy(s[i:])
@@ -322,8 +324,8 @@ func (o *Order) stmtList(l Nodes) {
// m = OMAKESLICE([]T, x); OCOPY(m, s)
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
-func orderMakeSliceCopy(s []*Node) {
- if Debug.N != 0 || instrumenting {
+func orderMakeSliceCopy(s []ir.Node) {
+ if base.Flag.N != 0 || instrumenting {
return
}
@@ -334,46 +336,46 @@ func orderMakeSliceCopy(s []*Node) {
asn := s[0]
copyn := s[1]
- if asn == nil || asn.Op != OAS {
+ if asn == nil || asn.Op() != ir.OAS {
return
}
- if asn.Left.Op != ONAME {
+ if asn.Left().Op() != ir.ONAME {
return
}
- if asn.Left.isBlank() {
+ if ir.IsBlank(asn.Left()) {
return
}
- maken := asn.Right
- if maken == nil || maken.Op != OMAKESLICE {
+ maken := asn.Right()
+ if maken == nil || maken.Op() != ir.OMAKESLICE {
return
}
- if maken.Esc == EscNone {
+ if maken.Esc() == EscNone {
return
}
- if maken.Left == nil || maken.Right != nil {
+ if maken.Left() == nil || maken.Right() != nil {
return
}
- if copyn.Op != OCOPY {
+ if copyn.Op() != ir.OCOPY {
return
}
- if copyn.Left.Op != ONAME {
+ if copyn.Left().Op() != ir.ONAME {
return
}
- if asn.Left.Sym != copyn.Left.Sym {
+ if asn.Left().Sym() != copyn.Left().Sym() {
return
}
- if copyn.Right.Op != ONAME {
+ if copyn.Right().Op() != ir.ONAME {
return
}
- if copyn.Left.Sym == copyn.Right.Sym {
+ if copyn.Left().Sym() == copyn.Right().Sym() {
return
}
- maken.Op = OMAKESLICECOPY
- maken.Right = copyn.Right
+ maken.SetOp(ir.OMAKESLICECOPY)
+ maken.SetRight(copyn.Right())
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
- maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
+ maken.SetBounded(maken.Left().Op() == ir.OLEN && samesafeexpr(maken.Left().Left(), copyn.Right()))
maken = typecheck(maken, ctxExpr)
@@ -384,18 +386,18 @@ func orderMakeSliceCopy(s []*Node) {
// edge inserts coverage instrumentation for libfuzzer.
func (o *Order) edge() {
- if Debug_libfuzzer == 0 {
+ if base.Debug.Libfuzzer == 0 {
return
}
// Create a new uint8 counter to be allocated in section
// __libfuzzer_extra_counters.
- counter := staticname(types.Types[TUINT8])
- counter.Name.SetLibfuzzerExtraCounter(true)
+ counter := staticname(types.Types[types.TUINT8])
+ counter.Name().SetLibfuzzerExtraCounter(true)
// counter += 1
- incr := nod(OASOP, counter, nodintconst(1))
- incr.SetSubOp(OADD)
+ incr := ir.Nod(ir.OASOP, counter, nodintconst(1))
+ incr.SetSubOp(ir.OADD)
incr = typecheck(incr, ctxStmt)
o.out = append(o.out, incr)
@@ -404,7 +406,7 @@ func (o *Order) edge() {
// orderBlock orders the block of statements in n into a new slice,
// 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 *Nodes, free map[string][]*Node) {
+func orderBlock(n *ir.Nodes, free map[string][]ir.Node) {
var order Order
order.free = free
mark := order.markTemp()
@@ -418,7 +420,7 @@ func orderBlock(n *Nodes, free map[string][]*Node) {
// 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 *Node) *Node {
+func (o *Order) exprInPlace(n ir.Node) ir.Node {
var order Order
order.free = o.free
n = order.expr(n, nil)
@@ -435,7 +437,7 @@ func (o *Order) exprInPlace(n *Node) *Node {
// The result of orderStmtInPlace MUST be assigned back to n, e.g.
// n.Left = orderStmtInPlace(n.Left)
// free is a map that can be used to obtain temporary variables by type.
-func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
+func orderStmtInPlace(n ir.Node, free map[string][]ir.Node) ir.Node {
var order Order
order.free = free
mark := order.markTemp()
@@ -445,60 +447,60 @@ func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
}
// init moves n's init list to o.out.
-func (o *Order) init(n *Node) {
- if n.mayBeShared() {
+func (o *Order) 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.
- if n.Ninit.Len() > 0 {
- Fatalf("order.init shared node with ninit")
+ if n.Init().Len() > 0 {
+ base.Fatalf("order.init shared node with ninit")
}
return
}
- o.stmtList(n.Ninit)
- n.Ninit.Set(nil)
+ o.stmtList(n.Init())
+ n.PtrInit().Set(nil)
}
// call orders the call expression n.
// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-func (o *Order) call(n *Node) {
- if n.Ninit.Len() > 0 {
+func (o *Order) call(n ir.Node) {
+ if n.Init().Len() > 0 {
// Caller should have already called o.init(n).
- Fatalf("%v with unexpected ninit", n.Op)
+ base.Fatalf("%v with unexpected ninit", n.Op())
}
// Builtin functions.
- if n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER {
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
- o.exprList(n.List)
+ if n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER {
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
+ o.exprList(n.List())
return
}
fixVariadicCall(n)
- n.Left = o.expr(n.Left, nil)
- o.exprList(n.List)
+ n.SetLeft(o.expr(n.Left(), nil))
+ o.exprList(n.List())
- if n.Op == OCALLINTER {
+ if n.Op() == ir.OCALLINTER {
return
}
- keepAlive := func(arg *Node) {
+ keepAlive := func(arg ir.Node) {
// If the argument is really a pointer being converted to uintptr,
// arrange for the pointer to be kept alive until the call returns,
// by copying it into a temp and marking that temp
// still alive when we pop the temp stack.
- if arg.Op == OCONVNOP && arg.Left.Type.IsUnsafePtr() {
- x := o.copyExpr(arg.Left, arg.Left.Type, false)
- arg.Left = x
- x.Name.SetAddrtaken(true) // ensure SSA keeps the x variable
- n.Nbody.Append(typecheck(nod(OVARLIVE, x, nil), ctxStmt))
+ if arg.Op() == ir.OCONVNOP && arg.Left().Type().IsUnsafePtr() {
+ x := o.copyExpr(arg.Left(), arg.Left().Type(), false)
+ arg.SetLeft(x)
+ x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
+ n.PtrBody().Append(typecheck(ir.Nod(ir.OVARLIVE, x, nil), ctxStmt))
}
}
// Check for "unsafe-uintptr" tag provided by escape analysis.
- for i, param := range n.Left.Type.Params().FieldSlice() {
+ for i, param := range n.Left().Type().Params().FieldSlice() {
if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
- if arg := n.List.Index(i); arg.Op == OSLICELIT {
- for _, elt := range arg.List.Slice() {
+ if arg := n.List().Index(i); arg.Op() == ir.OSLICELIT {
+ for _, elt := range arg.List().Slice() {
keepAlive(elt)
}
} else {
@@ -523,42 +525,42 @@ func (o *Order) call(n *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 *Node) {
- switch n.Op {
+func (o *Order) mapAssign(n ir.Node) {
+ switch n.Op() {
default:
- Fatalf("order.mapAssign %v", n.Op)
+ base.Fatalf("order.mapAssign %v", n.Op())
- case OAS, OASOP:
- if n.Left.Op == OINDEXMAP {
+ case ir.OAS, ir.OASOP:
+ if n.Left().Op() == ir.OINDEXMAP {
// 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 n.Right.Op == OAPPEND {
- s := n.Right.List.Slice()[1:]
+ if n.Right().Op() == ir.OAPPEND {
+ s := n.Right().List().Slice()[1:]
for i, n := range s {
s[i] = o.cheapExpr(n)
}
} else {
- n.Right = o.cheapExpr(n.Right)
+ n.SetRight(o.cheapExpr(n.Right()))
}
}
o.out = append(o.out, n)
- case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
- var post []*Node
- for i, m := range n.List.Slice() {
+ case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
+ var post []ir.Node
+ for i, m := range n.List().Slice() {
switch {
- case m.Op == OINDEXMAP:
- if !m.Left.IsAutoTmp() {
- m.Left = o.copyExpr(m.Left, m.Left.Type, false)
+ case m.Op() == ir.OINDEXMAP:
+ if !ir.IsAutoTmp(m.Left()) {
+ m.SetLeft(o.copyExpr(m.Left(), m.Left().Type(), false))
}
- if !m.Right.IsAutoTmp() {
- m.Right = o.copyExpr(m.Right, m.Right.Type, false)
+ if !ir.IsAutoTmp(m.Right()) {
+ m.SetRight(o.copyExpr(m.Right(), m.Right().Type(), false))
}
fallthrough
- case instrumenting && n.Op == OAS2FUNC && !m.isBlank():
- t := o.newTemp(m.Type, false)
- n.List.SetIndex(i, t)
- a := nod(OAS, m, t)
+ case instrumenting && n.Op() == ir.OAS2FUNC && !ir.IsBlank(m):
+ t := o.newTemp(m.Type(), false)
+ n.List().SetIndex(i, t)
+ a := ir.Nod(ir.OAS, m, t)
a = typecheck(a, ctxStmt)
post = append(post, a)
}
@@ -572,7 +574,7 @@ func (o *Order) mapAssign(n *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 *Node) {
+func (o *Order) stmt(n ir.Node) {
if n == nil {
return
}
@@ -580,62 +582,62 @@ func (o *Order) stmt(n *Node) {
lno := setlineno(n)
o.init(n)
- switch n.Op {
+ switch n.Op() {
default:
- Fatalf("order.stmt %v", n.Op)
+ base.Fatalf("order.stmt %v", n.Op())
- case OVARKILL, OVARLIVE, OINLMARK:
+ case ir.OVARKILL, ir.OVARLIVE, ir.OINLMARK:
o.out = append(o.out, n)
- case OAS:
+ case ir.OAS:
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, n.Left)
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), n.Left()))
o.mapAssign(n)
o.cleanTemp(t)
- case OASOP:
+ case ir.OASOP:
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
- if instrumenting || n.Left.Op == OINDEXMAP && (n.SubOp() == ODIV || n.SubOp() == OMOD) {
+ if instrumenting || n.Left().Op() == ir.OINDEXMAP && (n.SubOp() == ir.ODIV || n.SubOp() == ir.OMOD) {
// Rewrite m[k] op= r into m[k] = m[k] op r so
// that we can ensure that if op panics
// because r is zero, the panic happens before
// the map assignment.
- n.Left = o.safeExpr(n.Left)
+ n.SetLeft(o.safeExpr(n.Left()))
- l := treecopy(n.Left, src.NoXPos)
- if l.Op == OINDEXMAP {
+ l := treecopy(n.Left(), src.NoXPos)
+ if l.Op() == ir.OINDEXMAP {
l.SetIndexMapLValue(false)
}
- l = o.copyExpr(l, n.Left.Type, false)
- n.Right = nod(n.SubOp(), l, n.Right)
- n.Right = typecheck(n.Right, ctxExpr)
- n.Right = o.expr(n.Right, nil)
+ l = o.copyExpr(l, n.Left().Type(), false)
+ n.SetRight(ir.Nod(n.SubOp(), l, n.Right()))
+ n.SetRight(typecheck(n.Right(), ctxExpr))
+ n.SetRight(o.expr(n.Right(), nil))
- n.Op = OAS
+ n.SetOp(ir.OAS)
n.ResetAux()
}
o.mapAssign(n)
o.cleanTemp(t)
- case OAS2:
+ case ir.OAS2:
t := o.markTemp()
- o.exprList(n.List)
- o.exprList(n.Rlist)
+ o.exprList(n.List())
+ o.exprList(n.Rlist())
o.mapAssign(n)
o.cleanTemp(t)
// Special: avoid copy of func call n.Right
- case OAS2FUNC:
+ case ir.OAS2FUNC:
t := o.markTemp()
- o.exprList(n.List)
- o.init(n.Right)
- o.call(n.Right)
+ o.exprList(n.List())
+ o.init(n.Right())
+ o.call(n.Right())
o.as2(n)
o.cleanTemp(t)
@@ -645,114 +647,114 @@ func (o *Order) stmt(n *Node) {
//
// OAS2MAPR: make sure key is addressable if needed,
// and make sure OINDEXMAP is not copied out.
- case OAS2DOTTYPE, OAS2RECV, OAS2MAPR:
+ case ir.OAS2DOTTYPE, ir.OAS2RECV, ir.OAS2MAPR:
t := o.markTemp()
- o.exprList(n.List)
-
- switch r := n.Right; r.Op {
- case ODOTTYPE2, ORECV:
- r.Left = o.expr(r.Left, nil)
- case OINDEXMAP:
- r.Left = o.expr(r.Left, nil)
- r.Right = o.expr(r.Right, nil)
+ o.exprList(n.List())
+
+ switch r := n.Right(); r.Op() {
+ case ir.ODOTTYPE2, ir.ORECV:
+ r.SetLeft(o.expr(r.Left(), nil))
+ case ir.OINDEXMAP:
+ r.SetLeft(o.expr(r.Left(), nil))
+ r.SetRight(o.expr(r.Right(), nil))
// See similar conversion for OINDEXMAP below.
- _ = mapKeyReplaceStrConv(r.Right)
- r.Right = o.mapKeyTemp(r.Left.Type, r.Right)
+ _ = mapKeyReplaceStrConv(r.Right())
+ r.SetRight(o.mapKeyTemp(r.Left().Type(), r.Right()))
default:
- Fatalf("order.stmt: %v", r.Op)
+ base.Fatalf("order.stmt: %v", r.Op())
}
o.okAs2(n)
o.cleanTemp(t)
// Special: does not save n onto out.
- case OBLOCK, OEMPTY:
- o.stmtList(n.List)
+ case ir.OBLOCK, ir.OEMPTY:
+ o.stmtList(n.List())
// Special: n->left is not an expression; save as is.
- case OBREAK,
- OCONTINUE,
- ODCL,
- ODCLCONST,
- ODCLTYPE,
- OFALL,
- OGOTO,
- OLABEL,
- ORETJMP:
+ case ir.OBREAK,
+ ir.OCONTINUE,
+ ir.ODCL,
+ ir.ODCLCONST,
+ ir.ODCLTYPE,
+ ir.OFALL,
+ ir.OGOTO,
+ ir.OLABEL,
+ ir.ORETJMP:
o.out = append(o.out, n)
// Special: handle call arguments.
- case OCALLFUNC, OCALLINTER, OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
t := o.markTemp()
o.call(n)
o.out = append(o.out, n)
o.cleanTemp(t)
- case OCLOSE,
- OCOPY,
- OPRINT,
- OPRINTN,
- ORECOVER,
- ORECV:
+ case ir.OCLOSE,
+ ir.OCOPY,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.ORECOVER,
+ ir.ORECV:
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
- o.exprList(n.List)
- o.exprList(n.Rlist)
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
+ o.exprList(n.List())
+ o.exprList(n.Rlist())
o.out = append(o.out, n)
o.cleanTemp(t)
// Special: order arguments to inner call but not call itself.
- case ODEFER, OGO:
+ case ir.ODEFER, ir.OGO:
t := o.markTemp()
- o.init(n.Left)
- o.call(n.Left)
+ o.init(n.Left())
+ o.call(n.Left())
o.out = append(o.out, n)
o.cleanTemp(t)
- case ODELETE:
+ case ir.ODELETE:
t := o.markTemp()
- n.List.SetFirst(o.expr(n.List.First(), nil))
- n.List.SetSecond(o.expr(n.List.Second(), nil))
- n.List.SetSecond(o.mapKeyTemp(n.List.First().Type, n.List.Second()))
+ n.List().SetFirst(o.expr(n.List().First(), nil))
+ n.List().SetSecond(o.expr(n.List().Second(), nil))
+ n.List().SetSecond(o.mapKeyTemp(n.List().First().Type(), n.List().Second()))
o.out = append(o.out, n)
o.cleanTemp(t)
// Clean temporaries from condition evaluation at
// beginning of loop body and after for statement.
- case OFOR:
+ case ir.OFOR:
t := o.markTemp()
- n.Left = o.exprInPlace(n.Left)
- n.Nbody.Prepend(o.cleanTempNoPop(t)...)
- orderBlock(&n.Nbody, o.free)
- n.Right = orderStmtInPlace(n.Right, o.free)
+ n.SetLeft(o.exprInPlace(n.Left()))
+ n.PtrBody().Prepend(o.cleanTempNoPop(t)...)
+ orderBlock(n.PtrBody(), o.free)
+ n.SetRight(orderStmtInPlace(n.Right(), o.free))
o.out = append(o.out, n)
o.cleanTemp(t)
// Clean temporaries from condition at
// beginning of both branches.
- case OIF:
+ case ir.OIF:
t := o.markTemp()
- n.Left = o.exprInPlace(n.Left)
- n.Nbody.Prepend(o.cleanTempNoPop(t)...)
- n.Rlist.Prepend(o.cleanTempNoPop(t)...)
+ n.SetLeft(o.exprInPlace(n.Left()))
+ n.PtrBody().Prepend(o.cleanTempNoPop(t)...)
+ n.PtrRlist().Prepend(o.cleanTempNoPop(t)...)
o.popTemp(t)
- orderBlock(&n.Nbody, o.free)
- orderBlock(&n.Rlist, o.free)
+ orderBlock(n.PtrBody(), o.free)
+ orderBlock(n.PtrRlist(), o.free)
o.out = append(o.out, n)
// Special: argument will be converted to interface using convT2E
// so make sure it is an addressable temporary.
- case OPANIC:
+ case ir.OPANIC:
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- if !n.Left.Type.IsInterface() {
- n.Left = o.addrTemp(n.Left)
+ n.SetLeft(o.expr(n.Left(), nil))
+ if !n.Left().Type().IsInterface() {
+ n.SetLeft(o.addrTemp(n.Left()))
}
o.out = append(o.out, n)
o.cleanTemp(t)
- case ORANGE:
+ case ir.ORANGE:
// n.Right is the expression being ranged over.
// order it, and then make a copy if we need one.
// We almost always do, to ensure that we don't
@@ -766,40 +768,40 @@ func (o *Order) stmt(n *Node) {
// Mark []byte(str) range expression to reuse string backing storage.
// It is safe because the storage cannot be mutated.
- if n.Right.Op == OSTR2BYTES {
- n.Right.Op = OSTR2BYTESTMP
+ if n.Right().Op() == ir.OSTR2BYTES {
+ n.Right().SetOp(ir.OSTR2BYTESTMP)
}
t := o.markTemp()
- n.Right = o.expr(n.Right, nil)
+ n.SetRight(o.expr(n.Right(), nil))
orderBody := true
- switch n.Type.Etype {
+ switch n.Type().Etype {
default:
- Fatalf("order.stmt range %v", n.Type)
+ base.Fatalf("order.stmt range %v", n.Type())
- case TARRAY, TSLICE:
- if n.List.Len() < 2 || n.List.Second().isBlank() {
+ case types.TARRAY, types.TSLICE:
+ if n.List().Len() < 2 || ir.IsBlank(n.List().Second()) {
// for i := range x will only use x once, to compute len(x).
// No need to copy it.
break
}
fallthrough
- case TCHAN, TSTRING:
+ case types.TCHAN, types.TSTRING:
// chan, string, slice, array ranges use value multiple times.
// make copy.
- r := n.Right
+ r := n.Right()
- if r.Type.IsString() && r.Type != types.Types[TSTRING] {
- r = nod(OCONV, r, nil)
- r.Type = types.Types[TSTRING]
+ if r.Type().IsString() && r.Type() != types.Types[types.TSTRING] {
+ r = ir.Nod(ir.OCONV, r, nil)
+ r.SetType(types.Types[types.TSTRING])
r = typecheck(r, ctxExpr)
}
- n.Right = o.copyExpr(r, r.Type, false)
+ n.SetRight(o.copyExpr(r, r.Type(), false))
- case TMAP:
+ case types.TMAP:
if isMapClear(n) {
// Preserve the body of the map clear pattern so it can
// be detected during walk. The loop body will not be used
@@ -811,22 +813,22 @@ func (o *Order) stmt(n *Node) {
// copy the map value in case it is a map literal.
// TODO(rsc): Make tmp = literal expressions reuse tmp.
// For maps tmp is just one word so it hardly matters.
- r := n.Right
- n.Right = o.copyExpr(r, r.Type, false)
+ r := n.Right()
+ n.SetRight(o.copyExpr(r, r.Type(), false))
// prealloc[n] is the temp for the iterator.
// hiter contains pointers and needs to be zeroed.
- prealloc[n] = o.newTemp(hiter(n.Type), true)
+ prealloc[n] = o.newTemp(hiter(n.Type()), true)
}
- o.exprListInPlace(n.List)
+ o.exprListInPlace(n.List())
if orderBody {
- orderBlock(&n.Nbody, o.free)
+ orderBlock(n.PtrBody(), o.free)
}
o.out = append(o.out, n)
o.cleanTemp(t)
- case ORETURN:
- o.exprList(n.List)
+ case ir.ORETURN:
+ o.exprList(n.List())
o.out = append(o.out, n)
// Special: clean case temporaries in each block entry.
@@ -838,50 +840,50 @@ func (o *Order) stmt(n *Node) {
// reordered after the channel evaluation for a different
// case (if p were nil, then the timing of the fault would
// give this away).
- case OSELECT:
+ case ir.OSELECT:
t := o.markTemp()
- for _, n2 := range n.List.Slice() {
- if n2.Op != OCASE {
- Fatalf("order select case %v", n2.Op)
+ for _, n2 := range n.List().Slice() {
+ if n2.Op() != ir.OCASE {
+ base.Fatalf("order select case %v", n2.Op())
}
- r := n2.Left
+ r := n2.Left()
setlineno(n2)
// Append any new body prologue to ninit.
// The next loop will insert ninit into nbody.
- if n2.Ninit.Len() != 0 {
- Fatalf("order select ninit")
+ if n2.Init().Len() != 0 {
+ base.Fatalf("order select ninit")
}
if r == nil {
continue
}
- switch r.Op {
+ switch r.Op() {
default:
- Dump("select case", r)
- Fatalf("unknown op in select %v", r.Op)
+ ir.Dump("select case", r)
+ base.Fatalf("unknown op in select %v", r.Op())
// If this is case x := <-ch or case x, y := <-ch, the case has
// the ODCL nodes to declare x and y. We want to delay that
// declaration (and possible allocation) until inside the case body.
// Delete the ODCL nodes here and recreate them inside the body below.
- case OSELRECV, OSELRECV2:
+ case ir.OSELRECV, ir.OSELRECV2:
if r.Colas() {
i := 0
- if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
+ if r.Init().Len() != 0 && r.Init().First().Op() == ir.ODCL && r.Init().First().Left() == r.Left() {
i++
}
- if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
+ if i < r.Init().Len() && r.Init().Index(i).Op() == ir.ODCL && r.List().Len() != 0 && r.Init().Index(i).Left() == r.List().First() {
i++
}
- if i >= r.Ninit.Len() {
- r.Ninit.Set(nil)
+ if i >= r.Init().Len() {
+ r.PtrInit().Set(nil)
}
}
- if r.Ninit.Len() != 0 {
- dumplist("ninit", r.Ninit)
- Fatalf("ninit on select recv")
+ if r.Init().Len() != 0 {
+ ir.DumpList("ninit", r.Init())
+ base.Fatalf("ninit on select recv")
}
// case x = <-c
@@ -889,10 +891,10 @@ func (o *Order) stmt(n *Node) {
// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
// r->left == N means 'case <-c'.
// c is always evaluated; x and ok are only evaluated when assigned.
- r.Right.Left = o.expr(r.Right.Left, nil)
+ r.Right().SetLeft(o.expr(r.Right().Left(), nil))
- if r.Right.Left.Op != ONAME {
- r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
+ if r.Right().Left().Op() != ir.ONAME {
+ r.Right().SetLeft(o.copyExpr(r.Right().Left(), r.Right().Left().Type(), false))
}
// Introduce temporary for receive and move actual copy into case body.
@@ -901,91 +903,91 @@ func (o *Order) stmt(n *Node) {
// temporary per distinct type, sharing the temp among all receives
// with that temp. Similarly one ok bool could be shared among all
// the x,ok receives. Not worth doing until there's a clear need.
- if r.Left != nil && r.Left.isBlank() {
- r.Left = nil
+ if r.Left() != nil && ir.IsBlank(r.Left()) {
+ r.SetLeft(nil)
}
- if r.Left != nil {
+ if r.Left() != nil {
// use channel element type for temporary to avoid conversions,
// such as in case interfacevalue = <-intchan.
// the conversion happens in the OAS instead.
- tmp1 := r.Left
+ tmp1 := r.Left()
if r.Colas() {
- tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
tmp2 = typecheck(tmp2, ctxStmt)
- n2.Ninit.Append(tmp2)
+ n2.PtrInit().Append(tmp2)
}
- r.Left = o.newTemp(r.Right.Left.Type.Elem(), r.Right.Left.Type.Elem().HasPointers())
- tmp2 := nod(OAS, tmp1, r.Left)
+ r.SetLeft(o.newTemp(r.Right().Left().Type().Elem(), r.Right().Left().Type().Elem().HasPointers()))
+ tmp2 := ir.Nod(ir.OAS, tmp1, r.Left())
tmp2 = typecheck(tmp2, ctxStmt)
- n2.Ninit.Append(tmp2)
+ n2.PtrInit().Append(tmp2)
}
- if r.List.Len() != 0 && r.List.First().isBlank() {
- r.List.Set(nil)
+ if r.List().Len() != 0 && ir.IsBlank(r.List().First()) {
+ r.PtrList().Set(nil)
}
- if r.List.Len() != 0 {
- tmp1 := r.List.First()
+ if r.List().Len() != 0 {
+ tmp1 := r.List().First()
if r.Colas() {
- tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 := ir.Nod(ir.ODCL, tmp1, nil)
tmp2 = typecheck(tmp2, ctxStmt)
- n2.Ninit.Append(tmp2)
+ n2.PtrInit().Append(tmp2)
}
- r.List.Set1(o.newTemp(types.Types[TBOOL], false))
- tmp2 := okas(tmp1, r.List.First())
+ r.PtrList().Set1(o.newTemp(types.Types[types.TBOOL], false))
+ tmp2 := okas(tmp1, r.List().First())
tmp2 = typecheck(tmp2, ctxStmt)
- n2.Ninit.Append(tmp2)
+ n2.PtrInit().Append(tmp2)
}
- orderBlock(&n2.Ninit, o.free)
+ orderBlock(n2.PtrInit(), o.free)
- case OSEND:
- if r.Ninit.Len() != 0 {
- dumplist("ninit", r.Ninit)
- Fatalf("ninit on select send")
+ case ir.OSEND:
+ if r.Init().Len() != 0 {
+ ir.DumpList("ninit", r.Init())
+ base.Fatalf("ninit on select send")
}
// case c <- x
// r->left is c, r->right is x, both are always evaluated.
- r.Left = o.expr(r.Left, nil)
+ r.SetLeft(o.expr(r.Left(), nil))
- if !r.Left.IsAutoTmp() {
- r.Left = o.copyExpr(r.Left, r.Left.Type, false)
+ if !ir.IsAutoTmp(r.Left()) {
+ r.SetLeft(o.copyExpr(r.Left(), r.Left().Type(), false))
}
- r.Right = o.expr(r.Right, nil)
- if !r.Right.IsAutoTmp() {
- r.Right = o.copyExpr(r.Right, r.Right.Type, false)
+ r.SetRight(o.expr(r.Right(), nil))
+ if !ir.IsAutoTmp(r.Right()) {
+ r.SetRight(o.copyExpr(r.Right(), r.Right().Type(), false))
}
}
}
// Now that we have accumulated all the temporaries, clean them.
// Also insert any ninit queued during the previous loop.
// (The temporary cleaning must follow that ninit work.)
- for _, n3 := range n.List.Slice() {
- orderBlock(&n3.Nbody, o.free)
- n3.Nbody.Prepend(o.cleanTempNoPop(t)...)
+ for _, n3 := range n.List().Slice() {
+ orderBlock(n3.PtrBody(), o.free)
+ n3.PtrBody().Prepend(o.cleanTempNoPop(t)...)
// TODO(mdempsky): Is this actually necessary?
// walkselect appears to walk Ninit.
- n3.Nbody.Prepend(n3.Ninit.Slice()...)
- n3.Ninit.Set(nil)
+ n3.PtrBody().Prepend(n3.Init().Slice()...)
+ n3.PtrInit().Set(nil)
}
o.out = append(o.out, n)
o.popTemp(t)
// Special: value being sent is passed as a pointer; make it addressable.
- case OSEND:
+ case ir.OSEND:
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
if instrumenting {
// Force copying to the stack so that (chan T)(nil) <- x
// is still instrumented as a read of x.
- n.Right = o.copyExpr(n.Right, n.Right.Type, false)
+ n.SetRight(o.copyExpr(n.Right(), n.Right().Type(), false))
} else {
- n.Right = o.addrTemp(n.Right)
+ n.SetRight(o.addrTemp(n.Right()))
}
o.out = append(o.out, n)
o.cleanTemp(t)
@@ -997,35 +999,35 @@ func (o *Order) stmt(n *Node) {
// the if-else chain instead.)
// For now just clean all the temporaries at the end.
// In practice that's fine.
- case OSWITCH:
- if Debug_libfuzzer != 0 && !hasDefaultCase(n) {
+ case ir.OSWITCH:
+ if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
// Add empty "default:" case for instrumentation.
- n.List.Append(nod(OCASE, nil, nil))
+ n.PtrList().Append(ir.Nod(ir.OCASE, nil, nil))
}
t := o.markTemp()
- n.Left = o.expr(n.Left, nil)
- for _, ncas := range n.List.Slice() {
- if ncas.Op != OCASE {
- Fatalf("order switch case %v", ncas.Op)
+ n.SetLeft(o.expr(n.Left(), nil))
+ for _, ncas := range n.List().Slice() {
+ if ncas.Op() != ir.OCASE {
+ base.Fatalf("order switch case %v", ncas.Op())
}
- o.exprListInPlace(ncas.List)
- orderBlock(&ncas.Nbody, o.free)
+ o.exprListInPlace(ncas.List())
+ orderBlock(ncas.PtrBody(), o.free)
}
o.out = append(o.out, n)
o.cleanTemp(t)
}
- lineno = lno
+ base.Pos = lno
}
-func hasDefaultCase(n *Node) bool {
- for _, ncas := range n.List.Slice() {
- if ncas.Op != OCASE {
- Fatalf("expected case, found %v", ncas.Op)
+func hasDefaultCase(n ir.Node) bool {
+ for _, ncas := range n.List().Slice() {
+ if ncas.Op() != ir.OCASE {
+ base.Fatalf("expected case, found %v", ncas.Op())
}
- if ncas.List.Len() == 0 {
+ if ncas.List().Len() == 0 {
return true
}
}
@@ -1033,7 +1035,7 @@ func hasDefaultCase(n *Node) bool {
}
// exprList orders the expression list l into o.
-func (o *Order) exprList(l Nodes) {
+func (o *Order) exprList(l ir.Nodes) {
s := l.Slice()
for i := range s {
s[i] = o.expr(s[i], nil)
@@ -1042,7 +1044,7 @@ func (o *Order) exprList(l Nodes) {
// exprListInPlace orders the expression list l but saves
// the side effects on the individual expression ninit lists.
-func (o *Order) exprListInPlace(l Nodes) {
+func (o *Order) exprListInPlace(l ir.Nodes) {
s := l.Slice()
for i := range s {
s[i] = o.exprInPlace(s[i])
@@ -1050,7 +1052,7 @@ func (o *Order) exprListInPlace(l Nodes) {
}
// prealloc[x] records the allocation to use for x.
-var prealloc = map[*Node]*Node{}
+var prealloc = map[ir.Node]ir.Node{}
// expr orders a single expression, appending side
// effects to o.out as needed.
@@ -1059,7 +1061,7 @@ var prealloc = map[*Node]*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 *Node) *Node {
+func (o *Order) expr(n, lhs ir.Node) ir.Node {
if n == nil {
return n
}
@@ -1067,21 +1069,21 @@ func (o *Order) expr(n, lhs *Node) *Node {
lno := setlineno(n)
o.init(n)
- switch n.Op {
+ switch n.Op() {
default:
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
- o.exprList(n.List)
- o.exprList(n.Rlist)
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
+ o.exprList(n.List())
+ o.exprList(n.Rlist())
// Addition of strings turns into a function call.
// Allocate a temporary to hold the strings.
// Fewer than 5 strings use direct runtime helpers.
- case OADDSTR:
- o.exprList(n.List)
+ case ir.OADDSTR:
+ o.exprList(n.List())
- if n.List.Len() > 5 {
- t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
+ if n.List().Len() > 5 {
+ t := types.NewArray(types.Types[types.TSTRING], int64(n.List().Len()))
prealloc[n] = o.newTemp(t, false)
}
@@ -1095,22 +1097,22 @@ func (o *Order) expr(n, lhs *Node) *Node {
hasbyte := false
haslit := false
- for _, n1 := range n.List.Slice() {
- hasbyte = hasbyte || n1.Op == OBYTES2STR
- haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
+ for _, n1 := range n.List().Slice() {
+ hasbyte = hasbyte || n1.Op() == ir.OBYTES2STR
+ haslit = haslit || n1.Op() == ir.OLITERAL && len(n1.StringVal()) != 0
}
if haslit && hasbyte {
- for _, n2 := range n.List.Slice() {
- if n2.Op == OBYTES2STR {
- n2.Op = OBYTES2STRTMP
+ for _, n2 := range n.List().Slice() {
+ if n2.Op() == ir.OBYTES2STR {
+ n2.SetOp(ir.OBYTES2STRTMP)
}
}
}
- case OINDEXMAP:
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
+ case ir.OINDEXMAP:
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
needCopy := false
if !n.IndexMapLValue() {
@@ -1118,7 +1120,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
// can not be changed before the map index by forcing
// the map index to happen immediately following the
// conversions. See copyExpr a few lines below.
- needCopy = mapKeyReplaceStrConv(n.Right)
+ needCopy = mapKeyReplaceStrConv(n.Right())
if instrumenting {
// Race detector needs the copy so it can
@@ -1128,40 +1130,40 @@ func (o *Order) expr(n, lhs *Node) *Node {
}
// key must be addressable
- n.Right = o.mapKeyTemp(n.Left.Type, n.Right)
+ n.SetRight(o.mapKeyTemp(n.Left().Type(), n.Right()))
if needCopy {
- n = o.copyExpr(n, n.Type, false)
+ n = o.copyExpr(n, n.Type(), false)
}
// concrete type (not interface) argument might need an addressable
// temporary to pass to the runtime conversion routine.
- case OCONVIFACE:
- n.Left = o.expr(n.Left, nil)
- if n.Left.Type.IsInterface() {
+ case ir.OCONVIFACE:
+ n.SetLeft(o.expr(n.Left(), nil))
+ if n.Left().Type().IsInterface() {
break
}
- if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) {
+ if _, needsaddr := convFuncName(n.Left().Type(), n.Type()); needsaddr || isStaticCompositeLiteral(n.Left()) {
// Need a temp if we need to pass the address to the conversion function.
// We also process static composite literal node here, making a named static global
// whose address we can put directly in an interface (see OCONVIFACE case in walk).
- n.Left = o.addrTemp(n.Left)
+ n.SetLeft(o.addrTemp(n.Left()))
}
- case OCONVNOP:
- if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
+ case ir.OCONVNOP:
+ if n.Type().IsKind(types.TUNSAFEPTR) && n.Left().Type().IsKind(types.TUINTPTR) && (n.Left().Op() == ir.OCALLFUNC || n.Left().Op() == ir.OCALLINTER || n.Left().Op() == ir.OCALLMETH) {
// When reordering unsafe.Pointer(f()) into a separate
// statement, the conversion and function call must stay
// together. See golang.org/issue/15329.
- o.init(n.Left)
- o.call(n.Left)
- if lhs == nil || lhs.Op != ONAME || instrumenting {
- n = o.copyExpr(n, n.Type, false)
+ o.init(n.Left())
+ o.call(n.Left())
+ if lhs == nil || lhs.Op() != ir.ONAME || instrumenting {
+ n = o.copyExpr(n, n.Type(), false)
}
} else {
- n.Left = o.expr(n.Left, nil)
+ n.SetLeft(o.expr(n.Left(), nil))
}
- case OANDAND, OOROR:
+ case ir.OANDAND, ir.OOROR:
// ... = LHS && RHS
//
// var r bool
@@ -1171,78 +1173,78 @@ func (o *Order) expr(n, lhs *Node) *Node {
// }
// ... = r
- r := o.newTemp(n.Type, false)
+ r := o.newTemp(n.Type(), false)
// Evaluate left-hand side.
- lhs := o.expr(n.Left, nil)
- o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt))
+ lhs := o.expr(n.Left(), nil)
+ o.out = append(o.out, typecheck(ir.Nod(ir.OAS, r, lhs), ctxStmt))
// Evaluate right-hand side, save generated code.
saveout := o.out
o.out = nil
t := o.markTemp()
o.edge()
- rhs := o.expr(n.Right, nil)
- o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt))
+ rhs := o.expr(n.Right(), nil)
+ o.out = append(o.out, typecheck(ir.Nod(ir.OAS, r, rhs), ctxStmt))
o.cleanTemp(t)
gen := o.out
o.out = saveout
// If left-hand side doesn't cause a short-circuit, issue right-hand side.
- nif := nod(OIF, r, nil)
- if n.Op == OANDAND {
- nif.Nbody.Set(gen)
+ nif := ir.Nod(ir.OIF, r, nil)
+ if n.Op() == ir.OANDAND {
+ nif.PtrBody().Set(gen)
} else {
- nif.Rlist.Set(gen)
+ nif.PtrRlist().Set(gen)
}
o.out = append(o.out, nif)
n = r
- case OCALLFUNC,
- OCALLINTER,
- OCALLMETH,
- OCAP,
- OCOMPLEX,
- OCOPY,
- OIMAG,
- OLEN,
- OMAKECHAN,
- OMAKEMAP,
- OMAKESLICE,
- OMAKESLICECOPY,
- ONEW,
- OREAL,
- ORECOVER,
- OSTR2BYTES,
- OSTR2BYTESTMP,
- OSTR2RUNES:
+ case ir.OCALLFUNC,
+ ir.OCALLINTER,
+ ir.OCALLMETH,
+ ir.OCAP,
+ ir.OCOMPLEX,
+ ir.OCOPY,
+ ir.OIMAG,
+ ir.OLEN,
+ ir.OMAKECHAN,
+ ir.OMAKEMAP,
+ ir.OMAKESLICE,
+ ir.OMAKESLICECOPY,
+ ir.ONEW,
+ ir.OREAL,
+ ir.ORECOVER,
+ ir.OSTR2BYTES,
+ ir.OSTR2BYTESTMP,
+ ir.OSTR2RUNES:
if isRuneCount(n) {
// len([]rune(s)) is rewritten to runtime.countrunes(s) later.
- n.Left.Left = o.expr(n.Left.Left, nil)
+ n.Left().SetLeft(o.expr(n.Left().Left(), nil))
} else {
o.call(n)
}
- if lhs == nil || lhs.Op != ONAME || instrumenting {
- n = o.copyExpr(n, n.Type, false)
+ if lhs == nil || lhs.Op() != ir.ONAME || instrumenting {
+ n = o.copyExpr(n, n.Type(), false)
}
- case OAPPEND:
+ case ir.OAPPEND:
// Check for append(x, make([]T, y)...) .
if isAppendOfMake(n) {
- n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
- n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
+ n.List().SetFirst(o.expr(n.List().First(), nil)) // order x
+ n.List().Second().SetLeft(o.expr(n.List().Second().Left(), nil)) // order y
} else {
- o.exprList(n.List)
+ o.exprList(n.List())
}
- if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
- n = o.copyExpr(n, n.Type, false)
+ if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.List().First()) {
+ n = o.copyExpr(n, n.Type(), false)
}
- case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
- n.Left = o.expr(n.Left, nil)
+ case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
+ n.SetLeft(o.expr(n.Left(), nil))
low, high, max := n.SliceBounds()
low = o.expr(low, nil)
low = o.cheapExpr(low)
@@ -1251,65 +1253,65 @@ func (o *Order) expr(n, lhs *Node) *Node {
max = o.expr(max, nil)
max = o.cheapExpr(max)
n.SetSliceBounds(low, high, max)
- if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
- n = o.copyExpr(n, n.Type, false)
+ if lhs == nil || lhs.Op() != ir.ONAME && !samesafeexpr(lhs, n.Left()) {
+ n = o.copyExpr(n, n.Type(), false)
}
- case OCLOSURE:
- if n.Transient() && n.Func.Closure.Func.Cvars.Len() > 0 {
+ case ir.OCLOSURE:
+ if n.Transient() && n.Func().ClosureVars.Len() > 0 {
prealloc[n] = o.newTemp(closureType(n), false)
}
- case OSLICELIT, OCALLPART:
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
- o.exprList(n.List)
- o.exprList(n.Rlist)
+ case ir.OSLICELIT, ir.OCALLPART:
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
+ o.exprList(n.List())
+ o.exprList(n.Rlist())
if n.Transient() {
var t *types.Type
- switch n.Op {
- case OSLICELIT:
- t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
- case OCALLPART:
+ switch n.Op() {
+ case ir.OSLICELIT:
+ t = types.NewArray(n.Type().Elem(), n.Right().Int64Val())
+ case ir.OCALLPART:
t = partialCallType(n)
}
prealloc[n] = o.newTemp(t, false)
}
- case ODOTTYPE, ODOTTYPE2:
- n.Left = o.expr(n.Left, nil)
- if !isdirectiface(n.Type) || instrumenting {
- n = o.copyExpr(n, n.Type, true)
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ n.SetLeft(o.expr(n.Left(), nil))
+ if !isdirectiface(n.Type()) || instrumenting {
+ n = o.copyExpr(n, n.Type(), true)
}
- case ORECV:
- n.Left = o.expr(n.Left, nil)
- n = o.copyExpr(n, n.Type, true)
+ case ir.ORECV:
+ n.SetLeft(o.expr(n.Left(), nil))
+ n = o.copyExpr(n, n.Type(), true)
- case OEQ, ONE, OLT, OLE, OGT, OGE:
- n.Left = o.expr(n.Left, nil)
- n.Right = o.expr(n.Right, nil)
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
+ n.SetLeft(o.expr(n.Left(), nil))
+ n.SetRight(o.expr(n.Right(), nil))
- t := n.Left.Type
+ t := n.Left().Type()
switch {
case t.IsString():
// Mark string(byteSlice) arguments to reuse byteSlice backing
// buffer during conversion. String comparison does not
// memorize the strings for later use, so it is safe.
- if n.Left.Op == OBYTES2STR {
- n.Left.Op = OBYTES2STRTMP
+ if n.Left().Op() == ir.OBYTES2STR {
+ n.Left().SetOp(ir.OBYTES2STRTMP)
}
- if n.Right.Op == OBYTES2STR {
- n.Right.Op = OBYTES2STRTMP
+ if n.Right().Op() == ir.OBYTES2STR {
+ n.Right().SetOp(ir.OBYTES2STRTMP)
}
case t.IsStruct() || t.IsArray():
// for complex comparisons, we need both args to be
// addressable so we can pass them to the runtime.
- n.Left = o.addrTemp(n.Left)
- n.Right = o.addrTemp(n.Right)
+ n.SetLeft(o.addrTemp(n.Left()))
+ n.SetRight(o.addrTemp(n.Right()))
}
- case OMAPLIT:
+ case ir.OMAPLIT:
// Order map by converting:
// map[int]int{
// a(): b(),
@@ -1325,15 +1327,15 @@ func (o *Order) expr(n, lhs *Node) *Node {
// Without this special case, order would otherwise compute all
// the keys and values before storing any of them to the map.
// See issue 26552.
- entries := n.List.Slice()
+ entries := n.List().Slice()
statics := entries[:0]
- var dynamics []*Node
+ var dynamics []ir.Node
for _, r := range entries {
- if r.Op != OKEY {
- Fatalf("OMAPLIT entry not OKEY: %v\n", r)
+ if r.Op() != ir.OKEY {
+ base.Fatalf("OMAPLIT entry not OKEY: %v\n", r)
}
- if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
+ if !isStaticCompositeLiteral(r.Left()) || !isStaticCompositeLiteral(r.Right()) {
dynamics = append(dynamics, r)
continue
}
@@ -1341,45 +1343,45 @@ func (o *Order) expr(n, lhs *Node) *Node {
// Recursively ordering some static entries can change them to dynamic;
// e.g., OCONVIFACE nodes. See #31777.
r = o.expr(r, nil)
- if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
+ if !isStaticCompositeLiteral(r.Left()) || !isStaticCompositeLiteral(r.Right()) {
dynamics = append(dynamics, r)
continue
}
statics = append(statics, r)
}
- n.List.Set(statics)
+ n.PtrList().Set(statics)
if len(dynamics) == 0 {
break
}
// Emit the creation of the map (with all its static entries).
- m := o.newTemp(n.Type, false)
- as := nod(OAS, m, n)
+ m := o.newTemp(n.Type(), false)
+ as := ir.Nod(ir.OAS, m, n)
typecheck(as, ctxStmt)
o.stmt(as)
n = m
// Emit eval+insert of dynamic entries, one at a time.
for _, r := range dynamics {
- as := nod(OAS, nod(OINDEX, n, r.Left), r.Right)
+ as := ir.Nod(ir.OAS, ir.Nod(ir.OINDEX, n, r.Left()), r.Right())
typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
o.stmt(as)
}
}
- lineno = lno
+ base.Pos = lno
return n
}
// okas creates and returns an assignment of val to ok,
// including an explicit conversion if necessary.
-func okas(ok, val *Node) *Node {
- if !ok.isBlank() {
- val = conv(val, ok.Type)
+func okas(ok, val ir.Node) ir.Node {
+ if !ir.IsBlank(ok) {
+ val = conv(val, ok.Type())
}
- return nod(OAS, ok, val)
+ return ir.Nod(ir.OAS, ok, val)
}
// as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
@@ -1390,13 +1392,13 @@ func okas(ok, val *Node) *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 *Node) {
- tmplist := []*Node{}
- left := []*Node{}
- for ni, l := range n.List.Slice() {
- if !l.isBlank() {
- tmp := o.newTemp(l.Type, l.Type.HasPointers())
- n.List.SetIndex(ni, tmp)
+func (o *Order) as2(n ir.Node) {
+ tmplist := []ir.Node{}
+ left := []ir.Node{}
+ for ni, l := range n.List().Slice() {
+ if !ir.IsBlank(l) {
+ tmp := o.newTemp(l.Type(), l.Type().HasPointers())
+ n.List().SetIndex(ni, tmp)
tmplist = append(tmplist, tmp)
left = append(left, l)
}
@@ -1404,38 +1406,38 @@ func (o *Order) as2(n *Node) {
o.out = append(o.out, n)
- as := nod(OAS2, nil, nil)
- as.List.Set(left)
- as.Rlist.Set(tmplist)
+ as := ir.Nod(ir.OAS2, nil, nil)
+ as.PtrList().Set(left)
+ as.PtrRlist().Set(tmplist)
as = typecheck(as, ctxStmt)
o.stmt(as)
}
// okAs2 orders OAS2XXX with ok.
// Just like as2, this also adds temporaries to ensure left-to-right assignment.
-func (o *Order) okAs2(n *Node) {
- var tmp1, tmp2 *Node
- if !n.List.First().isBlank() {
- typ := n.Right.Type
+func (o *Order) okAs2(n ir.Node) {
+ var tmp1, tmp2 ir.Node
+ if !ir.IsBlank(n.List().First()) {
+ typ := n.Right().Type()
tmp1 = o.newTemp(typ, typ.HasPointers())
}
- if !n.List.Second().isBlank() {
- tmp2 = o.newTemp(types.Types[TBOOL], false)
+ if !ir.IsBlank(n.List().Second()) {
+ tmp2 = o.newTemp(types.Types[types.TBOOL], false)
}
o.out = append(o.out, n)
if tmp1 != nil {
- r := nod(OAS, n.List.First(), tmp1)
+ r := ir.Nod(ir.OAS, n.List().First(), tmp1)
r = typecheck(r, ctxStmt)
o.mapAssign(r)
- n.List.SetFirst(tmp1)
+ n.List().SetFirst(tmp1)
}
if tmp2 != nil {
- r := okas(n.List.Second(), tmp2)
+ r := okas(n.List().Second(), tmp2)
r = typecheck(r, ctxStmt)
o.mapAssign(r)
- n.List.SetSecond(tmp2)
+ n.List().SetSecond(tmp2)
}
}