mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: when CSEing two values, prefer the statement marked one
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>
This commit is contained in:
parent
00824f5ff5
commit
b1f3e38e41
2 changed files with 139 additions and 23 deletions
105
src/cmd/compile/internal/dwarfgen/linenum_test.go
Normal file
105
src/cmd/compile/internal/dwarfgen/linenum_test.go
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 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 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 {
|
||||
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++ {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue