Improved assembler performance
This commit is contained in:
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
// 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()
|
||||
|
||||
if config.TargetOS == config.Windows && len(data) == 0 {
|
||||
@ -15,6 +15,7 @@ func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
||||
}
|
||||
|
||||
c := compiler{
|
||||
assembler: a,
|
||||
code: make([]byte, 0, len(a.Instructions)*8),
|
||||
codeLabels: make(map[string]Address, 32),
|
||||
codePointers: make([]*pointer, 0, len(a.Instructions)*8),
|
||||
|
@ -8,8 +8,9 @@ import (
|
||||
)
|
||||
|
||||
func (c *compiler) call(x asm.Instruction) {
|
||||
switch data := x.Data.(type) {
|
||||
case *asm.Label:
|
||||
switch x.Type {
|
||||
case asm.TypeLabel:
|
||||
data := c.assembler.Param.Label[x.Index]
|
||||
c.code = x86.Call(c.code, 0x00_00_00_00)
|
||||
size := 4
|
||||
|
||||
@ -32,10 +33,12 @@ func (c *compiler) call(x asm.Instruction) {
|
||||
|
||||
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)
|
||||
|
||||
case *asm.Memory:
|
||||
case asm.TypeMemory:
|
||||
data := c.assembler.Param.Memory[x.Index]
|
||||
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,9 @@ import (
|
||||
func (c *compiler) compileARM(x asm.Instruction) {
|
||||
switch x.Mnemonic {
|
||||
case asm.CALL:
|
||||
switch data := x.Data.(type) {
|
||||
case *asm.Label:
|
||||
switch x.Type {
|
||||
case asm.TypeLabel:
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.Call(0))
|
||||
|
||||
@ -25,10 +26,10 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[data.Name]
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := (destination - position) / 4
|
||||
@ -39,13 +40,16 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
}
|
||||
|
||||
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(0x910003fd)
|
||||
|
||||
case asm.LOAD:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.MemoryRegister:
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int16(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
@ -55,14 +59,17 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
||||
}
|
||||
|
||||
case asm.MOVE:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterRegister:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
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))
|
||||
|
||||
case *asm.RegisterLabel:
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.LoadAddress(operands.Register, 0))
|
||||
|
||||
|
@ -8,40 +8,49 @@ import (
|
||||
func (c *compiler) compileX86(x asm.Instruction) {
|
||||
switch x.Mnemonic {
|
||||
case asm.ADD:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
case asm.AND:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
case asm.SUB:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
case asm.MUL:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
case asm.DIV:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterRegister:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
@ -55,8 +64,9 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
}
|
||||
|
||||
case asm.MODULO:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterRegister:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
@ -76,10 +86,12 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
return
|
||||
|
||||
case asm.COMPARE:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
@ -90,7 +102,7 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
c.jump(x)
|
||||
|
||||
case asm.LABEL:
|
||||
label := x.Data.(*asm.Label)
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
|
||||
case asm.LOAD:
|
||||
@ -100,30 +112,36 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
c.move(x)
|
||||
|
||||
case asm.NEGATE:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.Register:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.NegateRegister(c.code, operands.Register)
|
||||
}
|
||||
|
||||
case asm.OR:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
case asm.POP:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.Register:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.PopRegister(c.code, operands.Register)
|
||||
}
|
||||
|
||||
case asm.PUSH:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.Number:
|
||||
switch x.Type {
|
||||
case asm.TypeNumber:
|
||||
operands := c.assembler.Param.Number[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
@ -131,14 +149,16 @@ func (c *compiler) compileX86(x asm.Instruction) {
|
||||
c.code = x86.Return(c.code)
|
||||
|
||||
case asm.SHIFTL:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
}
|
||||
|
||||
case asm.SHIFTRS:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
|
||||
case asm.XOR:
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
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 {
|
||||
assembler *asm.Assembler
|
||||
code []byte
|
||||
data []byte
|
||||
codeLabels map[string]Address
|
||||
|
@ -8,10 +8,10 @@ import (
|
||||
)
|
||||
|
||||
func (c *compiler) dllCall(x asm.Instruction) {
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
||||
next := Address(len(c.code))
|
||||
position := next - 4
|
||||
label := x.Data.(*asm.Label)
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(position),
|
||||
|
@ -25,8 +25,8 @@ func (c *compiler) jump(x asm.Instruction) {
|
||||
c.code = x86.Jump8(c.code, 0x00)
|
||||
}
|
||||
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
size := 1
|
||||
label := x.Data.(*asm.Label)
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
|
@ -8,8 +8,10 @@ import (
|
||||
)
|
||||
|
||||
func (c *compiler) load(x asm.Instruction) {
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.MemoryRegister:
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
||||
} else {
|
||||
|
@ -8,14 +8,17 @@ import (
|
||||
)
|
||||
|
||||
func (c *compiler) move(x asm.Instruction) {
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.RegisterNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
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)
|
||||
|
||||
case *asm.RegisterLabel:
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||
start := Address(len(c.code))
|
||||
c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00)
|
||||
end := Address(len(c.code))
|
||||
|
@ -9,14 +9,17 @@ import (
|
||||
)
|
||||
|
||||
func (c *compiler) store(x asm.Instruction) {
|
||||
switch operands := x.Data.(type) {
|
||||
case *asm.MemoryNumber:
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryNumber:
|
||||
operands := c.assembler.Param.MemoryNumber[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Number)
|
||||
} else {
|
||||
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)
|
||||
|
||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||
@ -27,14 +30,13 @@ func (c *compiler) store(x asm.Instruction) {
|
||||
|
||||
size := 4
|
||||
opSize := len(c.code) - size - start
|
||||
memLabel := x.Data.(*asm.MemoryLabel)
|
||||
|
||||
c.codePointers = append(c.codePointers, &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(size),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.codeLabels[memLabel.Label]
|
||||
destination, exists := c.codeLabels[operands.Label]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
@ -43,7 +45,9 @@ func (c *compiler) store(x asm.Instruction) {
|
||||
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 {
|
||||
c.code = x86.StoreRegister(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Register)
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user