Skip to content

Commit 394d0be

Browse files
committed
cmd/compile: move arm64 over to new bounds check strategy
For all the static bounds checks in cmd/go, we have: 6877 just a single instruction (the call itself) 139 needs an additional reg-reg move 602 needs an additional constant load 25 needs some other instruction that's ~90% implemented using just a single instruction. Reduces the text size of cmd/go by ~0.8%. Total binary size is just barely smaller, ~0.2%. (The difference is the new pcdata table.) Change-Id: I416e9c196f5d8d0e8f08e191e6df3045e11dccbe Reviewed-on: https://go-review.googlesource.com/c/go/+/682496 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Michael Knyszek <[email protected]>
1 parent 3024785 commit 394d0be

File tree

7 files changed

+228
-153
lines changed

7 files changed

+228
-153
lines changed

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

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"cmd/compile/internal/types"
1717
"cmd/internal/obj"
1818
"cmd/internal/obj/arm64"
19+
"internal/abi"
1920
)
2021

2122
// loadByType returns the load instruction of the given type.
@@ -1122,12 +1123,91 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
11221123
// AuxInt encodes how many buffer entries we need.
11231124
p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1]
11241125

1125-
case ssa.OpARM64LoweredPanicBoundsA, ssa.OpARM64LoweredPanicBoundsB, ssa.OpARM64LoweredPanicBoundsC:
1126-
p := s.Prog(obj.ACALL)
1126+
case ssa.OpARM64LoweredPanicBoundsRR, ssa.OpARM64LoweredPanicBoundsRC, ssa.OpARM64LoweredPanicBoundsCR, ssa.OpARM64LoweredPanicBoundsCC:
1127+
// Compute the constant we put in the PCData entry for this call.
1128+
code, signed := ssa.BoundsKind(v.AuxInt).Code()
1129+
xIsReg := false
1130+
yIsReg := false
1131+
xVal := 0
1132+
yVal := 0
1133+
switch v.Op {
1134+
case ssa.OpARM64LoweredPanicBoundsRR:
1135+
xIsReg = true
1136+
xVal = int(v.Args[0].Reg() - arm64.REG_R0)
1137+
yIsReg = true
1138+
yVal = int(v.Args[1].Reg() - arm64.REG_R0)
1139+
case ssa.OpARM64LoweredPanicBoundsRC:
1140+
xIsReg = true
1141+
xVal = int(v.Args[0].Reg() - arm64.REG_R0)
1142+
c := v.Aux.(ssa.PanicBoundsC).C
1143+
if c >= 0 && c <= abi.BoundsMaxConst {
1144+
yVal = int(c)
1145+
} else {
1146+
// Move constant to a register
1147+
yIsReg = true
1148+
if yVal == xVal {
1149+
yVal = 1
1150+
}
1151+
p := s.Prog(arm64.AMOVD)
1152+
p.From.Type = obj.TYPE_CONST
1153+
p.From.Offset = c
1154+
p.To.Type = obj.TYPE_REG
1155+
p.To.Reg = arm64.REG_R0 + int16(yVal)
1156+
}
1157+
case ssa.OpARM64LoweredPanicBoundsCR:
1158+
yIsReg = true
1159+
yVal := int(v.Args[0].Reg() - arm64.REG_R0)
1160+
c := v.Aux.(ssa.PanicBoundsC).C
1161+
if c >= 0 && c <= abi.BoundsMaxConst {
1162+
xVal = int(c)
1163+
} else {
1164+
// Move constant to a register
1165+
if xVal == yVal {
1166+
xVal = 1
1167+
}
1168+
p := s.Prog(arm64.AMOVD)
1169+
p.From.Type = obj.TYPE_CONST
1170+
p.From.Offset = c
1171+
p.To.Type = obj.TYPE_REG
1172+
p.To.Reg = arm64.REG_R0 + int16(xVal)
1173+
}
1174+
case ssa.OpARM64LoweredPanicBoundsCC:
1175+
c := v.Aux.(ssa.PanicBoundsCC).Cx
1176+
if c >= 0 && c <= abi.BoundsMaxConst {
1177+
xVal = int(c)
1178+
} else {
1179+
// Move constant to a register
1180+
xIsReg = true
1181+
p := s.Prog(arm64.AMOVD)
1182+
p.From.Type = obj.TYPE_CONST
1183+
p.From.Offset = c
1184+
p.To.Type = obj.TYPE_REG
1185+
p.To.Reg = arm64.REG_R0 + int16(xVal)
1186+
}
1187+
c = v.Aux.(ssa.PanicBoundsCC).Cy
1188+
if c >= 0 && c <= abi.BoundsMaxConst {
1189+
yVal = int(c)
1190+
} else {
1191+
// Move constant to a register
1192+
yIsReg = true
1193+
yVal = 1
1194+
p := s.Prog(arm64.AMOVD)
1195+
p.From.Type = obj.TYPE_CONST
1196+
p.From.Offset = c
1197+
p.To.Type = obj.TYPE_REG
1198+
p.To.Reg = arm64.REG_R0 + int16(yVal)
1199+
}
1200+
}
1201+
c := abi.BoundsEncode(code, signed, xIsReg, yIsReg, xVal, yVal)
1202+
1203+
p := s.Prog(obj.APCDATA)
1204+
p.From.SetConst(abi.PCDATA_PanicBounds)
1205+
p.To.SetConst(int64(c))
1206+
p = s.Prog(obj.ACALL)
11271207
p.To.Type = obj.TYPE_MEM
11281208
p.To.Name = obj.NAME_EXTERN
1129-
p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
1130-
s.UseArgs(16) // space used in callee args area by assembly stubs
1209+
p.To.Sym = ir.Syms.PanicBounds
1210+
11311211
case ssa.OpARM64LoweredNilCheck:
11321212
// Issue a load which will fault if arg is nil.
11331213
p := s.Prog(arm64.AMOVB)

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,9 +601,11 @@
601601
// Publication barrier (0xe is ST option)
602602
(PubBarrier mem) => (DMB [0xe] mem)
603603

