aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ssa/regalloc.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2016-04-10 08:26:43 -0700
committerKeith Randall <khr@golang.org>2016-04-10 23:20:38 +0000
commit0004f34cefcdaad13a5131e3494fb2ff04877cd2 (patch)
tree1b2295a8f5cbdfc39020359d7e93a21db292ca89 /src/cmd/compile/internal/ssa/regalloc.go
parent6b33b0e98e9be77d98b026ae2adf10dd71be5a1b (diff)
downloadgo-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.go47
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)