aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2021-04-23 21:49:08 -0400
committerDavid Chase <drchase@google.com>2021-05-03 17:46:12 +0000
commit90ec25773523ac2c5e075f1e5d7519ee08201b8c (patch)
tree769352c6a7649417f79259c29b2aef5bc1769ea0 /src/cmd/compile/internal/ssa
parentb5842308892e0c4f9e772a42d5826f6f62f57be3 (diff)
downloadgo-90ec25773523ac2c5e075f1e5d7519ee08201b8c.tar.gz
go-90ec25773523ac2c5e075f1e5d7519ee08201b8c.zip
cmd/compile: make the stack allocator more careful about register args.
Assignment between input parameters causes them to have more than one "Name", and running this backwards from names to values can end up confusing (conflating) parameter spill slots. Around 105a6e9518, this cases a stack overflow running go test -race encoding/pem because two slice parameters spill (incorrectly) into the same stack slots (in the AB?I-defined parameter spill area). This also tickles a failure in cue, which turned out to be easier to isolate. Fixes #45851. Updates #40724. Change-Id: I39c56815bd6abb652f1ccbe83c47f4f373a125c3 Reviewed-on: https://go-review.googlesource.com/c/go/+/313212 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/cmd/compile/internal/ssa')
-rw-r--r--src/cmd/compile/internal/ssa/expand_calls.go6
-rw-r--r--src/cmd/compile/internal/ssa/stackalloc.go39
2 files changed, 44 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index 4d5376b344..133959204a 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -6,6 +6,7 @@ package ssa
import (
"cmd/compile/internal/abi"
+ "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
@@ -1601,7 +1602,10 @@ func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64,
x.f.OwnAux.abiInfo.String())
panic(fmt.Errorf("Op/Type mismatch, op=%s, type=%s", op.String(), t.String()))
}
- aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), baseArg.AuxInt + offset}
+ if baseArg.AuxInt != 0 {
+ base.Fatalf("BaseArg %s bound to registers has non-zero AuxInt", baseArg.LongString())
+ }
+ aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), offset}
if toReplace != nil && toReplace.Block == baseArg.Block {
toReplace.reset(op)
toReplace.Aux = aux
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index 8fe18e5f02..d962579122 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -145,6 +145,26 @@ func (s *stackAllocState) stackalloc() {
// Note: not "range f.NamedValues" above, because
// that would be nondeterministic.
for _, v := range f.NamedValues[name] {
+ if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
+ aux := v.Aux.(*AuxNameOffset)
+ // Never let an arg be bound to a differently named thing.
+ if name.N != aux.Name || name.Off != aux.Offset {
+ if f.pass.debug > stackDebug {
+ fmt.Printf("stackalloc register arg %s skipping name %s\n", v, name)
+ }
+ continue
+ }
+ } else if name.N.Class == ir.PPARAM && v.Op != OpArg {
+ // PPARAM's only bind to OpArg
+ if f.pass.debug > stackDebug {
+ fmt.Printf("stackalloc PPARAM name %s skipping non-Arg %s\n", name, v)
+ }
+ continue
+ }
+
+ if f.pass.debug > stackDebug {
+ fmt.Printf("stackalloc value %s to name %s\n", v, name)
+ }
names[v.ID] = name
}
}
@@ -165,6 +185,25 @@ func (s *stackAllocState) stackalloc() {
f.setHome(v, loc)
continue
}
+ // You might think this below would be the right idea, but you would be wrong.
+ // It almost works; as of 105a6e9518 - 2021-04-23,
+ // GOSSAHASH=11011011001011111 == cmd/compile/internal/noder.(*noder).embedded
+ // is compiled incorrectly. I believe the cause is one of those SSA-to-registers
+ // puzzles that the register allocator untangles; in the event that a register
+ // parameter does not end up bound to a name, "fixing" it is a bad idea.
+ //
+ //if f.DebugTest {
+ // if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
+ // aux := v.Aux.(*AuxNameOffset)
+ // loc := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
+ // if f.pass.debug > stackDebug {
+ // fmt.Printf("stackalloc Op%s %s to %s\n", v.Op, v, loc)
+ // }
+ // names[v.ID] = loc
+ // continue
+ // }
+ //}
+
}
// For each type, we keep track of all the stack slots we