diff --git a/src/codegen/createHints.go b/src/codegen/createHints.go index 924b869..ab51712 100644 --- a/src/codegen/createHints.go +++ b/src/codegen/createHints.go @@ -1,10 +1,15 @@ package codegen -import "git.urbach.dev/cli/q/src/ssa" +import ( + "git.urbach.dev/cli/q/src/ssa" +) // createHints recommends registers that a value must reside in later on. func (f *Function) createHints(step *step) { switch instr := step.Value.(type) { + case *ssa.BinaryOp: + f.ValueToStep[instr.Left].Hint(step.Register) + case *ssa.Call: for paramIndex, param := range instr.Arguments { f.ValueToStep[param].Hint(f.CPU.Call.In[paramIndex]) @@ -21,8 +26,17 @@ func (f *Function) createHints(step *step) { f.ValueToStep[param].Hint(f.CPU.ExternCall.In[r]) } + case *ssa.Int: + if step.Register == -1 { + users := step.Value.Users() + alive := f.ValueToStep[users[len(users)-1]].Index + step.Register = f.findFreeRegister(f.Steps[step.Index:alive]) + } + case *ssa.Parameter: - f.ValueToStep[instr].Register = f.CPU.Call.In[instr.Index] + if step.Register == -1 { + step.Register = f.CPU.Call.In[instr.Index] + } case *ssa.Return: for r, param := range instr.Arguments { diff --git a/src/codegen/createSteps.go b/src/codegen/createSteps.go index 353ebda..e351eae 100644 --- a/src/codegen/createSteps.go +++ b/src/codegen/createSteps.go @@ -1,6 +1,8 @@ package codegen import ( + "slices" + "git.urbach.dev/cli/q/src/ssa" ) @@ -20,7 +22,7 @@ func (f *Function) createSteps(ir ssa.IR) { f.ValueToStep[instr] = step } - for _, step := range f.Steps { + for _, step := range slices.Backward(f.Steps) { f.createHints(step) f.createLiveRanges(step) } diff --git a/src/codegen/fixRegisterConflicts.go b/src/codegen/fixRegisterConflicts.go index 602b04e..09fe9bb 100644 --- a/src/codegen/fixRegisterConflicts.go +++ b/src/codegen/fixRegisterConflicts.go @@ -5,33 +5,36 @@ import ( "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/ssa" + "git.urbach.dev/cli/q/src/token" ) // fixRegisterConflicts checks for conflicts where 2 values that are live at the same time use the same register. // It then assigns a new register to the value that was defined earlier. func (f *Function) fixRegisterConflicts() { for stepIndex, step := range f.Steps { + var clobbered []cpu.Register + + switch instr := step.Value.(type) { + case *ssa.BinaryOp: + if instr.Op == token.Div { + clobbered = f.CPU.Division + } + case *ssa.Call: + clobbered = f.CPU.Call.Clobbered + case *ssa.CallExtern: + clobbered = f.CPU.ExternCall.Clobbered + case *ssa.Syscall: + clobbered = f.CPU.Syscall.Clobbered + } + for i, live := range step.Live { if live.Register == -1 { continue } - var clobbered []cpu.Register - - switch step.Value.(type) { - case *ssa.Call: - clobbered = f.CPU.Call.Clobbered - case *ssa.CallExtern: - clobbered = f.CPU.ExternCall.Clobbered - case *ssa.Syscall: - clobbered = f.CPU.Syscall.Clobbered - case *ssa.BinaryOp: - - } - if live.Value != step.Value && slices.Contains(clobbered, live.Register) { live.Register = f.findFreeRegister(f.Steps[live.Index : stepIndex+1]) - goto next + continue } for _, previous := range step.Live[:i] { @@ -47,10 +50,9 @@ func (f *Function) fixRegisterConflicts() { previous.Register = f.findFreeRegister(f.Steps[previous.Index : stepIndex+1]) } else { live.Register = f.findFreeRegister(f.Steps[live.Index : stepIndex+1]) - goto next + break } } - next: } } } \ No newline at end of file diff --git a/src/cpu/CPU.go b/src/cpu/CPU.go index 94ddc17..577ba98 100644 --- a/src/cpu/CPU.go +++ b/src/cpu/CPU.go @@ -3,6 +3,7 @@ package cpu // CPU represents the processor. type CPU struct { General []Register + Division []Register Call ABI ExternCall ABI Syscall ABI diff --git a/src/x86/Registers.go b/src/x86/Registers.go index 62a4ec9..2cbc599 100644 --- a/src/x86/Registers.go +++ b/src/x86/Registers.go @@ -27,6 +27,7 @@ var ( R1, R2, R6, R7, R8, R9, R10, R11, // Clobbered R3, R12, R13, R14, R15, // Preserved }, + Division: []cpu.Register{R0, R2}, Call: cpu.ABI{ In: []cpu.Register{R0, R7, R6, R2, R10, R8, R9}, Out: []cpu.Register{R0, R2}, @@ -49,6 +50,7 @@ var ( MacCPU = cpu.CPU{ General: LinuxCPU.General, + Division: LinuxCPU.Division, Call: LinuxCPU.Call, ExternCall: LinuxCPU.ExternCall, Syscall: cpu.ABI{ @@ -64,7 +66,8 @@ var ( R1, R2, R8, R9, R10, R11, // Clobbered R3, R6, R7, R12, R13, R14, R15, // Preserved }, - Call: LinuxCPU.Call, + Division: LinuxCPU.Division, + Call: LinuxCPU.Call, ExternCall: cpu.ABI{ In: []cpu.Register{R1, R2, R8, R9}, Out: []cpu.Register{R0}, diff --git a/tests/math-10.q b/tests/math-10.q new file mode 100644 index 0000000..3969d0f --- /dev/null +++ b/tests/math-10.q @@ -0,0 +1,5 @@ +import os + +main() { + os.exit((2 + 3) * 2) +} \ No newline at end of file diff --git a/tests/math-2.q b/tests/math-2.q new file mode 100644 index 0000000..0e09e3a --- /dev/null +++ b/tests/math-2.q @@ -0,0 +1,5 @@ +import os + +main() { + os.exit((2 + 3) * 2 / 3 - 1) +} \ No newline at end of file diff --git a/tests/math-3.q b/tests/math-3.q new file mode 100644 index 0000000..2fd435b --- /dev/null +++ b/tests/math-3.q @@ -0,0 +1,5 @@ +import os + +main() { + os.exit((2 + 3) * 2 / 3) +} \ No newline at end of file diff --git a/tests/math-5.q b/tests/math-5.q new file mode 100644 index 0000000..2f91cca --- /dev/null +++ b/tests/math-5.q @@ -0,0 +1,5 @@ +import os + +main() { + os.exit(2 + 3) +} \ No newline at end of file diff --git a/tests/tests_test.go b/tests/tests_test.go index 8b4c620..f606f18 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -11,6 +11,10 @@ var tests = []testRun{ {"hello-3", "", "Hello\nHello\nHello\n", 0}, {"param-swap", "", "", 3}, {"script", "", "Hello\n", 0}, + {"math-5", "", "", 5}, + {"math-10", "", "", 10}, + {"math-3", "", "", 3}, + {"math-2", "", "", 2}, } func TestTests(t *testing.T) {