cmd/compile: rewrite to elide Slicemask from len==c>0 slicing

This might have been something that prove could be educated
into figuring out, but this also works, and it also helps
prove downstream.

Adjusted the prove test, because this change moved a message.

Cherry-picked from the dev.simd branch. This CL is not
necessarily SIMD specific. Apply early to reduce risk.

Change-Id: I5eabe639eff5db9cd9766a6a8666fdb4973829cb
Reviewed-on: https://go-review.googlesource.com/c/go/+/697715
Commit-Queue: David Chase <drchase@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Bypass: David Chase <drchase@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/708858
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
This commit is contained in:
David Chase 2025-08-20 12:29:02 -04:00 committed by Cherry Mui
parent 10e7968849
commit ec70d19023
3 changed files with 93 additions and 2 deletions

View file

@ -989,6 +989,10 @@
(Const64 <typ.Int> [0])
(Const64 <typ.Int> [0]))
// Special rule to help constant slicing; len > 0 implies cap > 0 implies Slicemask is all 1
(SliceMake (AddPtr <t> x (And64 y (Slicemask _))) w:(Const64 [c]) z) && c > 0 => (SliceMake (AddPtr <t> x y) w z)
(SliceMake (AddPtr <t> x (And32 y (Slicemask _))) w:(Const32 [c]) z) && c > 0 => (SliceMake (AddPtr <t> x y) w z)
// interface ops
(ConstInterface) =>
(IMake

View file

@ -422,6 +422,8 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpSliceCap(v)
case OpSliceLen:
return rewriteValuegeneric_OpSliceLen(v)
case OpSliceMake:
return rewriteValuegeneric_OpSliceMake(v)
case OpSlicePtr:
return rewriteValuegeneric_OpSlicePtr(v)
case OpSlicemask:
@ -30514,6 +30516,91 @@ func rewriteValuegeneric_OpSliceLen(v *Value) bool {
}
return false
}
func rewriteValuegeneric_OpSliceMake(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
// match: (SliceMake (AddPtr <t> x (And64 y (Slicemask _))) w:(Const64 [c]) z)
// cond: c > 0
// result: (SliceMake (AddPtr <t> x y) w z)
for {
if v_0.Op != OpAddPtr {
break
}
t := v_0.Type
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpAnd64 {
break
}
_ = v_0_1.Args[1]
v_0_1_0 := v_0_1.Args[0]
v_0_1_1 := v_0_1.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_1_0, v_0_1_1 = _i0+1, v_0_1_1, v_0_1_0 {
y := v_0_1_0
if v_0_1_1.Op != OpSlicemask {
continue
}
w := v_1
if w.Op != OpConst64 {
continue
}
c := auxIntToInt64(w.AuxInt)
z := v_2
if !(c > 0) {
continue
}
v.reset(OpSliceMake)
v0 := b.NewValue0(v.Pos, OpAddPtr, t)
v0.AddArg2(x, y)
v.AddArg3(v0, w, z)
return true
}
break
}
// match: (SliceMake (AddPtr <t> x (And32 y (Slicemask _))) w:(Const32 [c]) z)
// cond: c > 0
// result: (SliceMake (AddPtr <t> x y) w z)
for {
if v_0.Op != OpAddPtr {
break
}
t := v_0.Type
_ = v_0.Args[1]
x := v_0.Args[0]
v_0_1 := v_0.Args[1]
if v_0_1.Op != OpAnd32 {
break
}
_ = v_0_1.Args[1]
v_0_1_0 := v_0_1.Args[0]
v_0_1_1 := v_0_1.Args[1]
for _i0 := 0; _i0 <= 1; _i0, v_0_1_0, v_0_1_1 = _i0+1, v_0_1_1, v_0_1_0 {
y := v_0_1_0
if v_0_1_1.Op != OpSlicemask {
continue
}
w := v_1
if w.Op != OpConst32 {
continue
}
c := auxIntToInt32(w.AuxInt)
z := v_2
if !(c > 0) {
continue
}
v.reset(OpSliceMake)
v0 := b.NewValue0(v.Pos, OpAddPtr, t)
v0.AddArg2(x, y)
v.AddArg3(v0, w, z)
return true
}
break
}
return false
}
func rewriteValuegeneric_OpSlicePtr(v *Value) bool {
v_0 := v.Args[0]
// match: (SlicePtr (SliceMake (SlicePtr x) _ _))

View file

@ -511,10 +511,10 @@ func f19() (e int64, err error) {
func sm1(b []int, x int) {
// Test constant argument to slicemask.
useSlice(b[2:8]) // ERROR "Proved slicemask not needed$"
useSlice(b[2:8]) // optimized away earlier by rewrite
// Test non-constant argument with known limits.
if cap(b) > 10 {
useSlice(b[2:])
useSlice(b[2:]) // ERROR "Proved slicemask not needed$"
}
}