cmd/compile: start on ARM port

Start working on arm port.  Gets close to correct
code for fibonacci:
    func fib(n int) int {
        if n < 2 {
            return n
        }
        return fib(n-1) + fib(n-2)
    }

Still a lot to do, but this is a good starting point.

Cleaned up some arch-specific dependencies in regalloc.

Change-Id: I4301c6c31a8402168e50dcfee8bcf7aee73ea9d5
Reviewed-on: https://go-review.googlesource.com/21000
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2016-03-21 22:57:26 -07:00
parent 44d3f89e99
commit 4c9a470d46
13 changed files with 807 additions and 73 deletions

View file

@ -129,10 +129,11 @@ type regMask uint64
func (m regMask) String() string {
s := ""
for r := register(0); r < numRegs; r++ {
for r := register(0); m != 0; r++ {
if m>>r&1 == 0 {
continue
}
m &^= regMask(1) << r
if s != "" {
s += " "
}
@ -141,47 +142,6 @@ func (m regMask) String() string {
return s
}
// TODO: make arch-dependent
var numRegs register = 64
var registers = [...]Register{
Register{0, "AX"},
Register{1, "CX"},
Register{2, "DX"},
Register{3, "BX"},
Register{4, "SP"},
Register{5, "BP"},
Register{6, "SI"},
Register{7, "DI"},
Register{8, "R8"},
Register{9, "R9"},
Register{10, "R10"},
Register{11, "R11"},
Register{12, "R12"},
Register{13, "R13"},
Register{14, "R14"},
Register{15, "R15"},
Register{16, "X0"},
Register{17, "X1"},
Register{18, "X2"},
Register{19, "X3"},
Register{20, "X4"},
Register{21, "X5"},
Register{22, "X6"},
Register{23, "X7"},
Register{24, "X8"},
Register{25, "X9"},
Register{26, "X10"},
Register{27, "X11"},
Register{28, "X12"},
Register{29, "X13"},
Register{30, "X14"},
Register{31, "X15"},
Register{32, "SB"}, // pseudo-register for global base pointer (aka %rip)
// TODO: make arch-dependent
}
// countRegs returns the number of set bits in the register mask.
func countRegs(r regMask) int {
n := 0
@ -231,6 +191,11 @@ type regState struct {
type regAllocState struct {
f *Func
registers []Register
numRegs register
SPReg register
SBReg register
// for each block, its primary predecessor.
// A predecessor of b is primary if it is the closest
// predecessor that appears before b in the layout order.
@ -298,7 +263,7 @@ func (s *regAllocState) freeReg(r register) {
// Mark r as unused.
if s.f.pass.debug > regDebug {
fmt.Printf("freeReg %s (dump %s/%s)\n", registers[r].Name(), v, s.regs[r].c)
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
}
s.regs[r] = regState{}
s.values[v.ID].regs &^= regMask(1) << r
@ -328,7 +293,7 @@ func (s *regAllocState) setOrig(c *Value, v *Value) {
// r must be unused.
func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
if s.f.pass.debug > regDebug {
fmt.Printf("assignReg %s %s/%s\n", registers[r].Name(), v, c)
fmt.Printf("assignReg %s %s/%s\n", s.registers[r].Name(), v, c)
}
if s.regs[r].v != nil {
s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v)
@ -338,7 +303,7 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
s.regs[r] = regState{v, c}
s.values[v.ID].regs |= regMask(1) << r
s.used |= regMask(1) << r
s.f.setHome(c, &registers[r])
s.f.setHome(c, &s.registers[r])
}
// allocReg chooses a register for v from the set of registers in mask.
@ -377,14 +342,14 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
// SP and SB are allocated specially. No regular value should
// be allocated to them.
mask &^= 1<<4 | 1<<32
mask &^= 1<<s.SPReg | 1<<s.SBReg
// Find a register to spill. We spill the register containing the value
// whose next use is as far in the future as possible.
// https://en.wikipedia.org/wiki/Page_replacement_algorithm#The_theoretically_optimal_page_replacement_algorithm
var r register
maxuse := int32(-1)
for t := register(0); t < numRegs; t++ {
for t := register(0); t < s.numRegs; t++ {
if mask>>t&1 == 0 {
continue
}
@ -425,10 +390,10 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
if v.Op != OpSP {
mask &^= 1 << 4 // dont' spill SP
mask &^= 1 << s.SPReg // dont' spill SP
}
if v.Op != OpSB {
mask &^= 1 << 32 // don't spill SB
mask &^= 1 << s.SBReg // don't spill SB
}
mask &^= s.reserved()
@ -469,12 +434,22 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
func (s *regAllocState) init(f *Func) {
if numRegs > noRegister || numRegs > register(unsafe.Sizeof(regMask(0))*8) {
s.registers = f.Config.registers
s.numRegs = register(len(s.registers))
if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
panic("too many registers")
}
for r := register(0); r < s.numRegs; r++ {
if s.registers[r].Name() == "SP" {
s.SPReg = r
}
if s.registers[r].Name() == "SB" {
s.SBReg = r
}
}
s.f = f
s.regs = make([]regState, numRegs)
s.regs = make([]regState, s.numRegs)
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
for _, b := range f.Blocks {
@ -663,7 +638,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Drop any values which are no longer live.
// This may happen because at the end of p, a value may be
// live but only used by some other successor of p.
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v != nil && !liveSet.contains(v.ID) {
s.freeReg(r)
@ -687,7 +662,7 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf("starting merge block %s with end state of %s:\n", b, p)
for _, x := range s.endRegs[p.ID] {
fmt.Printf(" %s: orig:%s cache:%s\n", registers[x.r].Name(), x.v, x.c)
fmt.Printf(" %s: orig:%s cache:%s\n", s.registers[x.r].Name(), x.v, x.c)
}
}
@ -769,7 +744,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Save the starting state for use by merge edges.
var regList []startReg
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
@ -786,7 +761,7 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf("after phis\n")
for _, x := range s.startRegs[b.ID] {
fmt.Printf(" %s: v%d\n", registers[x.r].Name(), x.vid)
fmt.Printf(" %s: v%d\n", s.registers[x.r].Name(), x.vid)
}
}
}
@ -866,13 +841,13 @@ func (s *regAllocState) regalloc(f *Func) {
f.Fatalf("phi %s not at start of block", v)
}
if v.Op == OpSP {
s.assignReg(4, v, v) // TODO: arch-dependent
s.assignReg(s.SPReg, v, v)
b.Values = append(b.Values, v)
s.advanceUses(v)
continue
}
if v.Op == OpSB {
s.assignReg(32, v, v) // TODO: arch-dependent
s.assignReg(s.SBReg, v, v)
b.Values = append(b.Values, v)
s.advanceUses(v)
continue
@ -1030,7 +1005,7 @@ func (s *regAllocState) regalloc(f *Func) {
// Save end-of-block register state.
// First count how many, this cuts allocations in half.
k := 0
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
@ -1038,7 +1013,7 @@ func (s *regAllocState) regalloc(f *Func) {
k++
}
regList := make([]endReg, 0, k)
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
@ -1053,7 +1028,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, x := range s.live[b.ID] {
liveSet.add(x.ID)
}
for r := register(0); r < numRegs; r++ {
for r := register(0); r < s.numRegs; r++ {
v := s.regs[r].v
if v == nil {
continue
@ -1214,7 +1189,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Live registers can be sources.
for _, x := range srcReg {
e.set(&registers[x.r], x.v.ID, x.c, false)
e.set(&e.s.registers[x.r], x.v.ID, x.c, false)
}
// So can all of the spill locations.
for _, spillID := range stacklive {
@ -1226,7 +1201,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Figure out all the destinations we need.
dsts := e.destinations[:0]
for _, x := range dstReg {
dsts = append(dsts, dstRecord{&registers[x.r], x.vid, nil})
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil})
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
@ -1519,15 +1494,15 @@ func (e *edgeState) findRegFor(typ Type) Location {
// 3) a non-unique register
x := m &^ e.usedRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
x = m &^ e.uniqueRegs &^ e.finalRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
x = m &^ e.uniqueRegs
if x != 0 {
return &registers[pickReg(x)]
return &e.s.registers[pickReg(x)]
}
// No register is available. Allocate a temp location to spill a register to.