604-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
605-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
606-
(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
604+
(PanicBounds ...) => (LoweredPanicBoundsRR ...)
605+
(LoweredPanicBoundsRR [kind] x (MOVDconst [c]) mem) => (LoweredPanicBoundsRC [kind] x {PanicBoundsC{C:c}} mem)
606+
(LoweredPanicBoundsRR [kind] (MOVDconst [c]) y mem) => (LoweredPanicBoundsCR [kind] {PanicBoundsC{C:c}} y mem)
607+
(LoweredPanicBoundsRC [kind] {p} (MOVDconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:c, Cy:p.C}} mem)
608+
(LoweredPanicBoundsCR [kind] {p} (MOVDconst [c]) mem) => (LoweredPanicBoundsCC [kind] {PanicBoundsCC{Cx:p.C, Cy:c}} mem)
607609

608610
// Optimizations
609611

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,8 @@ func init() {
144144
gpspsbg = gpspg | buildReg("SB")
145145
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
146146
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
147-
r0 = buildReg("R0")
148-
r1 = buildReg("R1")
149-
r2 = buildReg("R2")
150-
r3 = buildReg("R3")
151147
rz = buildReg("ZERO")
148+
first16 = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15")
152149
)
153150
// Common regInfo
154151
var (
@@ -760,12 +757,15 @@ func init() {
760757
// Returns a pointer to a write barrier buffer in R25.
761758
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R16 R17 R30"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
762759

763-
// There are three of these functions so that they can have three different register inputs.
764-
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
765-
// default registers to match so we don't need to copy registers around unnecessarily.
766-
{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).
767-
{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).
768-
{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).
760+
// LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail.
761+
// the RC and CR versions are used when one of the arguments is a constant. CC is used
762+
// when both are constant (normally both 0, as prove derives the fact that a [0] bounds
763+
// failure means the length must have also been 0).
764+
// AuxInt contains a report code (see PanicBounds in genericOps.go).
765+
{name: "LoweredPanicBoundsRR", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{first16, first16}}, typ: "Mem", call: true}, // arg0=x, arg1=y, arg2=mem, returns memory.
766+
{name: "LoweredPanicBoundsRC", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true}, // arg0=x, arg1=mem, returns memory.
767+
{name: "LoweredPanicBoundsCR", argLength: 2, aux: "PanicBoundsC", reg: regInfo{inputs: []regMask{first16}}, typ: "Mem", call: true}, // arg0=y, arg1=mem, returns memory.
768+
{name: "LoweredPanicBoundsCC", argLength: 1, aux: "PanicBoundsCC", reg: regInfo{}, typ: "Mem", call: true}, // arg0=mem, returns memory.
769769

770770
// Prefetch instruction
771771
// Do prefetch arg0 address with option aux. arg0=addr, arg1=memory, aux=option.

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

Lines changed: 22 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 88 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)