]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge master (ecaa681) into dev.typeparams
authorMatthew Dempsky <mdempsky@google.com>
Mon, 26 Jul 2021 19:13:55 +0000 (12:13 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 26 Jul 2021 19:19:12 +0000 (12:19 -0700)
Conflicts:

- src/cmd/compile/internal/ssagen/ssa.go

  CL 336629 touched code that had already been removed on dev.typeparams.

Merge List:

+ 2021-07-26 ecaa6816bf doc: clarify non-nil zero length slice to array pointer conversion
+ 2021-07-26 1868f8296e crypto/x509: update iOS bundled roots to version 55188.120.1.0.1
+ 2021-07-25 849b791129 spec: use consistent capitalization for rune literal hex constants
+ 2021-07-23 0914646ab9 doc/1.17: fix two dead rfc links
+ 2021-07-22 052da5717e cmd/compile: do not change field offset in ABI analysis

Change-Id: Ie570ec3f6a3241e0495e39e8a73b3a09a9368605

1  2 
src/cmd/compile/internal/ssagen/ssa.go

index c087b71fe665d48c0893435b2c743f39f16fd130,dfa76006de790110b05def67fe3d8a4451584245..d2e0d57b28c3ad898e0a9fe8c8d9a11f14b15651
@@@ -279,6 -279,18 +279,6 @@@ func regAbiForFuncType(ft *types.Func) 
        return np > 0 && strings.Contains(ft.Params.FieldType(np-1).String(), magicLastTypeName)
  }
  
 -// getParam returns the Field of ith param of node n (which is a
 -// 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.CallExpr, i int) *types.Field {
 -      t := n.X.Type()
 -      if n.Op() == ir.OCALLMETH {
 -              base.Fatalf("OCALLMETH missed by walkCall")
 -      }
 -      return t.Params().Field(i)
 -}
 -
  // dvarint writes a varint v to the funcdata in symbol x and returns the new offset
  func dvarint(x *obj.LSym, off int, v int64) int {
        if v < 0 || v > 1e9 {
  // for stack variables are specified as the number of bytes below varp (pointer to the
  // top of the local variables) for their starting address. The format is:
  //
 -//  - Max total argument size among all the defers
  //  - Offset of the deferBits variable
  //  - Number of defers in the function
  //  - Information about each defer call, in reverse order of appearance in the function:
 -//    - Total argument size of the call
  //    - Offset of the closure value to call
 -//    - Number of arguments (including interface receiver or method receiver as first arg)
 -//    - Information about each argument
 -//      - Offset of the stored defer argument in this function's frame
 -//      - Size of the argument
 -//      - Offset of where argument should be placed in the args frame when making call
  func (s *state) emitOpenDeferInfo() {
        x := base.Ctxt.Lookup(s.curfn.LSym.Name + ".opendefer")
        s.curfn.LSym.Func().OpenCodedDeferInfo = x
        off := 0
 -
 -      // Compute maxargsize (max size of arguments for all defers)
 -      // first, so we can output it first to the funcdata
 -      var maxargsize int64
 -      for i := len(s.openDefers) - 1; i >= 0; i-- {
 -              r := s.openDefers[i]
 -              argsize := r.n.X.Type().ArgWidth() // TODO register args: but maybe use of abi0 will make this easy
 -              if argsize > maxargsize {
 -                      maxargsize = argsize
 -              }
 -      }
 -      off = dvarint(x, off, maxargsize)
        off = dvarint(x, off, -s.deferBitsTemp.FrameOffset())
        off = dvarint(x, off, int64(len(s.openDefers)))
  
        // Write in reverse-order, for ease of running in that order at runtime
        for i := len(s.openDefers) - 1; i >= 0; i-- {
                r := s.openDefers[i]
 -              off = dvarint(x, off, r.n.X.Type().ArgWidth())
                off = dvarint(x, off, -r.closureNode.FrameOffset())
 -              numArgs := len(r.argNodes)
 -              if r.rcvrNode != nil {
 -                      // If there's an interface receiver, treat/place it as the first
 -                      // arg. (If there is a method receiver, it's already included as
 -                      // first arg in r.argNodes.)
 -                      numArgs++
 -              }
 -              off = dvarint(x, off, int64(numArgs))
 -              argAdjust := 0 // presence of receiver offsets the parameter count.
 -              if r.rcvrNode != nil {
 -                      off = dvarint(x, off, -okOffset(r.rcvrNode.FrameOffset()))
 -                      off = dvarint(x, off, s.config.PtrSize)
 -                      off = dvarint(x, off, 0) // This is okay because defer records use ABI0 (for now)
 -                      argAdjust++
 -              }
 -
 -              // TODO(register args) assume abi0 for this?
 -              ab := s.f.ABI0
 -              pri := ab.ABIAnalyzeFuncType(r.n.X.Type().FuncType())
 -              for j, arg := range r.argNodes {
 -                      f := getParam(r.n, j)
 -                      off = dvarint(x, off, -okOffset(arg.FrameOffset()))
 -                      off = dvarint(x, off, f.Type.Size())
 -                      off = dvarint(x, off, okOffset(pri.InParam(j+argAdjust).FrameOffset(pri)))
 -              }
        }
  }
  
@@@ -523,7 -580,7 +523,7 @@@ func buildssa(fn *ir.Func, worker int) 
        }
  
        // Populate closure variables.
 -      if !fn.ClosureCalled() {
 +      if fn.Needctxt() {
                clo := s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)
                offset := int64(types.PtrSize) // PtrSize to skip past function entry PC field
                for _, n := range fn.ClosureVars {
        // it mimics the behavior of the former ABI (everything stored) and because it's not 100%
        // clear if naming conventions are respected in autogenerated code.
        // TODO figure out exactly what's unused, don't spill it. Make liveness fine-grained, also.
 -      // TODO non-amd64 architectures have link registers etc that may require adjustment here.
        for _, p := range params.InParams() {
                typs, offs := p.RegisterTypesAndOffsets()
                for i, t := range typs {
@@@ -807,6 -865,16 +807,6 @@@ type openDeferInfo struct 
        // function, method, or interface call, to store a closure that panic
        // processing can use for this defer.
        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.Name
 -      // The addresses of the argtmps where the evaluated arguments of the defer
 -      // function call are stored.
 -      argVals []*ssa.Value
 -      // The nodes representing the argtmps where the args of the defer are stored
 -      argNodes []*ir.Name
  }
  
  type state struct {
@@@ -1228,7 -1296,7 +1228,7 @@@ func (s *state) instrumentFields(t *typ
                if f.Sym.IsBlank() {
                        continue
                }
-               offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr)
+               offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
                s.instrumentFields(f.Type, offptr, kind)
        }
  }
@@@ -3115,7 -3183,7 +3115,7 @@@ func (s *state) expr(n ir.Node) *ssa.Va
                }
                fallthrough
  
 -      case ir.OCALLINTER, ir.OCALLMETH:
 +      case ir.OCALLINTER:
                n := n.(*ir.CallExpr)
                return s.callResult(n, callNormal)
  
                n := n.(*ir.CallExpr)
                return s.newValue1(ssa.OpGetG, n.Type(), s.mem())
  
 +      case ir.OGETCALLERPC:
 +              n := n.(*ir.CallExpr)
 +              return s.newValue0(ssa.OpGetCallerPC, n.Type())
 +
 +      case ir.OGETCALLERSP:
 +              n := n.(*ir.CallExpr)
 +              return s.newValue0(ssa.OpGetCallerSP, n.Type())
 +
        case ir.OAPPEND:
                return s.append(n.(*ir.CallExpr), false)
  
@@@ -4627,14 -4687,17 +4627,14 @@@ func (s *state) intrinsicArgs(n *ir.Cal
        return args
  }
  
 -// openDeferRecord adds code to evaluate and store the args for an open-code defer
 +// openDeferRecord adds code to evaluate and store the function for an open-code defer
  // call, and records info about the defer, so we can generate proper code on the
  // exit paths. n is the sub-node of the defer node that is the actual function
 -// call. We will also record funcdata information on where the args are stored
 +// call. We will also record funcdata information on where the function is 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.CallExpr) {
 -      var args []*ssa.Value
 -      var argNodes []*ir.Name
 -
 -      if buildcfg.Experiment.RegabiDefer && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
 +      if len(n.Args) != 0 || n.Op() != ir.OCALLFUNC || n.X.Type().NumResults() != 0 {
                s.Fatalf("defer call with arguments or results: %v", n)
        }
  
                n: n,
        }
        fn := n.X
 -      if n.Op() == ir.OCALLFUNC {
 -              // 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
 -              // call the function directly if it is a static function.
 -              closureVal := s.expr(fn)
 -              closure := s.openDeferSave(nil, fn.Type(), closureVal)
 -              opendefer.closureNode = closure.Aux.(*ir.Name)
 -              if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
 -                      opendefer.closure = closure
 -              }
 -      } else if n.Op() == ir.OCALLMETH {
 -              base.Fatalf("OCALLMETH missed by walkCall")
 -      } else {
 -              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
 -              // as a pointer for GC purposes.
 -              opendefer.rcvr = s.openDeferSave(nil, fn.Type().Recv().Type, rcvr)
 -              opendefer.closureNode = opendefer.closure.Aux.(*ir.Name)
 -              opendefer.rcvrNode = opendefer.rcvr.Aux.(*ir.Name)
 -      }
 -      for _, argn := range n.Args {
 -              var v *ssa.Value
 -              if TypeOK(argn.Type()) {
 -                      v = s.openDeferSave(nil, argn.Type(), s.expr(argn))
 -              } else {
 -                      v = s.openDeferSave(argn, argn.Type(), nil)
 -              }
 -              args = append(args, v)
 -              argNodes = append(argNodes, v.Aux.(*ir.Name))
 +      // 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
 +      // call the function directly if it is a static function.
 +      closureVal := s.expr(fn)
 +      closure := s.openDeferSave(fn.Type(), closureVal)
 +      opendefer.closureNode = closure.Aux.(*ir.Name)
 +      if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
 +              opendefer.closure = closure
        }
 -      opendefer.argVals = args
 -      opendefer.argNodes = argNodes
        index := len(s.openDefers)
        s.openDefers = append(s.openDefers, opendefer)
  
        // Update deferBits only after evaluation and storage to stack of
 -      // args/receiver/interface is successful.
 +      // the function is successful.
        bitvalue := s.constInt8(types.Types[types.TUINT8], 1<<uint(index))
        newDeferBits := s.newValue2(ssa.OpOr8, types.Types[types.TUINT8], s.variable(deferBitsVar, types.Types[types.TUINT8]), bitvalue)
        s.vars[deferBitsVar] = newDeferBits
  
  // openDeferSave generates SSA nodes to store a value (with type t) for an
  // open-coded defer at an explicit autotmp location on the stack, so it can be
 -// reloaded and used for the appropriate call on exit. If type t is SSAable, then
 -// val must be non-nil (and n should be nil) and val is the value to be stored. If
 -// type t is non-SSAable, then n must be non-nil (and val should be nil) and n is
 -// evaluated (via s.addr() below) to get the value that is to be stored. The
 -// function returns an SSA value representing a pointer to the autotmp location.
 -func (s *state) openDeferSave(n ir.Node, t *types.Type, val *ssa.Value) *ssa.Value {
 -      canSSA := TypeOK(t)
 -      var pos src.XPos
 -      if canSSA {
 -              pos = val.Pos
 -      } else {
 -              pos = n.Pos()
 +// reloaded and used for the appropriate call on exit. Type t must be a function type
 +// (therefore SSAable). val is the value to be stored. The function returns an SSA
 +// value representing a pointer to the autotmp location.
 +func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value {
 +      if !TypeOK(t) {
 +              s.Fatalf("openDeferSave of non-SSA-able type %v val=%v", t, val)
 +      }
 +      if !t.HasPointers() {
 +              s.Fatalf("openDeferSave of pointerless type %v val=%v", t, val)
        }
 -      argTemp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
 -      argTemp.SetOpenDeferSlot(true)
 -      var addrArgTemp *ssa.Value
 -      // Use OpVarLive to make sure stack slots for the args, etc. are not
 -      // removed by dead-store elimination
 +      pos := val.Pos
 +      temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
 +      temp.SetOpenDeferSlot(true)
 +      var addrTemp *ssa.Value
 +      // Use OpVarLive to make sure stack slot for the closure is not removed by
 +      // dead-store elimination
        if s.curBlock.ID != s.f.Entry.ID {
 -              // Force the argtmp storing this defer function/receiver/arg to be
 -              // declared in the entry block, so that it will be live for the
 -              // defer exit code (which will actually access it only if the
 -              // associated defer call has been activated).
 -              s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarDef, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][memVar])
 -              s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarLive, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][memVar])
 -              addrArgTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(argTemp.Type()), argTemp, s.sp, s.defvars[s.f.Entry.ID][memVar])
 +              // Force the tmp storing this defer function to be declared in the entry
 +              // block, so that it will be live for the defer exit code (which will
 +              // actually access it only if the associated defer call has been activated).
 +              s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarDef, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar])
 +              s.defvars[s.f.Entry.ID][memVar] = s.f.Entry.NewValue1A(src.NoXPos, ssa.OpVarLive, types.TypeMem, temp, s.defvars[s.f.Entry.ID][memVar])
 +              addrTemp = s.f.Entry.NewValue2A(src.NoXPos, ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.defvars[s.f.Entry.ID][memVar])
        } else {
                // Special case if we're still in the entry block. We can't use
                // the above code, since s.defvars[s.f.Entry.ID] isn't defined
                // until we end the entry block with s.endBlock().
 -              s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, argTemp, s.mem(), false)
 -              s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argTemp, s.mem(), false)
 -              addrArgTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(argTemp.Type()), argTemp, s.sp, s.mem(), false)
 -      }
 -      if t.HasPointers() {
 -              // Since we may use this argTemp during exit depending on the
 -              // deferBits, we must define it unconditionally on entry.
 -              // Therefore, we must make sure it is zeroed out in the entry
 -              // block if it contains pointers, else GC may wrongly follow an
 -              // uninitialized pointer value.
 -              argTemp.SetNeedzero(true)
 -      }
 -      if !canSSA {
 -              a := s.addr(n)
 -              s.move(t, addrArgTemp, a)
 -              return addrArgTemp
 -      }
 +              s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, temp, s.mem(), false)
 +              s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, temp, s.mem(), false)
 +              addrTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(temp.Type()), temp, s.sp, s.mem(), false)
 +      }
 +      // Since we may use this temp during exit depending on the
 +      // deferBits, we must define it unconditionally on entry.
 +      // Therefore, we must make sure it is zeroed out in the entry
 +      // block if it contains pointers, else GC may wrongly follow an
 +      // uninitialized pointer value.
 +      temp.SetNeedzero(true)
        // We are storing to the stack, hence we can avoid the full checks in
        // storeType() (no write barrier) and do a simple store().
 -      s.store(t, addrArgTemp, val)
 -      return addrArgTemp
 +      s.store(t, addrTemp, val)
 +      return addrTemp
  }
  
  // openDeferExit generates SSA for processing all the open coded defers at exit.
@@@ -4748,26 -4849,45 +4748,26 @@@ func (s *state) openDeferExit() 
                s.vars[deferBitsVar] = maskedval
  
                // Generate code to call the function call of the defer, using the
 -              // closure/receiver/args that were stored in argtmps at the point
 -              // of the defer statement.
 +              // closure that were stored in argtmps at the point of the defer
 +              // statement.
                fn := r.n.X
                stksize := fn.Type().ArgWidth()
 -              var ACArgs []*types.Type
 -              var ACResults []*types.Type
                var callArgs []*ssa.Value
 -              if r.rcvr != nil {
 -                      // rcvr in case of OCALLINTER
 -                      v := s.load(r.rcvr.Type.Elem(), r.rcvr)
 -                      ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
 -                      callArgs = append(callArgs, v)
 -              }
 -              for j, argAddrVal := range r.argVals {
 -                      f := getParam(r.n, j)
 -                      ACArgs = append(ACArgs, f.Type)
 -                      var a *ssa.Value
 -                      if !TypeOK(f.Type) {
 -                              a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem())
 -                      } else {
 -                              a = s.load(f.Type, argAddrVal)
 -                      }
 -                      callArgs = append(callArgs, a)
 -              }
                var call *ssa.Value
                if r.closure != nil {
                        v := s.load(r.closure.Type.Elem(), r.closure)
                        s.maybeNilCheckClosure(v, callDefer)
                        codeptr := s.rawLoad(types.Types[types.TUINTPTR], v)
 -                      aux := ssa.ClosureAuxCall(s.f.ABIDefault.ABIAnalyzeTypes(nil, ACArgs, ACResults))
 +                      aux := ssa.ClosureAuxCall(s.f.ABIDefault.ABIAnalyzeTypes(nil, nil, nil))
                        call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
                } else {
 -                      aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), s.f.ABIDefault.ABIAnalyzeTypes(nil, ACArgs, ACResults))
 +                      aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), s.f.ABIDefault.ABIAnalyzeTypes(nil, nil, nil))
                        call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
                }
                callArgs = append(callArgs, s.mem())
                call.AddArgs(callArgs...)
                call.AuxInt = stksize
 -              s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
 +              s.vars[memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, 0, call)
                // Make sure that the stack slots with pointers are kept live
                // through the call (which is a pre-emption point). Also, we will
                // use the first call of the last defer exit to compute liveness
                if r.closureNode != nil {
                        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, s.mem(), false)
 -                      }
 -              }
 -              for _, argNode := range r.argNodes {
 -                      if argNode.Type().HasPointers() {
 -                              s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argNode, s.mem(), false)
 -                      }
 -              }
  
                s.endBlock()
                s.startBlock(bEnd)
