pass: naive implementation of liveness
This commit is contained in:
6
ast.go
6
ast.go
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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
62
pass/reg.go
Normal 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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
41
reg/types.go
41
reg/types.go
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user