From: Keith Randall Date: Wed, 18 Jun 2025 23:55:06 +0000 (-0700) Subject: cmd/compile: move s390x over to new bounds check strategy X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7a1679d7ae32dd8a01bd355413ee77ba517f5f43;p=gostls13.git cmd/compile: move s390x over to new bounds check strategy Change-Id: I86ed1a60165b729bb88a8a418da0ea1b59b3dc10 Reviewed-on: https://go-review.googlesource.com/c/go/+/682499 LUCI-TryBot-Result: Go LUCI Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Keith Randall Reviewed-by: Michael Munday Reviewed-by: Mark Freeman --- diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index ad66bfb5d8..86efde4fa0 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -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: diff --git a/src/cmd/compile/internal/ssa/_gen/S390X.rules b/src/cmd/compile/internal/ssa/_gen/S390X.rules index 80e12f8e29..664bf4a89c 100644 --- a/src/cmd/compile/internal/ssa/_gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/_gen/S390X.rules @@ -458,9 +458,11 @@ // 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 diff --git a/src/cmd/compile/internal/ssa/_gen/S390XOps.go b/src/cmd/compile/internal/ssa/_gen/S390XOps.go index 38fb3cb074..c002d5bcc3 100644 --- a/src/cmd/compile/internal/ssa/_gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/_gen/S390XOps.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 38fd3f6a79..b9c5b1f77c 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -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, diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index a7fde81c47..07dbe7bf7a 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -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)) diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s index 7fc88009e8..4cc1c0eb10 100644 --- a/src/runtime/asm_s390x.s +++ b/src/runtime/asm_s390x.s @@ -892,76 +892,18 @@ TEXT runtime·gcWriteBarrier8(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(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(SB) + RET