q/src/asmc/compileARM.go

274 lines
8.0 KiB
Go

package asmc
import (
"encoding/binary"
"fmt"
"git.urbach.dev/cli/q/src/arm"
"git.urbach.dev/cli/q/src/asm"
)
func (c *compiler) compileARM(x asm.Instruction) {
switch x.Mnemonic {
case asm.CALL:
switch x.Type {
case asm.TypeLabel:
label := c.assembler.Param.Label[x.Index]
position := Address(len(c.code))
c.append(arm.Call(0))
pointer := &pointer{
Position: position,
OpSize: 0,
Size: 4,
}
pointer.Resolve = func() Address {
destination, exists := c.codeLabels[label.Name]
if !exists {
panic(fmt.Sprintf("unknown jump label %s", label.Name))
}
distance := (destination - position) / 4
return arm.Call(distance)
}
c.codePointers = append(c.codePointers, pointer)
default:
panic("not implemented")
}
case asm.LABEL:
label := c.assembler.Param.Label[x.Index]
c.codeLabels[label.Name] = Address(len(c.code))
if label.Type == asm.FunctionLabel {
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
}
case asm.LOAD:
switch x.Type {
case asm.TypeMemoryRegister:
operands := c.assembler.Param.MemoryRegister[x.Index]
if operands.Address.OffsetRegister < 0 {
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
} else {
panic("not implemented")
}
}
case asm.STORE:
switch x.Type {
case asm.TypeMemoryRegister:
operands := c.assembler.Param.MemoryRegister[x.Index]
if operands.Address.OffsetRegister < 0 {
c.append(arm.StoreRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
} else {
panic("not implemented")
}
case asm.TypeMemoryNumber:
operands := c.assembler.Param.MemoryNumber[x.Index]
if operands.Address.OffsetRegister < 0 {
tmp := arm.X28
c.code = arm.MoveRegisterNumber(c.code, tmp, operands.Number)
c.append(arm.StoreRegister(tmp, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
} else {
panic("not implemented")
}
}
case asm.PUSH:
switch x.Type {
case asm.TypeRegister:
operand := c.assembler.Param.Register[x.Index]
c.append(arm.SubRegisterNumber(arm.SP, arm.SP, 16))
c.append(arm.StoreRegister(operand.Register, arm.SP, 0, 8))
}
case asm.POP:
switch x.Type {
case asm.TypeRegister:
operand := c.assembler.Param.Register[x.Index]
c.append(arm.LoadRegister(operand.Register, arm.SP, 0, 8))
c.append(arm.AddRegisterNumber(arm.SP, arm.SP, 16))
}
case asm.AND:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
code, encodable := arm.AndRegisterNumber(operand.Register, operand.Register, operand.Number)
if encodable {
c.append(code)
} else {
tmp := arm.X28
c.code = arm.MoveRegisterNumberMI(c.code, tmp, operand.Number)
c.append(arm.AndRegisterRegister(operand.Register, operand.Register, tmp))
}
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.AndRegisterRegister(operand.Destination, operand.Destination, operand.Source))
}
case asm.OR:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
code, encodable := arm.OrRegisterNumber(operand.Register, operand.Register, operand.Number)
if encodable {
c.append(code)
} else {
tmp := arm.X28
c.code = arm.MoveRegisterNumberMI(c.code, tmp, operand.Number)
c.append(arm.OrRegisterRegister(operand.Register, operand.Register, tmp))
}
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.OrRegisterRegister(operand.Destination, operand.Destination, operand.Source))
}
case asm.XOR:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
code, encodable := arm.XorRegisterNumber(operand.Register, operand.Register, operand.Number)
if encodable {
c.append(code)
} else {
tmp := arm.X28
c.code = arm.MoveRegisterNumberMI(c.code, tmp, operand.Number)
c.append(arm.XorRegisterRegister(operand.Register, operand.Register, tmp))
}
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.XorRegisterRegister(operand.Destination, operand.Destination, operand.Source))
}
case asm.ADD:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
c.append(arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number))
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.AddRegisterRegister(operand.Destination, operand.Destination, operand.Source))
}
case asm.SUB:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
c.append(arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number))
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.SubRegisterRegister(operand.Destination, operand.Destination, operand.Source))
}
case asm.COMPARE:
switch x.Type {
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
c.append(arm.CompareRegisterNumber(operand.Register, operand.Number))
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.CompareRegisterRegister(operand.Destination, operand.Source))
}
case asm.DIV:
switch x.Type {
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.DivSigned(operand.Destination, operand.Destination, operand.Source))
case asm.TypeRegisterNumber:
panic("not implemented")
}
case asm.MUL:
switch x.Type {
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.MulRegisterRegister(operand.Destination, operand.Destination, operand.Source))
case asm.TypeRegisterNumber:
operand := c.assembler.Param.RegisterNumber[x.Index]
tmp := arm.X28
c.code = arm.MoveRegisterNumber(c.code, tmp, operand.Number)
c.append(arm.MulRegisterRegister(operand.Register, operand.Register, tmp))
}
case asm.MODULO:
switch x.Type {
case asm.TypeRegisterRegister:
operand := c.assembler.Param.RegisterRegister[x.Index]
tmp := arm.X28
c.append(arm.DivSigned(tmp, operand.Destination, operand.Source))
c.append(arm.MultiplySubtract(operand.Destination, tmp, operand.Source, operand.Destination))
case asm.TypeRegisterNumber:
panic("not implemented")
}
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
c.jumpARM(x)
case asm.MOVE:
switch x.Type {
case asm.TypeRegisterRegister:
operands := c.assembler.Param.RegisterRegister[x.Index]
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
case asm.TypeRegisterNumber:
operands := c.assembler.Param.RegisterNumber[x.Index]
c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
case asm.TypeRegisterLabel:
operands := c.assembler.Param.RegisterLabel[x.Index]
position := Address(len(c.code))
c.append(arm.LoadAddress(operands.Register, 0))
if operands.Label.Type == asm.DataLabel {
c.dataPointers = append(c.dataPointers, &pointer{
Position: position,
OpSize: 0,
Size: 4,
Resolve: func() Address {
destination, exists := c.dataLabels[operands.Label.Name]
if !exists {
panic("unknown label")
}
destination += c.dataStart - c.codeStart
distance := destination - position + 8
return arm.LoadAddress(operands.Register, int(distance))
},
})
} else {
panic("not implemented")
}
}
case asm.RETURN:
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
c.append(arm.Return())
case asm.SYSCALL:
c.append(arm.Syscall())
default:
panic("unknown mnemonic: " + x.Mnemonic.String())
}
}
func (c *compiler) append(code uint32) {
c.code = binary.LittleEndian.AppendUint32(c.code, code)
}