Improved code generation
This commit is contained in:
parent
1204591cdc
commit
4386392844
@ -68,16 +68,6 @@ func (a *Assembler) Call(name string) {
|
||||
})
|
||||
}
|
||||
|
||||
// Jump jumps to a position that is identified by a label.
|
||||
func (a *Assembler) Jump(name string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: JUMP,
|
||||
Data: &Label{
|
||||
Name: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Return returns back to the caller.
|
||||
func (a *Assembler) Return() {
|
||||
if len(a.Instructions) > 0 && a.Instructions[len(a.Instructions)-1].Mnemonic == RETURN {
|
||||
|
@ -4,10 +4,6 @@ import "git.akyoto.dev/cli/q/src/build/cpu"
|
||||
|
||||
// unnecessary returns true if the register/register operation can be skipped.
|
||||
func (a *Assembler) unnecessary(mnemonic Mnemonic, left cpu.Register, right cpu.Register) bool {
|
||||
if mnemonic == MOVE && left == right {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(a.Instructions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ func (f *Function) Compare(comparison *expression.Expression) error {
|
||||
return err
|
||||
}
|
||||
|
||||
f.cpu.Use(tmp)
|
||||
defer f.cpu.Free(tmp)
|
||||
return f.Execute(comparison.Token, tmp, right)
|
||||
}
|
||||
|
@ -37,22 +37,18 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
||||
|
||||
f.SaveRegister(f.cpu.Output[0])
|
||||
|
||||
for _, register := range registers {
|
||||
f.SaveRegister(register)
|
||||
}
|
||||
|
||||
// Push
|
||||
for _, register := range f.cpu.General {
|
||||
if f.cpu.IsUsed(register) {
|
||||
f.assembler.Register(asm.PUSH, register)
|
||||
f.Register(asm.PUSH, register)
|
||||
}
|
||||
}
|
||||
|
||||
// Call
|
||||
if isSyscall {
|
||||
f.assembler.Syscall()
|
||||
f.Syscall()
|
||||
} else {
|
||||
f.assembler.Call(funcName)
|
||||
f.Call(funcName)
|
||||
}
|
||||
|
||||
// Pop
|
||||
@ -60,7 +56,7 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
||||
register := f.cpu.General[i]
|
||||
|
||||
if f.cpu.IsUsed(register) {
|
||||
f.assembler.Register(asm.POP, register)
|
||||
f.Register(asm.POP, register)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab
|
||||
f.JumpIfTrue(left.Token.Text(), successLabel)
|
||||
|
||||
// Right
|
||||
f.assembler.Label(asm.LABEL, leftFailLabel)
|
||||
f.AddLabel(leftFailLabel)
|
||||
right := condition.Children[1]
|
||||
err = f.CompileCondition(right, successLabel, failLabel)
|
||||
|
||||
@ -52,7 +52,7 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab
|
||||
f.JumpIfFalse(left.Token.Text(), failLabel)
|
||||
|
||||
// Right
|
||||
f.assembler.Label(asm.LABEL, leftSuccessLabel)
|
||||
f.AddLabel(leftSuccessLabel)
|
||||
right := condition.Children[1]
|
||||
err = f.CompileCondition(right, successLabel, failLabel)
|
||||
|
||||
@ -79,17 +79,17 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab
|
||||
func (f *Function) JumpIfFalse(operator string, label string) {
|
||||
switch operator {
|
||||
case "==":
|
||||
f.assembler.Label(asm.JNE, label)
|
||||
f.Jump(asm.JNE, label)
|
||||
case "!=":
|
||||
f.assembler.Label(asm.JE, label)
|
||||
f.Jump(asm.JE, label)
|
||||
case ">":
|
||||
f.assembler.Label(asm.JLE, label)
|
||||
f.Jump(asm.JLE, label)
|
||||
case "<":
|
||||
f.assembler.Label(asm.JGE, label)
|
||||
f.Jump(asm.JGE, label)
|
||||
case ">=":
|
||||
f.assembler.Label(asm.JL, label)
|
||||
f.Jump(asm.JL, label)
|
||||
case "<=":
|
||||
f.assembler.Label(asm.JG, label)
|
||||
f.Jump(asm.JG, label)
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,16 +97,16 @@ func (f *Function) JumpIfFalse(operator string, label string) {
|
||||
func (f *Function) JumpIfTrue(operator string, label string) {
|
||||
switch operator {
|
||||
case "==":
|
||||
f.assembler.Label(asm.JE, label)
|
||||
f.Jump(asm.JE, label)
|
||||
case "!=":
|
||||
f.assembler.Label(asm.JNE, label)
|
||||
f.Jump(asm.JNE, label)
|
||||
case ">":
|
||||
f.assembler.Label(asm.JG, label)
|
||||
f.Jump(asm.JG, label)
|
||||
case "<":
|
||||
f.assembler.Label(asm.JL, label)
|
||||
f.Jump(asm.JL, label)
|
||||
case ">=":
|
||||
f.assembler.Label(asm.JGE, label)
|
||||
f.Jump(asm.JGE, label)
|
||||
case "<=":
|
||||
f.assembler.Label(asm.JLE, label)
|
||||
f.Jump(asm.JLE, label)
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func (f *Function) CompileDefinition(node *ast.Define) error {
|
||||
|
||||
func (f *Function) AddVariable(variable *Variable) {
|
||||
if config.Comments {
|
||||
f.assembler.Comment(fmt.Sprintf("%s = %s (%s, %d uses)", variable.Name, variable.Value, variable.Register, variable.Alive))
|
||||
f.Comment(fmt.Sprintf("%s = %s (%s, %d uses)", variable.Name, variable.Value, variable.Register, variable.Alive))
|
||||
}
|
||||
|
||||
f.variables[variable.Name] = variable
|
||||
@ -60,7 +60,7 @@ func (f *Function) useVariable(variable *Variable) {
|
||||
|
||||
if variable.Alive == 0 {
|
||||
if config.Comments {
|
||||
f.assembler.Comment(fmt.Sprintf("%s died (%s)", variable.Name, variable.Register))
|
||||
f.Comment(fmt.Sprintf("%s died (%s)", variable.Name, variable.Register))
|
||||
}
|
||||
|
||||
f.cpu.Free(variable.Register)
|
||||
|
@ -3,7 +3,6 @@ package core
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/ast"
|
||||
)
|
||||
|
||||
@ -17,8 +16,8 @@ func (f *Function) CompileIf(branch *ast.If) error {
|
||||
return err
|
||||
}
|
||||
|
||||
f.assembler.Label(asm.LABEL, success)
|
||||
defer f.assembler.Label(asm.LABEL, fail)
|
||||
f.AddLabel(success)
|
||||
defer f.AddLabel(fail)
|
||||
f.count.branch++
|
||||
return f.CompileAST(branch.Body)
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
// CompileLoop compiles a loop instruction.
|
||||
func (f *Function) CompileLoop(loop *ast.Loop) error {
|
||||
label := fmt.Sprintf("%s_loop_%d", f.Name, f.count.loop)
|
||||
f.assembler.Label(asm.LABEL, label)
|
||||
defer f.assembler.Jump(label)
|
||||
f.AddLabel(label)
|
||||
defer f.Jump(asm.JUMP, label)
|
||||
f.count.loop++
|
||||
return f.CompileAST(loop.Body)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
// CompileReturn compiles a return instruction.
|
||||
func (f *Function) CompileReturn(node *ast.Return) error {
|
||||
defer f.assembler.Return()
|
||||
defer f.Return()
|
||||
|
||||
if node.Value == nil {
|
||||
return nil
|
||||
|
@ -24,7 +24,6 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
||||
}
|
||||
|
||||
tmp := f.cpu.MustFindFree(f.cpu.General)
|
||||
f.cpu.Use(tmp)
|
||||
defer f.cpu.Free(tmp)
|
||||
|
||||
err := f.ExpressionToRegister(value, tmp)
|
||||
|
@ -11,22 +11,22 @@ import (
|
||||
func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error {
|
||||
switch operation.Text() {
|
||||
case "+", "+=":
|
||||
f.assembler.RegisterNumber(asm.ADD, register, number)
|
||||
f.RegisterNumber(asm.ADD, register, number)
|
||||
|
||||
case "-", "-=":
|
||||
f.assembler.RegisterNumber(asm.SUB, register, number)
|
||||
f.RegisterNumber(asm.SUB, register, number)
|
||||
|
||||
case "*", "*=":
|
||||
f.assembler.RegisterNumber(asm.MUL, register, number)
|
||||
f.RegisterNumber(asm.MUL, register, number)
|
||||
|
||||
case "/", "/=":
|
||||
f.assembler.RegisterNumber(asm.DIV, register, number)
|
||||
f.RegisterNumber(asm.DIV, register, number)
|
||||
|
||||
case "==", "!=", "<", "<=", ">", ">=":
|
||||
f.assembler.RegisterNumber(asm.COMPARE, register, number)
|
||||
f.RegisterNumber(asm.COMPARE, register, number)
|
||||
|
||||
case "=":
|
||||
f.assembler.RegisterNumber(asm.MOVE, register, number)
|
||||
f.RegisterNumber(asm.MOVE, register, number)
|
||||
|
||||
default:
|
||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||
|
@ -11,22 +11,22 @@ import (
|
||||
func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error {
|
||||
switch operation.Text() {
|
||||
case "+", "+=":
|
||||
f.assembler.RegisterRegister(asm.ADD, destination, source)
|
||||
f.RegisterRegister(asm.ADD, destination, source)
|
||||
|
||||
case "-", "-=":
|
||||
f.assembler.RegisterRegister(asm.SUB, destination, source)
|
||||
f.RegisterRegister(asm.SUB, destination, source)
|
||||
|
||||
case "*", "*=":
|
||||
f.assembler.RegisterRegister(asm.MUL, destination, source)
|
||||
f.RegisterRegister(asm.MUL, destination, source)
|
||||
|
||||
case "/", "/=":
|
||||
f.assembler.RegisterRegister(asm.DIV, destination, source)
|
||||
f.RegisterRegister(asm.DIV, destination, source)
|
||||
|
||||
case "==", "!=", "<", "<=", ">", ">=":
|
||||
f.assembler.RegisterRegister(asm.COMPARE, destination, source)
|
||||
f.RegisterRegister(asm.COMPARE, destination, source)
|
||||
|
||||
case "=":
|
||||
f.assembler.RegisterRegister(asm.MOVE, destination, source)
|
||||
f.RegisterRegister(asm.MOVE, destination, source)
|
||||
|
||||
default:
|
||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||
|
@ -18,7 +18,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
err := f.CompileCall(node)
|
||||
|
||||
if register != f.cpu.Output[0] {
|
||||
f.assembler.RegisterRegister(asm.MOVE, register, f.cpu.Output[0])
|
||||
f.RegisterRegister(asm.MOVE, register, f.cpu.Output[0])
|
||||
}
|
||||
|
||||
return err
|
||||
@ -34,8 +34,6 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
|
||||
if f.UsesRegister(right, register) {
|
||||
register = f.cpu.MustFindFree(f.cpu.General)
|
||||
} else {
|
||||
f.SaveRegister(register)
|
||||
}
|
||||
|
||||
f.cpu.Reserve(register)
|
||||
@ -45,11 +43,10 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
||||
return err
|
||||
}
|
||||
|
||||
f.cpu.Use(register)
|
||||
err = f.Execute(node.Token, register, right)
|
||||
|
||||
if register != final {
|
||||
f.assembler.RegisterRegister(asm.MOVE, final, register)
|
||||
f.RegisterRegister(asm.MOVE, final, register)
|
||||
f.cpu.Free(register)
|
||||
}
|
||||
|
||||
|
@ -46,9 +46,9 @@ func NewFunction(name string, file *fs.File, body token.List) *Function {
|
||||
// Compile turns a function into machine code.
|
||||
func (f *Function) Compile() {
|
||||
defer close(f.finished)
|
||||
f.assembler.Label(asm.LABEL, f.Name)
|
||||
f.AddLabel(f.Name)
|
||||
f.err = f.CompileTokens(f.Body)
|
||||
f.assembler.Return()
|
||||
f.Return()
|
||||
}
|
||||
|
||||
// CompileTokens compiles a token list.
|
||||
|
98
src/build/core/Instructions.go
Normal file
98
src/build/core/Instructions.go
Normal file
@ -0,0 +1,98 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/config"
|
||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||
)
|
||||
|
||||
func (f *Function) AddLabel(label string) {
|
||||
f.assembler.Label(asm.LABEL, label)
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Call(label string) {
|
||||
f.assembler.Call(label)
|
||||
f.cpu.Use(f.cpu.Output[0])
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Comment(comment string) {
|
||||
f.assembler.Comment(comment)
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Jump(mnemonic asm.Mnemonic, label string) {
|
||||
f.assembler.Label(mnemonic, label)
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Register(mnemonic asm.Mnemonic, a cpu.Register) {
|
||||
f.assembler.Register(mnemonic, a)
|
||||
|
||||
if mnemonic == asm.POP {
|
||||
f.cpu.Use(a)
|
||||
}
|
||||
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) RegisterNumber(mnemonic asm.Mnemonic, a cpu.Register, b int) {
|
||||
if f.cpu.IsUsed(a) && isDestructive(mnemonic) {
|
||||
f.SaveRegister(a)
|
||||
}
|
||||
|
||||
f.assembler.RegisterNumber(mnemonic, a, b)
|
||||
|
||||
if mnemonic == asm.MOVE {
|
||||
f.cpu.Use(a)
|
||||
}
|
||||
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) RegisterRegister(mnemonic asm.Mnemonic, a cpu.Register, b cpu.Register) {
|
||||
if mnemonic == asm.MOVE && a == b {
|
||||
return
|
||||
}
|
||||
|
||||
if f.cpu.IsUsed(a) && isDestructive(mnemonic) {
|
||||
f.SaveRegister(a)
|
||||
}
|
||||
|
||||
f.assembler.RegisterRegister(mnemonic, a, b)
|
||||
|
||||
if mnemonic == asm.MOVE {
|
||||
f.cpu.Use(a)
|
||||
}
|
||||
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Return() {
|
||||
f.assembler.Return()
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) Syscall() {
|
||||
f.assembler.Syscall()
|
||||
f.cpu.Use(f.cpu.Output[0])
|
||||
f.postInstruction()
|
||||
}
|
||||
|
||||
func (f *Function) postInstruction() {
|
||||
if !config.Assembler {
|
||||
return
|
||||
}
|
||||
|
||||
f.registerHistory = append(f.registerHistory, f.cpu.Used)
|
||||
}
|
||||
|
||||
func isDestructive(mnemonic asm.Mnemonic) bool {
|
||||
switch mnemonic {
|
||||
case asm.MOVE, asm.ADD, asm.SUB, asm.MUL, asm.DIV:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
@ -14,6 +14,12 @@ func (f *Function) SaveRegister(register cpu.Register) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, general := range f.cpu.General {
|
||||
if register == general {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var variable *Variable
|
||||
|
||||
for _, v := range f.variables {
|
||||
@ -29,13 +35,12 @@ func (f *Function) SaveRegister(register cpu.Register) {
|
||||
|
||||
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.Comment(fmt.Sprintf("save %s to %s", register, newRegister))
|
||||
}
|
||||
|
||||
f.assembler.RegisterRegister(asm.MOVE, newRegister, register)
|
||||
f.RegisterRegister(asm.MOVE, newRegister, register)
|
||||
f.cpu.Free(register)
|
||||
variable.Register = newRegister
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
||||
}
|
||||
|
||||
f.assembler.RegisterRegister(asm.MOVE, register, variable.Register)
|
||||
f.useVariable(variable)
|
||||
f.RegisterRegister(asm.MOVE, register, variable.Register)
|
||||
return nil
|
||||
|
||||
case token.Number:
|
||||
@ -33,7 +33,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
||||
return err
|
||||
}
|
||||
|
||||
f.assembler.RegisterNumber(asm.MOVE, register, n)
|
||||
f.RegisterNumber(asm.MOVE, register, n)
|
||||
return nil
|
||||
|
||||
case token.String:
|
||||
|
@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
@ -10,13 +11,14 @@ import (
|
||||
|
||||
// state is the data structure we embed in each function to preserve compilation state.
|
||||
type state struct {
|
||||
err error
|
||||
variables map[string]*Variable
|
||||
functions map[string]*Function
|
||||
finished chan struct{}
|
||||
assembler asm.Assembler
|
||||
cpu cpu.CPU
|
||||
count counter
|
||||
err error
|
||||
variables map[string]*Variable
|
||||
functions map[string]*Function
|
||||
registerHistory []uint64
|
||||
finished chan struct{}
|
||||
assembler asm.Assembler
|
||||
cpu cpu.CPU
|
||||
count counter
|
||||
}
|
||||
|
||||
// counter stores how often a certain statement appeared so we can generate a unique label from it.
|
||||
@ -28,30 +30,42 @@ type counter struct {
|
||||
|
||||
// PrintInstructions shows the assembly instructions.
|
||||
func (s *state) PrintInstructions() {
|
||||
ansi.Dim.Println("╭────────────────────────────────────────────────────╮")
|
||||
ansi.Dim.Println("╭──────────────────────────────────────────────────────────────────────────────╮")
|
||||
|
||||
for _, x := range s.assembler.Instructions {
|
||||
for i, x := range s.assembler.Instructions {
|
||||
ansi.Dim.Print("│ ")
|
||||
|
||||
switch x.Mnemonic {
|
||||
case asm.LABEL:
|
||||
ansi.Yellow.Printf("%-50s", x.Data.String()+":")
|
||||
ansi.Yellow.Printf("%-44s", x.Data.String()+":")
|
||||
|
||||
case asm.COMMENT:
|
||||
ansi.Dim.Printf("%-50s", x.Data.String())
|
||||
ansi.Dim.Printf("%-44s", x.Data.String())
|
||||
|
||||
default:
|
||||
ansi.Green.Printf("%-12s", x.Mnemonic.String())
|
||||
|
||||
if x.Data != nil {
|
||||
fmt.Printf("%-38s", x.Data.String())
|
||||
fmt.Printf("%-32s", x.Data.String())
|
||||
} else {
|
||||
fmt.Printf("%-38s", "")
|
||||
fmt.Printf("%-32s", "")
|
||||
}
|
||||
}
|
||||
|
||||
registers := bytes.Buffer{}
|
||||
used := s.registerHistory[i]
|
||||
|
||||
for _, reg := range s.cpu.All {
|
||||
if used&(1<<reg) != 0 {
|
||||
registers.WriteString("⬤ ")
|
||||
} else {
|
||||
registers.WriteString("◯ ")
|
||||
}
|
||||
}
|
||||
|
||||
ansi.Dim.Print(registers.String())
|
||||
ansi.Dim.Print(" │\n")
|
||||
}
|
||||
|
||||
ansi.Dim.Println("╰────────────────────────────────────────────────────╯")
|
||||
ansi.Dim.Println("╰──────────────────────────────────────────────────────────────────────────────╯")
|
||||
}
|
||||
|
@ -7,34 +7,34 @@ type CPU struct {
|
||||
Syscall []Register
|
||||
Input []Register
|
||||
Output []Register
|
||||
reserved uint64
|
||||
used uint64
|
||||
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.used &= ^(1 << reg)
|
||||
c.reserved &= ^(1 << reg)
|
||||
c.Used &= ^(1 << reg)
|
||||
c.Reserved &= ^(1 << reg)
|
||||
}
|
||||
|
||||
// IsReserved returns true if the register was marked for future use.
|
||||
func (c *CPU) IsReserved(reg Register) bool {
|
||||
return c.reserved&(1<<reg) != 0
|
||||
return c.Reserved&(1<<reg) != 0
|
||||
}
|
||||
|
||||
// IsUsed returns true if the register is currently in use and holds a value.
|
||||
func (c *CPU) IsUsed(reg Register) bool {
|
||||
return c.used&(1<<reg) != 0
|
||||
return c.Used&(1<<reg) != 0
|
||||
}
|
||||
|
||||
// Reserve reserves a register for future use.
|
||||
func (c *CPU) Reserve(reg Register) {
|
||||
c.reserved |= (1 << reg)
|
||||
c.Reserved |= (1 << reg)
|
||||
}
|
||||
|
||||
// Use marks a register to be currently in use which means it must be preserved across function calls.
|
||||
func (c *CPU) Use(reg Register) {
|
||||
c.used |= (1 << reg)
|
||||
c.Used |= (1 << reg)
|
||||
}
|
||||
|
||||
// FindFree tries to find a free register in the given slice of registers.
|
||||
|
12
tests/programs/param-multi.q
Normal file
12
tests/programs/param-multi.q
Normal file
@ -0,0 +1,12 @@
|
||||
main() {
|
||||
syscall(60, f(1, 2, 3))
|
||||
}
|
||||
|
||||
f(x, y, z) {
|
||||
w := g(4, 5, 6)
|
||||
return x + y + z + w
|
||||
}
|
||||
|
||||
g(x, y, z) {
|
||||
return x + y + z
|
||||
}
|
@ -21,14 +21,15 @@ var programs = []struct {
|
||||
{"square-sum", "", 25},
|
||||
{"chained-calls", "", 9},
|
||||
{"nested-calls", "", 4},
|
||||
{"overwrite", "", 3},
|
||||
{"param", "", 3},
|
||||
{"param-multi", "", 21},
|
||||
{"reuse", "", 3},
|
||||
{"return", "", 6},
|
||||
{"reassign", "", 2},
|
||||
{"branch", "", 0},
|
||||
{"branch-and", "", 0},
|
||||
{"branch-or", "", 0},
|
||||
{"branch-combined", "", 0},
|
||||
{"branch-both", "", 0},
|
||||
}
|
||||
|
||||
func TestPrograms(t *testing.T) {
|
||||
@ -42,7 +43,7 @@ func TestPrograms(t *testing.T) {
|
||||
func BenchmarkPrograms(b *testing.B) {
|
||||
for _, test := range programs {
|
||||
b.Run(test.Name, func(b *testing.B) {
|
||||
compiler := build.New(filepath.Join("programs", test.Name))
|
||||
compiler := build.New(filepath.Join("programs", test.Name+".q"))
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := compiler.Run()
|
||||
|
Loading…
Reference in New Issue
Block a user