Skip to content

Commit 076eae4

Browse files
committed
cmd/compile: move amd64 and 386 over to new bounds check strategy
Change-Id: I13f54f04ccb8452e625dba4249e0d56bafd1fad8 Reviewed-on: https://go-review.googlesource.com/c/go/+/682397 Reviewed-by: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent f703dc5 commit 076eae4

File tree

12 files changed

+631
-490
lines changed

12 files changed

+631
-490
lines changed

src/cmd/compile/internal/amd64/ssa.go

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"cmd/compile/internal/types"
1818
"cmd/internal/obj"
1919
"cmd/internal/obj/x86"
20+
"internal/abi"
2021
)
2122

2223
// ssaMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
@@ -1135,12 +1136,91 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
11351136
// AuxInt encodes how many buffer entries we need.
11361137
p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
11371138

1138-
case ssa.OpAMD64LoweredPanicBoundsA, ssa.OpAMD64LoweredPanicBoundsB, ssa.OpAMD64LoweredPanicBoundsC:
1139-
p := s.Prog(obj.ACALL)
1139+
case ssa.OpAMD64LoweredPanicBoundsRR, ssa.OpAMD64LoweredPanicBoundsRC, ssa.OpAMD64LoweredPanicBoundsCR, ssa.OpAMD64LoweredPanicBoundsCC:
1140+
// Compute the constant we put in the PCData entry for this call.
1141+
code, signed := ssa.BoundsKind(v.AuxInt).Code()
1142+
xIsReg := false
1143+
yIsReg := false
1144+
xVal := 0
1145+
yVal := 0
1146+
switch v.Op {
1147+
case ssa.OpAMD64LoweredPanicBoundsRR:
1148+
xIsReg = true
1149+
xVal = int(v.Args[0].Reg() - x86.REG_AX)
1150+
yIsReg = true
1151+
yVal = int(v.Args[1].Reg() - x86.REG_AX)
1152+
case ssa.OpAMD64LoweredPanicBoundsRC:
1153+
xIsReg = true
1154+
xVal = int(v.Args[0].Reg() - x86.REG_AX)
1155+
c := v.Aux.(ssa.PanicBoundsC).C
1156+
if c >= 0 && c <= abi.BoundsMaxConst {
1157+
yVal = int(c)
1158+
} else {
1159+
// Move constant to a register
1160+
yIsReg = true
1161+
if yVal == xVal {
1162+
yVal = 1
1163+
}
1164+
p := s.Prog(x86.AMOVQ)
1165+
p.From.Type = obj.TYPE_CONST
1166+
p.From.Offset = c
1167+
p.To.Type = obj.TYPE_REG
1168+
p.To.Reg = x86.REG_AX + int16(yVal)
1169+
}
1170+
case ssa.OpAMD64LoweredPanicBoundsCR:
1171+
yIsReg = true
1172+
yVal := int(v.Args[0].Reg() - x86.REG_AX)
1173+
c := v.Aux.(ssa.PanicBoundsC).C
1174+
if c >= 0 && c <= abi.BoundsMaxConst {
1175+
xVal = int(c)
1176+
} else {
1177+
// Move constant to a register
1178+
xIsReg = true
1179+
if xVal == yVal {
1180+
xVal = 1
1181+
}
1182+
p := s.Prog(x86.AMOVQ)
1183+
p.From.Type = obj.TYPE_CONST
1184+
p.From.Offset = c
1185+
p.To.Type = obj.TYPE_REG
1186+
p.To.Reg = x86.REG_AX + int16(xVal)
1187+
}
1188+
case ssa.OpAMD64LoweredPanicBoundsCC:
1189+
c := v.Aux.(ssa.PanicBoundsCC).Cx
1190+
if c >= 0 && c <= abi.BoundsMaxConst {
1191+
xVal = int(c)
1192+
} else {
1193+
// Move constant to a register
1194+
xIsReg = true
1195+
p := s.Prog(x86.AMOVQ)
1196+
p.From.Type = obj.TYPE_CONST
1197+
p.From.Offset = c
1198+
p.To.Type = obj.TYPE_REG
1199+
p.To.Reg = x86.REG_AX + int16(xVal)
1200+
}
1201+
c = v.Aux.(ssa.PanicBoundsCC).Cy
1202+
if c >= 0 && c <= abi.BoundsMaxConst {
1203+
yVal = int(c)
1204+
} else {
1205+
// Move constant to a register
1206+
yIsReg = true
1207+
yVal = 1
1208+
p := s.Prog(x86.AMOVQ)
1209+
p.From.Type = obj.TYPE_CONST
1210+
p.From.Offset = c
1211+
p.To.Type = obj.TYPE_REG
1212+
p.To.Reg = x86.REG_AX + int16(yVal)
1213+
}
1214+
}
1215+
c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
1216+
1217+
p := s.Prog(obj.APCDATA)
1218+
p.From.SetConst(abi.PCDATA_PanicBounds)
1219+
p.To.SetConst(int64(c))
1220+
p = s.Prog(obj.ACALL)
11401221
p.To.Type = obj.TYPE_MEM
11411222
p.To.Name = obj.NAME_EXTERN
1142-
p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
1143-
s.UseArgs(int64(2 * types.PtrSize)) // space used in callee args area by assembly stubs
1223+
p.To.Sym = ir.Syms.PanicBounds
11441224

11451225
case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
11461226
ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,

src/cmd/compile/internal/ssa/_gen/386.rules

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,16 @@
363363
// Write barrier.
364364
(WB ...) => (LoweredWB ...)
365365

366-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
367-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
368-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
366+
(PanicBounds ...) => (LoweredPanicBoundsRR ...)
367+
(PanicExtend ...) => (LoweredPanicExtendRR ...)
369368

