aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2025-09-23 16:31:26 -0700
committerCarlos Amedee <carlos@golang.org>2025-10-01 11:40:42 -0700
commit9b28db77709b3d5c0c38e3d2c333e28b97f6a624 (patch)
tree56a6415af82c353c556cf15cdae6d9bfaeb3516b
parent2e1e356e33b9c792a9643749a7626a1789197bb9 (diff)
downloadgo-9b28db77709b3d5c0c38e3d2c333e28b97f6a624.tar.xz
[release-branch.go1.24] cmd/compile: don't rely on loop info when there are irreducible loops
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 #75594 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/+/706575
-rw-r--r--src/cmd/compile/internal/ssa/tighten.go27
-rw-r--r--test/fixedbugs/issue75569.go77
2 files changed, 92 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
index 85b6a84cc3..bfb1862335 100644
--- a/src/cmd/compile/internal/ssa/tighten.go
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -118,18 +118,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
index 0000000000..8420641db2
--- /dev/null
+++ b/test/fixedbugs/issue75569.go
@@ -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)
+ }
+}