diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/order.go')
-rw-r--r-- | src/cmd/compile/internal/gc/order.go | 928 |
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) } } |