Something went wrong. Try again.
🌱 A minimal programming language and compiler. git.urbach.dev/cli/q
high-performance programming-language compiler
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899package arm
import ( "encoding/binary"
"git.urbach.dev/cli/q/src/cpu")
// MoveRegisterNumber moves a number into the given register.func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte { instruction, encodable := MoveRegisterNumberSI(destination, number)
if encodable { return binary.LittleEndian.AppendUint32(code, instruction) }
return MoveRegisterNumberMI(code, destination, number)}
// MoveRegisterNumberMI moves a number into the given register using movz and a series of movk instructions.func MoveRegisterNumberMI(code []byte, destination cpu.Register, number int) []byte { movz := MoveZero(destination, 0, uint16(number)) code = binary.LittleEndian.AppendUint32(code, movz) num := uint64(number) halfword := 1
for { num >>= 16
if num == 0 { return code }
movk := MoveKeep(destination, halfword, uint16(num)) code = binary.LittleEndian.AppendUint32(code, movk) halfword++ }}
// MoveRegisterNumberSI moves a number into the given register using a single instruction.func MoveRegisterNumberSI(destination cpu.Register, number int) (uint32, bool) { if cpu.SizeInt(number) <= 2 { if number < 0 { return MoveInvertedNumber(destination, uint16(^number), 0), true }
return MoveZero(destination, 0, uint16(number)), true }
if (number&0xFFFFFFFFFFFF == 0xFFFFFFFFFFFF) && cpu.SizeInt(number>>48) <= 2 { return MoveInvertedNumber(destination, uint16((^number)>>48), 3), true }
code, encodable := MoveBitmaskNumber(destination, number)
if encodable { return code, true }
if (number&0xFFFFFFFF == 0xFFFFFFFF) && cpu.SizeInt(number>>32) <= 2 { return MoveInvertedNumber(destination, uint16((^number)>>32), 2), true }
if (number&0xFFFF == 0xFFFF) && cpu.SizeInt(number>>16) <= 2 { return MoveInvertedNumber(destination, uint16((^number)>>16), 1), true }
return 0, false}
// MoveRegisterRegister copies a register to another register.func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 { if source == SP || destination == SP { code, _ := AddRegisterNumber(destination, source, 0) return code }
return OrRegisterRegister(destination, ZR, source)}
// MoveBitmaskNumber moves a bitmask immediate value to a register.func MoveBitmaskNumber(destination cpu.Register, number int) (uint32, bool) { return OrRegisterNumber(destination, ZR, number)}
// MoveInvertedNumber moves an inverted 16-bit immediate value to a register.func MoveInvertedNumber(destination cpu.Register, number uint16, shift uint32) uint32 { return 0b100100101<<23 | shift<<21 | regImm(destination, number)}
// MoveKeep moves a 16-bit integer into the given register and keeps all other bits.func MoveKeep(destination cpu.Register, halfword int, number uint16) uint32 { return 0b111100101<<23 | regImmHw(destination, halfword, number)}
// MoveZero moves a 16-bit integer into the given register and clears all other bits to zero.func MoveZero(destination cpu.Register, halfword int, number uint16) uint32 { return 0b110100101<<23 | regImmHw(destination, halfword, number)}