mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
44d3f89e99
commit
4c9a470d46
13 changed files with 807 additions and 73 deletions
|
|
@ -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, ®isters[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(®isters[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{®isters[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 ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs &^ e.finalRegs
|
||||
if x != 0 {
|
||||
return ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs
|
||||
if x != 0 {
|
||||
return ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
|
||||
// No register is available. Allocate a temp location to spill a register to.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue