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) }