Improved assembler performance
This commit is contained in:
@ -1,28 +1,10 @@
|
|||||||
package asm
|
package asm
|
||||||
|
|
||||||
import (
|
import "git.urbach.dev/cli/q/src/data"
|
||||||
"maps"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/data"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Assembler contains a list of instructions.
|
// Assembler contains a list of instructions.
|
||||||
type Assembler struct {
|
type Assembler struct {
|
||||||
Data data.Data
|
Data data.Data
|
||||||
Instructions []Instruction
|
Instructions []Instruction
|
||||||
}
|
Param Param
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,12 @@ func (a *Assembler) CanSkip(mnemonic Mnemonic, left cpu.Register, right cpu.Regi
|
|||||||
last := a.Instructions[len(a.Instructions)-1]
|
last := a.Instructions[len(a.Instructions)-1]
|
||||||
|
|
||||||
if mnemonic == MOVE && last.Mnemonic == MOVE {
|
if mnemonic == MOVE && last.Mnemonic == MOVE {
|
||||||
lastData, isRegReg := last.Data.(*RegisterRegister)
|
if last.Type != TypeRegisterRegister {
|
||||||
|
|
||||||
if !isRegReg {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastData := a.Param.RegisterRegister[last.Index]
|
||||||
|
|
||||||
if lastData.Destination == right && lastData.Source == left {
|
if lastData.Destination == right && lastData.Source == left {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@ func (a *Assembler) CanSkipReturn() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if last.Mnemonic == CALL {
|
if last.Mnemonic == CALL && last.Type == TypeLabel {
|
||||||
label, isLabel := last.Data.(*Label)
|
label := a.Param.Label[last.Index]
|
||||||
|
|
||||||
if isLabel && label.String() == "core.exit" {
|
if label.String() == "core.exit" {
|
||||||
return true
|
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
|
package asm
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Instruction represents a single instruction which can be converted to machine code.
|
// Instruction represents a single instruction which can be converted to machine code.
|
||||||
type Instruction struct {
|
type Instruction struct {
|
||||||
Data fmt.Stringer
|
|
||||||
Mnemonic Mnemonic
|
Mnemonic Mnemonic
|
||||||
|
Type Type
|
||||||
|
Index Index
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,12 @@ package asm
|
|||||||
|
|
||||||
// Comment adds a comment at the current position.
|
// Comment adds a comment at the current position.
|
||||||
func (a *Assembler) Comment(text string) {
|
func (a *Assembler) Comment(text string) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Label(COMMENT, text)
|
||||||
Mnemonic: COMMENT,
|
|
||||||
Data: &Label{
|
|
||||||
Name: text,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DLLCall calls a function in a DLL file.
|
// DLLCall calls a function in a DLL file.
|
||||||
func (a *Assembler) DLLCall(name string) {
|
func (a *Assembler) DLLCall(name string) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Label(DLLCALL, name)
|
||||||
Mnemonic: DLLCALL,
|
|
||||||
Data: &Label{
|
|
||||||
Name: name,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return returns back to the caller.
|
// Return returns back to the caller.
|
||||||
|
@ -14,8 +14,11 @@ func (data *Label) String() string {
|
|||||||
func (a *Assembler) Label(mnemonic Mnemonic, name string) {
|
func (a *Assembler) Label(mnemonic Mnemonic, name string) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &Label{
|
Type: TypeLabel,
|
||||||
Name: name,
|
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) {
|
func (a *Assembler) Memory(mnemonic Mnemonic, address Memory) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
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) {
|
func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label string) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &MemoryLabel{
|
Type: TypeMemoryLabel,
|
||||||
Address: address,
|
Index: Index(len(a.Param.MemoryLabel)),
|
||||||
Label: label,
|
})
|
||||||
},
|
|
||||||
|
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) {
|
func (a *Assembler) MemoryNumber(mnemonic Mnemonic, address Memory, number int) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &MemoryNumber{
|
Type: TypeMemoryNumber,
|
||||||
Address: address,
|
Index: Index(len(a.Param.MemoryNumber)),
|
||||||
Number: number,
|
})
|
||||||
},
|
|
||||||
|
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) {
|
func (a *Assembler) MemoryRegister(mnemonic Mnemonic, address Memory, register cpu.Register) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &MemoryRegister{
|
Type: TypeMemoryRegister,
|
||||||
Address: address,
|
Index: Index(len(a.Param.MemoryRegister)),
|
||||||
Register: register,
|
})
|
||||||
},
|
|
||||||
|
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) {
|
func (a *Assembler) Number(mnemonic Mnemonic, number int) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &Number{
|
Type: TypeNumber,
|
||||||
Number: number,
|
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) {
|
func (a *Assembler) Register(mnemonic Mnemonic, register cpu.Register) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &Register{
|
Type: TypeRegister,
|
||||||
Register: register,
|
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.
|
// 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{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &RegisterLabel{
|
Type: TypeRegisterLabel,
|
||||||
Register: reg,
|
Index: Index(len(a.Param.RegisterLabel)),
|
||||||
Label: label,
|
})
|
||||||
},
|
|
||||||
|
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.
|
// 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{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &RegisterNumber{
|
Type: TypeRegisterNumber,
|
||||||
Register: reg,
|
Index: Index(len(a.Param.RegisterNumber)),
|
||||||
Number: number,
|
})
|
||||||
},
|
|
||||||
|
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) {
|
func (a *Assembler) RegisterRegister(mnemonic Mnemonic, left cpu.Register, right cpu.Register) {
|
||||||
a.Instructions = append(a.Instructions, Instruction{
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
Mnemonic: mnemonic,
|
Mnemonic: mnemonic,
|
||||||
Data: &RegisterRegister{
|
Type: TypeRegisterRegister,
|
||||||
Destination: left,
|
Index: Index(len(a.Param.RegisterRegister)),
|
||||||
Source: right,
|
})
|
||||||
},
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Finalize generates the final machine code.
|
// Finalize generates the final machine code.
|
||||||
func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
func Finalize(a *asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
||||||
data, dataLabels := a.Data.Finalize()
|
data, dataLabels := a.Data.Finalize()
|
||||||
|
|
||||||
if config.TargetOS == config.Windows && len(data) == 0 {
|
if config.TargetOS == config.Windows && len(data) == 0 {
|
||||||
@ -15,6 +15,7 @@ func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := compiler{
|
c := compiler{
|
||||||
|
assembler: a,
|
||||||
code: make([]byte, 0, len(a.Instructions)*8),
|
code: make([]byte, 0, len(a.Instructions)*8),
|
||||||
codeLabels: make(map[string]Address, 32),
|
codeLabels: make(map[string]Address, 32),
|
||||||
codePointers: make([]*pointer, 0, len(a.Instructions)*8),
|
codePointers: make([]*pointer, 0, len(a.Instructions)*8),
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) call(x asm.Instruction) {
|
func (c *compiler) call(x asm.Instruction) {
|
||||||
switch data := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.Label:
|
case asm.TypeLabel:
|
||||||
|
data := c.assembler.Param.Label[x.Index]
|
||||||
c.code = x86.Call(c.code, 0x00_00_00_00)
|
c.code = x86.Call(c.code, 0x00_00_00_00)
|
||||||
size := 4
|
size := 4
|
||||||
|
|
||||||
@ -32,10 +33,12 @@ func (c *compiler) call(x asm.Instruction) {
|
|||||||
|
|
||||||
c.codePointers = append(c.codePointers, pointer)
|
c.codePointers = append(c.codePointers, pointer)
|
||||||
|
|
||||||
case *asm.Register:
|
case asm.TypeRegister:
|
||||||
|
data := c.assembler.Param.Register[x.Index]
|
||||||
c.code = x86.CallRegister(c.code, data.Register)
|
c.code = x86.CallRegister(c.code, data.Register)
|
||||||
|
|
||||||
case *asm.Memory:
|
case asm.TypeMemory:
|
||||||
|
data := c.assembler.Param.Memory[x.Index]
|
||||||
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,9 @@ import (
|
|||||||
func (c *compiler) compileARM(x asm.Instruction) {
|
func (c *compiler) compileARM(x asm.Instruction) {
|
||||||
switch x.Mnemonic {
|
switch x.Mnemonic {
|
||||||
case asm.CALL:
|
case asm.CALL:
|
||||||
switch data := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.Label:
|
case asm.TypeLabel:
|
||||||
|
label := c.assembler.Param.Label[x.Index]
|
||||||
position := Address(len(c.code))
|
position := Address(len(c.code))
|
||||||
c.append(arm.Call(0))
|
c.append(arm.Call(0))
|
||||||
|
|
||||||
@ -25,10 +26,10 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pointer.Resolve = func() Address {
|
pointer.Resolve = func() Address {
|
||||||
destination, exists := c.codeLabels[data.Name]
|
destination, exists := c.codeLabels[label.Name]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
distance := (destination - position) / 4
|
distance := (destination - position) / 4
|
||||||
@ -39,13 +40,16 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case asm.LABEL:
|
case asm.LABEL:
|
||||||
c.codeLabels[x.Data.(*asm.Label).Name] = Address(len(c.code))
|
label := c.assembler.Param.Label[x.Index]
|
||||||
|
c.codeLabels[label.Name] = Address(len(c.code))
|
||||||
c.append(0xa9be7bfd)
|
c.append(0xa9be7bfd)
|
||||||
c.append(0x910003fd)
|
c.append(0x910003fd)
|
||||||
|
|
||||||
case asm.LOAD:
|
case asm.LOAD:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.MemoryRegister:
|
case asm.TypeMemoryRegister:
|
||||||
|
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||||
|
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int16(operands.Address.Offset), operands.Address.Length))
|
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int16(operands.Address.Offset), operands.Address.Length))
|
||||||
} else {
|
} else {
|
||||||
@ -55,14 +59,17 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case asm.MOVE:
|
case asm.MOVE:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
||||||
|
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.append(arm.MoveRegisterNumber(operands.Register, operands.Number))
|
c.append(arm.MoveRegisterNumber(operands.Register, operands.Number))
|
||||||
|
|
||||||
case *asm.RegisterLabel:
|
case asm.TypeRegisterLabel:
|
||||||
|
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||||
position := Address(len(c.code))
|
position := Address(len(c.code))
|
||||||
c.append(arm.LoadAddress(operands.Register, 0))
|
c.append(arm.LoadAddress(operands.Register, 0))
|
||||||
|
|
||||||
|
@ -8,40 +8,49 @@ import (
|
|||||||
func (c *compiler) compileX86(x asm.Instruction) {
|
func (c *compiler) compileX86(x asm.Instruction) {
|
||||||
switch x.Mnemonic {
|
switch x.Mnemonic {
|
||||||
case asm.ADD:
|
case asm.ADD:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.AddRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.AddRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.AddRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.AddRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.AND:
|
case asm.AND:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.AndRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.AndRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.AndRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.AndRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.SUB:
|
case asm.SUB:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.SubRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.SubRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.SubRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.SubRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.MUL:
|
case asm.MUL:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.MulRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.MulRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.MulRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.MulRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.DIV:
|
case asm.DIV:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
if operands.Destination != x86.RAX {
|
if operands.Destination != x86.RAX {
|
||||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||||
}
|
}
|
||||||
@ -55,8 +64,9 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case asm.MODULO:
|
case asm.MODULO:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
if operands.Destination != x86.RAX {
|
if operands.Destination != x86.RAX {
|
||||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||||
}
|
}
|
||||||
@ -76,10 +86,12 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
case asm.COMPARE:
|
case asm.COMPARE:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.CompareRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.CompareRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.CompareRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.CompareRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +102,7 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
c.jump(x)
|
c.jump(x)
|
||||||
|
|
||||||
case asm.LABEL:
|
case asm.LABEL:
|
||||||
label := x.Data.(*asm.Label)
|
label := c.assembler.Param.Label[x.Index]
|
||||||
c.codeLabels[label.Name] = Address(len(c.code))
|
c.codeLabels[label.Name] = Address(len(c.code))
|
||||||
|
|
||||||
case asm.LOAD:
|
case asm.LOAD:
|
||||||
@ -100,30 +112,36 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
c.move(x)
|
c.move(x)
|
||||||
|
|
||||||
case asm.NEGATE:
|
case asm.NEGATE:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.Register:
|
case asm.TypeRegister:
|
||||||
|
operands := c.assembler.Param.Register[x.Index]
|
||||||
c.code = x86.NegateRegister(c.code, operands.Register)
|
c.code = x86.NegateRegister(c.code, operands.Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.OR:
|
case asm.OR:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.OrRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.OrRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.OrRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.OrRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.POP:
|
case asm.POP:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.Register:
|
case asm.TypeRegister:
|
||||||
|
operands := c.assembler.Param.Register[x.Index]
|
||||||
c.code = x86.PopRegister(c.code, operands.Register)
|
c.code = x86.PopRegister(c.code, operands.Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.PUSH:
|
case asm.PUSH:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.Number:
|
case asm.TypeNumber:
|
||||||
|
operands := c.assembler.Param.Number[x.Index]
|
||||||
c.code = x86.PushNumber(c.code, int32(operands.Number))
|
c.code = x86.PushNumber(c.code, int32(operands.Number))
|
||||||
case *asm.Register:
|
case asm.TypeRegister:
|
||||||
|
operands := c.assembler.Param.Register[x.Index]
|
||||||
c.code = x86.PushRegister(c.code, operands.Register)
|
c.code = x86.PushRegister(c.code, operands.Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,14 +149,16 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
c.code = x86.Return(c.code)
|
c.code = x86.Return(c.code)
|
||||||
|
|
||||||
case asm.SHIFTL:
|
case asm.SHIFTL:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.SHIFTRS:
|
case asm.SHIFTRS:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.ShiftRightSignedNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
c.code = x86.ShiftRightSignedNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,10 +169,12 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
|||||||
c.code = x86.Syscall(c.code)
|
c.code = x86.Syscall(c.code)
|
||||||
|
|
||||||
case asm.XOR:
|
case asm.XOR:
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.XorRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.XorRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.XorRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.XorRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package asmc
|
package asmc
|
||||||
|
|
||||||
import "git.urbach.dev/cli/q/src/dll"
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
|
"git.urbach.dev/cli/q/src/dll"
|
||||||
|
)
|
||||||
|
|
||||||
type compiler struct {
|
type compiler struct {
|
||||||
|
assembler *asm.Assembler
|
||||||
code []byte
|
code []byte
|
||||||
data []byte
|
data []byte
|
||||||
codeLabels map[string]Address
|
codeLabels map[string]Address
|
||||||
|
@ -8,10 +8,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) dllCall(x asm.Instruction) {
|
func (c *compiler) dllCall(x asm.Instruction) {
|
||||||
|
label := c.assembler.Param.Label[x.Index]
|
||||||
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
||||||
next := Address(len(c.code))
|
next := Address(len(c.code))
|
||||||
position := next - 4
|
position := next - 4
|
||||||
label := x.Data.(*asm.Label)
|
|
||||||
|
|
||||||
pointer := &pointer{
|
pointer := &pointer{
|
||||||
Position: Address(position),
|
Position: Address(position),
|
||||||
|
@ -25,8 +25,8 @@ func (c *compiler) jump(x asm.Instruction) {
|
|||||||
c.code = x86.Jump8(c.code, 0x00)
|
c.code = x86.Jump8(c.code, 0x00)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label := c.assembler.Param.Label[x.Index]
|
||||||
size := 1
|
size := 1
|
||||||
label := x.Data.(*asm.Label)
|
|
||||||
|
|
||||||
pointer := &pointer{
|
pointer := &pointer{
|
||||||
Position: Address(len(c.code) - size),
|
Position: Address(len(c.code) - size),
|
||||||
|
@ -8,8 +8,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) load(x asm.Instruction) {
|
func (c *compiler) load(x asm.Instruction) {
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.MemoryRegister:
|
case asm.TypeMemoryRegister:
|
||||||
|
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||||
|
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) move(x asm.Instruction) {
|
func (c *compiler) move(x asm.Instruction) {
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.RegisterNumber:
|
case asm.TypeRegisterNumber:
|
||||||
|
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||||
c.code = x86.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
c.code = x86.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
|
|
||||||
case *asm.RegisterRegister:
|
case asm.TypeRegisterRegister:
|
||||||
|
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, operands.Source)
|
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||||
|
|
||||||
case *asm.RegisterLabel:
|
case asm.TypeRegisterLabel:
|
||||||
|
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||||
start := Address(len(c.code))
|
start := Address(len(c.code))
|
||||||
c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00)
|
c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00)
|
||||||
end := Address(len(c.code))
|
end := Address(len(c.code))
|
||||||
|
@ -9,14 +9,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) store(x asm.Instruction) {
|
func (c *compiler) store(x asm.Instruction) {
|
||||||
switch operands := x.Data.(type) {
|
switch x.Type {
|
||||||
case *asm.MemoryNumber:
|
case asm.TypeMemoryNumber:
|
||||||
|
operands := c.assembler.Param.MemoryNumber[x.Index]
|
||||||
|
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Number)
|
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Number)
|
||||||
} else {
|
} else {
|
||||||
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Number)
|
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Number)
|
||||||
}
|
}
|
||||||
case *asm.MemoryLabel:
|
case asm.TypeMemoryLabel:
|
||||||
|
operands := c.assembler.Param.MemoryLabel[x.Index]
|
||||||
start := len(c.code)
|
start := len(c.code)
|
||||||
|
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
@ -27,14 +30,13 @@ func (c *compiler) store(x asm.Instruction) {
|
|||||||
|
|
||||||
size := 4
|
size := 4
|
||||||
opSize := len(c.code) - size - start
|
opSize := len(c.code) - size - start
|
||||||
memLabel := x.Data.(*asm.MemoryLabel)
|
|
||||||
|
|
||||||
c.codePointers = append(c.codePointers, &pointer{
|
c.codePointers = append(c.codePointers, &pointer{
|
||||||
Position: Address(len(c.code) - size),
|
Position: Address(len(c.code) - size),
|
||||||
OpSize: uint8(opSize),
|
OpSize: uint8(opSize),
|
||||||
Size: uint8(size),
|
Size: uint8(size),
|
||||||
Resolve: func() Address {
|
Resolve: func() Address {
|
||||||
destination, exists := c.codeLabels[memLabel.Label]
|
destination, exists := c.codeLabels[operands.Label]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
panic("unknown label")
|
panic("unknown label")
|
||||||
@ -43,7 +45,9 @@ func (c *compiler) store(x asm.Instruction) {
|
|||||||
return config.BaseAddress + c.codeStart + destination
|
return config.BaseAddress + c.codeStart + destination
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
case *asm.MemoryRegister:
|
case asm.TypeMemoryRegister:
|
||||||
|
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||||
|
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
c.code = x86.StoreRegister(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Register)
|
c.code = x86.StoreRegister(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Register)
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,8 +105,7 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions <
|
|||||||
return result, function.Err
|
return result, function.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.InstructionCount += len(function.Assembler.Instructions)
|
result.Count(function)
|
||||||
result.DataCount += len(function.Assembler.Data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for unused imports in all files
|
// Check for unused imports in all files
|
||||||
|
@ -7,13 +7,12 @@ import (
|
|||||||
|
|
||||||
// Result contains everything we need to write an executable file to disk.
|
// Result contains everything we need to write an executable file to disk.
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Init *core.Function
|
Init *core.Function
|
||||||
Main *core.Function
|
Main *core.Function
|
||||||
Functions map[string]*core.Function
|
Functions map[string]*core.Function
|
||||||
Traversed map[*core.Function]bool
|
Traversed map[*core.Function]bool
|
||||||
Code []byte
|
Code []byte
|
||||||
Data []byte
|
Data []byte
|
||||||
DLLs dll.List
|
DLLs dll.List
|
||||||
InstructionCount int
|
Statistics
|
||||||
DataCount int
|
|
||||||
}
|
}
|
||||||
|
35
src/compiler/Statistics.go
Normal file
35
src/compiler/Statistics.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package compiler
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/core"
|
||||||
|
|
||||||
|
// Statistics contains counters for all functions in the build.
|
||||||
|
type Statistics struct {
|
||||||
|
InstructionCount int
|
||||||
|
DataCount int
|
||||||
|
LabelCount int
|
||||||
|
NumberCount int
|
||||||
|
RegisterCount int
|
||||||
|
RegisterLabelCount int
|
||||||
|
RegisterNumberCount int
|
||||||
|
RegisterRegisterCount int
|
||||||
|
MemoryCount int
|
||||||
|
MemoryLabelCount int
|
||||||
|
MemoryNumberCount int
|
||||||
|
MemoryRegisterCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count adds statistics for this function.
|
||||||
|
func (s *Statistics) Count(function *core.Function) {
|
||||||
|
s.InstructionCount += len(function.Assembler.Instructions)
|
||||||
|
s.DataCount += len(function.Assembler.Data)
|
||||||
|
s.LabelCount += len(function.Assembler.Param.Label)
|
||||||
|
s.NumberCount += len(function.Assembler.Param.Number)
|
||||||
|
s.RegisterCount += len(function.Assembler.Param.Register)
|
||||||
|
s.RegisterLabelCount += len(function.Assembler.Param.RegisterLabel)
|
||||||
|
s.RegisterNumberCount += len(function.Assembler.Param.RegisterNumber)
|
||||||
|
s.RegisterRegisterCount += len(function.Assembler.Param.RegisterRegister)
|
||||||
|
s.MemoryCount += len(function.Assembler.Param.Memory)
|
||||||
|
s.MemoryLabelCount += len(function.Assembler.Param.MemoryLabel)
|
||||||
|
s.MemoryNumberCount += len(function.Assembler.Param.MemoryNumber)
|
||||||
|
s.MemoryRegisterCount += len(function.Assembler.Param.MemoryRegister)
|
||||||
|
}
|
@ -17,6 +17,18 @@ func (r *Result) finalize() {
|
|||||||
final := asm.Assembler{
|
final := asm.Assembler{
|
||||||
Instructions: make([]asm.Instruction, 0, r.InstructionCount+8),
|
Instructions: make([]asm.Instruction, 0, r.InstructionCount+8),
|
||||||
Data: make(map[string][]byte, r.DataCount),
|
Data: make(map[string][]byte, r.DataCount),
|
||||||
|
Param: asm.Param{
|
||||||
|
Label: make([]asm.Label, 0, r.LabelCount),
|
||||||
|
Number: make([]asm.Number, 0, r.NumberCount),
|
||||||
|
Register: make([]asm.Register, 0, r.RegisterCount),
|
||||||
|
RegisterLabel: make([]asm.RegisterLabel, 0, r.RegisterLabelCount),
|
||||||
|
RegisterNumber: make([]asm.RegisterNumber, 0, r.RegisterNumberCount),
|
||||||
|
RegisterRegister: make([]asm.RegisterRegister, 0, r.RegisterRegisterCount),
|
||||||
|
Memory: make([]asm.Memory, 0, r.MemoryCount),
|
||||||
|
MemoryLabel: make([]asm.MemoryLabel, 0, r.MemoryLabelCount),
|
||||||
|
MemoryNumber: make([]asm.MemoryNumber, 0, r.MemoryNumberCount),
|
||||||
|
MemoryRegister: make([]asm.MemoryRegister, 0, r.MemoryRegisterCount),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Traversed = make(map[*core.Function]bool, len(r.Functions))
|
r.Traversed = make(map[*core.Function]bool, len(r.Functions))
|
||||||
@ -24,7 +36,7 @@ func (r *Result) finalize() {
|
|||||||
// This will place the init function immediately after the entry point
|
// This will place the init function immediately after the entry point
|
||||||
// and also add everything the init function calls recursively.
|
// and also add everything the init function calls recursively.
|
||||||
r.eachFunction(r.Init, r.Traversed, func(f *core.Function) {
|
r.eachFunction(r.Init, r.Traversed, func(f *core.Function) {
|
||||||
final.Merge(f.Assembler)
|
final.Merge(&f.Assembler)
|
||||||
|
|
||||||
for _, library := range f.DLLs {
|
for _, library := range f.DLLs {
|
||||||
for _, fn := range library.Functions {
|
for _, fn := range library.Functions {
|
||||||
@ -50,5 +62,5 @@ func (r *Result) finalize() {
|
|||||||
final.DLLCall("kernel32.ExitProcess")
|
final.DLLCall("kernel32.ExitProcess")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Code, r.Data = asmc.Finalize(final, r.DLLs)
|
r.Code, r.Data = asmc.Finalize(&final, r.DLLs)
|
||||||
}
|
}
|
||||||
|
@ -26,19 +26,16 @@ func (f *Function) PrintInstructions() {
|
|||||||
|
|
||||||
switch x.Mnemonic {
|
switch x.Mnemonic {
|
||||||
case asm.LABEL:
|
case asm.LABEL:
|
||||||
ansi.Yellow.Printf("%-44s", x.Data.String()+":")
|
label := f.Assembler.Param.Label[x.Index]
|
||||||
|
ansi.Yellow.Printf("%-44s", label.String()+":")
|
||||||
|
|
||||||
case asm.COMMENT:
|
case asm.COMMENT:
|
||||||
ansi.Dim.Printf("%-44s", x.Data.String())
|
label := f.Assembler.Param.Label[x.Index]
|
||||||
|
ansi.Dim.Printf("%-44s", label.String())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ansi.Green.Printf("%-12s", x.Mnemonic.String())
|
ansi.Green.Printf("%-12s", x.Mnemonic.String())
|
||||||
|
fmt.Printf("%-32s", x.DataString(&f.Assembler))
|
||||||
if x.Data != nil {
|
|
||||||
fmt.Printf("%-32s", x.Data.String())
|
|
||||||
} else {
|
|
||||||
fmt.Printf("%-32s", "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registers := bytes.Buffer{}
|
registers := bytes.Buffer{}
|
||||||
|
Reference in New Issue
Block a user