From 0866ff348d7c4f628a04207b896151cdec28bd1d Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 27 Aug 2026 20:50:45 +0200 Subject: [PATCH] Fixed temporary register selection --- src/codegen/executeBinaryOp.go | 4 +-- src/codegen/executeCas.go | 4 +-- src/codegen/executeLoad.go | 4 +-- src/codegen/executeStore.go | 4 +-- src/codegen/spill.go | 14 ++++++++-- tests/spill-operands.q | 50 ++++++++++++++++++++++++++++++++++ tests/tests_test.go | 1 + 7 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 tests/spill-operands.q diff --git a/src/codegen/executeBinaryOp.go b/src/codegen/executeBinaryOp.go index 6e4cb34..3f0ec35 100644 --- a/src/codegen/executeBinaryOp.go +++ b/src/codegen/executeBinaryOp.go @@ -15,12 +15,12 @@ func (f *Function) executeBinaryOp(step *Step, instr *ssa.BinaryOp) { right := f.ValueToStep[instr.Right] live := slices.Concat(step.Live, []*Step{left, right}) source := f.resolveOperand(left, live) - operand := f.resolveOperand(right, live) + operand := f.resolveOperand(right, live, source) destination := step.Register isSpilled := f.isSpilled(destination) if isSpilled { - destination = f.findTempRegister(live) + destination = f.findTempRegister(live, source, operand) } if instr.Op.IsComparison() { diff --git a/src/codegen/executeCas.go b/src/codegen/executeCas.go index 4dcb18a..e8812c1 100755 --- a/src/codegen/executeCas.go +++ b/src/codegen/executeCas.go @@ -15,8 +15,8 @@ func (f *Function) executeCas(step *Step, instr *ssa.Cas) { newValue := f.ValueToStep[instr.Arguments[2]] live := slices.Concat(step.Live, []*Step{address, oldValue, newValue}) addressRegister := f.resolveOperand(address, live) - oldValueRegister := f.resolveOperand(oldValue, live) - newValueRegister := f.resolveOperand(newValue, live) + oldValueRegister := f.resolveOperand(oldValue, live, addressRegister) + newValueRegister := f.resolveOperand(newValue, live, addressRegister, oldValueRegister) if f.build.Arch == config.X86 && oldValueRegister != x86.R0 { f.Assembler.Append(&asm.Move{ diff --git a/src/codegen/executeLoad.go b/src/codegen/executeLoad.go index e4fe01c..e6554c4 100644 --- a/src/codegen/executeLoad.go +++ b/src/codegen/executeLoad.go @@ -20,12 +20,12 @@ func (f *Function) executeLoad(step *Step, instr *ssa.Load) { elementSize := elementType.Size() live := slices.Concat(step.Live, []*Step{address, index}) baseRegister := f.resolveOperand(address, live) - indexRegister := f.resolveOperand(index, live) + indexRegister := f.resolveOperand(index, live, baseRegister) destination := step.Register isSpilled := f.isSpilled(destination) if isSpilled { - destination = f.findTempRegister(live) + destination = f.findTempRegister(live, baseRegister, indexRegister) } if index.Register == -1 { diff --git a/src/codegen/executeStore.go b/src/codegen/executeStore.go index d64a3e4..8995f55 100644 --- a/src/codegen/executeStore.go +++ b/src/codegen/executeStore.go @@ -14,8 +14,8 @@ func (f *Function) executeStore(step *Step, instr *ssa.Store) { source := f.ValueToStep[instr.Value] live := slices.Concat(step.Live, []*Step{address, index, source}) baseRegister := f.resolveOperand(address, live) - indexRegister := f.resolveOperand(index, live) - sourceRegister := f.resolveOperand(source, live) + indexRegister := f.resolveOperand(index, live, baseRegister) + sourceRegister := f.resolveOperand(source, live, baseRegister, indexRegister) if sourceRegister == -1 { if indexRegister == -1 { diff --git a/src/codegen/spill.go b/src/codegen/spill.go index b4d002a..3baeec2 100644 --- a/src/codegen/spill.go +++ b/src/codegen/spill.go @@ -8,7 +8,7 @@ import ( ) // findTempRegister finds a temporary physical register that is not in use. -func (f *Function) findTempRegister(liveSteps []*Step) cpu.Register { +func (f *Function) findTempRegister(liveSteps []*Step, avoid ...cpu.Register) cpu.Register { usedRegisters := bitSet(0) for _, live := range liveSteps { @@ -19,6 +19,14 @@ func (f *Function) findTempRegister(liveSteps []*Step) cpu.Register { usedRegisters.Set(live.Register) } + for _, reg := range avoid { + if reg == -1 { + continue + } + + usedRegisters.Set(reg) + } + for _, reg := range f.CPU.General { if !usedRegisters.Has(reg) { return reg @@ -70,12 +78,12 @@ func (f *Function) loadSpill(step *Step, destination cpu.Register) { // resolveOperand returns the register to use for an operand. // If the operand is spilled, it loads it from the stack first. -func (f *Function) resolveOperand(step *Step, liveSteps []*Step) cpu.Register { +func (f *Function) resolveOperand(step *Step, liveSteps []*Step, avoid ...cpu.Register) cpu.Register { if !f.isSpilled(step.Register) { return step.Register } - tmp := f.findTempRegister(liveSteps) + tmp := f.findTempRegister(liveSteps, avoid...) f.loadSpill(step, tmp) return tmp } diff --git a/tests/spill-operands.q b/tests/spill-operands.q new file mode 100644 index 0000000..f76e25e --- /dev/null +++ b/tests/spill-operands.q @@ -0,0 +1,50 @@ +import io + +Point { + x int + y int +} + +main() { + v0 := -15 + v1 := 19 + v2 := 29 + v3 := -38 + total := 0 + total += rsum(0) + p1, p2 := pair(v2, v1) + total += p1 - p2 + s := Point{x: 1, y: 3} + s.x += 3 + s.y = s.y * 2 + total += s.x + s.y + pa := new(Point, 3) + pa[0] = mk(p1, v3) + pa[1] = mk(v0, s.y) + pa[2] = mk(p2, v2) + total += pa[0].x - pa[0].y + + switch { + s.x > 0 { sel := 11 } + _ { sel := -4 } + } + + total += sel + io.write(total) +} + +rsum(n int) -> int { + if n <= 0 { + return 3 + } + + return n + rsum(n - 1) +} + +pair(x int, y int) -> (int, int) { + return y + 0, x - 0 +} + +mk(x int, y int) -> Point { + return Point{x: x, y: y + 1} +} \ No newline at end of file diff --git a/tests/tests_test.go b/tests/tests_test.go index b17b38c..405410c 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -192,6 +192,7 @@ var tests = []run{ {"zero-alloc", nil, "", "", 0}, {"spill-call", nil, "", "", 0}, {"spill-call-binary", nil, "", "", 0}, + {"spill-operands", nil, "", "70", 0}, {"dead-value", nil, "", "", 0}, {"dead-value-load", nil, "", "", 0}, } -- 2.51.2