From: Keith Randall Date: Fri, 5 Sep 2025 17:19:17 +0000 (-0700) Subject: cmd/compile: when CSEing two values, prefer the statement marked one X-Git-Tag: go1.26rc1~909 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b1f3e38e41;p=gostls13.git 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 Reviewed-by: David Chase Reviewed-by: Alexander Musman LUCI-TryBot-Result: Go LUCI --- diff --git a/src/cmd/compile/internal/dwarfgen/linenum_test.go b/src/cmd/compile/internal/dwarfgen/linenum_test.go new file mode 100644 index 0000000000..05e72c2a06 --- /dev/null +++ b/src/cmd/compile/internal/dwarfgen/linenum_test.go @@ -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) + } + } + } +} diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index 66b22697f0..28eb4f76a9 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -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++ {