@@@ -4822,7 -4952,7 +4822,7 @@@ func (s *state) call(n *ir.CallExpr, k 
                }
        }
  
 -      if buildcfg.Experiment.RegabiDefer && k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
 +      if k != callNormal && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) {
                s.Fatalf("go/defer call with arguments: %v", n)
        }
  
                        // not the point of defer statement.
                        s.maybeNilCheckClosure(closure, k)
                }
 -      case ir.OCALLMETH:
 -              base.Fatalf("OCALLMETH missed by walkCall")
        case ir.OCALLINTER:
                if fn.Op() != ir.ODOTINTER {
                        s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
        var call *ssa.Value
        if k == callDeferStack {
                // Make a defer struct d on the stack.
 -              t := deferstruct(stksize)
 +              if stksize != 0 {
 +                      s.Fatalf("deferprocStack with non-zero stack size %d: %v", stksize, n)
 +              }
 +
 +              t := deferstruct()
                d := typecheck.TempAt(n.Pos(), s.curfn, t)
  
                s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, d, s.mem())
                addr := s.addr(d)
  
 -              // Must match reflect.go:deferstruct and src/runtime/runtime2.go:_defer.
 -              // 0: siz
 -              s.store(types.Types[types.TUINT32],
 -                      s.newValue1I(ssa.OpOffPtr, types.Types[types.TUINT32].PtrTo(), t.FieldOff(0), addr),
 -                      s.constInt32(types.Types[types.TUINT32], int32(stksize)))
 -              // 1: started, set in deferprocStack
 -              // 2: heap, set in deferprocStack
 -              // 3: openDefer
 -              // 4: sp, set in deferprocStack
 -              // 5: pc, set in deferprocStack
 -              // 6: fn
 +              // Must match deferstruct() below and src/runtime/runtime2.go:_defer.
 +              // 0: started, set in deferprocStack
 +              // 1: heap, set in deferprocStack
 +              // 2: openDefer
 +              // 3: sp, set in deferprocStack
 +              // 4: pc, set in deferprocStack
 +              // 5: fn
                s.store(closure.Type,
 -                      s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(6), addr),
 +                      s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(5), addr),
                        closure)
 -              // 7: panic, set in deferprocStack
 -              // 8: link, set in deferprocStack
 -              // 9: framepc
 -              // 10: varp
 -              // 11: fd
 -
 -              // Then, store all the arguments of the defer call.
 -              ft := fn.Type()
 -              off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
 -              args := n.Args
 -              i0 := 0
 -
 -              // Set receiver (for interface calls). Always a pointer.
 -              if rcvr != nil {
 -                      p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
 -                      s.store(types.Types[types.TUINTPTR], p, rcvr)
 -                      i0 = 1
 -              }
 -              // Set receiver (for method calls).
 -              if n.Op() == ir.OCALLMETH {
 -                      base.Fatalf("OCALLMETH missed by walkCall")
 -              }
 -              // Set other args.
 -              // This code is only used when RegabiDefer is not enabled, and arguments are always
 -              // passed on stack.
 -              for i, f := range ft.Params().Fields().Slice() {
 -                      s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params))
 -                      args = args[1:]
 -              }
 +              // 6: panic, set in deferprocStack
 +              // 7: link, set in deferprocStack
 +              // 8: fd
 +              // 9: varp
 +              // 10: framepc
  
                // Call runtime.deferprocStack with pointer to _defer record.
                ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
                callArgs = append(callArgs, addr, s.mem())
                call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
                call.AddArgs(callArgs...)
 -              if stksize < int64(types.PtrSize) {
 -                      // We need room for both the call to deferprocStack and the call to
 -                      // the deferred function.
 -                      stksize = int64(types.PtrSize)
 -              }
 -              call.AuxInt = stksize
 +              call.AuxInt = int64(types.PtrSize) // deferprocStack takes a *_defer arg
        } else {
                // Store arguments to stack, including defer/go arguments and receiver for method calls.
                // These are written in SP-offset order.
                argStart := base.Ctxt.FixedFrameSize()
                // Defer/go args.
                if k != callNormal {
 -                      // Write argsize and closure (args to newproc/deferproc).
 -                      argsize := s.constInt32(types.Types[types.TUINT32], int32(stksize))
 -                      ACArgs = append(ACArgs, types.Types[types.TUINT32]) // not argExtra
 -                      callArgs = append(callArgs, argsize)
 -                      ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
 +                      // Write closure (arg to newproc/deferproc).
 +                      ACArgs = append(ACArgs, types.Types[types.TUINTPTR]) // not argExtra
                        callArgs = append(callArgs, closure)
 -                      stksize += 2 * int64(types.PtrSize)
 -                      argStart += 2 * int64(types.PtrSize)
 +                      stksize += int64(types.PtrSize)
 +                      argStart += int64(types.PtrSize)
                }
  
                // Set receiver (for interface calls).
                // Write args.
                t := n.X.Type()
                args := n.Args
 -              if n.Op() == ir.OCALLMETH {
 -                      base.Fatalf("OCALLMETH missed by walkCall")
 -              }
  
                for _, p := range params.InParams() { // includes receiver for interface calls
                        ACArgs = append(ACArgs, p.Type)
@@@ -6754,12 -6921,8 +6754,12 @@@ func genssa(f *ssa.Func, pp *objw.Progs
                // recovers a panic, it will return to caller with right results.
                // The results are already in memory, because they are not SSA'd
                // when the function has defers (see canSSAName).
 -              if f.OwnAux.ABIInfo().OutRegistersUsed() != 0 {
 -                      Arch.LoadRegResults(&s, f)
 +              for _, o := range f.OwnAux.ABIInfo().OutParams() {
 +                      n := o.Name.(*ir.Name)
 +                      rts, offs := o.RegisterTypesAndOffsets()
 +                      for i := range o.Registers {
 +                              Arch.LoadRegResult(&s, f, rts[i], ssa.ObjRegForAbiReg(o.Registers[i], f.Config), n, offs[i])
 +                      }
                }
  
                pp.Prog(obj.ARET)
@@@ -7379,6 -7542,10 +7379,6 @@@ func (e *ssafn) Auto(pos src.XPos, t *t
        return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
  }
  
 -func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
 -      return reflectdata.ITabSym(it, offset)
 -}
 -
  // SplitSlot returns a slot representing the data of parent starting at offset.
  func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
        node := parent.N
@@@ -7509,8 -7676,9 +7509,8 @@@ func max8(a, b int8) int8 
        return b
  }
  
 -// deferstruct makes a runtime._defer structure, with additional space for
 -// stksize bytes of args.
 -func deferstruct(stksize int64) *types.Type {
 +// deferstruct makes a runtime._defer structure.
 +func deferstruct() *types.Type {
        makefield := func(name string, typ *types.Type) *types.Field {
                // Unlike the global makefield function, this one needs to set Pkg
                // because these types might be compared (in SSA CSE sorting).
                sym := &types.Sym{Name: name, Pkg: types.LocalPkg}
                return types.NewField(src.NoXPos, sym, typ)
        }
 -      argtype := types.NewArray(types.Types[types.TUINT8], stksize)
 -      argtype.Width = stksize
 -      argtype.Align = 1
        // These fields must match the ones in runtime/runtime2.go:_defer and
 -      // cmd/compile/internal/gc/ssa.go:(*state).call.
 +      // (*state).call above.
        fields := []*types.Field{
 -              makefield("siz", types.Types[types.TUINT32]),
                makefield("started", types.Types[types.TBOOL]),
                makefield("heap", types.Types[types.TBOOL]),
                makefield("openDefer", types.Types[types.TBOOL]),
                makefield("fn", types.Types[types.TUINTPTR]),
                makefield("_panic", types.Types[types.TUINTPTR]),
                makefield("link", types.Types[types.TUINTPTR]),
 -              makefield("framepc", types.Types[types.TUINTPTR]),
 -              makefield("varp", types.Types[types.TUINTPTR]),
                makefield("fd", types.Types[types.TUINTPTR]),
 -              makefield("args", argtype),
 +              makefield("varp", types.Types[types.TUINTPTR]),
 +              makefield("framepc", types.Types[types.TUINTPTR]),
        }
  
        // build struct holding the above fields