63 lines
1.1 KiB
Go
63 lines
1.1 KiB
Go
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
|
|
}
|