pass: naive implementation of liveness

This commit is contained in:
Michael McLoughlin
2018-12-02 23:59:29 -08:00
parent 7d4e18f4f4
commit b52c67f3fb
8 changed files with 1093 additions and 1000 deletions

6
ast.go
View File

@@ -45,9 +45,13 @@ type Instruction struct {
// CFG. // CFG.
Pred []*Instruction Pred []*Instruction
Succ []*Instruction Succ []*Instruction
// LiveIn/LiveOut are sets of live register IDs pre/post execution.
LiveIn map[reg.ID]bool
LiveOut map[reg.ID]bool
} }
func (i Instruction) node() {} func (i *Instruction) node() {}
func (i Instruction) TargetLabel() *Label { func (i Instruction) TargetLabel() *Label {
if !i.IsBranch { if !i.IsBranch {

View File

@@ -25,7 +25,7 @@ func (c *Context) Function(name string) {
c.file.Functions = append(c.file.Functions, c.function) c.file.Functions = append(c.file.Functions, c.function)
} }
func (c *Context) Instruction(i avo.Instruction) { func (c *Context) Instruction(i *avo.Instruction) {
c.node(i) c.node(i)
} }

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@ func (b *build) instruction(i inst.Instruction) {
// Context method. // Context method.
b.Printf("func (c *Context) %s(%s) {\n", i.Opcode, s.ParameterList()) b.Printf("func (c *Context) %s(%s) {\n", i.Opcode, s.ParameterList())
b.Printf("if inst, err := x86.%s(%s); err == nil", i.Opcode, s.Arguments()) b.Printf("if inst, err := x86.%s(%s); err == nil", i.Opcode, s.Arguments())
b.Printf(" { c.Instruction(*inst) }") b.Printf(" { c.Instruction(inst) }")
b.Printf(" else { c.AddError(err) }\n") b.Printf(" else { c.AddError(err) }\n")
b.Printf("}\n") b.Printf("}\n")

62
pass/reg.go Normal file
View File

@@ -0,0 +1,62 @@
package pass
import (
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/reg"
)
// Liveness computes register liveness.
func Liveness(fn *avo.Function) error {
is := fn.Instructions()
// Initialize to empty sets.
for _, i := range is {
i.LiveIn = map[reg.ID]bool{}
i.LiveOut = map[reg.ID]bool{}
}
// Iterative dataflow analysis.
for {
changes := false
for _, i := range is {
// in[n] = use[n] UNION (out[n] - def[n])
nin := len(i.LiveIn)
for _, r := range i.InputRegisters() {
i.LiveIn[r.ID()] = true
}
def := map[reg.ID]bool{}
for _, r := range i.OutputRegisters() {
def[r.ID()] = true
}
for id := range i.LiveOut {
if !def[id] {
i.LiveIn[id] = true
}
}
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
}
for id := range s.LiveIn {
i.LiveOut[id] = true
}
}
if len(i.LiveOut) != nout {
changes = true
}
}
if !changes {
break
}
}
return nil
}

View File

@@ -73,7 +73,7 @@ func (p *GoPrinter) function(f *Function) {
for _, node := range f.Nodes { for _, node := range f.Nodes {
switch n := node.(type) { switch n := node.(type) {
case Instruction: case *Instruction:
p.printf("\t%s\t%s\n", n.Opcode, joinOperands(n.Operands)) p.printf("\t%s\t%s\n", n.Opcode, joinOperands(n.Operands))
case Label: case Label:
p.printf("%s:\n", n) p.printf("%s:\n", n)

View File

@@ -22,3 +22,15 @@ func TestSpecBytes(t *testing.T) {
} }
} }
} }
func TestVirtualPhysicalHaveDifferentIDs(t *testing.T) {
// Confirm that ID() returns different results even when virtual and physical IDs are the same.
var v Virtual = virtual{id: 42}
var p Physical = register{id: 42}
if uint16(v.VirtualID()) != uint16(p.PhysicalID()) {
t.Fatal("test assumption violated: VirtualID and PhysicalID should agree")
}
if v.ID() == p.ID() {
t.Errorf("virtual and physical IDs should be different")
}
}

View File

@@ -1,6 +1,9 @@
package reg package reg
import "fmt" import (
"fmt"
"math"
)
type Size uint type Size uint
@@ -23,7 +26,7 @@ type Family struct {
registers []Physical registers []Physical
} }
func (f *Family) define(s Spec, id uint16, name string) Physical { func (f *Family) define(s Spec, id PID, name string) Physical {
r := register{ r := register{
id: id, id: id,
kind: f.Kind, kind: f.Kind,
@@ -34,7 +37,7 @@ func (f *Family) define(s Spec, id uint16, name string) Physical {
return r return r
} }
func (f *Family) Virtual(id uint16, s Size) Virtual { func (f *Family) Virtual(id VID, s Size) Virtual {
return virtual{ return virtual{
id: id, id: id,
kind: f.Kind, kind: f.Kind,
@@ -46,7 +49,14 @@ type private interface {
private() private()
} }
type (
ID uint32
VID uint16
PID uint16
)
type Register interface { type Register interface {
ID() ID
Kind() Kind Kind() Kind
Bytes() uint Bytes() uint
Asm() string Asm() string
@@ -54,18 +64,22 @@ type Register interface {
} }
type Virtual interface { type Virtual interface {
VirtualID() uint16 VirtualID() VID
Register Register
} }
type virtual struct { type virtual struct {
id uint16 id VID
kind Kind kind Kind
Size Size
} }
func (v virtual) VirtualID() uint16 { return v.id } func (v virtual) VirtualID() VID { return v.id }
func (v virtual) Kind() Kind { return v.kind } func (v virtual) Kind() Kind { return v.kind }
func (v virtual) ID() ID {
return (ID(math.MaxUint16) << 16) | ID(v.VirtualID())
}
func (v virtual) Asm() string { func (v virtual) Asm() string {
// TODO(mbm): decide on virtual register syntax // TODO(mbm): decide on virtual register syntax
@@ -75,22 +89,23 @@ func (v virtual) Asm() string {
func (v virtual) private() {} func (v virtual) private() {}
type Physical interface { type Physical interface {
PhysicalID() uint16 PhysicalID() PID
Mask() uint16 Mask() uint16
Register Register
} }
type register struct { type register struct {
id uint16 id PID
kind Kind kind Kind
name string name string
Spec Spec
} }
func (r register) PhysicalID() uint16 { return r.id } func (r register) PhysicalID() PID { return r.id }
func (r register) Kind() Kind { return r.kind } func (r register) ID() ID { return ID(r.id) }
func (r register) Asm() string { return r.name } func (r register) Kind() Kind { return r.kind }
func (r register) private() {} func (r register) Asm() string { return r.name }
func (r register) private() {}
type Spec uint16 type Spec uint16