]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: move s390x over to new bounds check strategy
authorKeith Randall <khr@golang.org>
Wed, 18 Jun 2025 23:55:06 +0000 (16:55 -0700)
committerKeith Randall <khr@golang.org>
Mon, 4 Aug 2025 17:08:22 +0000 (10:08 -0700)
Change-Id: I86ed1a60165b729bb88a8a418da0ea1b59b3dc10
Reviewed-on: https://go-review.googlesource.com/c/go/+/682499
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Michael Munday <mikemndy@gmail.com>
Reviewed-by: Mark Freeman <mark@golang.org>
src/cmd/compile/internal/s390x/ssa.go
src/cmd/compile/internal/ssa/_gen/S390X.rules
src/cmd/compile/internal/ssa/_gen/S390XOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteS390X.go
src/runtime/asm_s390x.s

index ad66bfb5d8533423c6692488bfb6a0c3fd021bcf..86efde4fa09b878e6c3b6861b53a59e54d02f317 100644 (file)
@@ -15,6 +15,7 @@ import (
        "cmd/compile/internal/types"
        "cmd/internal/obj"
        "cmd/internal/obj/s390x"
+       "internal/abi"
 )
 
 // ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
@@ -573,12 +574,92 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                p.To.Name = obj.NAME_EXTERN
                // AuxInt encodes how many buffer entries we need.
                p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
-       case ssa.OpS390XLoweredPanicBoundsA, ssa.OpS390XLoweredPanicBoundsB, ssa.OpS390XLoweredPanicBoundsC:
-               p := s.Prog(obj.ACALL)
+
+       case ssa.OpS390XLoweredPanicBoundsRR, ssa.OpS390XLoweredPanicBoundsRC, ssa.OpS390XLoweredPanicBoundsCR, ssa.OpS390XLoweredPanicBoundsCC:
+               // Compute the constant we put in the PCData entry for this call.
+               code, signed := ssa.BoundsKind(v.AuxInt).Code()
+               xIsReg := false
+               yIsReg := false
+               xVal := 0
+               yVal := 0
+               switch v.Op {
+               case ssa.OpS390XLoweredPanicBoundsRR:
+                       xIsReg = true
+                       xVal = int(v.Args[0].Reg() - s390x.REG_R0)
+                       yIsReg = true
+                       yVal = int(v.Args[1].Reg() - s390x.REG_R0)
+               case ssa.OpS390XLoweredPanicBoundsRC:
+                       xIsReg = true
+                       xVal = int(v.Args[0].Reg() - s390x.REG_R0)
+                       c := v.Aux.(ssa.PanicBoundsC).C
+                       if c >= 0 && c <= abi.BoundsMaxConst {
+                               yVal = int(c)
+                       } else {
+                               // Move constant to a register
+                               yIsReg = true
+                               if yVal == xVal {
+                                       yVal = 1
+                               }
+                               p := s.Prog(s390x.AMOVD)
+                               p.From.Type = obj.TYPE_CONST
+                               p.From.Offset = c
+                               p.To.Type = obj.TYPE_REG
+                               p.To.Reg = s390x.REG_R0 + int16(yVal)
+                       }
+               case ssa.OpS390XLoweredPanicBoundsCR:
+                       yIsReg = true
+                       yVal := int(v.Args[0].Reg() - s390x.REG_R0)
+                       c := v.Aux.(ssa.PanicBoundsC).C
+                       if c >= 0 && c <= abi.BoundsMaxConst {
+                               xVal = int(c)
+                       } else {
+                               // Move constant to a register
+                               if xVal == yVal {
+                                       xVal = 1
+                               }
+                               p := s.Prog(s390x.AMOVD)
+                               p.From.Type = obj.TYPE_CONST
+                               p.From.Offset = c
+                               p.To.Type = obj.TYPE_REG
+                               p.To.Reg = s390x.REG_R0 + int16(xVal)
+                       }
+               case ssa.OpS390XLoweredPanicBoundsCC:
+                       c := v.Aux.(ssa.PanicBoundsCC).Cx
+                       if c >= 0 && c <= abi.BoundsMaxConst {
+                               xVal = int(c)
+                       } else {
+                               // Move constant to a register
+                               xIsReg = true
+                               p := s.Prog(s390x.AMOVD)
+                               p.From.Type = obj.TYPE_CONST
+                               p.From.Offset = c
+                               p.To.Type = obj.TYPE_REG
+                               p.To.Reg = s390x.REG_R0 + int16(xVal)
+                       }
+                       c = v.Aux.(ssa.PanicBoundsCC).Cy
+                       if c >= 0 && c <= abi.BoundsMaxConst {
+                               yVal = int(c)
+                       } else {
+                               // Move constant to a register
+                               yIsReg = true
+                               yVal = 1
+                               p := s.Prog(s390x.AMOVD)
+                               p.From.Type = obj.TYPE_CONST
+                               p.From.Offset = c
+                               p.To.Type = obj.TYPE_REG
+                               p.To.Reg = s390x.REG_R0 + int16(yVal)
+                       }
+               }
+               c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
+
+               p := s.Prog(obj.APCDATA)
+               p.From.SetConst(abi.PCDATA_PanicBounds)
+               p.To.SetConst(int64(c))
+               p = s.Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
                p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
