[dev.ssa] cmd/compile: Deduplicate panic{index,slice,divide} calls

Panics are only distinguished by their type and line number, so
if we can trigger two of those panics in the same line, use the
same panic call.  For example, in a[i]+b[j] we need only one
panicindex call that both bounds checks can use.

Change-Id: Ia2b6d3b1a67f2775df05fb72b8a1b149833572b7
Reviewed-on: https://go-review.googlesource.com/16772
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2015-11-09 21:35:40 -08:00
parent 170589ee1c
commit 74e568f43a
1 changed files with 20 additions and 6 deletions

View File

@ -73,6 +73,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
s.f = s.config.NewFunc()
s.f.Name = name
s.exitCode = fn.Func.Exit
s.panics = map[funcLine]*ssa.Block{}
if name == os.Getenv("GOSSAFUNC") {
// TODO: tempfile? it is handy to have the location
@ -270,6 +271,15 @@ type state struct {
// line number stack. The current line number is top of stack
line []int32
// list of panic calls by function name and line number.
// Used to deduplicate panic calls.
panics map[funcLine]*ssa.Block
}
type funcLine struct {
f *Node
line int32
}
type ssaLabel struct {
@ -2517,14 +2527,18 @@ func (s *state) check(cmp *ssa.Value, fn *Node) {
b.Control = cmp
b.Likely = ssa.BranchLikely
bNext := s.f.NewBlock(ssa.BlockPlain)
bPanic := s.f.NewBlock(ssa.BlockPlain)
line := s.peekLine()
bPanic := s.panics[funcLine{fn, line}]
if bPanic == nil {
bPanic = s.f.NewBlock(ssa.BlockPlain)
s.panics[funcLine{fn, line}] = bPanic
s.startBlock(bPanic)
// The panic call takes/returns memory to ensure that the right
// memory state is observed if the panic happens.
s.rtcall(fn, false, nil)
}
b.AddEdgeTo(bNext)
b.AddEdgeTo(bPanic)
s.startBlock(bPanic)
// The panic call takes/returns memory to ensure that the right
// memory state is observed if the panic happens.
s.rtcall(fn, false, nil)
s.startBlock(bNext)
}