diff --git a/src/build/asm/Instructions.go b/src/build/asm/Instructions.go index 1adcd9d..57bab73 100644 --- a/src/build/asm/Instructions.go +++ b/src/build/asm/Instructions.go @@ -15,6 +15,10 @@ func (a *Assembler) RegisterNumber(mnemonic Mnemonic, reg cpu.Register, number i // RegisterRegister adds an instruction using two registers. func (a *Assembler) RegisterRegister(mnemonic Mnemonic, left cpu.Register, right cpu.Register) { + if a.unnecessary(mnemonic, left, right) { + return + } + a.Instructions = append(a.Instructions, Instruction{ Mnemonic: mnemonic, Data: &RegisterRegister{ diff --git a/src/build/asm/Optimizer.go b/src/build/asm/Optimizer.go new file mode 100644 index 0000000..d91daa1 --- /dev/null +++ b/src/build/asm/Optimizer.go @@ -0,0 +1,34 @@ +package asm + +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 + } + + last := a.Instructions[len(a.Instructions)-1] + + if mnemonic == MOVE && last.Mnemonic == MOVE { + data, isRegReg := last.Data.(*RegisterRegister) + + if !isRegReg { + return false + } + + if data.Destination == left && data.Source == right { + return true + } + + if data.Destination == right && data.Source == left { + return true + } + } + + return false +} diff --git a/src/build/core/CompileCall.go b/src/build/core/CompileCall.go index 4f063c9..a70c4b6 100644 --- a/src/build/core/CompileCall.go +++ b/src/build/core/CompileCall.go @@ -29,12 +29,6 @@ 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 { diff --git a/src/build/core/ExecuteRegisterRegister.go b/src/build/core/ExecuteRegisterRegister.go index d10205d..22a6be0 100644 --- a/src/build/core/ExecuteRegisterRegister.go +++ b/src/build/core/ExecuteRegisterRegister.go @@ -26,9 +26,7 @@ func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cp f.assembler.RegisterRegister(asm.COMPARE, destination, source) case "=": - if destination != source { - f.assembler.RegisterRegister(asm.MOVE, destination, source) - } + f.assembler.RegisterRegister(asm.MOVE, destination, source) default: return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) diff --git a/src/build/core/Function.go b/src/build/core/Function.go index a9d90b8..4eff587 100644 --- a/src/build/core/Function.go +++ b/src/build/core/Function.go @@ -47,6 +47,13 @@ func NewFunction(name string, file *fs.File, body token.List) *Function { func (f *Function) Compile() { defer close(f.finished) f.assembler.Label(asm.LABEL, f.Name) + + for _, register := range f.cpu.Input { + if f.cpu.IsUsed(register) { + f.SaveRegister(register) + } + } + f.err = f.CompileTokens(f.Body) f.assembler.Return() } diff --git a/src/build/core/TokenToRegister.go b/src/build/core/TokenToRegister.go index 7a9c428..3e25685 100644 --- a/src/build/core/TokenToRegister.go +++ b/src/build/core/TokenToRegister.go @@ -21,10 +21,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position) } - if register != variable.Register { - f.assembler.RegisterRegister(asm.MOVE, register, variable.Register) - } - + f.assembler.RegisterRegister(asm.MOVE, register, variable.Register) f.useVariable(variable) return nil diff --git a/tests/programs/parameters.q b/tests/programs/overwrite.q similarity index 100% rename from tests/programs/parameters.q rename to tests/programs/overwrite.q diff --git a/tests/programs_test.go b/tests/programs_test.go index c6724ea..3b494c5 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -21,7 +21,7 @@ var programs = []struct { {"square-sum.q", "", 25}, {"chained-calls.q", "", 9}, {"nested-calls.q", "", 4}, - {"parameters.q", "", 3}, + {"overwrite.q", "", 3}, {"reuse.q", "", 3}, {"return.q", "", 6}, {"reassign.q", "", 2},