]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.25] cmd/compile: don't rely on loop info when there are irreducib...
authorKeith Randall <khr@golang.org>
Tue, 23 Sep 2025 23:31:26 +0000 (16:31 -0700)
committerCarlos Amedee <carlos@golang.org>
Wed, 1 Oct 2025 18:40:47 +0000 (11:40 -0700)
Loop information is sketchy when there are irreducible loops.
Sometimes blocks inside 2 loops can be recorded as only being part of
the outer loop. That causes tighten to move values that want to move
into such a block to move out of the loop altogether, breaking the
invariant that operations have to be scheduled after their args.

Fixes #75595

Change-Id: Idd80e6d2268094b8ae6387563081fdc1e211856a
Reviewed-on: https://go-review.googlesource.com/c/go/+/706355
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
(cherry picked from commit f15cd63ec4860c4f2c23cc992843546e0265c332)
Reviewed-on: https://go-review.googlesource.com/c/go/+/706576

src/cmd/compile/internal/ssa/tighten.go
test/fixedbugs/issue75569.go [new file with mode: 0644]

index eb5007b26e29e49ce51891e65c415752dc66157f..0a4b56d5781a24ec409f54c8342fca5801e02136 100644 (file)
@@ -124,18 +124,21 @@ func tighten(f *Func) {
 
                // If the target location is inside a loop,
                // move the target location up to just before the loop head.
-               for _, b := range f.Blocks {
-                       origloop := loops.b2l[b.ID]
-                       for _, v := range b.Values {
-                               t := target[v.ID]
-                               if t == nil {
-                                       continue
-                               }
-                               targetloop := loops.b2l[t.ID]
-                               for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
-                                       t = idom[targetloop.header.ID]
-                                       target[v.ID] = t
-                                       targetloop = loops.b2l[t.ID]
+               if !loops.hasIrreducible {
+                       // Loop info might not be correct for irreducible loops. See issue 75569.
+                       for _, b := range f.Blocks {
+                               origloop := loops.b2l[b.ID]
+                               for _, v := range b.Values {
+                                       t := target[v.ID]
+                                       if t == nil {
+                                               continue
+                                       }
+                                       targetloop := loops.b2l[t.ID]
+                                       for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
+                                               t = idom[targetloop.header.ID]
+                                               target[v.ID] = t
+                                               targetloop = loops.b2l[t.ID]
+                                       }
                                }
                        }
                }
diff --git a/test/fixedbugs/issue75569.go b/test/fixedbugs/issue75569.go
new file mode 100644 (file)
index 0000000..8420641
--- /dev/null
@@ -0,0 +1,77 @@
+// run
+
+// 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 main
+
+func fff(a []int, b bool, p, q *int) {
+outer:
+       n := a[0]
+       a = a[1:]
+       switch n {
+       case 1:
+               goto one
+       case 2:
+               goto two
+       case 3:
+               goto three
+       case 4:
+               goto four
+       }
+
+one:
+       goto inner
+two:
+       goto outer
+three:
+       goto inner
+four:
+       goto innerSideEntry
+
+inner:
+       n = a[0]
+       a = a[1:]
+       switch n {
+       case 1:
+               goto outer
+       case 2:
+               goto inner
+       case 3:
+               goto innerSideEntry
+       default:
+               return
+       }
+innerSideEntry:
+       n = a[0]
+       a = a[1:]
+       switch n {
+       case 1:
+               goto outer
+       case 2:
+               goto inner
+       case 3:
+               goto inner
+       }
+       ggg(p, q)
+       goto inner
+}
+
+var b bool
+
+func ggg(p, q *int) {
+       n := *p + 5 // this +5 ends up in the entry block, well before the *p load
+       if b {
+               *q = 0
+       }
+       *p = n
+}
+
+func main() {
+       var x, y int
+       fff([]int{4, 4, 4}, false, &x, &y)
+       if x != 5 {
+               panic(x)
+       }
+}