From 5cbc3315a716c0c7628509033d6e3e49b512c716 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 9 Jul 2024 10:28:14 +0200 Subject: [PATCH] Added fibonacci example --- examples/fibonacci/fibonacci.q | 11 +++++++ src/build/arch/x64/Registers.go | 1 + src/build/core/CompileCall.go | 10 ++++-- src/build/core/CompileDefinition.go | 2 ++ src/build/core/ExpressionToRegister.go | 3 +- src/build/core/Function.go | 1 + src/build/core/SaveRegister.go | 37 ++++++++++++++++++++++ src/build/cpu/CPU.go | 44 ++++++++++++++++++-------- tests/examples_test.go | 1 + tests/programs/parameters.q | 12 +++++++ tests/programs_test.go | 1 + 11 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 examples/fibonacci/fibonacci.q create mode 100644 src/build/core/SaveRegister.go create mode 100644 tests/programs/parameters.q diff --git a/examples/fibonacci/fibonacci.q b/examples/fibonacci/fibonacci.q new file mode 100644 index 0000000..2bedfdb --- /dev/null +++ b/examples/fibonacci/fibonacci.q @@ -0,0 +1,11 @@ +main() { + syscall(60, fibonacci(10)) +} + +fibonacci(x) { + if x == 1 || x == 0 { + return x + } + + return fibonacci(x - 1) + fibonacci(x - 2) +} \ No newline at end of file diff --git a/src/build/arch/x64/Registers.go b/src/build/arch/x64/Registers.go index 6968338..2d9bd1c 100644 --- a/src/build/arch/x64/Registers.go +++ b/src/build/arch/x64/Registers.go @@ -22,6 +22,7 @@ const ( ) var ( + AllRegisters = []cpu.Register{RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15} SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9} GeneralRegisters = []cpu.Register{RCX, RBX, RBP, R11, R12, R13, R14, R15} CallRegisters = SyscallRegisters diff --git a/src/build/core/CompileCall.go b/src/build/core/CompileCall.go index 9c92950..4f063c9 100644 --- a/src/build/core/CompileCall.go +++ b/src/build/core/CompileCall.go @@ -29,6 +29,12 @@ func (f *Function) CompileCall(root *expression.Expression) error { registers = f.cpu.Syscall[:len(parameters)] } + for _, register := range f.cpu.Input { + if f.cpu.IsUsed(register) { + f.SaveRegister(register) + } + } + err := f.ExpressionsToRegisters(parameters, registers) if err != nil { @@ -37,7 +43,7 @@ func (f *Function) CompileCall(root *expression.Expression) error { // Push for _, register := range f.cpu.General { - if !f.cpu.IsFree(register) { + if f.cpu.IsUsed(register) { f.assembler.Register(asm.PUSH, register) } } @@ -53,7 +59,7 @@ func (f *Function) CompileCall(root *expression.Expression) error { for i := len(f.cpu.General) - 1; i >= 0; i-- { register := f.cpu.General[i] - if !f.cpu.IsFree(register) { + if f.cpu.IsUsed(register) { f.assembler.Register(asm.POP, register) } } diff --git a/src/build/core/CompileDefinition.go b/src/build/core/CompileDefinition.go index d9daf58..7243d17 100644 --- a/src/build/core/CompileDefinition.go +++ b/src/build/core/CompileDefinition.go @@ -47,6 +47,7 @@ func (f *Function) AddVariable(variable *Variable) { } f.variables[variable.Name] = variable + f.cpu.Reserve(variable.Register) f.cpu.Use(variable.Register) } @@ -85,6 +86,7 @@ func (f *Function) storeVariableInRegister(name string, value *expression.Expres panic("no free registers") } + f.cpu.Reserve(reg) err := f.ExpressionToRegister(value, reg) f.AddVariable(&Variable{ diff --git a/src/build/core/ExpressionToRegister.go b/src/build/core/ExpressionToRegister.go index 2f6cf6d..b532757 100644 --- a/src/build/core/ExpressionToRegister.go +++ b/src/build/core/ExpressionToRegister.go @@ -36,6 +36,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp register = f.cpu.MustFindFree(f.cpu.General) } + f.cpu.Reserve(register) err := f.ExpressionToRegister(left, register) if err != nil { @@ -47,8 +48,8 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp if register != final { f.assembler.RegisterRegister(asm.MOVE, final, register) + f.cpu.Free(register) } - f.cpu.Free(register) return err } diff --git a/src/build/core/Function.go b/src/build/core/Function.go index e19cf0f..a9d90b8 100644 --- a/src/build/core/Function.go +++ b/src/build/core/Function.go @@ -31,6 +31,7 @@ func NewFunction(name string, file *fs.File, body token.List) *Function { Instructions: make([]asm.Instruction, 0, 32), }, cpu: cpu.CPU{ + All: x64.AllRegisters, Input: x64.CallRegisters, General: x64.GeneralRegisters, Syscall: x64.SyscallRegisters, diff --git a/src/build/core/SaveRegister.go b/src/build/core/SaveRegister.go new file mode 100644 index 0000000..95ec385 --- /dev/null +++ b/src/build/core/SaveRegister.go @@ -0,0 +1,37 @@ +package core + +import ( + "fmt" + + "git.akyoto.dev/cli/q/src/build/asm" + "git.akyoto.dev/cli/q/src/build/config" + "git.akyoto.dev/cli/q/src/build/cpu" +) + +// SaveRegister attempts to move a variable occupying this register to another register. +func (f *Function) SaveRegister(register cpu.Register) { + var variable *Variable + + for _, v := range f.variables { + if v.Register == register { + variable = v + break + } + } + + if variable == nil || variable.Alive == 0 { + return + } + + newRegister := f.cpu.MustFindFree(f.cpu.General) + f.cpu.Reserve(newRegister) + f.cpu.Use(newRegister) + + if config.Comments { + f.assembler.Comment(fmt.Sprintf("save %s to %s", register, newRegister)) + } + + f.assembler.RegisterRegister(asm.MOVE, newRegister, register) + f.cpu.Free(register) + variable.Register = newRegister +} diff --git a/src/build/cpu/CPU.go b/src/build/cpu/CPU.go index ee028db..c3c5951 100644 --- a/src/build/cpu/CPU.go +++ b/src/build/cpu/CPU.go @@ -2,28 +2,45 @@ package cpu // CPU represents the processor. type CPU struct { - General []Register - Syscall []Register - Input []Register - Output []Register - usage uint64 -} - -func (c *CPU) Use(reg Register) { - c.usage |= (1 << reg) + All []Register + General []Register + Syscall []Register + Input []Register + Output []Register + reserved uint64 + used uint64 } +// Free will reset the reserved and used status which means the register can be allocated again. func (c *CPU) Free(reg Register) { - c.usage &= ^(1 << reg) + c.used &= ^(1 << reg) + c.reserved &= ^(1 << reg) } -func (c *CPU) IsFree(reg Register) bool { - return c.usage&(1<