diff --git a/src/codegen/clobberedRegisters.go b/src/codegen/clobberedRegisters.go index 9773b96..b9c0c20 100644 --- a/src/codegen/clobberedRegisters.go +++ b/src/codegen/clobberedRegisters.go @@ -7,8 +7,8 @@ import ( ) // clobberedRegisters returns the registers that are clobbered by the given instruction. -func (f *Function) clobberedRegisters(instr ssa.Value) []cpu.Register { - switch instr := instr.(type) { +func (f *Function) clobberedRegisters(step *Step) []cpu.Register { + switch instr := step.Value.(type) { case *ssa.BinaryOp: switch instr.Op { case token.Div, token.Mod: @@ -18,6 +18,8 @@ func (f *Function) clobberedRegisters(instr ssa.Value) []cpu.Register { default: return nil } + case *ssa.Branch, *ssa.Jump: + return phiMoveClobbered(step) case *ssa.Call: return f.CPU.Call.Clobbered case *ssa.CallExtern: diff --git a/src/codegen/findFreeRegister.go b/src/codegen/findFreeRegister.go index ef9dc37..d26131d 100644 --- a/src/codegen/findFreeRegister.go +++ b/src/codegen/findFreeRegister.go @@ -117,7 +117,7 @@ func (f *Function) findFreeRegister(step *Step) cpu.Register { // Find all the registers that this instruction // would clobber and mark them as used. - for _, reg := range f.clobberedRegisters(current.Value) { + for _, reg := range f.clobberedRegisters(current) { usedRegisters.Set(reg) } } @@ -146,4 +146,4 @@ func (f *Function) findFreeRegister(step *Step) cpu.Register { } panic("no free registers") -} +} \ No newline at end of file diff --git a/src/codegen/fixRegisterConflicts.go b/src/codegen/fixRegisterConflicts.go index 1d1c7c1..9fb566c 100644 --- a/src/codegen/fixRegisterConflicts.go +++ b/src/codegen/fixRegisterConflicts.go @@ -40,7 +40,7 @@ func (f *Function) fixRegisterConflicts() { } } - clobbered := f.clobberedRegisters(step.Value) + clobbered := f.clobberedRegisters(step) for i, live := range step.Live { if live.Register == -1 { diff --git a/src/codegen/insertPhiMoves.go b/src/codegen/insertPhiMoves.go index a257444..a87753d 100644 --- a/src/codegen/insertPhiMoves.go +++ b/src/codegen/insertPhiMoves.go @@ -20,6 +20,10 @@ func (f *Function) insertPhiMoves(step *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) { diff --git a/src/codegen/phiMoveClobbered.go b/src/codegen/phiMoveClobbered.go new file mode 100644 index 0000000..65edc1c --- /dev/null +++ b/src/codegen/phiMoveClobbered.go @@ -0,0 +1,32 @@ +package codegen + +import ( + "slices" + + "git.urbach.dev/cli/q/src/cpu" +) + +// phiMoveClobbered returns the destinations of phi moves. +func phiMoveClobbered(step *Step) []cpu.Register { + var clobbered []cpu.Register + + for _, live := range step.Live { + for phi := range live.Phis.All() { + if live.Register == phi.Register { + continue + } + + if slices.Contains(clobbered, phi.Register) { + continue + } + + if !slices.Contains(phi.Block.Predecessors, step.Block) { + continue + } + + clobbered = append(clobbered, phi.Register) + } + } + + return clobbered +} \ No newline at end of file diff --git a/tests/phi-reassign-copy.q b/tests/phi-reassign-copy.q new file mode 100644 index 0000000..c7ee621 --- /dev/null +++ b/tests/phi-reassign-copy.q @@ -0,0 +1,11 @@ +main() { + a := 4 + b := 8 + c := 7 + + if a != b { + c = a + } + + assert c == 4 +} \ No newline at end of file diff --git a/tests/tests_test.go b/tests/tests_test.go index 1572cd2..6b13913 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -56,6 +56,7 @@ var tests = []run{ {"phi-advanced", nil, "", "", 0}, {"phi-reassign", nil, "", "", 0}, {"phi-reassign-output", nil, "", "12345", 0}, + {"phi-reassign-copy", nil, "", "", 0}, {"phi-move-cycle", nil, "", "0\n14\n0\n", 0}, {"phi-move-reorder", nil, "", "0\n14\n0\n", 0}, {"min", nil, "", "", 0},