]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: cleanup for concrete types - ssa
authorRuss Cox <rsc@golang.org>
Thu, 10 Dec 2020 23:45:58 +0000 (18:45 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 17 Dec 2020 04:43:03 +0000 (04:43 +0000)
An automated rewrite will add concrete type assertions after
a test of n.Op(), when n can be safely type-asserted
(meaning, n is not reassigned a different type, n is not reassigned
and then used outside the scope of the type assertion,
and so on).

This sequence of CLs handles the code that the automated
rewrite does not: adding specific types to function arguments,
adjusting code not to call n.Left() etc when n may have multiple
representations, and so on.

This CL focuses on ssa.go.

Passes buildall w/ toolstash -cmp.

Change-Id: Iefacc7104dd9469e3c574149791ab0bff29f7fee
Reviewed-on: https://go-review.googlesource.com/c/go/+/277923
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/phi.go
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/walk.go

index 9342046dcce7bf584194200d34658525e801b351..3a19efd3252418304542a0cf1c5a14885ed7855e 100644 (file)
@@ -335,7 +335,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
                        }
                }
 
-               if isIntrinsicCall(n) {
+               if isIntrinsicCall(n.(*ir.CallExpr)) {
                        // Treat like any other node.
                        break
                }
@@ -583,7 +583,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
                if base.Flag.LowerM > 3 {
                        fmt.Printf("%v:call to func %+v\n", ir.Line(n), n.Left())
                }
-               if isIntrinsicCall(n) {
+               if isIntrinsicCall(n.(*ir.CallExpr)) {
                        break
                }
                if fn := inlCallee(n.Left()); fn != nil && fn.Inl != nil {
index 32c330b584a7684fed8d98332dc0d3b479c5cbb8..75ce18ff841e0ec78c787167a5e089324a4cde5a 100644 (file)
@@ -254,7 +254,9 @@ func (s *phiState) insertVarPhis(n int, var_ ir.Node, defs []*ssa.Block, typ *ty
                                hasPhi.add(c.ID)
                                v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
                                // Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
-                               s.s.addNamedValue(var_, v)
+                               if var_.Op() == ir.ONAME {
+                                       s.s.addNamedValue(var_.(*ir.Name), v)
+                               }
                                for range c.Preds {
                                        v.AddArg(s.placeholder) // Actual args will be filled in by resolveFwdRefs.
                                }
@@ -546,7 +548,9 @@ func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ ir.
        // Generate a FwdRef for the variable and return that.
        v := b.NewValue0A(line, ssa.OpFwdRef, t, FwdRefAux{N: var_})
        s.defvars[b.ID][var_] = v
-       s.s.addNamedValue(var_, v)
+       if var_.Op() == ir.ONAME {
+               s.s.addNamedValue(var_.(*ir.Name), v)
+       }
        s.fwdrefs = append(s.fwdrefs, v)
        return v
 }
index 9952bfcf366776362c067b9d17563ea7dfd237fa..6deb3ecc7a94b60d4e21e6e88efd92f5f300d55e 100644 (file)
@@ -206,8 +206,12 @@ type progeffectscache struct {
 // nor do we care about non-local variables,
 // nor do we care about empty structs (handled by the pointer check),
 // nor do we care about the fake PAUTOHEAP variables.
-func livenessShouldTrack(n ir.Node) bool {
-       return n.Op() == ir.ONAME && (n.Class() == ir.PAUTO || n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT) && n.Type().HasPointers()
+func livenessShouldTrack(nn ir.Node) bool {
+       if nn.Op() != ir.ONAME {
+               return false
+       }
+       n := nn.(*ir.Name)
+       return (n.Class() == ir.PAUTO || n.Class() == ir.PPARAM || n.Class() == ir.PPARAMOUT) && n.Type().HasPointers()
 }
 
 // getvariables returns the list of on-stack variables that we need to track
@@ -1165,7 +1169,7 @@ func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
        // Size args bitmaps to be just large enough to hold the largest pointer.
        // First, find the largest Xoffset node we care about.
        // (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
-       var maxArgNode ir.Node
+       var maxArgNode *ir.Name
        for _, n := range lv.vars {
                switch n.Class() {
                case ir.PPARAM, ir.PPARAMOUT:
index f13c45c2a618b8a492c8d40dcc784dfea34af1d2..4d9073a4b6bde4f96abc1c9009979300e2446dcc 100644 (file)
@@ -187,7 +187,7 @@ func initssaconfig() {
 // function/method/interface call), where the receiver of a method call is
 // considered as the 0th parameter. This does not include the receiver of an
 // interface call.
-func getParam(n ir.Node, i int) *types.Field {
+func getParam(n *ir.CallExpr, i int) *types.Field {
        t := n.Left().Type()
        if n.Op() == ir.OCALLMETH {
                if i == 0 {
@@ -559,20 +559,20 @@ func (s *state) updateUnsetPredPos(b *ssa.Block) {
 
 // Information about each open-coded defer.
 type openDeferInfo struct {
-       // The ODEFER node representing the function call of the defer
-       n ir.Node
+       // The node representing the call of the defer
+       n *ir.CallExpr
        // If defer call is closure call, the address of the argtmp where the
        // closure is stored.
        closure *ssa.Value
        // The node representing the argtmp where the closure is stored - used for
        // function, method, or interface call, to store a closure that panic
        // processing can use for this defer.
-       closureNode ir.Node
+       closureNode *ir.Name
        // If defer call is interface call, the address of the argtmp where the
        // receiver is stored
        rcvr *ssa.Value
        // The node representing the argtmp where the receiver is stored
-       rcvrNode ir.Node
+       rcvrNode *ir.Name
        // The addresses of the argtmps where the evaluated arguments of the defer
        // function call are stored.
        argVals []*ssa.Value
@@ -622,7 +622,7 @@ type state struct {
        sb       *ssa.Value
        // value representing address of where deferBits autotmp is stored
        deferBitsAddr *ssa.Value
-       deferBitsTemp ir.Node
+       deferBitsTemp *ir.Name
 
        // line number stack. The current line number is top of stack
        line []src.XPos
@@ -1134,6 +1134,7 @@ func (s *state) stmt(n ir.Node) {
 
        // Expression statements
        case ir.OCALLFUNC:
+               n := n.(*ir.CallExpr)
                if isIntrinsicCall(n) {
                        s.intrinsicCall(n)
                        return
@@ -1141,8 +1142,9 @@ func (s *state) stmt(n ir.Node) {
                fallthrough
 
        case ir.OCALLMETH, ir.OCALLINTER:
+               n := n.(*ir.CallExpr)
                s.callResult(n, callNormal)
-               if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME && n.Left().Class() == ir.PFUNC {
+               if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME && n.Left().(*ir.Name).Class() == ir.PFUNC {
                        if fn := n.Left().Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
                                n.Left().Sym().Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
                                m := s.mem()
@@ -1167,19 +1169,19 @@ func (s *state) stmt(n ir.Node) {
                        base.WarnfAt(n.Pos(), "%s defer", defertype)
                }
                if s.hasOpenDefers {
-                       s.openDeferRecord(n.Left())
+                       s.openDeferRecord(n.Left().(*ir.CallExpr))
                } else {
                        d := callDefer
                        if n.Esc() == EscNever {
                                d = callDeferStack
                        }
-                       s.callResult(n.Left(), d)
+                       s.callResult(n.Left().(*ir.CallExpr), d)
                }
        case ir.OGO:
-               s.callResult(n.Left(), callGo)
+               s.callResult(n.Left().(*ir.CallExpr), callGo)
 
        case ir.OAS2DOTTYPE:
-               res, resok := s.dottype(n.Rlist().First(), true)
+               res, resok := s.dottype(n.Rlist().First().(*ir.TypeAssertExpr), true)
                deref := false
                if !canSSAType(n.Rlist().First().Type()) {
                        if res.Op != ssa.OpLoad {
@@ -1201,10 +1203,11 @@ func (s *state) stmt(n ir.Node) {
 
        case ir.OAS2FUNC:
                // We come here only when it is an intrinsic call returning two values.
-               if !isIntrinsicCall(n.Rlist().First()) {
-                       s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Rlist().First())
+               call := n.Rlist().First().(*ir.CallExpr)
+               if !isIntrinsicCall(call) {
+                       s.Fatalf("non-intrinsic AS2FUNC not expanded %v", call)
                }
-               v := s.intrinsicCall(n.Rlist().First())
+               v := s.intrinsicCall(call)
                v1 := s.newValue1(ssa.OpSelect0, n.List().First().Type(), v)
                v2 := s.newValue1(ssa.OpSelect1, n.List().Second().Type(), v)
                s.assign(n.List().First(), v1, false, 0)
@@ -1212,7 +1215,7 @@ func (s *state) stmt(n ir.Node) {
                return
 
        case ir.ODCL:
-               if n.Left().Class() == ir.PAUTOHEAP {
+               if n.Left().(*ir.Name).Class() == ir.PAUTOHEAP {
                        s.Fatalf("DCL %v", n)
                }
 
@@ -1270,6 +1273,7 @@ func (s *state) stmt(n ir.Node) {
                                }
                                rhs = nil
                        case ir.OAPPEND:
+                               rhs := rhs.(*ir.CallExpr)
                                // Check whether we're writing the result of an append back to the same slice.
                                // If so, we handle it specially to avoid write barriers on the fast
                                // (non-growth) path.
@@ -1326,7 +1330,7 @@ func (s *state) stmt(n ir.Node) {
                }
 
                var skip skipMask
-               if rhs != nil && (rhs.Op() == ir.OSLICE || rhs.Op() == ir.OSLICE3 || rhs.Op() == ir.OSLICESTR) && samesafeexpr(rhs.Left(), n.Left()) {
+               if rhs != nil && (rhs.Op() == ir.OSLICE || rhs.Op() == ir.OSLICE3 || rhs.Op() == ir.OSLICESTR) && samesafeexpr(rhs.(*ir.SliceExpr).Left(), n.Left()) {
                        // We're assigning a slicing operation back to its source.
                        // Don't write back fields we aren't changing. See issue #14855.
                        i, j, k := rhs.SliceBounds()
@@ -1409,7 +1413,6 @@ func (s *state) stmt(n ir.Node) {
                b.Pos = s.lastPos.WithIsStmt()
 
        case ir.ORETJMP:
-               s.stmtList(n.List())
                b := s.exit()
                b.Kind = ssa.BlockRetJmp // override BlockRet
                b.Aux = n.Sym().Linksym()
@@ -1536,15 +1539,27 @@ func (s *state) stmt(n ir.Node) {
 
                prevBreak := s.breakTo
                s.breakTo = bEnd
+               var sym *types.Sym
+               var body ir.Nodes
+               if n.Op() == ir.OSWITCH {
+                       n := n.(*ir.SwitchStmt)
+                       sym = n.Sym()
+                       body = n.Body()
+               } else {
+                       n := n.(*ir.SelectStmt)
+                       sym = n.Sym()
+                       body = n.Body()
+               }
+
                var lab *ssaLabel
-               if sym := n.Sym(); sym != nil {
+               if sym != nil {
                        // labeled
                        lab = s.label(sym)
                        lab.breakTarget = bEnd
                }
 
                // generate body code
-               s.stmtList(n.Body())
+               s.stmtList(body)
 
                s.breakTo = prevBreak
                if lab != nil {
@@ -1576,15 +1591,16 @@ func (s *state) stmt(n ir.Node) {
 
        case ir.OVARLIVE:
                // Insert a varlive op to record that a variable is still live.
-               if !n.Left().Name().Addrtaken() {
-                       s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left())
+               v := n.Left().(*ir.Name)
+               if !v.Addrtaken() {
+                       s.Fatalf("VARLIVE variable %v must have Addrtaken set", v)
                }
-               switch n.Left().Class() {
+               switch v.Class() {
                case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
                default:
-                       s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left())
+                       s.Fatalf("VARLIVE variable %v must be Auto or Arg", v)
                }
-               s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left().(*ir.Name), s.mem())
+               s.vars[memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, v, s.mem())
 
        case ir.OCHECKNIL:
                p := s.expr(n.Left())
@@ -2395,6 +2411,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                return nil
 
        case ir.ODOTTYPE:
+               n := n.(*ir.TypeAssertExpr)
                res, _ := s.dottype(n, false)
                return res
 
@@ -2651,6 +2668,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                return s.load(n.Type(), p)
 
        case ir.ODOT:
+               n := n.(*ir.SelectorExpr)
                if n.Left().Op() == ir.OSTRUCTLIT {
                        // All literals with nonzero fields have already been
                        // rewritten during walk. Any that remain are just T{}
@@ -2726,6 +2744,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                }
 
        case ir.OLEN, ir.OCAP:
+               n := n.(*ir.UnaryExpr)
                switch {
                case n.Left().Type().IsSlice():
                        op := ssa.OpSliceLen
@@ -2798,19 +2817,21 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
 
        case ir.OCALLFUNC:
+               n := n.(*ir.CallExpr)
                if isIntrinsicCall(n) {
                        return s.intrinsicCall(n)
                }
                fallthrough
 
        case ir.OCALLINTER, ir.OCALLMETH:
+               n := n.(*ir.CallExpr)
                return s.callResult(n, callNormal)
 
        case ir.OGETG:
                return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
 
        case ir.OAPPEND:
-               return s.append(n, false)
+               return s.append(n.(*ir.CallExpr), false)
 
        case ir.OSTRUCTLIT, ir.OARRAYLIT:
                // All literals with nonzero fields have already been
@@ -2841,7 +2862,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
 // If inplace is true, it writes the result of the OAPPEND expression n
 // back to the slice being appended to, and returns nil.
 // inplace MUST be set to false if the slice can be SSA'd.
-func (s *state) append(n ir.Node, inplace bool) *ssa.Value {
+func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
        // If inplace is false, process as expression "append(s, e1, e2, e3)":
        //
        // ptr, len, cap := s
@@ -2923,9 +2944,12 @@ func (s *state) append(n ir.Node, inplace bool) *ssa.Value {
        r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[types.TINT], types.Types[types.TINT]}, taddr, p, l, c, nl)
 
        if inplace {
-               if sn.Op() == ir.ONAME && sn.Class() != ir.PEXTERN {
-                       // Tell liveness we're about to build a new slice
-                       s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn.(*ir.Name), s.mem())
+               if sn.Op() == ir.ONAME {
+                       sn := sn.(*ir.Name)
+                       if sn.Class() != ir.PEXTERN {
+                               // Tell liveness we're about to build a new slice
+                               s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
+                       }
                }
                capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, sliceCapOffset, addr)
                s.store(types.Types[types.TINT], capaddr, r[2])
@@ -3076,6 +3100,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
                        // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
 
                        // Grab information about the structure type.
+                       left := left.(*ir.SelectorExpr)
                        t := left.Left().Type()
                        nf := t.NumFields()
                        idx := fieldIdx(left)
@@ -3100,7 +3125,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
                        // TODO: do we need to update named values here?
                        return
                }
-               if left.Op() == ir.OINDEX && left.Left().Type().IsArray() {
+               if left.Op() == ir.OINDEX && left.(*ir.IndexExpr).Left().Type().IsArray() {
                        s.pushLine(left.Pos())
                        defer s.popLine()
                        // We're assigning to an element of an ssa-able array.
@@ -3126,6 +3151,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
                        s.assign(left.Left(), v, false, 0)
                        return
                }
+               left := left.(*ir.Name)
                // Update variable assignment.
                s.vars[left] = right
                s.addNamedValue(left, right)
@@ -3134,7 +3160,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
 
        // If this assignment clobbers an entire local variable, then emit
        // OpVarDef so liveness analysis knows the variable is redefined.
-       if base := clobberBase(left); base.Op() == ir.ONAME && base.Class() != ir.PEXTERN && skip == 0 {
+       if base := clobberBase(left); base.Op() == ir.ONAME && base.(*ir.Name).Class() != ir.PEXTERN && skip == 0 {
                s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base.(*ir.Name), s.mem(), !ir.IsAutoTmp(base))
        }
 
@@ -3309,7 +3335,7 @@ var intrinsics map[intrinsicKey]intrinsicBuilder
 
 // An intrinsicBuilder converts a call node n into an ssa value that
 // implements that call as an intrinsic. args is a list of arguments to the func.
-type intrinsicBuilder func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value
+type intrinsicBuilder func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value
 
 type intrinsicKey struct {
        arch *sys.Arch
@@ -3374,7 +3400,7 @@ func init() {
        /******** runtime ********/
        if !instrumenting {
                add("runtime", "slicebytetostringtmp",
-                       func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+                       func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                                // Compiler frontend optimizations emit OBYTES2STRTMP nodes
                                // for the backend instead of slicebytetostringtmp calls
                                // when not instrumenting.
@@ -3383,7 +3409,7 @@ func init() {
                        all...)
        }
        addF("runtime/internal/math", "MulUintptr",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                return s.newValue2(ssa.OpMul32uover, types.NewTuple(types.Types[types.TUINT], types.Types[types.TUINT]), args[0], args[1])
                        }
@@ -3391,90 +3417,90 @@ func init() {
                },
                sys.AMD64, sys.I386, sys.MIPS64)
        add("runtime", "KeepAlive",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
                        s.vars[memVar] = s.newValue2(ssa.OpKeepAlive, types.TypeMem, data, s.mem())
                        return nil
                },
                all...)
        add("runtime", "getclosureptr",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue0(ssa.OpGetClosurePtr, s.f.Config.Types.Uintptr)
                },
                all...)
 
        add("runtime", "getcallerpc",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue0(ssa.OpGetCallerPC, s.f.Config.Types.Uintptr)
                },
                all...)
 
        add("runtime", "getcallersp",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue0(ssa.OpGetCallerSP, s.f.Config.Types.Uintptr)
                },
                all...)
 
        /******** runtime/internal/sys ********/
        addF("runtime/internal/sys", "Ctz32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
        addF("runtime/internal/sys", "Ctz64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
        addF("runtime/internal/sys", "Bswap32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBswap32, types.Types[types.TUINT32], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
        addF("runtime/internal/sys", "Bswap64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBswap64, types.Types[types.TUINT64], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
 
        /******** runtime/internal/atomic ********/
        addF("runtime/internal/atomic", "Load",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Load8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoad8, types.NewTuple(types.Types[types.TUINT8], types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT8], v)
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Load64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
                },
                sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "LoadAcq",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoadAcq32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
                },
                sys.PPC64, sys.S390X)
        addF("runtime/internal/atomic", "LoadAcq64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
                },
                sys.PPC64)
        addF("runtime/internal/atomic", "Loadp",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, s.f.Config.Types.BytePtr, v)
@@ -3482,62 +3508,62 @@ func init() {
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
 
        addF("runtime/internal/atomic", "Store",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStore32, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Store8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStore8, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Store64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "StorepNoWB",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "StoreRel",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStoreRel32, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.PPC64, sys.S390X)
        addF("runtime/internal/atomic", "StoreRel64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.PPC64)
 
        addF("runtime/internal/atomic", "Xchg",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], args[1], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
                },
                sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Xchg64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], args[1], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
                },
                sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
 
-       type atomicOpEmitter func(s *state, n ir.Node, args []*ssa.Value, op ssa.Op, typ types.Kind)
+       type atomicOpEmitter func(s *state, n *ir.CallExpr, args []*ssa.Value, op ssa.Op, typ types.Kind)
 
        makeAtomicGuardedIntrinsicARM64 := func(op0, op1 ssa.Op, typ, rtyp types.Kind, emit atomicOpEmitter) intrinsicBuilder {
 
-               return func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        // Target Atomic feature is identified by dynamic detection
                        addr := s.entryNewValue1A(ssa.OpAddr, types.Types[types.TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
                        v := s.load(types.Types[types.TBOOL], addr)
@@ -3571,7 +3597,7 @@ func init() {
                }
        }
 
-       atomicXchgXaddEmitterARM64 := func(s *state, n ir.Node, args []*ssa.Value, op ssa.Op, typ types.Kind) {
+       atomicXchgXaddEmitterARM64 := func(s *state, n *ir.CallExpr, args []*ssa.Value, op ssa.Op, typ types.Kind) {
                v := s.newValue3(op, types.NewTuple(types.Types[typ], types.TypeMem), args[0], args[1], s.mem())
                s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
@@ -3584,14 +3610,14 @@ func init() {
                sys.ARM64)
 
        addF("runtime/internal/atomic", "Xadd",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[types.TUINT32], types.TypeMem), args[0], args[1], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT32], v)
                },
                sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Xadd64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[types.TUINT64], types.TypeMem), args[0], args[1], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TUINT64], v)
@@ -3606,28 +3632,28 @@ func init() {
                sys.ARM64)
 
        addF("runtime/internal/atomic", "Cas",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
                },
                sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "Cas64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
                },
                sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
        addF("runtime/internal/atomic", "CasRel",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
                        s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                        return s.newValue1(ssa.OpSelect0, types.Types[types.TBOOL], v)
                },
                sys.PPC64)
 
-       atomicCasEmitterARM64 := func(s *state, n ir.Node, args []*ssa.Value, op ssa.Op, typ types.Kind) {
+       atomicCasEmitterARM64 := func(s *state, n *ir.CallExpr, args []*ssa.Value, op ssa.Op, typ types.Kind) {
                v := s.newValue4(op, types.NewTuple(types.Types[types.TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
                s.vars[memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
                s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
@@ -3641,31 +3667,31 @@ func init() {
                sys.ARM64)
 
        addF("runtime/internal/atomic", "And8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
        addF("runtime/internal/atomic", "And",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
        addF("runtime/internal/atomic", "Or8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
        addF("runtime/internal/atomic", "Or",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        s.vars[memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
                        return nil
                },
                sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
 
-       atomicAndOrEmitterARM64 := func(s *state, n ir.Node, args []*ssa.Value, op ssa.Op, typ types.Kind) {
+       atomicAndOrEmitterARM64 := func(s *state, n *ir.CallExpr, args []*ssa.Value, op ssa.Op, typ types.Kind) {
                s.vars[memVar] = s.newValue3(op, types.TypeMem, args[0], args[1], s.mem())
        }
 
@@ -3714,52 +3740,52 @@ func init() {
 
        /******** math ********/
        addF("math", "Sqrt",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpSqrt, types.Types[types.TFLOAT64], args[0])
                },
                sys.I386, sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm)
        addF("math", "Trunc",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpTrunc, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
        addF("math", "Ceil",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCeil, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
        addF("math", "Floor",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpFloor, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
        addF("math", "Round",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpRound, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.PPC64, sys.S390X)
        addF("math", "RoundToEven",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpRoundToEven, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.S390X, sys.Wasm)
        addF("math", "Abs",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpAbs, types.Types[types.TFLOAT64], args[0])
                },
                sys.ARM64, sys.ARM, sys.PPC64, sys.Wasm)
        addF("math", "Copysign",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpCopysign, types.Types[types.TFLOAT64], args[0], args[1])
                },
                sys.PPC64, sys.Wasm)
        addF("math", "FMA",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue3(ssa.OpFMA, types.Types[types.TFLOAT64], args[0], args[1], args[2])
                },
                sys.ARM64, sys.PPC64, sys.S390X)
        addF("math", "FMA",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if !s.config.UseFMA {
                                s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
                                return s.variable(n, types.Types[types.TFLOAT64])
@@ -3791,7 +3817,7 @@ func init() {
                },
                sys.AMD64)
        addF("math", "FMA",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if !s.config.UseFMA {
                                s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
                                return s.variable(n, types.Types[types.TFLOAT64])
@@ -3824,8 +3850,8 @@ func init() {
                },
                sys.ARM)
 
-       makeRoundAMD64 := func(op ssa.Op) func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
-               return func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+       makeRoundAMD64 := func(op ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+               return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], x86HasSSE41)
                        b := s.endBlock()
                        b.Kind = ssa.BlockIf
@@ -3867,17 +3893,17 @@ func init() {
 
        /******** math/bits ********/
        addF("math/bits", "TrailingZeros64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz64, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "TrailingZeros32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz32, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "TrailingZeros16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        x := s.newValue1(ssa.OpZeroExt16to32, types.Types[types.TUINT32], args[0])
                        c := s.constInt32(types.Types[types.TUINT32], 1<<16)
                        y := s.newValue2(ssa.OpOr32, types.Types[types.TUINT32], x, c)
@@ -3885,12 +3911,12 @@ func init() {
                },
                sys.MIPS)
        addF("math/bits", "TrailingZeros16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz16, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.I386, sys.ARM, sys.ARM64, sys.Wasm)
        addF("math/bits", "TrailingZeros16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        x := s.newValue1(ssa.OpZeroExt16to64, types.Types[types.TUINT64], args[0])
                        c := s.constInt64(types.Types[types.TUINT64], 1<<16)
                        y := s.newValue2(ssa.OpOr64, types.Types[types.TUINT64], x, c)
@@ -3898,7 +3924,7 @@ func init() {
                },
                sys.S390X, sys.PPC64)
        addF("math/bits", "TrailingZeros8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        x := s.newValue1(ssa.OpZeroExt8to32, types.Types[types.TUINT32], args[0])
                        c := s.constInt32(types.Types[types.TUINT32], 1<<8)
                        y := s.newValue2(ssa.OpOr32, types.Types[types.TUINT32], x, c)
@@ -3906,12 +3932,12 @@ func init() {
                },
                sys.MIPS)
        addF("math/bits", "TrailingZeros8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpCtz8, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM, sys.ARM64, sys.Wasm)
        addF("math/bits", "TrailingZeros8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        x := s.newValue1(ssa.OpZeroExt8to64, types.Types[types.TUINT64], args[0])
                        c := s.constInt64(types.Types[types.TUINT64], 1<<8)
                        y := s.newValue2(ssa.OpOr64, types.Types[types.TUINT64], x, c)
@@ -3923,17 +3949,17 @@ func init() {
        // ReverseBytes inlines correctly, no need to intrinsify it.
        // ReverseBytes16 lowers to a rotate, no need for anything special here.
        addF("math/bits", "Len64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitLen64, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "Len32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
                },
                sys.AMD64, sys.ARM64)
        addF("math/bits", "Len32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
                        }
@@ -3942,7 +3968,7 @@ func init() {
                },
                sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "Len16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                x := s.newValue1(ssa.OpZeroExt16to32, types.Types[types.TUINT32], args[0])
                                return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], x)
@@ -3952,12 +3978,12 @@ func init() {
                },
                sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "Len16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitLen16, types.Types[types.TINT], args[0])
                },
                sys.AMD64)
        addF("math/bits", "Len8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                x := s.newValue1(ssa.OpZeroExt8to32, types.Types[types.TUINT32], args[0])
                                return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], x)
@@ -3967,12 +3993,12 @@ func init() {
                },
                sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        addF("math/bits", "Len8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitLen8, types.Types[types.TINT], args[0])
                },
                sys.AMD64)
        addF("math/bits", "Len",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                return s.newValue1(ssa.OpBitLen32, types.Types[types.TINT], args[0])
                        }
@@ -3981,27 +4007,27 @@ func init() {
                sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
        // LeadingZeros is handled because it trivially calls Len.
        addF("math/bits", "Reverse64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitRev64, types.Types[types.TINT], args[0])
                },
                sys.ARM64)
        addF("math/bits", "Reverse32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitRev32, types.Types[types.TINT], args[0])
                },
                sys.ARM64)
        addF("math/bits", "Reverse16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitRev16, types.Types[types.TINT], args[0])
                },
                sys.ARM64)
        addF("math/bits", "Reverse8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpBitRev8, types.Types[types.TINT], args[0])
                },
                sys.ARM64)
        addF("math/bits", "Reverse",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        if s.config.PtrSize == 4 {
                                return s.newValue1(ssa.OpBitRev32, types.Types[types.TINT], args[0])
                        }
@@ -4009,29 +4035,29 @@ func init() {
                },
                sys.ARM64)
        addF("math/bits", "RotateLeft8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpRotateLeft8, types.Types[types.TUINT8], args[0], args[1])
                },
                sys.AMD64)
        addF("math/bits", "RotateLeft16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpRotateLeft16, types.Types[types.TUINT16], args[0], args[1])
                },
                sys.AMD64)
        addF("math/bits", "RotateLeft32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpRotateLeft32, types.Types[types.TUINT32], args[0], args[1])
                },
                sys.AMD64, sys.ARM, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
        addF("math/bits", "RotateLeft64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpRotateLeft64, types.Types[types.TUINT64], args[0], args[1])
                },
                sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
        alias("math/bits", "RotateLeft", "math/bits", "RotateLeft64", p8...)
 
-       makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
-               return func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+       makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
+               return func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[types.TBOOL], x86HasPOPCNT)
                        b := s.endBlock()
                        b.Kind = ssa.BlockIf
@@ -4066,7 +4092,7 @@ func init() {
                makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64),
                sys.AMD64)
        addF("math/bits", "OnesCount64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpPopCount64, types.Types[types.TINT], args[0])
                },
                sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
@@ -4074,7 +4100,7 @@ func init() {
                makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32),
                sys.AMD64)
        addF("math/bits", "OnesCount32",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpPopCount32, types.Types[types.TINT], args[0])
                },
                sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
@@ -4082,12 +4108,12 @@ func init() {
                makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16),
                sys.AMD64)
        addF("math/bits", "OnesCount16",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpPopCount16, types.Types[types.TINT], args[0])
                },
                sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
        addF("math/bits", "OnesCount8",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue1(ssa.OpPopCount8, types.Types[types.TINT], args[0])
                },
                sys.S390X, sys.PPC64, sys.Wasm)
@@ -4095,25 +4121,25 @@ func init() {
                makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
                sys.AMD64)
        addF("math/bits", "Mul64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1])
                },
                sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X, sys.MIPS64)
        alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE)
        addF("math/bits", "Add64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
                },
                sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X)
        alias("math/bits", "Add", "math/bits", "Add64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X)
        addF("math/bits", "Sub64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue3(ssa.OpSub64borrow, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1], args[2])
                },
                sys.AMD64, sys.ARM64, sys.S390X)
        alias("math/bits", "Sub", "math/bits", "Sub64", sys.ArchAMD64, sys.ArchARM64, sys.ArchS390X)
        addF("math/bits", "Div64",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        // check for divide-by-zero/overflow and panic with appropriate message
                        cmpZero := s.newValue2(s.ssaOp(ir.ONE, types.Types[types.TUINT64]), types.Types[types.TBOOL], args[2], s.zeroVal(types.Types[types.TUINT64]))
                        s.check(cmpZero, panicdivide)
@@ -4173,7 +4199,7 @@ func init() {
 
        /******** math/big ********/
        add("math/big", "mulWW",
-               func(s *state, n ir.Node, args []*ssa.Value) *ssa.Value {
+               func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
                        return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[types.TUINT64], types.Types[types.TUINT64]), args[0], args[1])
                },
                sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64LE, sys.ArchPPC64, sys.ArchS390X)
@@ -4211,7 +4237,7 @@ func findIntrinsic(sym *types.Sym) intrinsicBuilder {
        return intrinsics[intrinsicKey{thearch.LinkArch.Arch, pkg, fn}]
 }
 
-func isIntrinsicCall(n ir.Node) bool {
+func isIntrinsicCall(n *ir.CallExpr) bool {
        if n == nil {
                return false
        }
@@ -4223,7 +4249,7 @@ func isIntrinsicCall(n ir.Node) bool {
 }
 
 // intrinsicCall converts a call to a recognized intrinsic function into the intrinsic SSA operation.
-func (s *state) intrinsicCall(n ir.Node) *ssa.Value {
+func (s *state) intrinsicCall(n *ir.CallExpr) *ssa.Value {
        v := findIntrinsic(n.Left().Sym())(s, n, s.intrinsicArgs(n))
        if ssa.IntrinsicsDebug > 0 {
                x := v
@@ -4239,13 +4265,14 @@ func (s *state) intrinsicCall(n ir.Node) *ssa.Value {
 }
 
 // intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them.
-func (s *state) intrinsicArgs(n ir.Node) []*ssa.Value {
+func (s *state) intrinsicArgs(n *ir.CallExpr) []*ssa.Value {
        // Construct map of temps; see comments in s.call about the structure of n.
        temps := map[ir.Node]*ssa.Value{}
        for _, a := range n.List().Slice() {
                if a.Op() != ir.OAS {
                        s.Fatalf("non-assignment as a temp function argument %v", a.Op())
                }
+               a := a.(*ir.AssignStmt)
                l, r := a.Left(), a.Right()
                if l.Op() != ir.ONAME {
                        s.Fatalf("non-ONAME temp function argument %v", a.Op())
@@ -4274,7 +4301,7 @@ func (s *state) intrinsicArgs(n ir.Node) []*ssa.Value {
 // call. We will also record funcdata information on where the args are stored
 // (as well as the deferBits variable), and this will enable us to run the proper
 // defer calls during panics.
-func (s *state) openDeferRecord(n ir.Node) {
+func (s *state) openDeferRecord(n *ir.CallExpr) {
        // Do any needed expression evaluation for the args (including the
        // receiver, if any). This may be evaluating something like 'autotmp_3 =
        // once.mutex'. Such a statement will create a mapping in s.vars[] from
@@ -4296,13 +4323,14 @@ func (s *state) openDeferRecord(n ir.Node) {
                closureVal := s.expr(fn)
                closure := s.openDeferSave(nil, fn.Type(), closureVal)
                opendefer.closureNode = closure.Aux.(*ir.Name)
-               if !(fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC) {
+               if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class() == ir.PFUNC) {
                        opendefer.closure = closure
                }
        } else if n.Op() == ir.OCALLMETH {
                if fn.Op() != ir.ODOTMETH {
                        base.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
                }
+               fn := fn.(*ir.SelectorExpr)
                closureVal := s.getMethodClosure(fn)
                // We must always store the function value in a stack slot for the
                // runtime panic code to use. But in the defer exit code, we will
@@ -4313,6 +4341,7 @@ func (s *state) openDeferRecord(n ir.Node) {
                if fn.Op() != ir.ODOTINTER {
                        base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
                }
+               fn := fn.(*ir.SelectorExpr)
                closure, rcvr := s.getClosureAndRcvr(fn)
                opendefer.closure = s.openDeferSave(nil, closure.Type, closure)
                // Important to get the receiver type correct, so it is recognized
@@ -4517,11 +4546,11 @@ func (s *state) openDeferExit() {
                // use the first call of the last defer exit to compute liveness
                // for the deferreturn, so we want all stack slots to be live.
                if r.closureNode != nil {
-                       s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode.(*ir.Name), s.mem(), false)
+                       s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
                }
                if r.rcvrNode != nil {
                        if r.rcvrNode.Type().HasPointers() {
-                               s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.rcvrNode.(*ir.Name), s.mem(), false)
+                               s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.rcvrNode, s.mem(), false)
                        }
                }
                for _, argNode := range r.argNodes {
@@ -4535,17 +4564,17 @@ func (s *state) openDeferExit() {
        }
 }
 
-func (s *state) callResult(n ir.Node, k callKind) *ssa.Value {
+func (s *state) callResult(n *ir.CallExpr, k callKind) *ssa.Value {
        return s.call(n, k, false)
 }
 
-func (s *state) callAddr(n ir.Node, k callKind) *ssa.Value {
+func (s *state) callAddr(n *ir.CallExpr, k callKind) *ssa.Value {
        return s.call(n, k, true)
 }
 
 // Calls the function n using the specified call type.
 // Returns the address of the return value (or nil if none).
-func (s *state) call(n ir.Node, k callKind, returnResultAddr bool) *ssa.Value {
+func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Value {
        s.prevCall = nil
        var sym *types.Sym     // target symbol (if static)
        var closure *ssa.Value // ptr to closure to run (if dynamic)
@@ -4569,7 +4598,7 @@ func (s *state) call(n ir.Node, k callKind, returnResultAddr bool) *ssa.Value {
        switch n.Op() {
        case ir.OCALLFUNC:
                testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
-               if k == callNormal && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC {
+               if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class() == ir.PFUNC {
                        sym = fn.Sym()
                        break
                }
@@ -4583,6 +4612,7 @@ func (s *state) call(n ir.Node, k callKind, returnResultAddr bool) *ssa.Value {
                if fn.Op() != ir.ODOTMETH {
                        s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
                }
+               fn := fn.(*ir.SelectorExpr)
                testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
                if k == callNormal {
                        sym = fn.Sym()
@@ -4595,6 +4625,7 @@ func (s *state) call(n ir.Node, k callKind, returnResultAddr bool) *ssa.Value {
                if fn.Op() != ir.ODOTINTER {
                        s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
                }
+               fn := fn.(*ir.SelectorExpr)
                testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
                var iclosure *ssa.Value
                iclosure, rcvr = s.getClosureAndRcvr(fn)
@@ -4847,7 +4878,7 @@ func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
 }
 
 // getMethodClosure returns a value representing the closure for a method call
-func (s *state) getMethodClosure(fn ir.Node) *ssa.Value {
+func (s *state) getMethodClosure(fn *ir.SelectorExpr) *ssa.Value {
        // Make a name n2 for the function.
        // fn.Sym might be sync.(*Mutex).Unlock.
        // Make a PFUNC node out of that, then evaluate it.
@@ -4864,7 +4895,7 @@ func (s *state) getMethodClosure(fn ir.Node) *ssa.Value {
 
 // getClosureAndRcvr returns values for the appropriate closure and receiver of an
 // interface call
-func (s *state) getClosureAndRcvr(fn ir.Node) (*ssa.Value, *ssa.Value) {
+func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
        i := s.expr(fn.Left())
        itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
        s.nilCheck(itab)
@@ -4967,6 +4998,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
                p := s.exprPtr(n.Left(), n.Bounded(), n.Pos())
                return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
        case ir.OCLOSUREREAD:
+               n := n.(*ir.ClosureReadExpr)
                return s.newValue1I(ssa.OpOffPtr, t, n.Offset(),
                        s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr))
        case ir.OCONVNOP:
@@ -4976,8 +5008,10 @@ func (s *state) addr(n ir.Node) *ssa.Value {
                addr := s.addr(n.Left())
                return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
        case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
+               n := n.(*ir.CallExpr)
                return s.callAddr(n, callNormal)
        case ir.ODOTTYPE:
+               n := n.(*ir.TypeAssertExpr)
                v, _ := s.dottype(n, false)
                if v.Op != ssa.OpLoad {
                        s.Fatalf("dottype of non-load")
@@ -4998,22 +5032,34 @@ func (s *state) canSSA(n ir.Node) bool {
        if base.Flag.N != 0 {
                return false
        }
-       for n.Op() == ir.ODOT || (n.Op() == ir.OINDEX && n.Left().Type().IsArray()) {
-               n = n.Left()
+       for {
+               nn := n
+               if nn.Op() == ir.ODOT {
+                       n = nn.Left()
+                       continue
+               }
+               if nn.Op() == ir.OINDEX {
+                       if nn.Left().Type().IsArray() {
+                               n = nn.Left()
+                               continue
+                       }
+               }
+               break
        }
        if n.Op() != ir.ONAME {
                return false
        }
-       if n.Name().Addrtaken() {
+       name := n.(*ir.Name)
+       if name.Addrtaken() {
                return false
        }
-       if isParamHeapCopy(n) {
+       if isParamHeapCopy(name) {
                return false
        }
-       if n.Class() == ir.PAUTOHEAP {
-               s.Fatalf("canSSA of PAUTOHEAP %v", n)
+       if name.Class() == ir.PAUTOHEAP {
+               s.Fatalf("canSSA of PAUTOHEAP %v", name)
        }
-       switch n.Class() {
+       switch name.Class() {
        case ir.PEXTERN:
                return false
        case ir.PPARAMOUT:
@@ -5031,13 +5077,13 @@ func (s *state) canSSA(n ir.Node) bool {
                        return false
                }
        }
-       if n.Class() == ir.PPARAM && n.Sym() != nil && n.Sym().Name == ".this" {
+       if name.Class() == ir.PPARAM && name.Sym() != nil && name.Sym().Name == ".this" {
                // wrappers generated by genwrapper need to update
                // the .this pointer in place.
                // TODO: treat as a PPARAMOUT?
                return false
        }
-       return canSSAType(n.Type())
+       return canSSAType(name.Type())
        // TODO: try to make more variables SSAable?
 }
 
@@ -5736,7 +5782,7 @@ func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n ir.Node, x *ssa.Value, ft,
 }
 
 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
-func (s *state) referenceTypeBuiltin(n ir.Node, x *ssa.Value) *ssa.Value {
+func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value {
        if !n.Left().Type().IsMap() && !n.Left().Type().IsChan() {
                s.Fatalf("node must be a map or a channel")
        }
@@ -5893,7 +5939,7 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *
 // dottype generates SSA for a type assertion node.
 // commaok indicates whether to panic or return a bool.
 // If commaok is false, resok will be nil.
-func (s *state) dottype(n ir.Node, commaok bool) (res, resok *ssa.Value) {
+func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
        iface := s.expr(n.Left())   // input interface
        target := s.expr(n.Right()) // target type
        byteptr := s.f.Config.Types.BytePtr
@@ -6029,7 +6075,7 @@ func (s *state) dottype(n ir.Node, commaok bool) (res, resok *ssa.Value) {
        if !commaok {
                // on failure, panic by calling panicdottype
                s.startBlock(bFail)
-               taddr := s.expr(n.Right().Right())
+               taddr := s.expr(n.Right().(*ir.AddrExpr).Right())
                if n.Left().Type().IsEmptyInterface() {
                        s.rtcall(panicdottypeE, false, nil, itab, target, taddr)
                } else {
@@ -6095,25 +6141,27 @@ func (s *state) dottype(n ir.Node, commaok bool) (res, resok *ssa.Value) {
 }
 
 // variable returns the value of a variable at the current location.
-func (s *state) variable(name ir.Node, t *types.Type) *ssa.Value {
-       v := s.vars[name]
+func (s *state) variable(n ir.Node, t *types.Type) *ssa.Value {
+       v := s.vars[n]
        if v != nil {
                return v
        }
-       v = s.fwdVars[name]
+       v = s.fwdVars[n]
        if v != nil {
                return v
        }
 
        if s.curBlock == s.f.Entry {
                // No variable should be live at entry.
-               s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, name, v)
+               s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, n, v)
        }
        // Make a FwdRef, which records a value that's live on block input.
        // We'll find the matching definition as part of insertPhis.
-       v = s.newValue0A(ssa.OpFwdRef, t, FwdRefAux{N: name})
-       s.fwdVars[name] = v
-       s.addNamedValue(name, v)
+       v = s.newValue0A(ssa.OpFwdRef, t, FwdRefAux{N: n})
+       s.fwdVars[n] = v
+       if n.Op() == ir.ONAME {
+               s.addNamedValue(n.(*ir.Name), v)
+       }
        return v
 }
 
@@ -6121,7 +6169,7 @@ func (s *state) mem() *ssa.Value {
        return s.variable(memVar, types.TypeMem)
 }
 
-func (s *state) addNamedValue(n ir.Node, v *ssa.Value) {
+func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
        if n.Class() == ir.Pxxx {
                // Don't track our marker nodes (memVar etc.).
                return
@@ -6174,7 +6222,7 @@ type SSAGenState struct {
        bstart []*obj.Prog
 
        // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
-       ScratchFpMem ir.Node
+       ScratchFpMem *ir.Name
 
        maxarg int64 // largest frame size for arguments to calls made by the function
 
@@ -6877,9 +6925,9 @@ func CheckLoweredGetClosurePtr(v *ssa.Value) {
        }
 }
 
-// AutoVar returns a *Node and int64 representing the auto variable and offset within it
+// AutoVar returns a *Name and int64 representing the auto variable and offset within it
 // where v should be spilled.
-func AutoVar(v *ssa.Value) (ir.Node, int64) {
+func AutoVar(v *ssa.Value) (*ir.Name, int64) {
        loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
        if v.Type.Size() > loc.Type.Size() {
                v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
@@ -6990,7 +7038,7 @@ func (s *SSAGenState) UseArgs(n int64) {
 }
 
 // fieldIdx finds the index of the field referred to by the ODOT node n.
-func fieldIdx(n ir.Node) int {
+func fieldIdx(n *ir.SelectorExpr) int {
        t := n.Left().Type()
        f := n.Sym()
        if !t.IsStruct() {
@@ -7019,7 +7067,7 @@ func fieldIdx(n ir.Node) int {
 type ssafn struct {
        curfn        *ir.Func
        strings      map[string]*obj.LSym // map from constant string to data symbols
-       scratchFpMem ir.Node              // temp for floating point register / memory moves on some architectures
+       scratchFpMem *ir.Name             // temp for floating point register / memory moves on some architectures
        stksize      int64                // stack size for current frame
        stkptrsize   int64                // prefix of stack containing pointers
        log          bool                 // print ssa debug to the stdout
@@ -7211,11 +7259,15 @@ func (e *ssafn) MyImportPath() string {
 }
 
 func clobberBase(n ir.Node) ir.Node {
-       if n.Op() == ir.ODOT && n.Left().Type().NumFields() == 1 {
-               return clobberBase(n.Left())
+       if n.Op() == ir.ODOT {
+               if n.Left().Type().NumFields() == 1 {
+                       return clobberBase(n.Left())
+               }
        }
-       if n.Op() == ir.OINDEX && n.Left().Type().IsArray() && n.Left().Type().NumElem() == 1 {
-               return clobberBase(n.Left())
+       if n.Op() == ir.OINDEX {
+               if n.Left().Type().IsArray() && n.Left().Type().NumElem() == 1 {
+                       return clobberBase(n.Left())
+               }
        }
        return n
 }
index 041eb900c803ac7418510929864fe6f7332de1c3..cc0b3d847d1ad98374950bac11e8d2fb36cc5133 100644 (file)
@@ -743,7 +743,7 @@ func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
                walkexprlistsafe(n.List().Slice(), init)
                r = walkexpr(r, init)
 
-               if isIntrinsicCall(r) {
+               if isIntrinsicCall(r.(*ir.CallExpr)) {
                        n.PtrRlist().Set1(r)
                        return n
                }