370-
(PanicExtend [kind] hi lo y mem) && boundsABI(kind) == 0 => (LoweredPanicExtendA [kind] hi lo y mem)
371-
(PanicExtend [kind] hi lo y mem) && boundsABI(kind) == 1 => (LoweredPanicExtendB [kind] hi lo y mem)
372-
(PanicExtend [kind] hi lo y mem) && boundsABI(kind) == 2 => (LoweredPanicExtendC [kind] hi lo y mem)
369+
(LoweredPanicBoundsRR [kind] x (MOVLconst [c]) mem) => (LoweredPanicBoundsRC [kind] x {PanicBoundsC{C:int64(c)}} mem)
370+
(LoweredPanicBoundsRR [kind] (MOVLconst [c]) y mem) => (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:int64(c)}} y mem)
371+
(LoweredPanicBoundsRC [kind] {p} (MOVLconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:int64(c), Cy:p.C}} mem)
372+
373+
(LoweredPanicExtendRR [kind] hi lo (MOVLconst [c]) mem) => (LoweredPanicExtendRC [kind] hi lo {PanicBoundsC{C:int64(c)}} mem)
374+
(LoweredPanicExtendRR [kind] (MOVLconst [hi]) (MOVLconst [lo]) y mem) => (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:int64(hi)<<32 + int64(uint32(lo))}} y mem)
375+
(LoweredPanicExtendRC [kind] {p} (MOVLconst [hi]) (MOVLconst [lo]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:int64(hi)<<32+int64(uint32(lo)), Cy:p.C}} mem)
373376

374377
// ***************************
375378
// Above: lowering rules

src/cmd/compile/internal/ssa/_gen/386Ops.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ func init() {
7676
cx = buildReg("CX")
7777
dx = buildReg("DX")
7878
bx = buildReg("BX")
79-
si = buildReg("SI")
8079
gp = buildReg("AX CX DX BX BP SI DI")
8180
fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7")
8281
gpsp = gp | buildReg("SP")
@@ -523,16 +522,19 @@ func init() {
523522
// Returns a pointer to a write barrier buffer in DI.
524523
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave &^ gp, outputs: []regMask{buildReg("DI")}}, clobberFlags: true, aux: "Int64"},
525524

526-
// There are three of these functions so that they can have three different register inputs.
527-
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
528-
// default registers to match so we don't need to copy registers around unnecessarily.
529-
{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{dx, bx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
530-
{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{cx, dx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
531-
{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{ax, cx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
532-
// Extend ops are the same as Bounds ops except the indexes are 64-bit.
533-
{name: "LoweredPanicExtendA", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{si, dx, bx}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
534-
{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{si, cx, dx}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
535-
{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{si, ax, cx}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
525+
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
526+
// the RC and CR versions are used when one of the arguments is a constant. CC is used
527+
// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
528+
// failure means the length must have also been 0).
529+
// AuxInt contains a report code (see PanicBounds in genericOps.go).
530+
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp, gp}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
531+
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
532+
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
533+
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
534+
535+
// Same as above, but the x value is 64 bits.
536+
{name: "LoweredPanicExtendRR", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{ax | cx | dx | bx, ax | cx | dx | bx, gp}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=y, arg3=mem, returns memory.
537+
{name: "LoweredPanicExtendRC", argLength: 3, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{ax | cx | dx | bx, ax | cx | dx | bx}}, typ: "Mem", call: true}, // arg0=x_hi, arg1=x_lo, arg2=mem, returns memory.
536538

537539
// Constant flag values. For any comparison, there are 5 possible
538540
// outcomes: the three from the signed total order (<,==,>) and the

src/cmd/compile/internal/ssa/_gen/AMD64.rules

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -558,9 +558,11 @@
558558
// Write barrier.
559559
(WB ...) => (LoweredWB ...)
560560

561-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
562-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
563-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
561+
(PanicBounds ...) => (LoweredPanicBoundsRR ...)
562+
(LoweredPanicBoundsRR [kind] x (MOVQconst [c]) mem) => (LoweredPanicBoundsRC [kind] x {PanicBoundsC{C:c}} mem)
563+
(LoweredPanicBoundsRR [kind] (MOVQconst [c]) y mem) => (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:c}} y mem)
564+
(LoweredPanicBoundsRC [kind] {p} (MOVQconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:c, Cy:p.C}} mem)
565+
(LoweredPanicBoundsCR [kind] {p} (MOVQconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:p.C, Cy:c}} mem)
564566

565567
// lowering rotates
566568
(RotateLeft8 ...) => (ROLB ...)

src/cmd/compile/internal/ssa/_gen/AMD64Ops.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ func init() {
9595
ax = buildReg("AX")
9696
cx = buildReg("CX")
9797
dx = buildReg("DX")
98-
bx = buildReg("BX")
9998
gp = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15")
10099
g = buildReg("g")
101100
fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14")
@@ -986,12 +985,15 @@ func init() {
986985

987986
{name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None"},
988987

989-
// There are three of these functions so that they can have three different register inputs.
990-
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
991-
// default registers to match so we don't need to copy registers around unnecessarily.
992-
{name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{dx, bx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
993-
{name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{cx, dx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
994-
{name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{ax, cx}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in generic.go).
988+
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
989+
// the RC and CR versions are used when one of the arguments is a constant. CC is used
990+
// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
991+
// failure means the length must have also been 0).
992+
// AuxInt contains a report code (see PanicBounds in genericOps.go).
993+
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{gp, gp}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
994+
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
995+
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{gp}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
996+
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
995997

996998
// Constant flag values. For any comparison, there are 5 possible
997999
// outcomes: the three from the signed total order (<,==,>) and the

0 commit comments

Comments
 (0)