-               s.UseArgs(16) // space used in callee args area by assembly stubs
+               p.To.Sym = ir.Syms.PanicBounds
+
        case ssa.OpS390XFLOGR, ssa.OpS390XPOPCNT,
                ssa.OpS390XNEG, ssa.OpS390XNEGW,
                ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
index 80e12f8e29d6d2ee21739a1fb4ff23d882dbefcf..664bf4a89c9024a7858b55ddfab525c191487f11 100644 (file)
 // Write barrier.
 (WB ...) => (LoweredWB ...)
 
-(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
-(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
-(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
+(PanicBounds ...) => (LoweredPanicBoundsRR ...)
+(LoweredPanicBoundsRR [kind] x (MOVDconst [c]) mem) => (LoweredPanicBoundsRC [kind] x {PanicBoundsC{C:c}} mem)
+(LoweredPanicBoundsRR [kind] (MOVDconst [c]) y mem) => (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:c}} y mem)
+(LoweredPanicBoundsRC [kind] {p} (MOVDconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:c, Cy:p.C}} mem)
+(LoweredPanicBoundsCR [kind] {p} (MOVDconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:p.C, Cy:c}} mem)
 
 // ***************************
 // Above: lowering rules
index 38fb3cb0748932c7c1181e7f90bc5a8ee3ce7adc..c002d5bcc382a3e665f10e04bde799748d2a8948 100644 (file)
@@ -114,6 +114,7 @@ func init() {
                sb  = buildReg("SB")
                r0  = buildReg("R0")
                tmp = buildReg("R11") // R11 is used as a temporary in a small number of instructions.
+               lr  = buildReg("R14")
 
                // R10 is reserved by the assembler.
                gp   = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14")
@@ -518,12 +519,15 @@ func init() {
                // Returns a pointer to a write barrier buffer in R9.
                {name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R14") | r1, outputs: []regMask{r9}}, clobberFlags: true, aux: "Int64"},
 
-               // There are three of these functions so that they can have three different register inputs.
-               // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
-               // default registers to match so we don't need to copy registers around unnecessarily.
-               {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
-               {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
-               {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r0, r1}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
+               // LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
+               // the RC and CR versions are used when one of the arguments is a constant. CC is used
+               // when both are constant (normally both 0, as prove derives the fact that a [0] bounds
+               // failure means the length must have also been 0).
+               // AuxInt contains a report code (see PanicBounds in genericOps.go).
+               {name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp &^ lr, gp &^ lr}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
+               {name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true},    // arg0=x, arg1=mem, returns memory.
+               {name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp &^ lr}}, typ: "Mem", call: true},    // arg0=y, arg1=mem, returns memory.
+               {name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true},                              // arg0=mem, returns memory.
 
                // Constant condition code values. The condition code can be 0, 1, 2 or 3.
                {name: "FlagEQ"}, // CC=0 (equal)
index 38fd3f6a795f799cadfbc66a71da14cd0d3f328a..b9c5b1f77cc858617d7047f2eacf3d64de5704e9 100644 (file)
@@ -2843,9 +2843,10 @@ const (
        OpS390XLoweredRound32F
        OpS390XLoweredRound64F
        OpS390XLoweredWB
-       OpS390XLoweredPanicBoundsA
-       OpS390XLoweredPanicBoundsB
-       OpS390XLoweredPanicBoundsC
+       OpS390XLoweredPanicBoundsRR
+       OpS390XLoweredPanicBoundsRC
+       OpS390XLoweredPanicBoundsCR
+       OpS390XLoweredPanicBoundsCC
        OpS390XFlagEQ
        OpS390XFlagLT
        OpS390XFlagGT
@@ -38525,41 +38526,46 @@ var opcodeTable = [...]opInfo{
                },
        },
        {
-               name:    "LoweredPanicBoundsA",
+               name:    "LoweredPanicBoundsRR",
                auxType: auxInt64,
                argLen:  3,
                call:    true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 4}, // R2
-                               {1, 8}, // R3
+                               {0, 7167}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12
+                               {1, 7167}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12
                        },
                },
        },
        {
-               name:    "LoweredPanicBoundsB",
-               auxType: auxInt64,
-               argLen:  3,
+               name:    "LoweredPanicBoundsRC",
+               auxType: auxPanicBoundsC,
+               argLen:  2,
                call:    true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 2}, // R1
