Implemented return values
This commit is contained in:
parent
3e47a12ecd
commit
83640ba590
@ -1,19 +1,8 @@
|
||||
// Comment
|
||||
main() {
|
||||
address := 4194304 + 1
|
||||
length := (0 + 50 - 20) * 10 / 100
|
||||
|
||||
loop {
|
||||
print(address, length)
|
||||
}
|
||||
x := f(2, 3)
|
||||
syscall(60, x)
|
||||
}
|
||||
|
||||
// Comment
|
||||
print(address, length) {
|
||||
write(length-2, address, length)
|
||||
}
|
||||
|
||||
// Comment
|
||||
write(fd, address, length) {
|
||||
syscall(1, fd, address, length)
|
||||
f(x, y) {
|
||||
return (x + y) * (x + y)
|
||||
}
|
@ -3,7 +3,6 @@ package build
|
||||
import (
|
||||
"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/cpu"
|
||||
"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)
|
||||
}
|
||||
|
||||
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 {
|
||||
panic("no free registers")
|
||||
}
|
||||
}
|
||||
|
||||
f.cpu.Use(temporary)
|
||||
defer f.cpu.Free(temporary)
|
||||
@ -122,6 +128,20 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
|
||||
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]
|
||||
right := root.Children[1]
|
||||
|
||||
@ -131,46 +151,21 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
|
||||
return err
|
||||
}
|
||||
|
||||
f.SaveRegister(register)
|
||||
return f.Execute(operation, register, right)
|
||||
}
|
||||
|
||||
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
||||
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
||||
var destinations []cpu.Register
|
||||
|
||||
for i := len(expressions) - 1; i >= 0; i-- {
|
||||
original := registers[i]
|
||||
expression := expressions[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
|
||||
}
|
||||
register := registers[i]
|
||||
|
||||
err := f.ExpressionToRegister(expression, register)
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
|
@ -1,17 +1,38 @@
|
||||
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.
|
||||
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
|
||||
funcName := expr.Children[0].Token.Text()
|
||||
parameters := expr.Children[1:]
|
||||
var (
|
||||
funcName = expr.Children[0].Token.Text()
|
||||
parameters = expr.Children[1:]
|
||||
isSyscall = funcName == "syscall"
|
||||
registers []cpu.Register
|
||||
)
|
||||
|
||||
if funcName == "syscall" {
|
||||
defer f.assembler.Syscall()
|
||||
return f.ExpressionsToRegisters(parameters, f.cpu.Syscall)
|
||||
if isSyscall {
|
||||
registers = f.cpu.Syscall
|
||||
} else {
|
||||
registers = f.cpu.Call
|
||||
}
|
||||
|
||||
defer f.assembler.Call(funcName)
|
||||
return f.ExpressionsToRegisters(parameters, f.cpu.Call)
|
||||
registers = registers[:len(parameters)]
|
||||
|
||||
for _, register := range registers {
|
||||
f.SaveRegister(register)
|
||||
}
|
||||
|
||||
err := f.ExpressionsToRegisters(parameters, registers)
|
||||
|
||||
if isSyscall {
|
||||
f.assembler.Syscall()
|
||||
} else {
|
||||
f.assembler.Call(funcName)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -7,12 +7,18 @@ import (
|
||||
|
||||
// CompileReturn compiles a return instruction.
|
||||
func (f *Function) CompileReturn(tokens token.List) error {
|
||||
if len(tokens) > 1 {
|
||||
value := expression.Parse(tokens[1:])
|
||||
defer value.Close()
|
||||
// TODO: Set the return value
|
||||
}
|
||||
defer f.assembler.Return()
|
||||
|
||||
f.assembler.Return()
|
||||
if len(tokens) == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
value := expression.Parse(tokens[1:])
|
||||
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer value.Close()
|
||||
return f.ExpressionToRegister(value, f.cpu.Return[0])
|
||||
}
|
||||
|
37
src/build/SaveRegister.go
Normal file
37
src/build/SaveRegister.go
Normal 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
|
||||
}
|
@ -22,7 +22,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
CallRegisters = []cpu.Register{RDI, RSI, RDX, RCX, R8, R9}
|
||||
CallRegisters = SyscallRegisters
|
||||
GeneralRegisters = []cpu.Register{RBX, RBP, R12, R13, R14, R15}
|
||||
SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9}
|
||||
ReturnValueRegisters = []cpu.Register{RAX, RCX, R11}
|
||||
|
@ -66,6 +66,10 @@ func (a *Assembler) Jump(name string) {
|
||||
|
||||
// Return returns back to the caller.
|
||||
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})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user