Skip to content

Commit 00715d0

Browse files
mdempskygopherbot
authored andcommitted
cmd/compile/internal/walk: copy SSA-able variables
order.go ensures expressions that are passed to the runtime by address are in fact addressable. However, in the case of local variables, if the variable hasn't already been marked as addrtaken, then taking its address here will effectively prevent the variable from being converted to SSA form. Instead, it's better to just copy the variable into a new temporary, which we can pass by address instead. This ensures the original variable can still be converted to SSA form. Fixes #63332. Change-Id: I182376d98d419df8bf07c400d84c344c9b82c0fb Reviewed-on: https://go-review.googlesource.com/c/go/+/541715 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Matthew Dempsky <[email protected]>
1 parent e5615ad commit 00715d0

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

src/cmd/compile/internal/walk/order.go

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"cmd/compile/internal/base"
1212
"cmd/compile/internal/ir"
1313
"cmd/compile/internal/reflectdata"
14+
"cmd/compile/internal/ssa"
1415
"cmd/compile/internal/staticinit"
1516
"cmd/compile/internal/typecheck"
1617
"cmd/compile/internal/types"
@@ -231,14 +232,29 @@ func (o *orderState) addrTemp(n ir.Node) ir.Node {
231232
vstat = typecheck.Expr(vstat).(*ir.Name)
232233
return vstat
233234
}
235+
236+
// Prevent taking the address of an SSA-able local variable (#63332).
237+
//
238+
// TODO(mdempsky): Note that OuterValue unwraps OCONVNOPs, but
239+
// IsAddressable does not. It should be possible to skip copying for
240+
// at least some of these OCONVNOPs (e.g., reinsert them after the
241+
// OADDR operation), but at least walkCompare needs to be fixed to
242+
// support that (see trybot failures on go.dev/cl/541715, PS1).
234243
if ir.IsAddressable(n) {
244+
if name, ok := ir.OuterValue(n).(*ir.Name); ok && name.Op() == ir.ONAME {
245+
if name.Class == ir.PAUTO && !name.Addrtaken() && ssa.CanSSA(name.Type()) {
246+
goto Copy
247+
}
248+
}
249+
235250
return n
236251
}
252+
253+
Copy:
237254
return o.copyExpr(n)
238255
}
239256

240257
// mapKeyTemp prepares n to be a key in a map runtime call and returns n.
241-
// It should only be used for map runtime calls which have *_fast* versions.
242258
// The first parameter is the position of n's containing node, for use in case
243259
// that n's position is not unique (e.g., if n is an ONAME).
244260
func (o *orderState) mapKeyTemp(outerPos src.XPos, t *types.Type, n ir.Node) ir.Node {
@@ -603,8 +619,38 @@ func (o *orderState) stmt(n ir.Node) {
603619
case ir.OAS:
604620
n := n.(*ir.AssignStmt)
605621
t := o.markTemp()
622+
623+
// There's a delicate interaction here between two OINDEXMAP
624+
// optimizations.
625+
//
626+
// First, we want to handle m[k] = append(m[k], ...) with a single
627+
// runtime call to mapassign. This requires the m[k] expressions to
628+
// satisfy ir.SameSafeExpr in walkAssign.
629+
//
630+
// But if k is a slow map key type that's passed by reference (e.g.,
631+
// byte), then we want to avoid marking user variables as addrtaken,
632+
// if that might prevent the compiler from keeping k in a register.
633+
//
634+
// TODO(mdempsky): It would be better if walk was responsible for
635+
// inserting temporaries as needed.
636+
mapAppend := n.X.Op() == ir.OINDEXMAP && n.Y.Op() == ir.OAPPEND &&
637+
ir.SameSafeExpr(n.X, n.Y.(*ir.CallExpr).Args[0])
638+
606639
n.X = o.expr(n.X, nil)
607-
n.Y = o.expr(n.Y, n.X)
640+
if mapAppend {
641+
indexLHS := n.X.(*ir.IndexExpr)
642+
indexLHS.X = o.cheapExpr(indexLHS.X)
643+
indexLHS.Index = o.cheapExpr(indexLHS.Index)
644+
645+
call := n.Y.(*ir.CallExpr)
646+
indexRHS := call.Args[0].(*ir.IndexExpr)
647+
indexRHS.X = indexLHS.X
648+
indexRHS.Index = indexLHS.Index
649+
650+
o.exprList(call.Args[1:])
651+
} else {
652+
n.Y = o.expr(n.Y, n.X)
653+
}
608654
o.mapAssign(n)
609655
o.popTemp(t)
610656

@@ -1158,7 +1204,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
11581204
}
11591205
}
11601206

1161-
// key must be addressable
1207+
// key may need to be be addressable
11621208
n.Index = o.mapKeyTemp(n.Pos(), n.X.Type(), n.Index)
11631209
if needCopy {
11641210
return o.copyExpr(n)

test/codegen/issue63332.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// asmcheck
2+
3+
// Copyright 2023 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 codegen
8+
9+
func issue63332(c chan int) {
10+
x := 0
11+
// amd64:-`MOVQ`
12+
x += 2
13+
c <- x
14+
}

0 commit comments

Comments
 (0)