-                               {1, 4}, // R2
+                               {0, 7167}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12
                        },
                },
        },
        {
-               name:    "LoweredPanicBoundsC",
-               auxType: auxInt64,
-               argLen:  3,
+               name:    "LoweredPanicBoundsCR",
+               auxType: auxPanicBoundsC,
+               argLen:  2,
                call:    true,
                reg: regInfo{
                        inputs: []inputInfo{
-                               {0, 1}, // R0
-                               {1, 2}, // R1
+                               {0, 7167}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12
                        },
                },
        },
+       {
+               name:    "LoweredPanicBoundsCC",
+               auxType: auxPanicBoundsCC,
+               argLen:  1,
+               call:    true,
+               reg:     regInfo{},
+       },
        {
                name:   "FlagEQ",
                argLen: 0,
index a7fde81c4789b2f2749adeb6db3a79ea9dcddae8..07dbe7bf7a697c8b7b3e5294a6541353ce5c45bd 100644 (file)
@@ -477,7 +477,8 @@ func rewriteValueS390X(v *Value) bool {
                v.Op = OpS390XORW
                return true
        case OpPanicBounds:
-               return rewriteValueS390X_OpPanicBounds(v)
+               v.Op = OpS390XLoweredPanicBoundsRR
+               return true
        case OpPopCount16:
                return rewriteValueS390X_OpPopCount16(v)
        case OpPopCount32:
@@ -644,6 +645,12 @@ func rewriteValueS390X(v *Value) bool {
                return rewriteValueS390X_OpS390XLTDBR(v)
        case OpS390XLTEBR:
                return rewriteValueS390X_OpS390XLTEBR(v)
+       case OpS390XLoweredPanicBoundsCR:
+               return rewriteValueS390X_OpS390XLoweredPanicBoundsCR(v)
+       case OpS390XLoweredPanicBoundsRC:
+               return rewriteValueS390X_OpS390XLoweredPanicBoundsRC(v)
+       case OpS390XLoweredPanicBoundsRR:
+               return rewriteValueS390X_OpS390XLoweredPanicBoundsRR(v)
        case OpS390XLoweredRound32F:
                return rewriteValueS390X_OpS390XLoweredRound32F(v)
        case OpS390XLoweredRound64F:
@@ -3971,60 +3978,6 @@ func rewriteValueS390X_OpOffPtr(v *Value) bool {
                return true
        }
 }
-func rewriteValueS390X_OpPanicBounds(v *Value) bool {
-       v_2 := v.Args[2]
-       v_1 := v.Args[1]
-       v_0 := v.Args[0]
-       // match: (PanicBounds [kind] x y mem)
-       // cond: boundsABI(kind) == 0
-       // result: (LoweredPanicBoundsA [kind] x y mem)
-       for {
-               kind := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               mem := v_2
-               if !(boundsABI(kind) == 0) {
-                       break
-               }
-               v.reset(OpS390XLoweredPanicBoundsA)
-               v.AuxInt = int64ToAuxInt(kind)
-               v.AddArg3(x, y, mem)
-               return true
-       }
-       // match: (PanicBounds [kind] x y mem)
-       // cond: boundsABI(kind) == 1
-       // result: (LoweredPanicBoundsB [kind] x y mem)
-       for {
-               kind := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               mem := v_2
-               if !(boundsABI(kind) == 1) {
-                       break
-               }
-               v.reset(OpS390XLoweredPanicBoundsB)
-               v.AuxInt = int64ToAuxInt(kind)
-               v.AddArg3(x, y, mem)
-               return true
-       }
-       // match: (PanicBounds [kind] x y mem)
-       // cond: boundsABI(kind) == 2
-       // result: (LoweredPanicBoundsC [kind] x y mem)
-       for {
-               kind := auxIntToInt64(v.AuxInt)
-               x := v_0
-               y := v_1
-               mem := v_2
-               if !(boundsABI(kind) == 2) {
-                       break
-               }
-               v.reset(OpS390XLoweredPanicBoundsC)
-               v.AuxInt = int64ToAuxInt(kind)
-               v.AddArg3(x, y, mem)
-               return true
-       }
-       return false
-}
 func rewriteValueS390X_OpPopCount16(v *Value) bool {
        v_0 := v.Args[0]
        b := v.Block
@@ -8147,6 +8100,86 @@ func rewriteValueS390X_OpS390XLTEBR(v *Value) bool {
        }
        return false
 }
+func rewriteValueS390X_OpS390XLoweredPanicBoundsCR(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (LoweredPanicBoundsCR [kind] {p} (MOVDconst [c]) mem)
+       // result: (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:p.C, Cy:c}} mem)
+       for {
+               kind := auxIntToInt64(v.AuxInt)
+               p := auxToPanicBoundsC(v.Aux)
+               if v_0.Op != OpS390XMOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               mem := v_1
+               v.reset(OpS390XLoweredPanicBoundsCC)
+               v.AuxInt = int64ToAuxInt(kind)
+               v.Aux = panicBoundsCCToAux(PanicBoundsCC{Cx: p.C, Cy: c})
+               v.AddArg(mem)
+               return true
+       }
+       return false
+}
+func rewriteValueS390X_OpS390XLoweredPanicBoundsRC(v *Value) bool {
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (LoweredPanicBoundsRC [kind] {p} (MOVDconst [c]) mem)
+       // result: (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:c, Cy:p.C}} mem)
+       for {
+               kind := auxIntToInt64(v.AuxInt)
+               p := auxToPanicBoundsC(v.Aux)
+               if v_0.Op != OpS390XMOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               mem := v_1
+               v.reset(OpS390XLoweredPanicBoundsCC)
+               v.AuxInt = int64ToAuxInt(kind)
+               v.Aux = panicBoundsCCToAux(PanicBoundsCC{Cx: c, Cy: p.C})
+               v.AddArg(mem)
+               return true
+       }
+       return false
+}
+func rewriteValueS390X_OpS390XLoweredPanicBoundsRR(v *Value) bool {
+       v_2 := v.Args[2]
+       v_1 := v.Args[1]
+       v_0 := v.Args[0]
+       // match: (LoweredPanicBoundsRR [kind] x (MOVDconst [c]) mem)
+       // result: (LoweredPanicBoundsRC [kind] x {PanicBoundsC{C:c}} mem)
+       for {
+               kind := auxIntToInt64(v.AuxInt)
+               x := v_0
+               if v_1.Op != OpS390XMOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_1.AuxInt)
+               mem := v_2
+               v.reset(OpS390XLoweredPanicBoundsRC)
+               v.AuxInt = int64ToAuxInt(kind)
+               v.Aux = panicBoundsCToAux(PanicBoundsC{C: c})
+               v.AddArg2(x, mem)
+               return true
+       }
+       // match: (LoweredPanicBoundsRR [kind] (MOVDconst [c]) y mem)
+       // result: (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:c}} y mem)
+       for {
+               kind := auxIntToInt64(v.AuxInt)
+               if v_0.Op != OpS390XMOVDconst {
+                       break
+               }
+               c := auxIntToInt64(v_0.AuxInt)
+               y := v_1
+               mem := v_2
+               v.reset(OpS390XLoweredPanicBoundsCR)
+               v.AuxInt = int64ToAuxInt(kind)
+               v.Aux = panicBoundsCToAux(PanicBoundsC{C: c})
+               v.AddArg2(y, mem)
+               return true
+       }
+       return false
+}
 func rewriteValueS390X_OpS390XLoweredRound32F(v *Value) bool {
        v_0 := v.Args[0]
        // match: (LoweredRound32F x:(FMOVSconst))
index 7fc88009e88a85c39fe9a4e055a3a84ae4825405..4cc1c0eb10488689d3769b4c9370a8e0657e5386 100644 (file)
@@ -892,76 +892,18 @@ TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0
        MOVD    $64, R9
        JMP     gcWriteBarrier<>(SB)
 
-// Note: these functions use a special calling convention to save generated code space.
-// Arguments are passed in registers, but the space for those arguments are allocated
-// in the caller's stack frame. These stubs write the args into that stack space and
-// then tail call to the corresponding runtime handler.
-// The tail call makes these stubs disappear in backtraces.
-TEXT runtime·panicIndex(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicIndex(SB)
-TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicIndexU(SB)
-TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSliceAlen(SB)
-TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSliceAlenU(SB)
-TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSliceAcap(SB)
-TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSliceAcapU(SB)
-TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicSliceB(SB)
-TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicSliceBU(SB)
-TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16
-       MOVD    R2, x+0(FP)
-       MOVD    R3, y+8(FP)
-       JMP     runtime·goPanicSlice3Alen(SB)
-TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16
-       MOVD    R2, x+0(FP)
-       MOVD    R3, y+8(FP)
-       JMP     runtime·goPanicSlice3AlenU(SB)
-TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16
-       MOVD    R2, x+0(FP)
-       MOVD    R3, y+8(FP)
-       JMP     runtime·goPanicSlice3Acap(SB)
-TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16
-       MOVD    R2, x+0(FP)
-       MOVD    R3, y+8(FP)
-       JMP     runtime·goPanicSlice3AcapU(SB)
-TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSlice3B(SB)
-TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16
-       MOVD    R1, x+0(FP)
-       MOVD    R2, y+8(FP)
-       JMP     runtime·goPanicSlice3BU(SB)
-TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicSlice3C(SB)
-TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16
-       MOVD    R0, x+0(FP)
-       MOVD    R1, y+8(FP)
-       JMP     runtime·goPanicSlice3CU(SB)
-TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16
-       MOVD    R2, x+0(FP)
-       MOVD    R3, y+8(FP)
-       JMP     runtime·goPanicSliceConvert(SB)
+TEXT runtime·panicBounds<ABIInternal>(SB),NOSPLIT,$144-0
+       NO_LOCAL_POINTERS
+       // Save all 16 int registers that could have an index in them.
+       // They may be pointers, but if they are they are dead.
+       STMG    R0, R12, 24(R15)
+       // Note that R10 @ 104 is not needed, it is an assembler temp
+       // skip R13 aka G @ 128
+       // skip R14 aka LR @ 136
+       // skip R15 aka SP @ 144
+
+       MOVD    R14, 8(R15)     // PC immediately after call to panicBounds
+       ADD     $24, R15, R0    // pointer to save area
+       MOVD    R0, 16(R15)
+       CALL    runtime·panicBounds64<ABIInternal>(SB)
+       RET