Improved assembler performance
This commit is contained in:
@ -1,28 +1,10 @@
|
||||
package asm
|
||||
|
||||
import (
|
||||
"maps"
|
||||
|
||||
"git.urbach.dev/cli/q/src/data"
|
||||
)
|
||||
import "git.urbach.dev/cli/q/src/data"
|
||||
|
||||
// Assembler contains a list of instructions.
|
||||
type Assembler struct {
|
||||
Data data.Data
|
||||
Instructions []Instruction
|
||||
}
|
||||
|
||||
// Merge combines the contents of this assembler with another one.
|
||||
func (a *Assembler) Merge(b Assembler) {
|
||||
maps.Copy(a.Data, b.Data)
|
||||
a.Instructions = append(a.Instructions, b.Instructions...)
|
||||
}
|
||||
|
||||
// SetData sets the data for the given label.
|
||||
func (a *Assembler) SetData(label string, bytes []byte) {
|
||||
if a.Data == nil {
|
||||
a.Data = data.Data{}
|
||||
}
|
||||
|
||||
a.Data.Insert(label, bytes)
|
||||
Param Param
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ func (a *Assembler) CanSkip(mnemonic Mnemonic, left cpu.Register, right cpu.Regi
|
||||
last := a.Instructions[len(a.Instructions)-1]
|
||||
|
||||
if mnemonic == MOVE && last.Mnemonic == MOVE {
|
||||
lastData, isRegReg := last.Data.(*RegisterRegister)
|
||||
|
||||
if !isRegReg {
|
||||
if last.Type != TypeRegisterRegister {
|
||||
return false
|
||||
}
|
||||
|
||||
lastData := a.Param.RegisterRegister[last.Index]
|
||||
|
||||
if lastData.Destination == right && lastData.Source == left {
|
||||
return true
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ func (a *Assembler) CanSkipReturn() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if last.Mnemonic == CALL {
|
||||
label, isLabel := last.Data.(*Label)
|
||||
if last.Mnemonic == CALL && last.Type == TypeLabel {
|
||||
label := a.Param.Label[last.Index]
|
||||
|
||||
if isLabel && label.String() == "core.exit" {
|
||||
if label.String() == "core.exit" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
28
src/asm/DataString.go
Normal file
28
src/asm/DataString.go
Normal file
@ -0,0 +1,28 @@
|
||||
package asm
|
||||
|
||||
func (x Instruction) DataString(a *Assembler) string {
|
||||
switch x.Type {
|
||||
case TypeLabel:
|
||||
return a.Param.Label[x.Index].String()
|
||||
case TypeNumber:
|
||||
return a.Param.Number[x.Index].String()
|
||||
case TypeRegister:
|
||||
return a.Param.Register[x.Index].String()
|
||||
case TypeRegisterLabel:
|
||||
return a.Param.RegisterLabel[x.Index].String()
|
||||
case TypeRegisterNumber:
|
||||
return a.Param.RegisterNumber[x.Index].String()
|
||||
case TypeRegisterRegister:
|
||||
return a.Param.RegisterRegister[x.Index].String()
|
||||
case TypeMemory:
|
||||
return a.Param.Memory[x.Index].String()
|
||||
case TypeMemoryLabel:
|
||||
return a.Param.MemoryLabel[x.Index].String()
|
||||
case TypeMemoryNumber:
|
||||
return a.Param.MemoryNumber[x.Index].String()
|
||||
case TypeMemoryRegister:
|
||||
return a.Param.MemoryRegister[x.Index].String()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
3
src/asm/Index.go
Normal file
3
src/asm/Index.go
Normal file
@ -0,0 +1,3 @@
|
||||
package asm
|
||||
|
||||
type Index = uint16
|
@ -1,9 +1,8 @@
|
||||
package asm
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Instruction represents a single instruction which can be converted to machine code.
|
||||
type Instruction struct {
|
||||
Data fmt.Stringer
|
||||
Mnemonic Mnemonic
|
||||
Type Type
|
||||
Index Index
|
||||
}
|
||||
|
@ -2,22 +2,12 @@ package asm
|
||||
|
||||
// Comment adds a comment at the current position.
|
||||
func (a *Assembler) Comment(text string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: COMMENT,
|
||||
Data: &Label{
|
||||
Name: text,
|
||||
},
|
||||
})
|
||||
a.Label(COMMENT, text)
|
||||
}
|
||||
|
||||
// DLLCall calls a function in a DLL file.
|
||||
func (a *Assembler) DLLCall(name string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: DLLCALL,
|
||||
Data: &Label{
|
||||
Name: name,
|
||||
},
|
||||
})
|
||||
a.Label(DLLCALL, name)
|
||||
}
|
||||
|
||||
// Return returns back to the caller.
|
||||
|
@ -14,8 +14,11 @@ func (data *Label) String() string {
|
||||
func (a *Assembler) Label(mnemonic Mnemonic, name string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &Label{
|
||||
Name: name,
|
||||
},
|
||||
Type: TypeLabel,
|
||||
Index: Index(len(a.Param.Label)),
|
||||
})
|
||||
|
||||
a.Param.Label = append(a.Param.Label, Label{
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
|
@ -56,6 +56,9 @@ func (mem *Memory) String() string {
|
||||
func (a *Assembler) Memory(mnemonic Mnemonic, address Memory) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &address,
|
||||
Type: TypeMemory,
|
||||
Index: Index(len(a.Param.Memory)),
|
||||
})
|
||||
|
||||
a.Param.Memory = append(a.Param.Memory, address)
|
||||
}
|
||||
|
@ -15,9 +15,12 @@ func (data *MemoryLabel) String() string {
|
||||
func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &MemoryLabel{
|
||||
Address: address,
|
||||
Label: label,
|
||||
},
|
||||
Type: TypeMemoryLabel,
|
||||
Index: Index(len(a.Param.MemoryLabel)),
|
||||
})
|
||||
|
||||
a.Param.MemoryLabel = append(a.Param.MemoryLabel, MemoryLabel{
|
||||
Address: address,
|
||||
Label: label,
|
||||
})
|
||||
}
|
||||
|
@ -17,9 +17,12 @@ func (data *MemoryNumber) String() string {
|
||||
func (a *Assembler) MemoryNumber(mnemonic Mnemonic, address Memory, number int) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &MemoryNumber{
|
||||
Address: address,
|
||||
Number: number,
|
||||
},
|
||||
Type: TypeMemoryNumber,
|
||||
Index: Index(len(a.Param.MemoryNumber)),
|
||||
})
|
||||
|
||||
a.Param.MemoryNumber = append(a.Param.MemoryNumber, MemoryNumber{
|
||||
Address: address,
|
||||
Number: number,
|
||||
})
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ func (data *MemoryRegister) String() string {
|
||||
func (a *Assembler) MemoryRegister(mnemonic Mnemonic, address Memory, register cpu.Register) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &MemoryRegister{
|
||||
Address: address,
|
||||
Register: register,
|
||||
},
|
||||
Type: TypeMemoryRegister,
|
||||
Index: Index(len(a.Param.MemoryRegister)),
|
||||
})
|
||||
|
||||
a.Param.MemoryRegister = append(a.Param.MemoryRegister, MemoryRegister{
|
||||
Address: address,
|
||||
Register: register,
|
||||
})
|
||||
}
|
||||
|
46
src/asm/Merge.go
Normal file
46
src/asm/Merge.go
Normal file
@ -0,0 +1,46 @@
|
||||
package asm
|
||||
|
||||
import "maps"
|
||||
|
||||
// Merge combines the contents of this assembler with another one.
|
||||
func (a *Assembler) Merge(b *Assembler) {
|
||||
maps.Copy(a.Data, b.Data)
|
||||
from := len(a.Instructions)
|
||||
a.Instructions = append(a.Instructions, b.Instructions...)
|
||||
|
||||
for i := from; i < len(a.Instructions); i++ {
|
||||
switch a.Instructions[i].Type {
|
||||
case TypeLabel:
|
||||
a.Instructions[i].Index += Index(len(a.Param.Label))
|
||||
case TypeNumber:
|
||||
a.Instructions[i].Index += Index(len(a.Param.Number))
|
||||
case TypeRegister:
|
||||
a.Instructions[i].Index += Index(len(a.Param.Register))
|
||||
case TypeRegisterLabel:
|
||||
a.Instructions[i].Index += Index(len(a.Param.RegisterLabel))
|
||||
case TypeRegisterNumber:
|
||||
a.Instructions[i].Index += Index(len(a.Param.RegisterNumber))
|
||||
case TypeRegisterRegister:
|
||||
a.Instructions[i].Index += Index(len(a.Param.RegisterRegister))
|
||||
case TypeMemory:
|
||||
a.Instructions[i].Index += Index(len(a.Param.Memory))
|
||||
case TypeMemoryLabel:
|
||||
a.Instructions[i].Index += Index(len(a.Param.MemoryLabel))
|
||||
case TypeMemoryNumber:
|
||||
a.Instructions[i].Index += Index(len(a.Param.MemoryNumber))
|
||||
case TypeMemoryRegister:
|
||||
a.Instructions[i].Index += Index(len(a.Param.MemoryRegister))
|
||||
}
|
||||
}
|
||||
|
||||
a.Param.Label = append(a.Param.Label, b.Param.Label...)
|
||||
a.Param.Number = append(a.Param.Number, b.Param.Number...)
|
||||
a.Param.Register = append(a.Param.Register, b.Param.Register...)
|
||||
a.Param.RegisterLabel = append(a.Param.RegisterLabel, b.Param.RegisterLabel...)
|
||||
a.Param.RegisterNumber = append(a.Param.RegisterNumber, b.Param.RegisterNumber...)
|
||||
a.Param.RegisterRegister = append(a.Param.RegisterRegister, b.Param.RegisterRegister...)
|
||||
a.Param.Memory = append(a.Param.Memory, b.Param.Memory...)
|
||||
a.Param.MemoryLabel = append(a.Param.MemoryLabel, b.Param.MemoryLabel...)
|
||||
a.Param.MemoryNumber = append(a.Param.MemoryNumber, b.Param.MemoryNumber...)
|
||||
a.Param.MemoryRegister = append(a.Param.MemoryRegister, b.Param.MemoryRegister...)
|
||||
}
|
@ -18,8 +18,11 @@ func (data *Number) String() string {
|
||||
func (a *Assembler) Number(mnemonic Mnemonic, number int) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &Number{
|
||||
Number: number,
|
||||
},
|
||||
Type: TypeNumber,
|
||||
Index: Index(len(a.Param.Number)),
|
||||
})
|
||||
|
||||
a.Param.Number = append(a.Param.Number, Number{
|
||||
Number: number,
|
||||
})
|
||||
}
|
||||
|
15
src/asm/Param.go
Normal file
15
src/asm/Param.go
Normal file
@ -0,0 +1,15 @@
|
||||
package asm
|
||||
|
||||
// Param stores all the parameters for the instructions.
|
||||
type Param struct {
|
||||
Label []Label
|
||||
Number []Number
|
||||
Register []Register
|
||||
RegisterLabel []RegisterLabel
|
||||
RegisterNumber []RegisterNumber
|
||||
RegisterRegister []RegisterRegister
|
||||
Memory []Memory
|
||||
MemoryLabel []MemoryLabel
|
||||
MemoryNumber []MemoryNumber
|
||||
MemoryRegister []MemoryRegister
|
||||
}
|
@ -18,8 +18,11 @@ func (data *Register) String() string {
|
||||
func (a *Assembler) Register(mnemonic Mnemonic, register cpu.Register) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &Register{
|
||||
Register: register,
|
||||
},
|
||||
Type: TypeRegister,
|
||||
Index: Index(len(a.Param.Register)),
|
||||
})
|
||||
|
||||
a.Param.Register = append(a.Param.Register, Register{
|
||||
Register: register,
|
||||
})
|
||||
}
|
||||
|
@ -18,12 +18,15 @@ func (data *RegisterLabel) String() string {
|
||||
}
|
||||
|
||||
// RegisterLabel adds an instruction with a register and a label.
|
||||
func (a *Assembler) RegisterLabel(mnemonic Mnemonic, reg cpu.Register, label string) {
|
||||
func (a *Assembler) RegisterLabel(mnemonic Mnemonic, register cpu.Register, label string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &RegisterLabel{
|
||||
Register: reg,
|
||||
Label: label,
|
||||
},
|
||||
Type: TypeRegisterLabel,
|
||||
Index: Index(len(a.Param.RegisterLabel)),
|
||||
})
|
||||
|
||||
a.Param.RegisterLabel = append(a.Param.RegisterLabel, RegisterLabel{
|
||||
Register: register,
|
||||
Label: label,
|
||||
})
|
||||
}
|
||||
|
@ -18,12 +18,15 @@ func (data *RegisterNumber) String() string {
|
||||
}
|
||||
|
||||
// RegisterNumber adds an instruction with a register and a number.
|
||||
func (a *Assembler) RegisterNumber(mnemonic Mnemonic, reg cpu.Register, number int) {
|
||||
func (a *Assembler) RegisterNumber(mnemonic Mnemonic, register cpu.Register, number int) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &RegisterNumber{
|
||||
Register: reg,
|
||||
Number: number,
|
||||
},
|
||||
Type: TypeRegisterNumber,
|
||||
Index: Index(len(a.Param.RegisterNumber)),
|
||||
})
|
||||
|
||||
a.Param.RegisterNumber = append(a.Param.RegisterNumber, RegisterNumber{
|
||||
Register: register,
|
||||
Number: number,
|
||||
})
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ func (data *RegisterRegister) String() string {
|
||||
func (a *Assembler) RegisterRegister(mnemonic Mnemonic, left cpu.Register, right cpu.Register) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: mnemonic,
|
||||
Data: &RegisterRegister{
|
||||
Destination: left,
|
||||
Source: right,
|
||||
},
|
||||
Type: TypeRegisterRegister,
|
||||
Index: Index(len(a.Param.RegisterRegister)),
|
||||
})
|
||||
|
||||
a.Param.RegisterRegister = append(a.Param.RegisterRegister, RegisterRegister{
|
||||
Destination: left,
|
||||
Source: right,
|
||||
})
|
||||
}
|
||||
|
12
src/asm/SetData.go
Normal file
12
src/asm/SetData.go
Normal file
@ -0,0 +1,12 @@
|
||||
package asm
|
||||
|
||||
import "git.urbach.dev/cli/q/src/data"
|
||||
|
||||
// SetData sets the data for the given label.
|
||||
func (a *Assembler) SetData(label string, bytes []byte) {
|
||||
if a.Data == nil {
|
||||
a.Data = data.Data{}
|
||||
}
|
||||
|
||||
a.Data.Insert(label, bytes)
|
||||
}
|
17
src/asm/Type.go
Normal file
17
src/asm/Type.go
Normal file
@ -0,0 +1,17 @@
|
||||
package asm
|
||||
|
||||
type Type uint8
|
||||
|
||||
const (
|
||||
TypeNone Type = iota
|
||||
TypeLabel
|
||||
TypeNumber
|
||||
TypeRegister
|
||||
TypeRegisterLabel
|
||||
TypeRegisterNumber
|
||||
TypeRegisterRegister
|
||||
TypeMemory
|
||||
TypeMemoryLabel
|
||||
TypeMemoryNumber
|
||||
TypeMemoryRegister
|
||||
)
|
36
src/asm/bench_test.go
Normal file
36
src/asm/bench_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package asm_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
)
|
||||
|
||||
func BenchmarkMerge(b *testing.B) {
|
||||
n := 100
|
||||
all := make([]*asm.Assembler, 0, n)
|
||||
|
||||
for range n {
|
||||
f := &asm.Assembler{}
|
||||
f.Number(asm.PUSH, 1)
|
||||
f.Number(asm.PUSH, 2)
|
||||
f.Number(asm.PUSH, 3)
|
||||
all = append(all, f)
|
||||
}
|
||||
|
||||
for b.Loop() {
|
||||
final := asm.Assembler{}
|
||||
|
||||
for _, f := range all {
|
||||
final.Merge(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNumber(b *testing.B) {
|
||||
a := asm.Assembler{}
|
||||
|
||||
for b.Loop() {
|
||||
a.Number(asm.PUSH, 42)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user