Files
avo/pass/reg.go

122 lines
2.4 KiB
Go
Raw Normal View History

2018-12-02 23:59:29 -08:00
package pass
import (
"errors"
2018-12-02 23:59:29 -08:00
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/operand"
2018-12-02 23:59:29 -08:00
"github.com/mmcloughlin/avo/reg"
)
// Liveness computes register liveness.
func Liveness(fn *avo.Function) error {
// Note this implementation is initially naive so as to be "obviously correct".
// There are a well-known optimizations we can apply if necessary.
2018-12-02 23:59:29 -08:00
is := fn.Instructions()
// Initialize to empty sets.
for _, i := range is {
2018-12-03 22:39:43 -08:00
i.LiveIn = reg.NewEmptySet()
i.LiveOut = reg.NewEmptySet()
2018-12-02 23:59:29 -08:00
}
// Iterative dataflow analysis.
for {
changes := false
for _, i := range is {
// in[n] = use[n] UNION (out[n] - def[n])
nin := len(i.LiveIn)
2018-12-03 22:39:43 -08:00
i.LiveIn.Update(reg.NewSetFromSlice(i.InputRegisters()))
def := reg.NewSetFromSlice(i.OutputRegisters())
i.LiveIn.Update(i.LiveOut.Difference(def))
2018-12-02 23:59:29 -08:00
if len(i.LiveIn) != nin {
changes = true
}
// out[n] = UNION[s IN succ[n]] in[s]
nout := len(i.LiveOut)
for _, s := range i.Succ {
if s == nil {
continue
}
2018-12-03 22:39:43 -08:00
i.LiveOut.Update(s.LiveIn)
2018-12-02 23:59:29 -08:00
}
if len(i.LiveOut) != nout {
changes = true
}
}
if !changes {
break
}
}
return nil
}
2018-12-03 22:39:43 -08:00
func AllocateRegisters(fn *avo.Function) error {
2018-12-12 00:02:22 -08:00
// Populate allocators (one per kind).
as := map[reg.Kind]*Allocator{}
for _, i := range fn.Instructions() {
2018-12-12 00:02:22 -08:00
for _, r := range i.Registers() {
k := r.Kind()
if _, found := as[k]; !found {
a, err := NewAllocatorForKind(k)
if err != nil {
return err
}
as[k] = a
}
2018-12-12 00:02:22 -08:00
as[k].Add(r)
}
}
2018-12-12 00:02:22 -08:00
// Record register interferences.
for _, i := range fn.Instructions() {
for _, d := range i.OutputRegisters() {
k := d.Kind()
out := i.LiveOut.OfKind(k)
out.Discard(d)
as[k].AddInterferenceSet(d, out)
}
}
// Execute register allocation.
fn.Allocation = reg.NewEmptyAllocation()
for _, a := range as {
al, err := a.Allocate()
if err != nil {
return err
}
if err := fn.Allocation.Merge(al); err != nil {
return err
}
}
return nil
}
func BindRegisters(fn *avo.Function) error {
for _, i := range fn.Instructions() {
for idx := range i.Operands {
i.Operands[idx] = operand.ApplyAllocation(i.Operands[idx], fn.Allocation)
}
}
return nil
}
func VerifyAllocation(fn *avo.Function) error {
// All registers should be physical.
for _, i := range fn.Instructions() {
for _, r := range i.Registers() {
if reg.ToPhysical(r) == nil {
return errors.New("non physical register found")
}
}
}
2018-12-03 22:39:43 -08:00
return nil
}