pass: doc exported symbols (#9)
This commit is contained in:
@@ -13,6 +13,7 @@ type edge struct {
|
|||||||
X, Y reg.Register
|
X, Y reg.Register
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocator is a graph-coloring register allocator.
|
||||||
type Allocator struct {
|
type Allocator struct {
|
||||||
registers []reg.Physical
|
registers []reg.Physical
|
||||||
allocation reg.Allocation
|
allocation reg.Allocation
|
||||||
@@ -21,6 +22,7 @@ type Allocator struct {
|
|||||||
vidtopid map[reg.VID]reg.PID
|
vidtopid map[reg.VID]reg.PID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAllocator builds an allocator for the given physical registers.
|
||||||
func NewAllocator(rs []reg.Physical) (*Allocator, error) {
|
func NewAllocator(rs []reg.Physical) (*Allocator, error) {
|
||||||
if len(rs) == 0 {
|
if len(rs) == 0 {
|
||||||
return nil, errors.New("no registers")
|
return nil, errors.New("no registers")
|
||||||
@@ -33,6 +35,7 @@ func NewAllocator(rs []reg.Physical) (*Allocator, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAllocatorForKind builds an allocator for the given kind of registers.
|
||||||
func NewAllocatorForKind(k reg.Kind) (*Allocator, error) {
|
func NewAllocatorForKind(k reg.Kind) (*Allocator, error) {
|
||||||
f := reg.FamilyOfKind(k)
|
f := reg.FamilyOfKind(k)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
@@ -41,12 +44,14 @@ func NewAllocatorForKind(k reg.Kind) (*Allocator, error) {
|
|||||||
return NewAllocator(f.Registers())
|
return NewAllocator(f.Registers())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddInterferenceSet records that r interferes with every register in s. Convenience wrapper around AddInterference.
|
||||||
func (a *Allocator) AddInterferenceSet(r reg.Register, s reg.Set) {
|
func (a *Allocator) AddInterferenceSet(r reg.Register, s reg.Set) {
|
||||||
for y := range s {
|
for y := range s {
|
||||||
a.AddInterference(r, y)
|
a.AddInterference(r, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddInterference records that x and y must be assigned to non-conflicting physical registers.
|
||||||
func (a *Allocator) AddInterference(x, y reg.Register) {
|
func (a *Allocator) AddInterference(x, y reg.Register) {
|
||||||
a.Add(x)
|
a.Add(x)
|
||||||
a.Add(y)
|
a.Add(y)
|
||||||
@@ -65,6 +70,7 @@ func (a *Allocator) Add(r reg.Register) {
|
|||||||
a.possible[v] = a.possibleregisters(v)
|
a.possible[v] = a.possibleregisters(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate allocates physical registers.
|
||||||
func (a *Allocator) Allocate() (reg.Allocation, error) {
|
func (a *Allocator) Allocate() (reg.Allocation, error) {
|
||||||
for {
|
for {
|
||||||
if err := a.update(); err != nil {
|
if err := a.update(); err != nil {
|
||||||
|
|||||||
12
pass/pass.go
12
pass/pass.go
@@ -1,3 +1,4 @@
|
|||||||
|
// Package pass implements processing passes on avo Files.
|
||||||
package pass
|
package pass
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,6 +8,8 @@ import (
|
|||||||
"github.com/mmcloughlin/avo/printer"
|
"github.com/mmcloughlin/avo/printer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Compile pass compiles an avo file. Upon successful completion the avo file
|
||||||
|
// may be printed to Go assembly.
|
||||||
var Compile = Concat(
|
var Compile = Concat(
|
||||||
FunctionPass(LabelTarget),
|
FunctionPass(LabelTarget),
|
||||||
FunctionPass(CFG),
|
FunctionPass(CFG),
|
||||||
@@ -17,18 +20,24 @@ var Compile = Concat(
|
|||||||
Func(IncludeTextFlagHeader),
|
Func(IncludeTextFlagHeader),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Interface for a processing pass.
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
Execute(*avo.File) error
|
Execute(*avo.File) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Func adapts a function to the pass Interface.
|
||||||
type Func func(*avo.File) error
|
type Func func(*avo.File) error
|
||||||
|
|
||||||
|
// Execute calls p.
|
||||||
func (p Func) Execute(f *avo.File) error {
|
func (p Func) Execute(f *avo.File) error {
|
||||||
return p(f)
|
return p(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FunctionPass is a convenience for implementing a full file pass with a
|
||||||
|
// function that operates on each avo Function independently.
|
||||||
type FunctionPass func(*avo.Function) error
|
type FunctionPass func(*avo.Function) error
|
||||||
|
|
||||||
|
// Execute calls p on every function in the file. Exits on the first error.
|
||||||
func (p FunctionPass) Execute(f *avo.File) error {
|
func (p FunctionPass) Execute(f *avo.File) error {
|
||||||
for _, fn := range f.Functions() {
|
for _, fn := range f.Functions() {
|
||||||
if err := p(fn); err != nil {
|
if err := p(fn); err != nil {
|
||||||
@@ -38,6 +47,7 @@ func (p FunctionPass) Execute(f *avo.File) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Concat returns a pass that executes the given passes in order, stopping on the first error.
|
||||||
func Concat(passes ...Interface) Interface {
|
func Concat(passes ...Interface) Interface {
|
||||||
return Func(func(f *avo.File) error {
|
return Func(func(f *avo.File) error {
|
||||||
for _, p := range passes {
|
for _, p := range passes {
|
||||||
@@ -49,11 +59,13 @@ func Concat(passes ...Interface) Interface {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output pass prints a file.
|
||||||
type Output struct {
|
type Output struct {
|
||||||
Writer io.WriteCloser
|
Writer io.WriteCloser
|
||||||
Printer printer.Printer
|
Printer printer.Printer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute prints f with the configured Printer and writes output to Writer.
|
||||||
func (o *Output) Execute(f *avo.File) error {
|
func (o *Output) Execute(f *avo.File) error {
|
||||||
b, err := o.Printer.Print(f)
|
b, err := o.Printer.Print(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ func Liveness(fn *avo.Function) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllocateRegisters performs register allocation.
|
||||||
func AllocateRegisters(fn *avo.Function) error {
|
func AllocateRegisters(fn *avo.Function) error {
|
||||||
// Populate allocators (one per kind).
|
// Populate allocators (one per kind).
|
||||||
as := map[reg.Kind]*Allocator{}
|
as := map[reg.Kind]*Allocator{}
|
||||||
@@ -108,6 +109,7 @@ func AllocateRegisters(fn *avo.Function) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BindRegisters applies the result of register allocation, replacing all virtual registers with their assigned physical registers.
|
||||||
func BindRegisters(fn *avo.Function) error {
|
func BindRegisters(fn *avo.Function) error {
|
||||||
for _, i := range fn.Instructions() {
|
for _, i := range fn.Instructions() {
|
||||||
for idx := range i.Operands {
|
for idx := range i.Operands {
|
||||||
@@ -117,6 +119,7 @@ func BindRegisters(fn *avo.Function) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyAllocation performs sanity checks following register allocation.
|
||||||
func VerifyAllocation(fn *avo.Function) error {
|
func VerifyAllocation(fn *avo.Function) error {
|
||||||
// All registers should be physical.
|
// All registers should be physical.
|
||||||
for _, i := range fn.Instructions() {
|
for _, i := range fn.Instructions() {
|
||||||
|
|||||||
Reference in New Issue
Block a user