Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980package codegen
import ( "slices"
"git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/ssa")
// insertPhiMoves moves all live values that are part of a Phi instruction// from their current register to the Phi target register.// It must be called right before a Jump instruction.func (f *Function) insertPhiMoves(step *Step) { var ( moves []*asm.Move sourceSteps = map[cpu.Register]*Step{} destinationSteps = map[cpu.Register]*Step{} )
for _, live := range step.Live { for phi := range live.Phis.All() { if live.Register == phi.Register { continue }
predecessors := phi.Block.Predecessors
if !slices.Contains(predecessors, step.Block) { continue }
matches := false
for index, value := range phi.Value.(*ssa.Phi).Arguments { if value == live.Value && predecessors[index] == step.Block { matches = true break } }
if !matches { continue }
destinationSteps[phi.Register] = phi sourceSteps[live.Register] = live
moves = append(moves, &asm.Move{ Destination: phi.Register, Source: live.Register, }) } }
free := f.freeTempRegisters(step.Live) scheduled, ok := ScheduleMoves(moves, free)
if !ok { panic("no free register for move scheduling") }
for _, move := range scheduled { source := move.Source destination := move.Destination
switch { case f.isSpilled(source) && f.isSpilled(destination): tmp := f.findTempRegister(step.Live) f.loadSpill(sourceSteps[source], tmp) f.storeSpill(destinationSteps[destination], tmp) case f.isSpilled(source): f.loadSpill(sourceSteps[source], destination) case f.isSpilled(destination): f.storeSpill(destinationSteps[destination], source) default: f.Assembler.Append(move) } }}