]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: when CSEing two values, prefer the statement marked one
authorKeith Randall <khr@golang.org>
Fri, 5 Sep 2025 17:19:17 +0000 (10:19 -0700)
committerKeith Randall <khr@google.com>
Wed, 10 Sep 2025 20:31:18 +0000 (13:31 -0700)
Fixes #75249

Change-Id: Ifd61bf5341f23ce2c9735e607e00d987489caacf
Reviewed-on: https://go-review.googlesource.com/c/go/+/701295
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Alexander Musman <alexander.musman@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/dwarfgen/linenum_test.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/cse.go

diff --git a/src/cmd/compile/internal/dwarfgen/linenum_test.go b/src/cmd/compile/internal/dwarfgen/linenum_test.go
new file mode 100644 (file)
index 0000000..05e72c2
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2025 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 dwarfgen
+
+import (
+       "debug/dwarf"
+       "internal/platform"
+       "internal/testenv"
+       "io"
+       "runtime"
+       "testing"
+)
+
+func TestIssue75249(t *testing.T) {
+       testenv.MustHaveGoRun(t)
+       t.Parallel()
+
+       if !platform.ExecutableHasDWARF(runtime.GOOS, runtime.GOARCH) {
+               t.Skipf("skipping on %s/%s: no DWARF symbol table in executables", runtime.GOOS, runtime.GOARCH)
+       }
+
+       code := `
+package main
+
+type Data struct {
+        Field1 int
+        Field2 *int
+        Field3 int
+        Field4 *int
+        Field5 int
+        Field6 *int
+        Field7 int
+        Field8 *int
+}
+
+//go:noinline
+func InitializeData(d *Data) {
+        d.Field1++            // line 16
+        d.Field2 = d.Field4
+        d.Field3++
+        d.Field4 = d.Field6
+        d.Field5++
+        d.Field6 = d.Field8
+        d.Field7++
+        d.Field8 = d.Field2   // line 23
+}
+
+func main() {
+        var data Data
+        InitializeData(&data)
+}
+`
+
+       _, f := gobuild(t, t.TempDir(), true, []testline{{line: code}})
+       defer f.Close()
+
+       dwarfData, err := f.DWARF()
+       if err != nil {
+               t.Fatal(err)
+       }
+       dwarfReader := dwarfData.Reader()
+
+       for {
+               entry, err := dwarfReader.Next()
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if entry == nil {
+                       break
+               }
+               if entry.Tag != dwarf.TagCompileUnit {
+                       continue
+               }
+               name := entry.AttrField(dwarf.AttrName)
+               if name == nil || name.Class != dwarf.ClassString || name.Val != "main" {
+                       continue
+               }
+               lr, err := dwarfData.LineReader(entry)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               stmts := map[int]bool{}
+               for {
+                       var le dwarf.LineEntry
+                       err := lr.Next(&le)
+                       if err == io.EOF {
+                               break
+                       }
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if !le.IsStmt {
+                               continue
+                       }
+                       stmts[le.Line] = true
+               }
+               for i := 16; i <= 23; i++ {
+                       if !stmts[i] {
+                               t.Errorf("missing statement at line %d", i)
+                       }
+               }
+       }
+}
index 66b22697f06952761c3c7ebe4cc1f5be4a372011..28eb4f76a9d134e15f0d96aed53b240c06fd8719 100644 (file)
@@ -181,34 +181,45 @@ func cse(f *Func) {
        for _, e := range partition {
                slices.SortFunc(e, func(v, w *Value) int {
                        c := cmp.Compare(sdom.domorder(v.Block), sdom.domorder(w.Block))
-                       if v.Op != OpLocalAddr || c != 0 {
+                       if c != 0 {
                                return c
                        }
-                       // compare the memory args for OpLocalAddrs in the same block
-                       vm := v.Args[1]
-                       wm := w.Args[1]
-                       if vm == wm {
-                               return 0
-                       }
-                       // if the two OpLocalAddrs are in the same block, and one's memory
-                       // arg also in the same block, but the other one's memory arg not,
-                       // the latter must be in an ancestor block
-                       if vm.Block != v.Block {
-                               return -1
+                       if v.Op == OpLocalAddr {
+                               // compare the memory args for OpLocalAddrs in the same block
+                               vm := v.Args[1]
+                               wm := w.Args[1]
+                               if vm == wm {
+                                       return 0
+                               }
+                               // if the two OpLocalAddrs are in the same block, and one's memory
+                               // arg also in the same block, but the other one's memory arg not,
+                               // the latter must be in an ancestor block
+                               if vm.Block != v.Block {
+                                       return -1
+                               }
+                               if wm.Block != w.Block {
+                                       return +1
+                               }
+                               // use store order if the memory args are in the same block
+                               vs := storeOrdering(vm, o)
+                               ws := storeOrdering(wm, o)
+                               if vs <= 0 {
+                                       f.Fatalf("unable to determine the order of %s", vm.LongString())
+                               }
+                               if ws <= 0 {
+                                       f.Fatalf("unable to determine the order of %s", wm.LongString())
+                               }
+                               return cmp.Compare(vs, ws)
                        }
-                       if wm.Block != w.Block {
+                       vStmt := v.Pos.IsStmt() == src.PosIsStmt
+                       wStmt := w.Pos.IsStmt() == src.PosIsStmt
+                       if vStmt != wStmt {
+                               if vStmt {
+                                       return -1
+                               }
                                return +1
                        }
-                       // use store order if the memory args are in the same block
-                       vs := storeOrdering(vm, o)
-                       ws := storeOrdering(wm, o)
-                       if vs <= 0 {
-                               f.Fatalf("unable to determine the order of %s", vm.LongString())
-                       }
-                       if ws <= 0 {
-                               f.Fatalf("unable to determine the order of %s", wm.LongString())
-                       }
-                       return cmp.Compare(vs, ws)
+                       return 0
                })
 
                for i := 0; i < len(e)-1; i++ {