cmd/compile: preserve pointerness during splitload

386 and AMD64's splitload could silently change
a pointer type to an int type. Fix that.
Add type preservation to the narrower widths for symmetry,
even though it doesn't matter in the same way there.

Change-Id: I155d136dd43989900d26f2a7f014d7300fdbb7cb
Reviewed-on: https://go-review.googlesource.com/c/go/+/777820
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
Josh Bleecher Snyder 2026-05-12 18:17:07 -07:00 committed by Gopher Robot
parent c203e4ecb9
commit 80123ef4bf
5 changed files with 82 additions and 48 deletions

View file

@ -4,7 +4,7 @@
// See the top of AMD64splitload.rules for discussion of these rules.
(CMP(L|W|B)load {sym} [off] ptr x mem) => (CMP(L|W|B) (MOV(L|W|B)load {sym} [off] ptr mem) x)
(CMP(L|W|B)load {sym} [off] ptr x mem) => (CMP(L|W|B) (MOV(L|W|B)load <x.Type> {sym} [off] ptr mem) x)
(CMPLconstload {sym} [vo] ptr mem) => (CMPLconst (MOVLload {sym} [vo.Off()] ptr mem) [vo.Val()])
(CMPWconstload {sym} [vo] ptr mem) => (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()])

View file

@ -16,7 +16,7 @@
// For example:
// (CMPBconstload c (ADDQ x y)) -> (CMPBconstloadidx1 c x y) -> (CMPB c (MOVBloadidx1 x y))
(CMP(Q|L|W|B)load {sym} [off] ptr x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)load {sym} [off] ptr mem) x)
(CMP(Q|L|W|B)load {sym} [off] ptr x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)load <x.Type> {sym} [off] ptr mem) x)
(CMP(Q|L|W|B)constload {sym} [vo] ptr mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)load {sym} [vo.Off()] ptr mem) x)
@ -25,10 +25,10 @@
(CMPWconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPWconst (MOVWload {sym} [vo.Off()] ptr mem) [vo.Val16()])
(CMPBconstload {sym} [vo] ptr mem) && vo.Val() != 0 => (CMPBconst (MOVBload {sym} [vo.Off()] ptr mem) [vo.Val8()])
(CMP(Q|L|W|B)loadidx1 {sym} [off] ptr idx x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)loadidx1 {sym} [off] ptr idx mem) x)
(CMPQloadidx8 {sym} [off] ptr idx x mem) => (CMPQ (MOVQloadidx8 {sym} [off] ptr idx mem) x)
(CMPLloadidx4 {sym} [off] ptr idx x mem) => (CMPL (MOVLloadidx4 {sym} [off] ptr idx mem) x)
(CMPWloadidx2 {sym} [off] ptr idx x mem) => (CMPW (MOVWloadidx2 {sym} [off] ptr idx mem) x)
(CMP(Q|L|W|B)loadidx1 {sym} [off] ptr idx x mem) => (CMP(Q|L|W|B) (MOV(Q|L|W|B)loadidx1 <x.Type> {sym} [off] ptr idx mem) x)
(CMPQloadidx8 {sym} [off] ptr idx x mem) => (CMPQ (MOVQloadidx8 <x.Type> {sym} [off] ptr idx mem) x)
(CMPLloadidx4 {sym} [off] ptr idx x mem) => (CMPL (MOVLloadidx4 <x.Type> {sym} [off] ptr idx mem) x)
(CMPWloadidx2 {sym} [off] ptr idx x mem) => (CMPW (MOVWloadidx2 <x.Type> {sym} [off] ptr idx mem) x)
(CMP(Q|L|W|B)constloadidx1 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TEST(Q|L|W|B) x:(MOV(Q|L|W|B)loadidx1 {sym} [vo.Off()] ptr idx mem) x)
(CMPQconstloadidx8 {sym} [vo] ptr idx mem) && vo.Val() == 0 => (TESTQ x:(MOVQloadidx8 {sym} [vo.Off()] ptr idx mem) x)

View file

@ -46,9 +46,8 @@ func rewriteValue386splitload_Op386CMPBload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPBload {sym} [off] ptr x mem)
// result: (CMPB (MOVBload {sym} [off] ptr mem) x)
// result: (CMPB (MOVBload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -56,7 +55,7 @@ func rewriteValue386splitload_Op386CMPBload(v *Value) bool {
x := v_1
mem := v_2
v.reset(Op386CMPB)
v0 := b.NewValue0(v.Pos, Op386MOVBload, typ.UInt8)
v0 := b.NewValue0(v.Pos, Op386MOVBload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -91,9 +90,8 @@ func rewriteValue386splitload_Op386CMPLload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPLload {sym} [off] ptr x mem)
// result: (CMPL (MOVLload {sym} [off] ptr mem) x)
// result: (CMPL (MOVLload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -101,7 +99,7 @@ func rewriteValue386splitload_Op386CMPLload(v *Value) bool {
x := v_1
mem := v_2
v.reset(Op386CMPL)
v0 := b.NewValue0(v.Pos, Op386MOVLload, typ.UInt32)
v0 := b.NewValue0(v.Pos, Op386MOVLload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -136,9 +134,8 @@ func rewriteValue386splitload_Op386CMPWload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPWload {sym} [off] ptr x mem)
// result: (CMPW (MOVWload {sym} [off] ptr mem) x)
// result: (CMPW (MOVWload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -146,7 +143,7 @@ func rewriteValue386splitload_Op386CMPWload(v *Value) bool {
x := v_1
mem := v_2
v.reset(Op386CMPW)
v0 := b.NewValue0(v.Pos, Op386MOVWload, typ.UInt16)
v0 := b.NewValue0(v.Pos, Op386MOVWload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)

