373 lines
8.4 KiB
Go
373 lines
8.4 KiB
Go
package regalloc
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Following mock types are used for testing.
|
|
type (
|
|
// mockFunction implements Function.
|
|
mockFunction struct {
|
|
iter int
|
|
blocks []*mockBlock
|
|
befores, afters []storeOrReloadInfo
|
|
lnfRoots []*mockBlock
|
|
}
|
|
|
|
storeOrReloadInfo struct {
|
|
reload bool
|
|
v VReg
|
|
instr Instr
|
|
}
|
|
|
|
// mockBlock implements Block.
|
|
mockBlock struct {
|
|
id int32
|
|
instructions []*mockInstr
|
|
preds, succs []*mockBlock
|
|
_preds, _succs []Block
|
|
iter int
|
|
_entry bool
|
|
_loop bool
|
|
lnfChildren []*mockBlock
|
|
blockParams []VReg
|
|
}
|
|
|
|
// mockInstr implements Instr.
|
|
mockInstr struct {
|
|
next, prev *mockInstr
|
|
defs, uses []VReg
|
|
isCopy, isCall, isIndirect bool
|
|
}
|
|
)
|
|
|
|
func (m *mockFunction) LowestCommonAncestor(blk1, blk2 Block) Block { panic("TODO") }
|
|
|
|
func (m *mockFunction) Idom(blk Block) Block { panic("TODO") }
|
|
|
|
func (m *mockFunction) SwapAtEndOfBlock(x1, x2, tmp VReg, block Block) { panic("TODO") }
|
|
|
|
func (m *mockFunction) InsertMoveBefore(dst, src VReg, instr Instr) { panic("TODO") }
|
|
|
|
func newMockFunction(blocks ...*mockBlock) *mockFunction {
|
|
return &mockFunction{blocks: blocks}
|
|
}
|
|
|
|
func (m *mockFunction) loopNestingForestRoots(blocks ...*mockBlock) {
|
|
m.lnfRoots = blocks
|
|
}
|
|
|
|
func newMockBlock(id int32, instructions ...*mockInstr) *mockBlock {
|
|
if len(instructions) > 0 {
|
|
instructions[0].prev = nil
|
|
for i := 1; i < len(instructions); i++ {
|
|
instructions[i].prev = instructions[i-1]
|
|
instructions[i-1].next = instructions[i]
|
|
}
|
|
instructions[len(instructions)-1].next = nil
|
|
}
|
|
return &mockBlock{id: id, instructions: instructions}
|
|
}
|
|
|
|
func newMockInstr() *mockInstr {
|
|
return &mockInstr{}
|
|
}
|
|
|
|
// String implements fmt.Stringer for debugging.
|
|
func (m *mockFunction) String() string {
|
|
var block []string
|
|
for _, b := range m.blocks {
|
|
block = append(block, "\t"+b.String())
|
|
}
|
|
return fmt.Sprintf("mockFunction:\n%s", strings.Join(block, ",\n"))
|
|
}
|
|
|
|
// String implements fmt.Stringer for debugging.
|
|
func (m *mockInstr) String() string {
|
|
return fmt.Sprintf("mockInstr{defs=%v, uses=%v}", m.defs, m.uses)
|
|
}
|
|
|
|
// String implements fmt.Stringer for debugging.
|
|
func (m *mockBlock) String() string {
|
|
var preds []int32
|
|
for _, p := range m.preds {
|
|
preds = append(preds, p.id)
|
|
}
|
|
return fmt.Sprintf("mockBlock{\n\tid=%v,\n\tinstructions=%v,\n\tpreds=%v,\n}", m.id, preds, m.instructions)
|
|
}
|
|
|
|
func (m *mockBlock) addPred(b *mockBlock) {
|
|
m.preds = append(m.preds, b)
|
|
m._preds = append(m._preds, b)
|
|
b._succs = append(b._succs, m)
|
|
b.succs = append(b.succs, m)
|
|
}
|
|
|
|
func (m *mockInstr) use(uses ...VReg) *mockInstr {
|
|
m.uses = uses
|
|
return m
|
|
}
|
|
|
|
func (m *mockInstr) def(defs ...VReg) *mockInstr {
|
|
m.defs = defs
|
|
return m
|
|
}
|
|
|
|
func (m *mockBlock) loop(children ...*mockBlock) *mockBlock {
|
|
m._loop = true
|
|
m.lnfChildren = children
|
|
return m
|
|
}
|
|
|
|
func (m *mockBlock) entry() *mockBlock {
|
|
m._entry = true
|
|
return m
|
|
}
|
|
|
|
func (m *mockInstr) asCopy() *mockInstr {
|
|
m.isCopy = true
|
|
return m
|
|
}
|
|
|
|
func (m *mockInstr) asCall() *mockInstr { //nolint:unused
|
|
m.isCall = true
|
|
return m
|
|
}
|
|
|
|
func (m *mockInstr) asIndirectCall() *mockInstr { //nolint:unused
|
|
m.isIndirect = true
|
|
return m
|
|
}
|
|
|
|
// StoreRegisterAfter implements Function.StoreRegisterAfter.
|
|
func (m *mockFunction) StoreRegisterAfter(v VReg, instr Instr) {
|
|
m.afters = append(m.afters, storeOrReloadInfo{false, v, instr})
|
|
}
|
|
|
|
// ReloadRegisterBefore implements Function.ReloadRegisterBefore.
|
|
func (m *mockFunction) ReloadRegisterBefore(v VReg, instr Instr) {
|
|
m.befores = append(m.befores, storeOrReloadInfo{true, v, instr})
|
|
}
|
|
|
|
// StoreRegisterBefore implements Function.StoreRegisterBefore.
|
|
func (m *mockFunction) StoreRegisterBefore(v VReg, instr Instr) {
|
|
m.befores = append(m.befores, storeOrReloadInfo{false, v, instr})
|
|
}
|
|
|
|
// ReloadRegisterAfter implements Function.ReloadRegisterAfter.
|
|
func (m *mockFunction) ReloadRegisterAfter(v VReg, instr Instr) {
|
|
m.afters = append(m.afters, storeOrReloadInfo{true, v, instr})
|
|
}
|
|
|
|
// ClobberedRegisters implements Function.ClobberedRegisters.
|
|
func (m *mockFunction) ClobberedRegisters(regs []VReg) {
|
|
// TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
// Done implements Function.Done.
|
|
func (m *mockFunction) Done() {}
|
|
|
|
// PostOrderBlockIteratorBegin implements Block.
|
|
func (m *mockFunction) PostOrderBlockIteratorBegin() Block {
|
|
m.iter = 1
|
|
l := len(m.blocks)
|
|
return m.blocks[l-1]
|
|
}
|
|
|
|
// PostOrderBlockIteratorNext implements Block.
|
|
func (m *mockFunction) PostOrderBlockIteratorNext() Block {
|
|
if m.iter == len(m.blocks) {
|
|
return nil
|
|
}
|
|
l := len(m.blocks)
|
|
ret := m.blocks[l-m.iter-1]
|
|
m.iter++
|
|
return ret
|
|
}
|
|
|
|
// ReversePostOrderBlockIteratorBegin implements Block.
|
|
func (m *mockFunction) ReversePostOrderBlockIteratorBegin() Block {
|
|
m.iter = 1
|
|
return m.blocks[0]
|
|
}
|
|
|
|
// ReversePostOrderBlockIteratorNext implements Block.
|
|
func (m *mockFunction) ReversePostOrderBlockIteratorNext() Block {
|
|
if m.iter == len(m.blocks) {
|
|
return nil
|
|
}
|
|
ret := m.blocks[m.iter]
|
|
m.iter++
|
|
return ret
|
|
}
|
|
|
|
// ID implements Block.
|
|
func (m *mockBlock) ID() int32 {
|
|
return m.id
|
|
}
|
|
|
|
// InstrIteratorBegin implements Block.
|
|
func (m *mockBlock) InstrIteratorBegin() Instr {
|
|
if len(m.instructions) == 0 {
|
|
return nil
|
|
}
|
|
m.iter = 1
|
|
return m.instructions[0]
|
|
}
|
|
|
|
// InstrIteratorNext implements Block.
|
|
func (m *mockBlock) InstrIteratorNext() Instr {
|
|
if m.iter == len(m.instructions) {
|
|
return nil
|
|
}
|
|
ret := m.instructions[m.iter]
|
|
m.iter++
|
|
return ret
|
|
}
|
|
|
|
// InstrRevIteratorBegin implements Block.
|
|
func (m *mockBlock) InstrRevIteratorBegin() Instr {
|
|
if len(m.instructions) == 0 {
|
|
return nil
|
|
}
|
|
m.iter = len(m.instructions)
|
|
return m.InstrRevIteratorNext()
|
|
}
|
|
|
|
// InstrRevIteratorNext implements Block.
|
|
func (m *mockBlock) InstrRevIteratorNext() Instr {
|
|
m.iter--
|
|
if m.iter < 0 {
|
|
return nil
|
|
}
|
|
return m.instructions[m.iter]
|
|
}
|
|
|
|
// Preds implements Block.
|
|
func (m *mockBlock) Preds() int {
|
|
return len(m._preds)
|
|
}
|
|
|
|
// BlockParams implements Block.
|
|
func (m *mockBlock) BlockParams(ret *[]VReg) []VReg {
|
|
*ret = append((*ret)[:0], m.blockParams...)
|
|
return *ret
|
|
}
|
|
|
|
func (m *mockBlock) blockParam(v VReg) {
|
|
m.blockParams = append(m.blockParams, v)
|
|
}
|
|
|
|
// Pred implements Instr.
|
|
func (m *mockBlock) Pred(i int) Block { return m._preds[i] }
|
|
|
|
// Defs implements Instr.
|
|
func (m *mockInstr) Defs(ret *[]VReg) []VReg {
|
|
*ret = append((*ret)[:0], m.defs...)
|
|
return *ret
|
|
}
|
|
|
|
// AddedBeforeRegAlloc implements Instr.
|
|
func (m *mockInstr) AddedBeforeRegAlloc() bool { return true }
|
|
|
|
// Uses implements Instr.
|
|
func (m *mockInstr) Uses(ret *[]VReg) []VReg {
|
|
*ret = append((*ret)[:0], m.uses...)
|
|
return *ret
|
|
}
|
|
|
|
// IsCopy implements Instr.
|
|
func (m *mockInstr) IsCopy() bool { return m.isCopy }
|
|
|
|
// IsCall implements Instr.
|
|
func (m *mockInstr) IsCall() bool { return m.isCall }
|
|
|
|
// IsIndirectCall implements Instr.
|
|
func (m *mockInstr) IsIndirectCall() bool { return m.isIndirect }
|
|
|
|
// IsReturn implements Instr.
|
|
func (m *mockInstr) IsReturn() bool { return false }
|
|
|
|
// Next implements Instr.
|
|
func (m *mockInstr) Next() Instr { return m.next }
|
|
|
|
// Prev implements Instr.
|
|
func (m *mockInstr) Prev() Instr { return m.prev }
|
|
|
|
// Entry implements Entry.
|
|
func (m *mockBlock) Entry() bool { return m._entry }
|
|
|
|
// AssignUses implements Instr.
|
|
func (m *mockInstr) AssignUse(index int, reg VReg) {
|
|
if index >= len(m.uses) {
|
|
m.uses = append(m.uses, make([]VReg, 5)...)
|
|
}
|
|
m.uses[index] = reg
|
|
}
|
|
|
|
// AssignDef implements Instr.
|
|
func (m *mockInstr) AssignDef(reg VReg) {
|
|
m.defs = []VReg{reg}
|
|
}
|
|
|
|
var (
|
|
_ Function = (*mockFunction)(nil)
|
|
_ Block = (*mockBlock)(nil)
|
|
_ Instr = (*mockInstr)(nil)
|
|
)
|
|
|
|
func (m *mockFunction) LoopNestingForestRoots() int {
|
|
return len(m.lnfRoots)
|
|
}
|
|
|
|
func (m *mockFunction) LoopNestingForestRoot(i int) Block {
|
|
return m.lnfRoots[i]
|
|
}
|
|
|
|
func (m *mockBlock) LoopHeader() bool {
|
|
return m._loop
|
|
}
|
|
|
|
func (m *mockBlock) Succs() int {
|
|
return len(m.succs)
|
|
}
|
|
|
|
func (m *mockBlock) Succ(i int) Block {
|
|
return m.succs[i]
|
|
}
|
|
|
|
func (m *mockBlock) LoopNestingForestChildren() int {
|
|
return len(m.lnfChildren)
|
|
}
|
|
|
|
func (m *mockBlock) LoopNestingForestChild(i int) Block {
|
|
return m.lnfChildren[i]
|
|
}
|
|
|
|
func (m *mockBlock) BeginInstr() Instr {
|
|
if len(m.instructions) == 0 {
|
|
return nil
|
|
}
|
|
return m.instructions[0]
|
|
}
|
|
|
|
func (m *mockBlock) EndInstr() Instr {
|
|
if len(m.instructions) == 0 {
|
|
return nil
|
|
}
|
|
return m.instructions[len(m.instructions)-1]
|
|
}
|
|
|
|
func (m *mockBlock) LastInstrForInsertion() Instr {
|
|
if len(m.instructions) == 0 {
|
|
return nil
|
|
}
|
|
return m.instructions[len(m.instructions)-1]
|
|
}
|
|
|
|
func (m *mockBlock) FirstInstr() Instr {
|
|
return m.instructions[0]
|
|
}
|