Implemented return values

This commit is contained in:
Eduard Urbach 2024-06-29 21:06:59 +02:00
parent 3e47a12ecd
commit 83640ba590
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 113 additions and 61 deletions

View File

@ -1,19 +1,8 @@
// Comment
main() { main() {
address := 4194304 + 1 x := f(2, 3)
length := (0 + 50 - 20) * 10 / 100 syscall(60, x)
loop {
print(address, length)
}
} }
// Comment f(x, y) {
print(address, length) { return (x + y) * (x + y)
write(length-2, address, length)
}
// Comment
write(fd, address, length) {
syscall(1, fd, address, length)
} }

View File

@ -3,7 +3,6 @@ package build
import ( import (
"strconv" "strconv"
"git.akyoto.dev/cli/q/src/build/arch/x64"
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/expression"
@ -17,11 +16,18 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
return f.ExecuteLeaf(operation, register, value.Token) return f.ExecuteLeaf(operation, register, value.Token)
} }
temporary, found := f.cpu.FindFree(f.cpu.General) var temporary cpu.Register
if isFunctionCall(value) {
temporary = f.cpu.Return[0]
} else {
found := false
temporary, found = f.cpu.FindFree(f.cpu.General)
if !found { if !found {
panic("no free registers") panic("no free registers")
} }
}
f.cpu.Use(temporary) f.cpu.Use(temporary)
defer f.cpu.Free(temporary) defer f.cpu.Free(temporary)
@ -122,6 +128,20 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
return f.TokenToRegister(operation, register) return f.TokenToRegister(operation, register)
} }
if isFunctionCall(root) {
err := f.CompileFunctionCall(root)
if err != nil {
return err
}
if register != f.cpu.Return[0] {
f.assembler.RegisterRegister(asm.MOVE, register, f.cpu.Return[0])
}
return nil
}
left := root.Children[0] left := root.Children[0]
right := root.Children[1] right := root.Children[1]
@ -131,46 +151,21 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
return err return err
} }
f.SaveRegister(register)
return f.Execute(operation, register, right) return f.Execute(operation, register, right)
} }
// ExpressionsToRegisters moves multiple expressions into the specified registers. // ExpressionsToRegisters moves multiple expressions into the specified registers.
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error { func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
var destinations []cpu.Register
for i := len(expressions) - 1; i >= 0; i-- { for i := len(expressions) - 1; i >= 0; i-- {
original := registers[i]
expression := expressions[i] expression := expressions[i]
register := registers[i]
if expression.IsLeaf() {
variable, exists := f.variables[expression.Token.Text()]
if exists && variable.Register == original {
continue
}
}
register := original
save := !f.cpu.IsFree(register)
if save {
register = x64.RAX
}
err := f.ExpressionToRegister(expression, register) err := f.ExpressionToRegister(expression, register)
if err != nil { if err != nil {
return err return err
} }
if save {
destinations = append(destinations, original)
f.assembler.Register(asm.PUSH, x64.RAX)
}
}
for i := len(destinations) - 1; i >= 0; i-- {
f.assembler.Register(asm.POP, destinations[i])
} }
return nil return nil

View File

@ -1,17 +1,38 @@
package build package build
import "git.akyoto.dev/cli/q/src/build/expression" import (
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression"
)
// CompileFunctionCall executes a function call. // CompileFunctionCall executes a function call.
func (f *Function) CompileFunctionCall(expr *expression.Expression) error { func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
funcName := expr.Children[0].Token.Text() var (
parameters := expr.Children[1:] funcName = expr.Children[0].Token.Text()
parameters = expr.Children[1:]
isSyscall = funcName == "syscall"
registers []cpu.Register
)
if funcName == "syscall" { if isSyscall {
defer f.assembler.Syscall() registers = f.cpu.Syscall
return f.ExpressionsToRegisters(parameters, f.cpu.Syscall) } else {
registers = f.cpu.Call
} }
defer f.assembler.Call(funcName) registers = registers[:len(parameters)]
return f.ExpressionsToRegisters(parameters, f.cpu.Call)
for _, register := range registers {
f.SaveRegister(register)
}
err := f.ExpressionsToRegisters(parameters, registers)
if isSyscall {
f.assembler.Syscall()
} else {
f.assembler.Call(funcName)
}
return err
} }

View File

@ -7,12 +7,18 @@ import (
// CompileReturn compiles a return instruction. // CompileReturn compiles a return instruction.
func (f *Function) CompileReturn(tokens token.List) error { func (f *Function) CompileReturn(tokens token.List) error {
if len(tokens) > 1 { defer f.assembler.Return()
value := expression.Parse(tokens[1:])
defer value.Close() if len(tokens) == 1 {
// TODO: Set the return value return nil
} }
f.assembler.Return() value := expression.Parse(tokens[1:])
if value == nil {
return nil return nil
}
defer value.Close()
return f.ExpressionToRegister(value, f.cpu.Return[0])
} }

37
src/build/SaveRegister.go Normal file
View File

@ -0,0 +1,37 @@
package build
import (
"git.akyoto.dev/cli/q/src/build/asm"
"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) {
if f.cpu.IsFree(register) {
return
}
var variable *Variable
for _, v := range f.variables {
if v.Register == register {
variable = v
break
}
}
if variable == nil || variable.UsesRemaining == 0 {
return
}
newRegister, exists := f.cpu.FindFree(f.cpu.General)
if !exists {
panic("no free registers")
}
f.assembler.RegisterRegister(asm.MOVE, newRegister, register)
f.cpu.Free(register)
f.cpu.Use(newRegister)
variable.Register = newRegister
}

View File

@ -22,7 +22,7 @@ const (
) )
var ( var (
CallRegisters = []cpu.Register{RDI, RSI, RDX, RCX, R8, R9} CallRegisters = SyscallRegisters
GeneralRegisters = []cpu.Register{RBX, RBP, R12, R13, R14, R15} GeneralRegisters = []cpu.Register{RBX, RBP, R12, R13, R14, R15}
SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9} SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9}
ReturnValueRegisters = []cpu.Register{RAX, RCX, R11} ReturnValueRegisters = []cpu.Register{RAX, RCX, R11}

View File

@ -66,6 +66,10 @@ func (a *Assembler) Jump(name string) {
// Return returns back to the caller. // Return returns back to the caller.
func (a *Assembler) Return() { func (a *Assembler) Return() {
if len(a.Instructions) > 0 && a.Instructions[len(a.Instructions)-1].Mnemonic == RETURN {
return
}
a.Instructions = append(a.Instructions, Instruction{Mnemonic: RETURN}) a.Instructions = append(a.Instructions, Instruction{Mnemonic: RETURN})
} }