View file

@ -151,9 +151,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPBload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPBload {sym} [off] ptr x mem)
// result: (CMPB (MOVBload {sym} [off] ptr mem) x)
// result: (CMPB (MOVBload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -161,7 +160,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBload(v *Value) bool {
x := v_1
mem := v_2
v.reset(OpAMD64CMPB)
v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, typ.UInt8)
v0 := b.NewValue0(v.Pos, OpAMD64MOVBload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -175,9 +174,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPBloadidx1(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPBloadidx1 {sym} [off] ptr idx x mem)
// result: (CMPB (MOVBloadidx1 {sym} [off] ptr idx mem) x)
// result: (CMPB (MOVBloadidx1 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -186,7 +184,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPBloadidx1(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPB)
v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, typ.UInt8)
v0 := b.NewValue0(v.Pos, OpAMD64MOVBloadidx1, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -343,9 +341,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPLload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPLload {sym} [off] ptr x mem)
// result: (CMPL (MOVLload {sym} [off] ptr mem) x)
// result: (CMPL (MOVLload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -353,7 +350,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLload(v *Value) bool {
x := v_1
mem := v_2
v.reset(OpAMD64CMPL)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -367,9 +364,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPLloadidx1(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPLloadidx1 {sym} [off] ptr idx x mem)
// result: (CMPL (MOVLloadidx1 {sym} [off] ptr idx mem) x)
// result: (CMPL (MOVLloadidx1 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -378,7 +374,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLloadidx1(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPL)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, typ.UInt32)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx1, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -392,9 +388,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPLloadidx4(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPLloadidx4 {sym} [off] ptr idx x mem)
// result: (CMPL (MOVLloadidx4 {sym} [off] ptr idx mem) x)
// result: (CMPL (MOVLloadidx4 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -403,7 +398,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPLloadidx4(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPL)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, typ.UInt32)
v0 := b.NewValue0(v.Pos, OpAMD64MOVLloadidx4, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -560,9 +555,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPQload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPQload {sym} [off] ptr x mem)
// result: (CMPQ (MOVQload {sym} [off] ptr mem) x)
// result: (CMPQ (MOVQload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -570,7 +564,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQload(v *Value) bool {
x := v_1
mem := v_2
v.reset(OpAMD64CMPQ)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -584,9 +578,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPQloadidx1(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPQloadidx1 {sym} [off] ptr idx x mem)
// result: (CMPQ (MOVQloadidx1 {sym} [off] ptr idx mem) x)
// result: (CMPQ (MOVQloadidx1 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -595,7 +588,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQloadidx1(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPQ)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, typ.UInt64)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx1, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -609,9 +602,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPQloadidx8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPQloadidx8 {sym} [off] ptr idx x mem)
// result: (CMPQ (MOVQloadidx8 {sym} [off] ptr idx mem) x)
// result: (CMPQ (MOVQloadidx8 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -620,7 +612,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPQloadidx8(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPQ)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, typ.UInt64)
v0 := b.NewValue0(v.Pos, OpAMD64MOVQloadidx8, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -777,9 +769,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPWload {sym} [off] ptr x mem)
// result: (CMPW (MOVWload {sym} [off] ptr mem) x)
// result: (CMPW (MOVWload <x.Type> {sym} [off] ptr mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -787,7 +778,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWload(v *Value) bool {
x := v_1
mem := v_2
v.reset(OpAMD64CMPW)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg2(ptr, mem)
@ -801,9 +792,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPWloadidx1(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPWloadidx1 {sym} [off] ptr idx x mem)
// result: (CMPW (MOVWloadidx1 {sym} [off] ptr idx mem) x)
// result: (CMPW (MOVWloadidx1 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -812,7 +802,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWloadidx1(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPW)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, typ.UInt16)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx1, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)
@ -826,9 +816,8 @@ func rewriteValueAMD64splitload_OpAMD64CMPWloadidx2(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (CMPWloadidx2 {sym} [off] ptr idx x mem)
// result: (CMPW (MOVWloadidx2 {sym} [off] ptr idx mem) x)
// result: (CMPW (MOVWloadidx2 <x.Type> {sym} [off] ptr idx mem) x)
for {
off := auxIntToInt32(v.AuxInt)
sym := auxToSym(v.Aux)
@ -837,7 +826,7 @@ func rewriteValueAMD64splitload_OpAMD64CMPWloadidx2(v *Value) bool {
x := v_2
mem := v_3
v.reset(OpAMD64CMPW)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, typ.UInt16)
v0 := b.NewValue0(v.Pos, OpAMD64MOVWloadidx2, x.Type)
v0.AuxInt = int32ToAuxInt(off)
v0.Aux = symToAux(sym)
v0.AddArg3(ptr, idx, mem)

View file

@ -0,0 +1,48 @@
// run
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// splitload rewrites must preserve pointer-typed loads so
// spilled values remain visible to stack maps across stack growth.
package main
type splitLoadObj struct{ x int }
var sink byte
//go:noinline
func splitLoadGrow(n int) {
var buf [2048]byte
buf[n&2047] = byte(n)
if n > 0 {
splitLoadGrow(n - 1)
}
sink = buf[n&2047]
}
//go:noinline
func splitLoadPointerCompare(pp **splitLoadObj, q *splitLoadObj, a, b, m int) int {
cond := q == *pp
x := a
if cond {
x = b
}
z := x & m
splitLoadGrow(1000)
if cond {
return z
}
return x
}
func main() {
var obj splitLoadObj
slot := &obj
if got := splitLoadPointerCompare(&slot, &obj, 10, 6, 1); got != 0 {
println("splitLoadPointerCompare(...) =", got, "want 0")
panic("FAIL")
}
}