Skip to content

Commit

Permalink
Fixes fixes fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ziflex committed Nov 5, 2024
1 parent 51f8593 commit 9ceb596
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 444 deletions.
154 changes: 13 additions & 141 deletions pkg/compiler/allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ type (
// RegisterStatus tracks register usage
RegisterStatus struct {
IsAllocated bool
LastUse int // Instruction number of last use
NextUse int // Instruction number of next use
Type RegisterType // Type of variable stored
Lifetime *RegisterLifetime // Lifetime information
Type RegisterType // Type of variable stored
}

RegisterLifetime struct {
Expand All @@ -22,32 +19,27 @@ type (

RegisterSequence struct {
Registers []runtime.Operand
Lifetime *RegisterLifetime
}

// RegisterAllocator manages register allocation
RegisterAllocator struct {
registers map[runtime.Operand]*RegisterStatus
nextRegister runtime.Operand
currentInstr int
lifetimes map[string]*RegisterLifetime
usageGraph map[runtime.Operand]map[runtime.Operand]bool
}
)

const (
Temp RegisterType = iota // Short-lived intermediate results
Var // Local variables
Iter // FOR loop iterators
Result // Final result variables
State // FOR loop state
Result // FOR loop result
)

func NewRegisterAllocator() *RegisterAllocator {
return &RegisterAllocator{
registers: make(map[runtime.Operand]*RegisterStatus),
nextRegister: runtime.NoopOperand + 1, // we start at 1 to avoid NoopOperand
lifetimes: make(map[string]*RegisterLifetime),
usageGraph: make(map[runtime.Operand]map[runtime.Operand]bool),
}
}

Expand All @@ -67,28 +59,25 @@ func (ra *RegisterAllocator) Allocate(regType RegisterType) runtime.Operand {
// Initialize register status
ra.registers[newReg] = &RegisterStatus{
IsAllocated: true,
LastUse: ra.currentInstr,
NextUse: -1,
Type: regType,
Lifetime: &RegisterLifetime{Start: ra.currentInstr},
}

return newReg
}

// Free marks a register as available
func (ra *RegisterAllocator) Free(reg runtime.Operand) {
if status, exists := ra.registers[reg]; exists {
status.IsAllocated = false
status.Lifetime.End = ra.currentInstr
//if status, exists := ra.registers[reg]; exists {
//status.IsAllocated = false
//status.Lifetime.End = ra.currentInstr

// Clean up interference graph
delete(ra.usageGraph, reg)

for _, edges := range ra.usageGraph {
delete(edges, reg)
}
}
//// Clean up interference graph
//delete(ra.usageGraph, reg)
//
//for _, edges := range ra.usageGraph {
// delete(edges, reg)
//}
//}
}

// findFreeRegister looks for an unused register
Expand All @@ -100,58 +89,13 @@ func (ra *RegisterAllocator) findFreeRegister() (runtime.Operand, bool) {
}
}

// TODO: Implement register reuse
// If no free registers, try to find one that's no longer needed
//var candidate runtime.Operand
//var found bool
//maxLastUse := -1
//
//for reg, status := range ra.registers {
// if status.NextUse == -1 && status.LastUse > maxLastUse {
// maxLastUse = status.LastUse
// candidate = reg
// found = true
// }
//}
//
//if found {
// // Free the candidate register
// ra.Free(candidate)
//
// return candidate, true
//}

return 0, false
}

// UpdateUse updates the usage information for a register
func (ra *RegisterAllocator) UpdateUse(reg runtime.Operand) {
status := ra.registers[reg]

if status == nil {
return
}

status.LastUse = ra.currentInstr

// Update interference graph for simultaneously live registers
for otherReg, otherStatus := range ra.registers {
if otherReg != reg && otherStatus.IsAllocated &&
ra.registersInterfere(reg, otherReg) {
ra.addInterference(reg, otherReg)
}
}

ra.currentInstr++
}

// AllocateSequence allocates a sequence of registers for function arguments or similar uses
func (ra *RegisterAllocator) AllocateSequence(count int) *RegisterSequence {
sequence := &RegisterSequence{
Registers: make([]runtime.Operand, count),
Lifetime: &RegisterLifetime{
Start: ra.currentInstr,
},
}

// First pass: try to find contiguous free registers
Expand All @@ -166,12 +110,7 @@ func (ra *RegisterAllocator) AllocateSequence(count int) *RegisterSequence {
// Initialize or update register status
ra.registers[reg] = &RegisterStatus{
IsAllocated: true,
LastUse: ra.currentInstr,
NextUse: -1,
Type: Temp,
Lifetime: &RegisterLifetime{
Start: ra.currentInstr,
},
}
}
} else {
Expand All @@ -182,9 +121,6 @@ func (ra *RegisterAllocator) AllocateSequence(count int) *RegisterSequence {
}
}

// Update interference graph for the sequence
ra.updateSequenceInterference(sequence)

return sequence
}

Expand Down Expand Up @@ -221,73 +157,9 @@ func (ra *RegisterAllocator) isContiguousBlockFree(start runtime.Operand, count
return true
}

// updateSequenceInterference updates interference information for sequence registers
func (ra *RegisterAllocator) updateSequenceInterference(seq *RegisterSequence) {
// Add interference between sequence registers
for i := 0; i < len(seq.Registers); i++ {
for j := i + 1; j < len(seq.Registers); j++ {
ra.addInterference(seq.Registers[i], seq.Registers[j])
}
}

// Add interference with other live registers
for _, seqReg := range seq.Registers {
for otherReg, otherStatus := range ra.registers {
if otherStatus.IsAllocated {
found := false
for _, r := range seq.Registers {
if r == otherReg {
found = true
break
}
}
if !found {
ra.addInterference(seqReg, otherReg)
}
}
}
}
}

// FreeSequence frees all registers in a sequence
func (ra *RegisterAllocator) FreeSequence(seq *RegisterSequence) {
seq.Lifetime.End = ra.currentInstr

for _, reg := range seq.Registers {
ra.Free(reg)
}
}

// UpdateSequenceUse updates usage information for all registers in a sequence
func (ra *RegisterAllocator) UpdateSequenceUse(seq *RegisterSequence) {
for _, reg := range seq.Registers {
ra.UpdateUse(reg)
}
}

// registersInterfere checks if two registers have overlapping lifetimes
func (ra *RegisterAllocator) registersInterfere(reg1, reg2 runtime.Operand) bool {
status1 := ra.registers[reg1]
status2 := ra.registers[reg2]

if status1 == nil || status2 == nil {
return false
}

// Registers interfere if their lifetimes overlap
return status1.Lifetime.Start <= status2.Lifetime.End &&
status2.Lifetime.Start <= status1.Lifetime.End
}

// addInterference records that two registers interfere
func (ra *RegisterAllocator) addInterference(reg1, reg2 runtime.Operand) {
if ra.usageGraph[reg1] == nil {
ra.usageGraph[reg1] = make(map[runtime.Operand]bool)
}
if ra.usageGraph[reg2] == nil {
ra.usageGraph[reg2] = make(map[runtime.Operand]bool)
}

ra.usageGraph[reg1][reg2] = true
ra.usageGraph[reg2][reg1] = true
}
Loading

0 comments on commit 9ceb596

Please sign in to comment.