Implemented return values
This commit is contained in:
parent
3e47a12ecd
commit
83640ba590
@ -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)
|
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
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 (
|
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}
|
||||||
|
@ -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})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user