1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2018-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * arch.go 12 * 13 * Created on May 26, 2018 14 * Author Massimiliano Ghilardi 15 */ 16 17package arm64 18 19import ( 20 "fmt" 21 22 "github.com/cosmos72/gomacro/jit/common" 23) 24 25type Arm64 struct { 26} 27 28func init() { 29 common.Archs[ARM64] = Arm64{} 30} 31 32// implement Arch interface 33func (Arm64) Id() ArchId { 34 return ARM64 35} 36 37func (Arm64) String() string { 38 return NAME 39} 40 41func (Arm64) RegIdConfig() RegIdConfig { 42 return RegIdConfig{ 43 RLo: RLo, 44 RHi: RHi, 45 RSP: RSP, 46 RVAR: RVAR, 47 RAllocFirst: RLo, 48 } 49} 50 51func (Arm64) RegIdValid(id RegId) bool { 52 return id >= RLo && id < RHi // XZR/XSP is valid only in few, hand-checked cases 53} 54 55func (Arm64) RegIdString(id RegId) string { 56 var s string 57 if id >= RLo && id <= RHi { 58 s = regName8[id] 59 } 60 if s == "" { 61 s = fmt.Sprintf("unknown_reg(%#x)", uint8(id)) 62 } 63 return s 64} 65 66func (Arm64) RegValid(r Reg) bool { 67 // XZR/XSP is valid only in few, hand-checked cases 68 return r.RegId().Valid() && r.Kind().Size() != 0 69} 70 71func (Arm64) RegString(r Reg) string { 72 var s string 73 id := r.RegId() 74 if id >= RLo && id <= RHi { 75 switch r.Kind().Size() { 76 case 1, 2, 4: 77 s = regName4[id] 78 case 8: 79 s = regName8[id] 80 } 81 } 82 if s == "" { 83 s = fmt.Sprintf("unknown_reg(%#x,%v)", uint8(id), r.Kind()) 84 } 85 return s 86} 87 88func (arch Arm64) MemString(m Mem) string { 89 var regstr string 90 regid := m.RegId() 91 if regid == XZR { 92 regstr = "xsp" 93 } else { 94 regstr = arch.RegIdString(regid) 95 } 96 return fmt.Sprintf("%v@{%s+%v}", m.Kind(), regstr, m.Offset()) 97 98} 99 100// print arm64 machine code as sequence of 4-byte instructions 101func (Arm64) CodeString(code MachineCode) string { 102 const hexdigit string = "0123456789abcdef" 103 bytes := code.Bytes 104 i, j, n := 0, 0, len(bytes) 105 buf := make([]byte, (n+3)/4*9) 106 for ; i+4 <= n; i += 4 { 107 buf[j+0] = hexdigit[bytes[i+3]>>4] 108 buf[j+1] = hexdigit[bytes[i+3]&0xF] 109 buf[j+2] = hexdigit[bytes[i+2]>>4] 110 buf[j+3] = hexdigit[bytes[i+2]&0xF] 111 buf[j+4] = hexdigit[bytes[i+1]>>4] 112 buf[j+5] = hexdigit[bytes[i+1]&0xF] 113 buf[j+6] = hexdigit[bytes[i+0]>>4] 114 buf[j+7] = hexdigit[bytes[i+0]&0xF] 115 buf[j+8] = ' ' 116 j += 9 117 } 118 for k := n - 1; k >= i; k-- { 119 buf[j+0] = hexdigit[bytes[k]>>4] 120 buf[j+1] = hexdigit[bytes[k]&0xF] 121 j += 2 122 } 123 return string(buf[:j]) 124} 125 126// Prologue used to add the following instruction to generated code, 127// but now it does nothing, because adding ANY code is the user's responsibility: 128// ldr x29, [sp, #8] 129// equivalent to: 130// asm.Asm(MOV, MakeMem(8, XSP, Uint64), MakeReg(X29, Uint64)) 131func (Arm64) Prologue(asm *Asm) *Asm { 132 // return asm.Uint32(0xf94007fd) 133 // equivalent: 134 // return asm.Asm(MOV, MakeMem(8, XSP, Uint64), MakeReg(X29, Uint64)) 135 return asm 136} 137 138func (arch Arm64) Epilogue(asm *Asm) *Asm { 139 return arch.Op0(asm, RET) 140} 141 142func (Arm64) Init(asm *Asm, start SaveSlot, end SaveSlot) *Asm { 143 asm.RegIncUse(X28) // pointer to goroutine-local data 144 asm.RegIncUse(X30) // return address register 145 asm.RegIncUse(XZR) // zero register / stack pointer 146 return asm 147} 148