]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: pull multiple adds out of an unsafe.Pointer<->uintptr conversion
authorKeith Randall <khr@golang.org>
Mon, 18 Nov 2024 23:52:13 +0000 (15:52 -0800)
committerKeith Randall <khr@golang.org>
Thu, 21 Nov 2024 22:57:04 +0000 (22:57 +0000)
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 <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/ssa/_gen/generic.rules
src/cmd/compile/internal/ssa/rewritegeneric.go
test/codegen/unsafe.go [new file with mode: 0644]

index 9a2bb96a1b2d94d58c539a258d4a149d0f03c0ad..9e2e8772c154ab4c6e25fd1fe0eb0ce0ff59994c 100644 (file)
 // 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) <a.Type> off1 off2))
 
 // strength reduction of divide by a constant.
 // See ../magic.go for a detailed description of these algorithms.
index e4d6b45cf2cb8b37ffddbdaca99b075915761670..4cb287c9b7a0edd696bd96a6e3116973c76fb709 100644 (file)
@@ -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 <a.Type> 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 <a.Type> 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 (file)
index 0000000..1f1bdf2
--- /dev/null
@@ -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)
+}