From: Keith Randall Date: Mon, 18 Nov 2024 23:52:13 +0000 (-0800) Subject: cmd/compile: pull multiple adds out of an unsafe.Pointer<->uintptr conversion X-Git-Tag: go1.24rc1~123 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f0b01092429a449313c9f54434417337ed26b20b;p=gostls13.git cmd/compile: pull multiple adds out of an unsafe.Pointer<->uintptr conversion This came up in some swissmap code. Change-Id: I3c6705a5cafec8cb4953dfa9535cf0b45255cc83 Reviewed-on: https://go-review.googlesource.com/c/go/+/629516 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: David Chase --- diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 9a2bb96a1b..9e2e8772c1 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -988,6 +988,9 @@ // Get rid of Convert ops for pointer arithmetic on unsafe.Pointer. (Convert (Add(64|32) (Convert ptr mem) off) mem) => (AddPtr ptr off) (Convert (Convert ptr mem) mem) => ptr +// Note: it is important that the target rewrite is ptr+(off1+off2), not (ptr+off1)+off2. +// We must ensure that no intermediate computations are invalid pointers. +(Convert a:(Add(64|32) (Add(64|32) (Convert ptr mem) off1) off2) mem) => (AddPtr ptr (Add(64|32) off1 off2)) // strength reduction of divide by a constant. // See ../magic.go for a detailed description of these algorithms. diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index e4d6b45cf2..4cb287c9b7 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -5759,6 +5759,7 @@ func rewriteValuegeneric_OpConstString(v *Value) bool { func rewriteValuegeneric_OpConvert(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block // match: (Convert (Add64 (Convert ptr mem) off) mem) // result: (AddPtr ptr off) for { @@ -5823,6 +5824,80 @@ func rewriteValuegeneric_OpConvert(v *Value) bool { v.copyOf(ptr) return true } + // match: (Convert a:(Add64 (Add64 (Convert ptr mem) off1) off2) mem) + // result: (AddPtr ptr (Add64 off1 off2)) + for { + a := v_0 + if a.Op != OpAdd64 { + break + } + _ = a.Args[1] + a_0 := a.Args[0] + a_1 := a.Args[1] + for _i0 := 0; _i0 <= 1; _i0, a_0, a_1 = _i0+1, a_1, a_0 { + if a_0.Op != OpAdd64 { + continue + } + _ = a_0.Args[1] + a_0_0 := a_0.Args[0] + a_0_1 := a_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, a_0_0, a_0_1 = _i1+1, a_0_1, a_0_0 { + if a_0_0.Op != OpConvert { + continue + } + mem := a_0_0.Args[1] + ptr := a_0_0.Args[0] + off1 := a_0_1 + off2 := a_1 + if mem != v_1 { + continue + } + v.reset(OpAddPtr) + v0 := b.NewValue0(v.Pos, OpAdd64, a.Type) + v0.AddArg2(off1, off2) + v.AddArg2(ptr, v0) + return true + } + } + break + } + // match: (Convert a:(Add32 (Add32 (Convert ptr mem) off1) off2) mem) + // result: (AddPtr ptr (Add32 off1 off2)) + for { + a := v_0 + if a.Op != OpAdd32 { + break + } + _ = a.Args[1] + a_0 := a.Args[0] + a_1 := a.Args[1] + for _i0 := 0; _i0 <= 1; _i0, a_0, a_1 = _i0+1, a_1, a_0 { + if a_0.Op != OpAdd32 { + continue + } + _ = a_0.Args[1] + a_0_0 := a_0.Args[0] + a_0_1 := a_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, a_0_0, a_0_1 = _i1+1, a_0_1, a_0_0 { + if a_0_0.Op != OpConvert { + continue + } + mem := a_0_0.Args[1] + ptr := a_0_0.Args[0] + off1 := a_0_1 + off2 := a_1 + if mem != v_1 { + continue + } + v.reset(OpAddPtr) + v0 := b.NewValue0(v.Pos, OpAdd32, a.Type) + v0.AddArg2(off1, off2) + v.AddArg2(ptr, v0) + return true + } + } + break + } return false } func rewriteValuegeneric_OpCtz16(v *Value) bool { diff --git a/test/codegen/unsafe.go b/test/codegen/unsafe.go new file mode 100644 index 0000000000..1f1bdf2a95 --- /dev/null +++ b/test/codegen/unsafe.go @@ -0,0 +1,16 @@ +// asmcheck + +// Copyright 2024 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. + +package codegen + +import "unsafe" + +func f(p unsafe.Pointer, x, y uintptr) int64 { + p = unsafe.Pointer(uintptr(p) + x + y) + // amd64:`MOVQ\s\(.*\)\(.*\*1\), ` + // arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\), ` + return *(*int64)(p) +}