ast: move "ast" types from root to ir sub-package

Closes #32
This commit is contained in:
Michael McLoughlin
2019-01-06 14:21:10 -08:00
parent 4a920c22b5
commit 0f63e0906d
15 changed files with 3925 additions and 3925 deletions

View File

@@ -4,16 +4,16 @@ import (
"errors"
"fmt"
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/ir"
)
// LabelTarget populates the LabelTarget of the given function. This maps from
// label name to the following instruction.
func LabelTarget(fn *avo.Function) error {
target := map[avo.Label]*avo.Instruction{}
func LabelTarget(fn *ir.Function) error {
target := map[ir.Label]*ir.Instruction{}
for idx := 0; idx < len(fn.Nodes); idx++ {
// Is this a label?
lbl, ok := fn.Nodes[idx].(avo.Label)
lbl, ok := fn.Nodes[idx].(ir.Label)
if !ok {
continue
}
@@ -27,7 +27,7 @@ func LabelTarget(fn *avo.Function) error {
}
idx++
// Should be an instruction.
i, ok := fn.Nodes[idx].(*avo.Instruction)
i, ok := fn.Nodes[idx].(*ir.Instruction)
if !ok {
return errors.New("instruction should follow a label")
}
@@ -38,14 +38,14 @@ func LabelTarget(fn *avo.Function) error {
}
// CFG constructs the call-flow-graph for the function.
func CFG(fn *avo.Function) error {
func CFG(fn *ir.Function) error {
is := fn.Instructions()
n := len(is)
// Populate successors.
for i := 0; i < n; i++ {
cur := is[i]
var nxt *avo.Instruction
var nxt *ir.Instruction
if i+1 < n {
nxt = is[i+1]
}

View File

@@ -5,22 +5,21 @@ import (
"sort"
"testing"
"github.com/mmcloughlin/avo/ir"
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo"
)
func TestLabelTarget(t *testing.T) {
expect := map[avo.Label]*avo.Instruction{
expect := map[ir.Label]*ir.Instruction{
"lblA": {Opcode: "A"},
"lblB": {Opcode: "B"},
}
f := avo.NewFunction("happypath")
f := ir.NewFunction("happypath")
for lbl, i := range expect {
f.AddLabel(lbl)
f.AddInstruction(i)
f.AddInstruction(&avo.Instruction{Opcode: "IDK"})
f.AddInstruction(&ir.Instruction{Opcode: "IDK"})
}
if err := LabelTarget(f); err != nil {
@@ -33,11 +32,11 @@ func TestLabelTarget(t *testing.T) {
}
func TestLabelTargetDuplicate(t *testing.T) {
f := avo.NewFunction("dupelabel")
f.AddLabel(avo.Label("lblA"))
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddLabel(avo.Label("lblA"))
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f := ir.NewFunction("dupelabel")
f.AddLabel(ir.Label("lblA"))
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddLabel(ir.Label("lblA"))
f.AddInstruction(&ir.Instruction{Opcode: "A"})
err := LabelTarget(f)
@@ -47,9 +46,9 @@ func TestLabelTargetDuplicate(t *testing.T) {
}
func TestLabelTargetEndsWithLabel(t *testing.T) {
f := avo.NewFunction("endswithlabel")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddLabel(avo.Label("theend"))
f := ir.NewFunction("endswithlabel")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddLabel(ir.Label("theend"))
err := LabelTarget(f)
@@ -59,10 +58,10 @@ func TestLabelTargetEndsWithLabel(t *testing.T) {
}
func TestLabelTargetInstructionFollowLabel(t *testing.T) {
f := avo.NewFunction("expectinstafterlabel")
f.AddLabel(avo.Label("lblA"))
f.AddLabel(avo.Label("lblB"))
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f := ir.NewFunction("expectinstafterlabel")
f.AddLabel(ir.Label("lblA"))
f.AddLabel(ir.Label("lblB"))
f.AddInstruction(&ir.Instruction{Opcode: "A"})
err := LabelTarget(f)
@@ -72,9 +71,9 @@ func TestLabelTargetInstructionFollowLabel(t *testing.T) {
}
func TestCFGSingleBasicBlock(t *testing.T) {
f := avo.NewFunction("simple")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddInstruction(&avo.Instruction{Opcode: "B"})
f := ir.NewFunction("simple")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddInstruction(&ir.Instruction{Opcode: "B"})
f.AddInstruction(Terminal("RET"))
if err := ComputeCFG(t, f); err != nil {
@@ -95,11 +94,11 @@ func TestCFGSingleBasicBlock(t *testing.T) {
}
func TestCFGCondBranch(t *testing.T) {
f := avo.NewFunction("condbranch")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddLabel(avo.Label("lblB"))
f.AddInstruction(&avo.Instruction{Opcode: "B"})
f.AddInstruction(&avo.Instruction{Opcode: "C"})
f := ir.NewFunction("condbranch")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddLabel(ir.Label("lblB"))
f.AddInstruction(&ir.Instruction{Opcode: "B"})
f.AddInstruction(&ir.Instruction{Opcode: "C"})
f.AddInstruction(CondBranch("J", "lblB"))
f.AddInstruction(Terminal("RET"))
@@ -117,10 +116,10 @@ func TestCFGCondBranch(t *testing.T) {
}
func TestCFGUncondBranch(t *testing.T) {
f := avo.NewFunction("uncondbranch")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddLabel(avo.Label("lblB"))
f.AddInstruction(&avo.Instruction{Opcode: "B"})
f := ir.NewFunction("uncondbranch")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddLabel(ir.Label("lblB"))
f.AddInstruction(&ir.Instruction{Opcode: "B"})
f.AddInstruction(UncondBranch("JMP", "lblB"))
if err := ComputeCFG(t, f); err != nil {
@@ -135,11 +134,11 @@ func TestCFGUncondBranch(t *testing.T) {
}
func TestCFGJumpForward(t *testing.T) {
f := avo.NewFunction("forward")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f := ir.NewFunction("forward")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddInstruction(CondBranch("J", "done"))
f.AddInstruction(&avo.Instruction{Opcode: "B"})
f.AddLabel(avo.Label("done"))
f.AddInstruction(&ir.Instruction{Opcode: "B"})
f.AddLabel(ir.Label("done"))
f.AddInstruction(Terminal("RET"))
if err := ComputeCFG(t, f); err != nil {
@@ -155,13 +154,13 @@ func TestCFGJumpForward(t *testing.T) {
}
func TestCFGMultiReturn(t *testing.T) {
f := avo.NewFunction("multireturn")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f := ir.NewFunction("multireturn")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddInstruction(CondBranch("J", "fork"))
f.AddInstruction(&avo.Instruction{Opcode: "B"})
f.AddInstruction(&ir.Instruction{Opcode: "B"})
f.AddInstruction(Terminal("RET1"))
f.AddLabel(avo.Label("fork"))
f.AddInstruction(&avo.Instruction{Opcode: "C"})
f.AddLabel(ir.Label("fork"))
f.AddInstruction(&ir.Instruction{Opcode: "C"})
f.AddInstruction(Terminal("RET2"))
if err := ComputeCFG(t, f); err != nil {
@@ -179,8 +178,8 @@ func TestCFGMultiReturn(t *testing.T) {
}
func TestCFGShortLoop(t *testing.T) {
f := avo.NewFunction("shortloop")
f.AddLabel(avo.Label("cycle"))
f := ir.NewFunction("shortloop")
f.AddLabel(ir.Label("cycle"))
f.AddInstruction(UncondBranch("JMP", "cycle"))
if err := ComputeCFG(t, f); err != nil {
@@ -193,8 +192,8 @@ func TestCFGShortLoop(t *testing.T) {
}
func TestCFGUndefinedLabel(t *testing.T) {
f := avo.NewFunction("undeflabel")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f := ir.NewFunction("undeflabel")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddInstruction(CondBranch("J", "undef"))
err := ComputeCFG(t, f)
@@ -205,9 +204,9 @@ func TestCFGUndefinedLabel(t *testing.T) {
}
func TestCFGMissingLabel(t *testing.T) {
f := avo.NewFunction("missinglabel")
f.AddInstruction(&avo.Instruction{Opcode: "A"})
f.AddInstruction(&avo.Instruction{Opcode: "J", IsBranch: true}) // no label operand
f := ir.NewFunction("missinglabel")
f.AddInstruction(&ir.Instruction{Opcode: "A"})
f.AddInstruction(&ir.Instruction{Opcode: "J", IsBranch: true}) // no label operand
err := ComputeCFG(t, f)
if err == nil {
t.Fatal("expect error on missing label")
@@ -215,13 +214,13 @@ func TestCFGMissingLabel(t *testing.T) {
}
// Terminal builds a terminal instruction.
func Terminal(opcode string) *avo.Instruction {
return &avo.Instruction{Opcode: opcode, IsTerminal: true}
func Terminal(opcode string) *ir.Instruction {
return &ir.Instruction{Opcode: opcode, IsTerminal: true}
}
// CondBranch builds a conditional branch instruction to the given label.
func CondBranch(opcode, lbl string) *avo.Instruction {
return &avo.Instruction{
func CondBranch(opcode, lbl string) *ir.Instruction {
return &ir.Instruction{
Opcode: opcode,
Operands: []operand.Op{operand.LabelRef(lbl)},
IsBranch: true,
@@ -230,8 +229,8 @@ func CondBranch(opcode, lbl string) *avo.Instruction {
}
// UncondBranch builds an unconditional branch instruction to the given label.
func UncondBranch(opcode, lbl string) *avo.Instruction {
return &avo.Instruction{
func UncondBranch(opcode, lbl string) *ir.Instruction {
return &ir.Instruction{
Opcode: opcode,
Operands: []operand.Op{operand.LabelRef(lbl)},
IsBranch: true,
@@ -239,7 +238,7 @@ func UncondBranch(opcode, lbl string) *avo.Instruction {
}
}
func ComputeCFG(t *testing.T, f *avo.Function) error {
func ComputeCFG(t *testing.T, f *ir.Function) error {
t.Helper()
if err := LabelTarget(f); err != nil {
t.Fatal(err)
@@ -247,11 +246,11 @@ func ComputeCFG(t *testing.T, f *avo.Function) error {
return CFG(f)
}
func AssertSuccessors(t *testing.T, f *avo.Function, expect map[string][]string) {
func AssertSuccessors(t *testing.T, f *ir.Function, expect map[string][]string) {
AssertEqual(t, "successors", OpcodeSuccessorGraph(f), expect)
}
func AssertPredecessors(t *testing.T, f *avo.Function, expect map[string][]string) {
func AssertPredecessors(t *testing.T, f *ir.Function, expect map[string][]string) {
AssertEqual(t, "predecessors", OpcodePredecessorGraph(f), expect)
}
@@ -264,17 +263,17 @@ func AssertEqual(t *testing.T, what string, got, expect interface{}) {
}
// OpcodeSuccessorGraph builds a map from opcode name to successor opcode names.
func OpcodeSuccessorGraph(f *avo.Function) map[string][]string {
return OpcodeGraph(f, func(i *avo.Instruction) []*avo.Instruction { return i.Succ })
func OpcodeSuccessorGraph(f *ir.Function) map[string][]string {
return OpcodeGraph(f, func(i *ir.Instruction) []*ir.Instruction { return i.Succ })
}
// OpcodePredecessorGraph builds a map from opcode name to predecessor opcode names.
func OpcodePredecessorGraph(f *avo.Function) map[string][]string {
return OpcodeGraph(f, func(i *avo.Instruction) []*avo.Instruction { return i.Pred })
func OpcodePredecessorGraph(f *ir.Function) map[string][]string {
return OpcodeGraph(f, func(i *ir.Instruction) []*ir.Instruction { return i.Pred })
}
// OpcodeGraph builds a map from opcode name to neighboring opcode names. Each list of neighbors is sorted.
func OpcodeGraph(f *avo.Function, neighbors func(*avo.Instruction) []*avo.Instruction) map[string][]string {
func OpcodeGraph(f *ir.Function, neighbors func(*ir.Instruction) []*ir.Instruction) map[string][]string {
g := map[string][]string{}
for _, i := range f.Instructions() {
opcodes := []string{}

View File

@@ -4,7 +4,7 @@ package pass
import (
"io"
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/ir"
"github.com/mmcloughlin/avo/printer"
)
@@ -22,23 +22,23 @@ var Compile = Concat(
// Interface for a processing pass.
type Interface interface {
Execute(*avo.File) error
Execute(*ir.File) error
}
// Func adapts a function to the pass Interface.
type Func func(*avo.File) error
type Func func(*ir.File) error
// Execute calls p.
func (p Func) Execute(f *avo.File) error {
func (p Func) Execute(f *ir.File) error {
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(*ir.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 *ir.File) error {
for _, fn := range f.Functions() {
if err := p(fn); err != nil {
return err
@@ -49,7 +49,7 @@ func (p FunctionPass) Execute(f *avo.File) error {
// Concat returns a pass that executes the given passes in order, stopping on the first error.
func Concat(passes ...Interface) Interface {
return Func(func(f *avo.File) error {
return Func(func(f *ir.File) error {
for _, p := range passes {
if err := p.Execute(f); err != nil {
return err
@@ -66,7 +66,7 @@ type Output struct {
}
// 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 *ir.File) error {
b, err := o.Printer.Print(f)
if err != nil {
return err

View File

@@ -3,13 +3,13 @@ package pass
import (
"errors"
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/ir"
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
)
// Liveness computes register liveness.
func Liveness(fn *avo.Function) error {
func Liveness(fn *ir.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.
@@ -67,7 +67,7 @@ func Liveness(fn *avo.Function) error {
}
// AllocateRegisters performs register allocation.
func AllocateRegisters(fn *avo.Function) error {
func AllocateRegisters(fn *ir.Function) error {
// Populate allocators (one per kind).
as := map[reg.Kind]*Allocator{}
for _, i := range fn.Instructions() {
@@ -110,7 +110,7 @@ func AllocateRegisters(fn *avo.Function) error {
}
// 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 *ir.Function) error {
for _, i := range fn.Instructions() {
for idx := range i.Operands {
i.Operands[idx] = operand.ApplyAllocation(i.Operands[idx], fn.Allocation)
@@ -120,7 +120,7 @@ func BindRegisters(fn *avo.Function) error {
}
// VerifyAllocation performs sanity checks following register allocation.
func VerifyAllocation(fn *avo.Function) error {
func VerifyAllocation(fn *ir.Function) error {
// All registers should be physical.
for _, i := range fn.Instructions() {
for _, r := range i.Registers() {

View File

@@ -4,11 +4,11 @@ import (
"testing"
"github.com/mmcloughlin/avo/internal/test"
"github.com/mmcloughlin/avo/ir"
"github.com/mmcloughlin/avo/reg"
"github.com/mmcloughlin/avo/pass"
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/build"
"github.com/mmcloughlin/avo/operand"
)
@@ -57,7 +57,7 @@ func AssertRegistersMatchSet(t *testing.T, rs []reg.Register, s reg.Set) {
}
}
func ConstructLiveness(t *testing.T, ctx *build.Context) *avo.Function {
func ConstructLiveness(t *testing.T, ctx *build.Context) *ir.Function {
f, err := ctx.Result()
if err != nil {
build.LogError(test.Logger(t), err, 0)
@@ -70,7 +70,7 @@ func ConstructLiveness(t *testing.T, ctx *build.Context) *avo.Function {
}
fn := fns[0]
passes := []func(*avo.Function) error{
passes := []func(*ir.Function) error{
pass.LabelTarget,
pass.CFG,
pass.Liveness,

View File

@@ -1,12 +1,12 @@
package pass
import (
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/attr"
"github.com/mmcloughlin/avo/ir"
)
// IncludeTextFlagHeader includes textflag.h if necessary.
func IncludeTextFlagHeader(f *avo.File) error {
func IncludeTextFlagHeader(f *ir.File) error {
const textflagheader = "textflag.h"
// Check if we already have it.
@@ -25,13 +25,13 @@ func IncludeTextFlagHeader(f *avo.File) error {
}
// requirestextflags returns whether the file uses flags in the textflags.h header.
func requirestextflags(f *avo.File) bool {
func requirestextflags(f *ir.File) bool {
for _, s := range f.Sections {
var a attr.Attribute
switch s := s.(type) {
case *avo.Function:
case *ir.Function:
a = s.Attributes
case *avo.Global:
case *ir.Global:
a = s.Attributes
}
if a.ContainsTextFlags() {