Skip to content

Commit f15cd63

Browse files
committed
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 #75569 Change-Id: Idd80e6d2268094b8ae6387563081fdc1e211856a Reviewed-on: https://go-review.googlesource.com/c/go/+/706355 Reviewed-by: David Chase <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 371c1d2 commit f15cd63

File tree

2 files changed

+92
-12
lines changed

2 files changed

+92
-12
lines changed

src/cmd/compile/internal/ssa/tighten.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,21 @@ func tighten(f *Func) {
123123

124124
// If the target location is inside a loop,
125125
// move the target location up to just before the loop head.
126-
for _, b := range f.Blocks {
127-
origloop := loops.b2l[b.ID]
128-
for _, v := range b.Values {
129-
t := target[v.ID]
130-
if t == nil {
131-
continue
132-
}
133-
targetloop := loops.b2l[t.ID]
134-
for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
135-
t = idom[targetloop.header.ID]
136-
target[v.ID] = t
137-
targetloop = loops.b2l[t.ID]
126+
if !loops.hasIrreducible {
127+
// Loop info might not be correct for irreducible loops. See issue 75569.
128+
for _, b := range f.Blocks {
129+
origloop := loops.b2l[b.ID]
130+
for _, v := range b.Values {
131+
t := target[v.ID]
132+
if t == nil {
133+
continue
134+
}
135+
targetloop := loops.b2l[t.ID]
136+
for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
137+
t = idom[targetloop.header.ID]
138+
target[v.ID] = t
139+
targetloop = loops.b2l[t.ID]
140+
}
138141
}
139142
}
140143
}

test/fixedbugs/issue75569.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func fff(a []int, b bool, p, q *int) {
10+
outer:
11+
n := a[0]
12+
a = a[1:]
13+
switch n {
14+
case 1:
15+
goto one
16+
case 2:
17+
goto two
18+
case 3:
19+
goto three
20+
case 4:
21+
goto four
22+
}
23+
24+
one:
25+
goto inner
26+
two:
27+
goto outer
28+
three:
29+
goto inner
30+
four:
31+
goto innerSideEntry
32+
33+
inner:
34+
n = a[0]
35+
a = a[1:]
36+
switch n {
37+
case 1:
38+
goto outer
39+
case 2:
40+
goto inner
41+
case 3:
42+
goto innerSideEntry
43+
default:
44+
return
45+
}
46+
innerSideEntry:
47+
n = a[0]
48+
a = a[1:]
49+
switch n {
50+
case 1:
51+
goto outer
52+
case 2:
53+
goto inner
54+
case 3:
55+
goto inner
56+
}
57+
ggg(p, q)
58+
goto inner
59+
}
60+
61+
var b bool
62+
63+
func ggg(p, q *int) {
64+
n := *p + 5 // this +5 ends up in the entry block, well before the *p load
65+
if b {
66+
*q = 0
67+
}
68+
*p = n
69+
}
70+
71+
func main() {
72+
var x, y int
73+
fff([]int{4, 4, 4}, false, &x, &y)
74+
if x != 5 {
75+
panic(x)
76+
}
77+
}

0 commit comments

Comments
 (0)