diff options
| author | Keith Randall <khr@golang.org> | 2016-04-10 08:26:43 -0700 |
|---|---|---|
| committer | Keith Randall <khr@golang.org> | 2016-04-10 23:20:38 +0000 |
| commit | 0004f34cefcdaad13a5131e3494fb2ff04877cd2 (patch) | |
| tree | 1b2295a8f5cbdfc39020359d7e93a21db292ca89 /src/cmd/compile/internal/ssa/regalloc.go | |
| parent | 6b33b0e98e9be77d98b026ae2adf10dd71be5a1b (diff) | |
| download | go-0004f34cefcdaad13a5131e3494fb2ff04877cd2.tar.xz | |
cmd/compile: regalloc enforces 2-address instructions
Instead of being a hint, resultInArg0 is now enforced by regalloc.
This allows us to delete all the code from amd64/ssa.go which
deals with converting from a semantically three-address instruction
into some copies plus a two-address instruction.
Change-Id: Id4f39a80be4b678718bfd42a229f9094ab6ecd7c
Reviewed-on: https://go-review.googlesource.com/21816
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/ssa/regalloc.go')
| -rw-r--r-- | src/cmd/compile/internal/ssa/regalloc.go | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index aec23a1368..dfae8612d6 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -527,6 +527,18 @@ func (s *regAllocState) advanceUses(v *Value) { } } +// liveAfterCurrentInstruction reports whether v is live after +// the current instruction is completed. v must be used by the +// current instruction. +func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool { + u := s.values[v.ID].uses + d := u.dist + for u != nil && u.dist == d { + u = u.next + } + return u != nil && u.dist > d +} + // Sets the state of the registers to that encoded in regs. func (s *regAllocState) setState(regs []endReg) { s.freeRegs(s.used) @@ -891,6 +903,27 @@ func (s *regAllocState) regalloc(f *Func) { args[i.idx] = s.allocValToReg(v.Args[i.idx], i.regs, true, v.Line) } + // If the output clobbers the input register, and the input register is + // live beyond the instruction, make another copy of the input register so + // we don't have to reload the value from the spill location. + if opcodeTable[v.Op].resultInArg0 && + s.liveAfterCurrentInstruction(v.Args[0]) && + countRegs(s.values[v.Args[0].ID].regs) == 1 { + + if opcodeTable[v.Op].commutative && + (!s.liveAfterCurrentInstruction(v.Args[1]) || + countRegs(s.values[v.Args[1].ID].regs) > 1) { + // Input #1 is dead after the instruction, or we have + // more than one copy of it in a register. Either way, + // use that input as the one that is clobbered. + args[0], args[1] = args[1], args[0] + } else { + m := s.compatRegs(v.Args[0].Type) + m &^= s.values[v.Args[0].ID].regs // a register not already holding v.Args[0] + s.allocValToReg(v.Args[0], m, true, v.Line) + } + } + // Now that all args are in regs, we're ready to issue the value itself. // Before we pick a register for the output value, allow input registers // to be deallocated. We do this here so that the output can use the @@ -908,19 +941,9 @@ func (s *regAllocState) regalloc(f *Func) { s.f.Fatalf("bad mask %s\n", v.LongString()) } if opcodeTable[v.Op].resultInArg0 { + // Output must use the same register as input 0. r := register(s.f.getHome(args[0].ID).(*Register).Num) - if (mask&^s.used)>>r&1 != 0 { - mask = regMask(1) << r - } - if opcodeTable[v.Op].commutative { - r := register(s.f.getHome(args[1].ID).(*Register).Num) - if (mask&^s.used)>>r&1 != 0 { - mask = regMask(1) << r - } - } - // TODO: enforce resultInArg0 always, instead of treating it - // as a hint. Then we don't need the special cases adding - // moves all throughout ssa.go:genValue. + mask = regMask(1) << r } r := s.allocReg(v, mask) s.assignReg(r, v, v) |
